diff --git a/doc/qtcreator/src/debugger/creator-debug-views.qdoc b/doc/qtcreator/src/debugger/creator-debug-views.qdoc index 8880b64218b..ad8d948c753 100644 --- a/doc/qtcreator/src/debugger/creator-debug-views.qdoc +++ b/doc/qtcreator/src/debugger/creator-debug-views.qdoc @@ -146,7 +146,8 @@ \generatelist studio-how-to-debug \else - \sa {Debug}{How To: Debug}, {Debugging}, {Debuggers}, {Debugger} + \sa {Add breakpoints}, {Debug}{How To: Debug}, {Debugging}, {Debuggers}, + {Debugger} \endif */ diff --git a/qt_attributions.json b/qt_attributions.json index 987502609df..008ff353943 100644 --- a/qt_attributions.json +++ b/qt_attributions.json @@ -612,11 +612,11 @@ "QDocModule": "qtcreator", "QtParts": ["tools"], "QtUsage": "Used for async/await support in Lua modules.", - "Path": "src/plugins/lua/bindings", + "Path": "src/plugins/lua/scripts", "Description": "lua-async-await implements the async/await pattern in Lua.", "Homepage": "https://github.com/ms-jpq/lua-async-await", "License": "MIT License", - "LicenseFile": "src/plugins/lua/bindings/ASYNC-LICENSE.txt", + "LicenseFile": "src/plugins/lua/scripts/ASYNC-LICENSE.txt", "Copyright": "Copyright (c) 2008 Paul Evans" }, { @@ -625,11 +625,11 @@ "QDocModule": "qtcreator", "QtParts": ["tools"], "QtUsage": "Used for pretty printing from Lua scripts.", - "Path": "share/qtcreator/lua-plugins/luatests", + "Path": "src/plugins/lua/scripts", "Description": "inspect.lua is a library for pretty printing complex objects in Lua.", "Homepage": "https://github.com/kikito/inspect.lua", "License": "MIT License", - "LicenseFile": "share/qtcreator/lua-plugins/luatests/INSPECT-LICENSE.txt", + "LicenseFile": "src/plugins/lua/scripts/INSPECT-LICENSE.txt", "Copyright": "Copyright (c) 2022 Enrique García Cota" }, { @@ -662,4 +662,3 @@ "Copyright": "Copyright 2011 The Apache Software Foundation" } ] - diff --git a/share/qtcreator/templates/wizards/projects/consoleapp/CMakeLists-Qt6.txt b/share/qtcreator/templates/wizards/projects/consoleapp/CMakeLists-Qt6.txt index a4161a01f5d..162310fb356 100644 --- a/share/qtcreator/templates/wizards/projects/consoleapp/CMakeLists-Qt6.txt +++ b/share/qtcreator/templates/wizards/projects/consoleapp/CMakeLists-Qt6.txt @@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.19) project(%{ProjectName} LANGUAGES CXX) @if %{HasTranslation} -find_package(Qt6 REQUIRED COMPONENTS Core LinguistTools) +find_package(Qt6 6.5 REQUIRED COMPONENTS Core LinguistTools) @else -find_package(Qt6 REQUIRED COMPONENTS Core) +find_package(Qt6 6.5 REQUIRED COMPONENTS Core) @endif qt_standard_project_setup() @@ -25,6 +25,8 @@ target_link_libraries(%{ProjectName} Qt::Core ) +include(GNUInstallDirs) + install(TARGETS %{ProjectName} BUNDLE DESTINATION . RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} diff --git a/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json b/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json index 9e59d4d8c33..759ec220f85 100644 --- a/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json +++ b/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json @@ -58,7 +58,7 @@ "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" }, { - "trKey": "CMake for Qt 6", + "trKey": "CMake for Qt 6.5 and Later", "value": "cmake-qt6", "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" }, diff --git a/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json index 7ce0c621901..a1534182145 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json @@ -152,11 +152,6 @@ "target": "%{ProjectDirectory}/%{ImportModuleName}/Constants.qml", "condition": "%{QdsProjectStyle}" }, - { - "source": "%{QdsWizardPath}/shared-plugin/name/DirectoryFontLoader.qml.tpl", - "target": "%{ProjectDirectory}/%{ImportModuleName}/DirectoryFontLoader.qml", - "condition": "%{QdsProjectStyle}" - }, { "source": "%{QdsWizardPath}/shared-plugin/name/EventListModel.qml.tpl", "target": "%{ProjectDirectory}/%{ImportModuleName}/EventListModel.qml", diff --git a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists-Qt6.txt b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists-Qt6.txt index 7f63269cdd0..f2395d7a0b5 100644 --- a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists-Qt6.txt +++ b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists-Qt6.txt @@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.19) project(%{ProjectName} LANGUAGES CXX) @if %{HasTranslation} -find_package(Qt6 REQUIRED COMPONENTS Core Widgets LinguistTools) +find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets LinguistTools) @else -find_package(Qt6 REQUIRED COMPONENTS Core Widgets) +find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets) @endif qt_standard_project_setup() @@ -32,6 +32,8 @@ target_link_libraries(%{ProjectName} Qt::Widgets ) +include(GNUInstallDirs) + install(TARGETS %{ProjectName} BUNDLE DESTINATION . RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} diff --git a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json index 9e3fd48bca3..de20629065d 100644 --- a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json @@ -64,7 +64,7 @@ "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" }, { - "trKey": "CMake for Qt 6", + "trKey": "CMake for Qt 6.5 and Later", "value": "cmake-qt6", "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" }, diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index f645ae120b9..8bc892f3070 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -15239,12 +15239,12 @@ Zum Beispiel bewirkt die Angabe "Revision: 15" dass der Branch auf Rev Fallback-Stil: - Clang Format command: - Ausführbare Datei von Clang Format: + ClangFormat command: + Ausführbare Datei von ClangFormat: - Clang Format - Clang Format + ClangFormat + ClangFormat Use file uncrustify.cfg defined in project files diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index 7b728df9070..6014cf39f1d 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -15352,12 +15352,12 @@ Par exemple, « Revision : 15 » laissera la branche à la révis Style de repli : - Clang Format command: - Commande de Clang Format : + ClangFormat command: + Commande de ClangFormat : - Clang Format - Clang Format + ClangFormat + ClangFormat No description available. diff --git a/src/app/main.cpp b/src/app/main.cpp index 9da6030f5e5..755169fc8db 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -418,12 +418,11 @@ bool startCrashpad(const AppInfo &appInfo, bool crashReportingEnabled) const QString databasePath = appInfo.crashReports.path(); const QString handlerPath = (appInfo.libexec / "crashpad_handler").path(); #ifdef Q_OS_WIN - handlerPath += ".exe"; base::FilePath database(databasePath.toStdWString()); - base::FilePath handler(handlerPath.toStdWString()); + base::FilePath handler(HostOsInfo::withExecutableSuffix(handlerPath).toStdWString()); #elif defined(Q_OS_MACOS) || defined(Q_OS_LINUX) base::FilePath database(databasePath.toStdString()); - base::FilePath handler(handlerPath.toStdString()); + base::FilePath handler(HostOsInfo::withExecutableSuffix(handlerPath).toStdString()); #endif std::unique_ptr db = CrashReportDatabase::Initialize(database); diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp index dc1f0085bec..e15c495f6ea 100644 --- a/src/libs/advanceddockingsystem/dockmanager.cpp +++ b/src/libs/advanceddockingsystem/dockmanager.cpp @@ -1311,7 +1311,7 @@ expected_str DockManager::cloneWorkspace(const QString &originalFileNam const FilePath clonePath = workspaceNameToFilePath(cloneName); - const expected_str copyResult = originalPath.copyFile(clonePath); + const Result copyResult = originalPath.copyFile(clonePath); if (!copyResult) return make_unexpected(Tr::tr("Could not clone \"%1\" due to: %2") .arg(originalPath.toUserOutput(), copyResult.error())); @@ -1337,21 +1337,21 @@ expected_str DockManager::renameWorkspace(const QString &originalFileNa return originalFileName; } -expected_str DockManager::resetWorkspacePreset(const QString &fileName) +Result DockManager::resetWorkspacePreset(const QString &fileName) { qCInfo(adsLog) << "Reset workspace" << fileName; Workspace *w = workspace(fileName); if (!w) - return make_unexpected(Tr::tr("Workspace \"%1\" does not exist.").arg(fileName)); + return Result::Error(Tr::tr("Workspace \"%1\" does not exist.").arg(fileName)); if (!w->isPreset()) - return make_unexpected(Tr::tr("Workspace \"%1\" is not a preset.").arg(fileName)); + return Result::Error(Tr::tr("Workspace \"%1\" is not a preset.").arg(fileName)); const FilePath filePath = w->filePath(); if (!filePath.removeFile()) - return make_unexpected(Tr::tr("Cannot remove \"%1\".").arg(filePath.toUserOutput())); + return Result::Error(Tr::tr("Cannot remove \"%1\".").arg(filePath.toUserOutput())); return presetDirectory().pathAppended(fileName).copyFile(filePath); } @@ -1400,7 +1400,7 @@ expected_str DockManager::importWorkspace(const QString &filePath) const FilePath targetFilePath = userDirectory().pathAppended(fileName); - const expected_str copyResult = sourceFilePath.copyFile(targetFilePath); + const Result copyResult = sourceFilePath.copyFile(targetFilePath); if (!copyResult) return make_unexpected( Tr::tr("Could not copy \"%1\" to \"%2\" due to: %3") @@ -1441,7 +1441,7 @@ expected_str DockManager::exportWorkspace(const QString &targetFilePath Tr::tr("The workspace \"%1\" does not exist ").arg(workspaceFile.toUserOutput())); // Finally copy the workspace to the target - const expected_str copyResult = workspaceFile.copyFile(targetFile); + const Result copyResult = workspaceFile.copyFile(targetFile); if (!copyResult) return make_unexpected( Tr::tr("Could not copy \"%1\" to \"%2\" due to: %3") @@ -1675,7 +1675,7 @@ void DockManager::syncWorkspacePresets() continue; } - const expected_str copyResult = filePath.copyFile( + const Result copyResult = filePath.copyFile( userDirectory().pathAppended(filePath.fileName())); if (!copyResult) qWarning() << QString("Could not copy '%1' to '%2' due to %3") diff --git a/src/libs/advanceddockingsystem/dockmanager.h b/src/libs/advanceddockingsystem/dockmanager.h index f0e30a5418a..aa527be8861 100644 --- a/src/libs/advanceddockingsystem/dockmanager.h +++ b/src/libs/advanceddockingsystem/dockmanager.h @@ -739,7 +739,7 @@ public: Utils::expected_str renameWorkspace(const QString &originalFileName, const QString &newName); - Utils::expected_str resetWorkspacePreset(const QString &fileName); + Utils::Result resetWorkspacePreset(const QString &fileName); /** * \brief Save the currently active workspace. diff --git a/src/libs/gocmdbridge/client/bridgedfileaccess.cpp b/src/libs/gocmdbridge/client/bridgedfileaccess.cpp index dcd17b23e30..67e864047c7 100644 --- a/src/libs/gocmdbridge/client/bridgedfileaccess.cpp +++ b/src/libs/gocmdbridge/client/bridgedfileaccess.cpp @@ -33,61 +33,60 @@ expected_str run(const CommandLine &cmdLine, const QByteArray &inputDat return p.readAllStandardOutput().trimmed(); } -Utils::expected_str FileAccess::init(const Utils::FilePath &pathToBridge) +Result FileAccess::init(const FilePath &pathToBridge) { m_client = std::make_unique(pathToBridge); auto startResult = m_client->start(); if (!startResult) - return make_unexpected(QString("Could not start cmdbridge: %1").arg(startResult.error())); + return Result::Error(QString("Could not start cmdbridge: %1").arg(startResult.error())); try { if (!startResult->isValid()) startResult->waitForFinished(); m_environment = startResult->takeResult(); } catch (const std::exception &e) { - return make_unexpected( + return Result::Error( Tr::tr("Error starting cmdbridge: %1").arg(QString::fromLocal8Bit(e.what()))); } - return {}; + return Result::Ok; } -expected_str FileAccess::deployAndInit( - const FilePath &libExecPath, const FilePath &remoteRootPath) +Result FileAccess::deployAndInit(const FilePath &libExecPath, const FilePath &remoteRootPath) { if (remoteRootPath.isEmpty()) - return make_unexpected(Tr::tr("Remote root path is empty")); + return Result::Error(Tr::tr("Remote root path is empty")); if (!remoteRootPath.isAbsolutePath()) - return make_unexpected(Tr::tr("Remote root path is not absolute")); + return Result::Error(Tr::tr("Remote root path is not absolute")); const auto whichDD = run({remoteRootPath.withNewPath("which"), {"dd"}}); if (!whichDD) // TODO: Support Windows? - return make_unexpected(Tr::tr("Could not find dd on remote host: %1").arg(whichDD.error())); + return Result::Error(Tr::tr("Could not find dd on remote host: %1").arg(whichDD.error())); qCDebug(faLog) << "Found dd on remote host:" << *whichDD; const expected_str unameOs = run({remoteRootPath.withNewPath("uname"), {"-s"}}); if (!unameOs) { - return make_unexpected( + return Result::Error( QString("Could not determine OS on remote host: %1").arg(unameOs.error())); } Utils::expected_str osType = osTypeFromString(*unameOs); if (!osType) - return make_unexpected(osType.error()); + return Result::Error(osType.error()); qCDebug(faLog) << "Remote host OS:" << *unameOs; const expected_str unameArch = run({remoteRootPath.withNewPath("uname"), {"-m"}}); if (!unameArch) { - return make_unexpected( + return Result::Error( QString("Could not determine architecture on remote host: %1").arg(unameArch.error())); } const Utils::expected_str osArch = osArchFromString(*unameArch); if (!osArch) - return make_unexpected(osArch.error()); + return Result::Error(osArch.error()); qCDebug(faLog) << "Remote host architecture:" << *unameArch; @@ -95,7 +94,7 @@ expected_str FileAccess::deployAndInit( = Client::getCmdBridgePath(*osType, *osArch, libExecPath); if (!cmdBridgePath) { - return make_unexpected( + return Result::Error( QString("Could not determine compatible cmdbridge for remote host: %1") .arg(cmdBridgePath.error())); } @@ -106,7 +105,7 @@ expected_str FileAccess::deployAndInit( const auto cmdBridgeFileData = cmdBridgePath->fileContents(); if (!cmdBridgeFileData) { - return make_unexpected( + return Result::Error( QString("Could not read cmdbridge file: %1").arg(cmdBridgeFileData.error())); } @@ -114,7 +113,7 @@ expected_str FileAccess::deployAndInit( {remoteRootPath.withNewPath("mktemp"), {"-t", "cmdbridge.XXXXXXXXXX"}}); if (!tmpFile) { - return make_unexpected( + return Result::Error( QString("Could not create temporary file: %1").arg(tmpFile.error())); } @@ -125,7 +124,7 @@ expected_str FileAccess::deployAndInit( const auto makeExecutable = run({remoteRootPath.withNewPath("chmod"), {"+x", *tmpFile}}); if (!makeExecutable) { - return make_unexpected( + return Result::Error( QString("Could not make temporary file executable: %1").arg(makeExecutable.error())); } @@ -468,26 +467,26 @@ expected_str FileAccess::writeFileContents(const FilePath &filePath, } } -expected_str FileAccess::removeFile(const Utils::FilePath &filePath) const +Result FileAccess::removeFile(const FilePath &filePath) const { try { Utils::expected_str> f = m_client->removeFile(filePath.nativePath()); if (!f) - return make_unexpected(f.error()); + return Result::Error(f.error()); f->waitForFinished(); } catch (const std::system_error &e) { if (e.code().value() == ENOENT) - return make_unexpected(Tr::tr("File does not exist")); + return Result::Error(Tr::tr("File does not exist")); qCWarning(faLog) << "Error removing file:" << e.what(); - return make_unexpected( + return Result::Error( Tr::tr("Error removing file: %1").arg(QString::fromLocal8Bit(e.what()))); } catch (const std::exception &e) { qCWarning(faLog) << "Error removing file:" << e.what(); - return make_unexpected( + return Result::Error( Tr::tr("Error removing file: %1").arg(QString::fromLocal8Bit(e.what()))); } - return {}; + return Result::Ok; } bool FileAccess::removeRecursively(const Utils::FilePath &filePath, QString *error) const @@ -530,37 +529,35 @@ bool FileAccess::createDirectory(const Utils::FilePath &filePath) const } } -expected_str FileAccess::copyFile(const Utils::FilePath &filePath, - const Utils::FilePath &target) const +Result FileAccess::copyFile(const FilePath &filePath, const FilePath &target) const { try { auto f = m_client->copyFile(filePath.nativePath(), target.nativePath()); - QTC_ASSERT_EXPECTED(f, return {}); + QTC_ASSERT_EXPECTED(f, return Result::Ok); f->waitForFinished(); - return {}; + return Result::Ok; } catch (const std::exception &e) { - return make_unexpected( + return Result::Error( Tr::tr("Error copying file: %1").arg(QString::fromLocal8Bit(e.what()))); } } -expected_str FileAccess::renameFile( - const Utils::FilePath &filePath, const Utils::FilePath &target) const +Result FileAccess::renameFile(const FilePath &filePath, const FilePath &target) const { try { Utils::expected_str> f = m_client->renameFile(filePath.nativePath(), target.nativePath()); if (!f) - return make_unexpected(f.error()); + return Result::Error(f.error()); f->waitForFinished(); if (!f) - return make_unexpected(f.error()); + return Result::Error(f.error()); } catch (const std::exception &e) { - return make_unexpected( + return Result::Error( Tr::tr("Error renaming file: %1").arg(QString::fromLocal8Bit(e.what()))); } - return {}; + return Result::Ok; } Environment FileAccess::deviceEnvironment() const @@ -574,15 +571,15 @@ expected_str> FileAccess::watch(const FilePath return m_client->watch(filePath.nativePath()); } -Utils::expected_str FileAccess::signalProcess(int pid, ControlSignal signal) const +Result FileAccess::signalProcess(int pid, ControlSignal signal) const { try { auto f = m_client->signalProcess(pid, signal); - QTC_ASSERT_EXPECTED(f, return {}); + QTC_ASSERT_EXPECTED(f, return Result::Ok); f->waitForFinished(); - return {}; + return Result::Ok; } catch (const std::exception &e) { - return make_unexpected( + return Result::Error( Tr::tr("Error killing process: %1").arg(QString::fromLocal8Bit(e.what()))); }; } diff --git a/src/libs/gocmdbridge/client/bridgedfileaccess.h b/src/libs/gocmdbridge/client/bridgedfileaccess.h index 2d6ffb72278..54fcbd58bc3 100644 --- a/src/libs/gocmdbridge/client/bridgedfileaccess.h +++ b/src/libs/gocmdbridge/client/bridgedfileaccess.h @@ -27,17 +27,17 @@ class QTCREATOR_CMDBRIDGE_EXPORT FileAccess : public Utils::DeviceFileAccess public: ~FileAccess() override; - Utils::expected_str deployAndInit( + Utils::Result deployAndInit( const Utils::FilePath &libExecPath, const Utils::FilePath &remoteRootPath); - Utils::expected_str init(const Utils::FilePath &pathToBridge); + Utils::Result init(const Utils::FilePath &pathToBridge); - Utils::expected_str signalProcess(int pid, Utils::ControlSignal signal) const; + Utils::Result signalProcess(int pid, Utils::ControlSignal signal) const; Utils::Environment deviceEnvironment() const override; protected: - Utils::expected_str reinit(); + Utils::Result reinit(); void iterateDirectory(const Utils::FilePath &filePath, const Utils::FilePath::IterateDirCallback &callBack, @@ -69,16 +69,16 @@ protected: Utils::expected_str writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const override; - Utils::expected_str removeFile(const Utils::FilePath &filePath) const override; + Utils::Result removeFile(const Utils::FilePath &filePath) const override; bool removeRecursively(const Utils::FilePath &filePath, QString *error) const override; bool ensureExistingFile(const Utils::FilePath &filePath) const override; bool createDirectory(const Utils::FilePath &filePath) const override; - Utils::expected_str copyFile(const Utils::FilePath &filePath, - const Utils::FilePath &target) const override; + Utils::Result copyFile(const Utils::FilePath &filePath, + const Utils::FilePath &target) const override; - Utils::expected_str renameFile( + Utils::Result renameFile( const Utils::FilePath &filePath, const Utils::FilePath &target) const override; Utils::expected_str createTempFile(const Utils::FilePath &filePath) override; diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 07150b3d00a..0eeb083d877 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -294,6 +294,14 @@ void BaseAspect::addLabeledItem(Layout &parent, QWidget *widget) } } +void BaseAspect::addLabeledItems(Layouting::Layout &parent, const QList &widgets) +{ + if (QLabel *l = createLabel()) + parent.addItem(l); + for (auto widget : widgets) + parent.addItem(widget); +} + /*! Sets \a labelText as text for the separate label in the visual representation of this aspect. @@ -3162,6 +3170,7 @@ void AspectContainer::addToLayoutImpl(Layouting::Layout &parent) void AspectContainer::registerAspect(BaseAspect *aspect, bool takeOwnership) { aspect->setAutoApply(isAutoApply()); + aspect->setEnabled(isEnabled()); d->m_items.append(aspect); if (takeOwnership) d->m_ownedItems.append(aspect); @@ -3316,6 +3325,14 @@ void AspectContainer::setUndoStack(QUndoStack *undoStack) aspect->setUndoStack(undoStack); } +void AspectContainer::setEnabled(bool enabled) +{ + BaseAspect::setEnabled(enabled); + + for (BaseAspect *aspect : std::as_const(d->m_items)) + aspect->setEnabled(enabled); +} + void AspectContainer::setMacroExpander(MacroExpander *expander) { BaseAspect::setMacroExpander(expander); diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index f1c59c908b2..6c3b62cdbe7 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -98,7 +98,7 @@ public: QUndoStack *undoStack() const; bool isEnabled() const; - void setEnabled(bool enabled); + virtual void setEnabled(bool enabled); void setEnabler(BoolAspect *checker); bool isReadOnly() const; @@ -237,6 +237,7 @@ protected: QLabel *createLabel(); void addLabeledItem(Layouting::Layout &parent, QWidget *widget); + void addLabeledItems(Layouting::Layout &parent, const QList &widgets); void setDataCreatorHelper(const DataCreator &creator) const; void setDataClonerHelper(const DataCloner &cloner) const; @@ -996,6 +997,7 @@ public: void setAutoApply(bool on) override; bool isDirty() override; void setUndoStack(QUndoStack *undoStack) override; + void setEnabled(bool enabled) override; void setMacroExpander(MacroExpander *expander); diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index ab07c83dee4..e318cc7df0a 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -117,22 +117,21 @@ bool DeviceFileAccess::hasHardLinks(const FilePath &filePath) const return false; } -expected_str DeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const +Result DeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const { if (isWritableDirectory(filePath)) - return {}; + return Result::Ok; if (exists(filePath)) { - return make_unexpected(Tr::tr("Path \"%1\" exists but is not a writable directory.") + return Result::Error(Tr::tr("Path \"%1\" exists but is not a writable directory.") .arg(filePath.toUserOutput())); } const bool result = createDirectory(filePath); if (result) - return {}; + return Result::Ok; - return make_unexpected( - Tr::tr("Failed to create directory \"%1\".").arg(filePath.toUserOutput())); + return Result::Error(Tr::tr("Failed to create directory \"%1\".").arg(filePath.toUserOutput())); } bool DeviceFileAccess::ensureExistingFile(const FilePath &filePath) const @@ -155,11 +154,10 @@ bool DeviceFileAccess::exists(const FilePath &filePath) const return false; } -expected_str DeviceFileAccess::removeFile(const FilePath &filePath) const +Result DeviceFileAccess::removeFile(const FilePath &filePath) const { - Q_UNUSED(filePath) QTC_CHECK(false); - return make_unexpected( + return Result::Error( Tr::tr("removeFile is not implemented for \"%1\".").arg(filePath.toUserOutput())); } @@ -171,18 +169,17 @@ bool DeviceFileAccess::removeRecursively(const FilePath &filePath, QString *erro return false; } -expected_str DeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const +Result DeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const { - Q_UNUSED(filePath) Q_UNUSED(target) QTC_CHECK(false); - return make_unexpected( + return Result::Error( Tr::tr("copyFile is not implemented for \"%1\".").arg(filePath.toUserOutput())); } -expected_str copyRecursively_fallback(const FilePath &src, const FilePath &target) +static Result copyRecursively_fallback(const FilePath &src, const FilePath &target) { - expected_str result; + Result result = Result::Ok; src.iterateDirectory( [&target, &src, &result](const FilePath &path) { const FilePath relative = path.relativePathFrom(src); @@ -202,16 +199,15 @@ expected_str copyRecursively_fallback(const FilePath &src, const FilePath return result; } -expected_str DeviceFileAccess::copyRecursively(const FilePath &src, - const FilePath &target) const +Result DeviceFileAccess::copyRecursively(const FilePath &src, const FilePath &target) const { if (!src.isDir()) { - return make_unexpected( + return Result::Error( Tr::tr("Cannot copy from \"%1\", it is not a directory.").arg(src.toUserOutput())); } - const expected_str result = target.ensureWritableDir(); + const Result result = target.ensureWritableDir(); if (!result) { - return make_unexpected(Tr::tr("Cannot copy \"%1\" to \"%2\": %3") + return Result::Error(Tr::tr("Cannot copy \"%1\" to \"%2\": %3") .arg(src.toUserOutput()) .arg(target.toUserOutput()) .arg(result.error())); @@ -254,7 +250,7 @@ expected_str DeviceFileAccess::copyRecursively(const FilePath &src, if (srcProcess.result() != ProcessResult::FinishedWithSuccess) { targetProcess.kill(); - return make_unexpected( + return Result::Error( Tr::tr("Failed to copy recursively from \"%1\" to \"%2\" while " "trying to create tar archive from source: %3") .arg(src.toUserOutput(), target.toUserOutput(), srcProcess.readAllStandardError())); @@ -263,23 +259,22 @@ expected_str DeviceFileAccess::copyRecursively(const FilePath &src, targetProcess.waitForFinished(); if (targetProcess.result() != ProcessResult::FinishedWithSuccess) { - return make_unexpected(Tr::tr("Failed to copy recursively from \"%1\" to \"%2\" while " + return Result::Error(Tr::tr("Failed to copy recursively from \"%1\" to \"%2\" while " "trying to extract tar archive to target: %3") .arg(src.toUserOutput(), target.toUserOutput(), targetProcess.readAllStandardError())); } - return {}; + return Result::Ok; #endif } -expected_str DeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const +Result DeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const { - Q_UNUSED(filePath) Q_UNUSED(target) QTC_CHECK(false); - return make_unexpected( + return Result::Error( Tr::tr("renameFile is not implemented for \"%1\".").arg(filePath.toUserOutput())); } @@ -684,22 +679,22 @@ bool DesktopDeviceFileAccess::hasHardLinks(const FilePath &filePath) const return false; } -expected_str DesktopDeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const +Result DesktopDeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const { const QFileInfo fi(filePath.path()); if (fi.isDir() && fi.isWritable()) - return {}; + return Result::Ok; if (fi.exists()) { - return make_unexpected(Tr::tr("Path \"%1\" exists but is not a writable directory.") + return Result::Error(Tr::tr("Path \"%1\" exists but is not a writable directory.") .arg(filePath.toUserOutput())); } const bool result = QDir().mkpath(filePath.path()); if (result) - return {}; + return Result::Ok; - return make_unexpected( + return Result::Error( Tr::tr("Failed to create directory \"%1\".").arg(filePath.toUserOutput())); } @@ -724,12 +719,12 @@ bool DesktopDeviceFileAccess::exists(const FilePath &filePath) const return !filePath.isEmpty() && QFileInfo::exists(filePath.path()); } -expected_str DesktopDeviceFileAccess::removeFile(const FilePath &filePath) const +Result DesktopDeviceFileAccess::removeFile(const FilePath &filePath) const { QFile f(filePath.path()); if (!f.remove()) - return make_unexpected(f.errorString()); - return {}; + return Result::Error(f.errorString()); + return Result::Ok; } static bool checkToRefuseRemoveStandardLocationDirectory(const QString &dirPath, @@ -806,26 +801,26 @@ bool DesktopDeviceFileAccess::removeRecursively(const FilePath &filePath, QStrin return true; } -expected_str DesktopDeviceFileAccess::copyFile(const FilePath &filePath, +Result DesktopDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const { QFile srcFile(filePath.path()); if (srcFile.copy(target.path())) - return {}; - return make_unexpected( + return Result::Ok; + return Result::Error( Tr::tr("Failed to copy file \"%1\" to \"%2\": %3") .arg(filePath.toUserOutput(), target.toUserOutput(), srcFile.errorString())); } -expected_str DesktopDeviceFileAccess::renameFile( +Result DesktopDeviceFileAccess::renameFile( const FilePath &filePath, const FilePath &target) const { QFile f(filePath.path()); if (f.rename(target.path())) - return {}; - return make_unexpected( + return Result::Ok; + return Result::Error( Tr::tr("Failed to rename file \"%1\" to \"%2\": %3") .arg(filePath.toUserOutput(), target.toUserOutput(), f.errorString())); } @@ -1060,9 +1055,14 @@ QByteArray DesktopDeviceFileAccess::fileId(const FilePath &filePath) const // UnixDeviceAccess +static QString disconnectedMessage() +{ + return Tr::tr("Device is not connected"); +} + static Utils::unexpected make_unexpected_disconnected() { - return make_unexpected(Tr::tr("Device is not connected")); + return make_unexpected(disconnectedMessage()); } UnixDeviceFileAccess::~UnixDeviceFileAccess() = default; @@ -1175,20 +1175,21 @@ bool UnixDeviceFileAccess::exists(const FilePath &filePath) const return runInShellSuccess({"test", {"-e", path}, OsType::OsTypeLinux}); } -expected_str UnixDeviceFileAccess::removeFile(const FilePath &filePath) const +Result UnixDeviceFileAccess::removeFile(const FilePath &filePath) const { if (disconnected()) - return make_unexpected_disconnected(); + return Result::Error(disconnectedMessage()); RunResult result = runInShell({"rm", {filePath.path()}, OsType::OsTypeLinux}); if (result.exitCode != 0) - return make_unexpected(QString::fromUtf8(result.stdErr)); - return {}; + return Result::Error(QString::fromUtf8(result.stdErr)); + return Result::Ok; } bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString *error) const { if (disconnected()) return false; + QTC_ASSERT(filePath.path().startsWith('/'), return false); const QString path = filePath.cleanPath().path(); @@ -1206,36 +1207,35 @@ bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString * return result.exitCode == 0; } -expected_str UnixDeviceFileAccess::copyFile(const FilePath &filePath, - const FilePath &target) const +Result UnixDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const { if (disconnected()) - return make_unexpected_disconnected(); + return Result::Error(disconnectedMessage()); const RunResult result = runInShell( {"cp", {filePath.path(), target.path()}, OsType::OsTypeLinux}); if (result.exitCode != 0) { - return make_unexpected(Tr::tr("Failed to copy file \"%1\" to \"%2\": %3") + return Result::Error(Tr::tr("Failed to copy file \"%1\" to \"%2\": %3") .arg(filePath.toUserOutput(), target.toUserOutput(), QString::fromUtf8(result.stdErr))); } - return {}; + return Result::Ok; } -expected_str UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const +Result UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const { if (disconnected()) - return make_unexpected_disconnected(); + return Result::Error(disconnectedMessage()); - auto result = runInShell({"mv", {filePath.path(), target.path()}, OsType::OsTypeLinux}); + RunResult result = runInShell({"mv", {filePath.path(), target.path()}, OsType::OsTypeLinux}); if (result.exitCode != 0) { - return make_unexpected(Tr::tr("Failed to rename file \"%1\" to \"%2\": %3") + return Result::Error(Tr::tr("Failed to rename file \"%1\" to \"%2\": %3") .arg(filePath.toUserOutput(), target.toUserOutput(), QString::fromUtf8(result.stdErr))); } - return {}; + return Result::Ok; } FilePath UnixDeviceFileAccess::symLinkTarget(const FilePath &filePath) const diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index 97aa014ab21..d5c82a0076c 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -38,16 +38,15 @@ protected: virtual bool isDirectory(const FilePath &filePath) const; virtual bool isSymLink(const FilePath &filePath) const; virtual bool hasHardLinks(const FilePath &filePath) const; - virtual expected_str ensureWritableDirectory(const FilePath &filePath) const; + virtual Result ensureWritableDirectory(const FilePath &filePath) const; virtual bool ensureExistingFile(const FilePath &filePath) const; virtual bool createDirectory(const FilePath &filePath) const; virtual bool exists(const FilePath &filePath) const; - virtual expected_str removeFile(const FilePath &filePath) const; + virtual Result removeFile(const FilePath &filePath) const; virtual bool removeRecursively(const FilePath &filePath, QString *error) const; - virtual expected_str copyFile(const FilePath &filePath, const FilePath &target) const; - virtual expected_str copyRecursively(const FilePath &filePath, - const FilePath &target) const; - virtual expected_str renameFile(const FilePath &filePath, const FilePath &target) const; + virtual Result copyFile(const FilePath &filePath, const FilePath &target) const; + virtual Result copyRecursively(const FilePath &filePath, const FilePath &target) const; + virtual Result renameFile(const FilePath &filePath, const FilePath &target) const; virtual FilePath symLinkTarget(const FilePath &filePath) const; virtual FilePathInfo filePathInfo(const FilePath &filePath) const; @@ -97,14 +96,14 @@ protected: bool isDirectory(const FilePath &filePath) const override; bool isSymLink(const FilePath &filePath) const override; bool hasHardLinks(const FilePath &filePath) const override; - expected_str ensureWritableDirectory(const FilePath &filePath) const override; + Result ensureWritableDirectory(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; - expected_str removeFile(const FilePath &filePath) const override; + Result removeFile(const FilePath &filePath) const override; bool removeRecursively(const FilePath &filePath, QString *error) const override; - expected_str copyFile(const FilePath &filePath, const FilePath &target) const override; - expected_str renameFile(const FilePath &filePath, const FilePath &target) const override; + Result copyFile(const FilePath &filePath, const FilePath &target) const override; + Result renameFile(const FilePath &filePath, const FilePath &target) const override; FilePath symLinkTarget(const FilePath &filePath) const override; FilePathInfo filePathInfo(const FilePath &filePath) const override; @@ -159,10 +158,10 @@ protected: bool ensureExistingFile(const FilePath &filePath) const override; bool createDirectory(const FilePath &filePath) const override; bool exists(const FilePath &filePath) const override; - expected_str removeFile(const FilePath &filePath) const override; + Result removeFile(const FilePath &filePath) const override; bool removeRecursively(const FilePath &filePath, QString *error) const override; - expected_str copyFile(const FilePath &filePath, const FilePath &target) const override; - expected_str renameFile(const FilePath &filePath, const FilePath &target) const override; + Result copyFile(const FilePath &filePath, const FilePath &target) const override; + Result renameFile(const FilePath &filePath, const FilePath &target) const override; FilePathInfo filePathInfo(const FilePath &filePath) const override; FilePath symLinkTarget(const FilePath &filePath) const override; diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index d52b6fea04c..c7231a9976a 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -551,7 +551,7 @@ void FilePath::setParts(const QStringView scheme, const QStringView host, QStrin \sa createDir() */ -expected_str FilePath::ensureWritableDir() const +Result FilePath::ensureWritableDir() const { return fileAccess()->ensureWritableDirectory(*this); } @@ -1980,7 +1980,7 @@ OsType FilePath::osType() const return s_deviceHooks.osType(*this); } -expected_str FilePath::removeFile() const +Result FilePath::removeFile() const { return fileAccess()->removeFile(*this); } @@ -1997,18 +1997,18 @@ bool FilePath::removeRecursively(QString *error) const return fileAccess()->removeRecursively(*this, error); } -expected_str FilePath::copyRecursively(const FilePath &target) const +Result FilePath::copyRecursively(const FilePath &target) const { return fileAccess()->copyRecursively(*this, target); } -expected_str FilePath::copyFile(const FilePath &target) const +Result FilePath::copyFile(const FilePath &target) const { if (!isSameDevice(target)) { // FIXME: This does not scale. const expected_str contents = fileContents(); if (!contents) { - return make_unexpected( + return Result::Error( Tr::tr("Error while trying to copy file: %1").arg(contents.error())); } @@ -2016,38 +2016,41 @@ expected_str FilePath::copyFile(const FilePath &target) const const expected_str copyResult = target.writeFileContents(*contents); if (!copyResult) - return make_unexpected(Tr::tr("Could not copy file: %1").arg(copyResult.error())); + return Result::Error(Tr::tr("Could not copy file: %1").arg(copyResult.error())); if (!target.setPermissions(perms)) { target.removeFile(); - return make_unexpected( + return Result::Error( Tr::tr("Could not set permissions on \"%1\"").arg(target.toString())); } - return {}; + return Result::Ok; } return fileAccess()->copyFile(*this, target); } -expected_str FilePath::renameFile(const FilePath &target) const +Result FilePath::renameFile(const FilePath &target) const { if (isSameDevice(target)) return fileAccess()->renameFile(*this, target); - return copyFile(target).and_then([this, &target] { - return removeFile().or_else( - [this, &target](const QString &removeError) -> expected_str { - // If we fail to remove the source file, we remove the target file to return to the - // original state. - expected_str rmResult = target.removeFile(); - QTC_CHECK_EXPECTED(rmResult); - return make_unexpected( - Tr::tr("Failed to move %1 to %2. Removing the source file failed: %3") - .arg(toUserOutput()) - .arg(target.toUserOutput()) - .arg(removeError)); - }); - }); + const Result copyResult = copyFile(target); + if (!copyResult) + return copyResult; + + const Result removeResult = removeFile(); + if (removeResult) + return Result::Ok; + + // If we fail to remove the source file, we remove the target file to return to the + // original state. + Result rmResult = target.removeFile(); + QTC_CHECK_EXPECTED(rmResult); + return Result::Error( + Tr::tr("Failed to move %1 to %2. Removing the source file failed: %3") + .arg(toUserOutput()) + .arg(target.toUserOutput()) + .arg(rmResult.error())); } qint64 FilePath::fileSize() const diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 982ec3ea94f..b79ef3c1d71 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -152,7 +152,7 @@ public: bool isWritableDir() const; bool isWritableFile() const; - expected_str ensureWritableDir() const; + Result ensureWritableDir() const; bool ensureExistingFile() const; bool isExecutableFile() const; bool isReadableFile() const; @@ -170,11 +170,11 @@ public: QFile::Permissions permissions() const; bool setPermissions(QFile::Permissions permissions) const; OsType osType() const; - expected_str removeFile() const; + Result removeFile() const; bool removeRecursively(QString *error = nullptr) const; - expected_str copyRecursively(const FilePath &target) const; - expected_str copyFile(const FilePath &target) const; - expected_str renameFile(const FilePath &target) const; + Result copyRecursively(const FilePath &target) const; + Result copyFile(const FilePath &target) const; + Result renameFile(const FilePath &target) const; qint64 fileSize() const; qint64 bytesAvailable() const; bool createDir() const; diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 319235d7c49..d011cd5a4d8 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -735,7 +735,7 @@ bool FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgt tgtFilePath.removeFile(); } - const expected_str copyResult = srcFilePath.copyFile(tgtFilePath); + const Result copyResult = srcFilePath.copyFile(tgtFilePath); // TODO forward error to caller instead of assert, since IO errors can always be expected QTC_ASSERT_EXPECTED(copyResult, return false); diff --git a/src/libs/utils/fsengine/fsenginehandler.cpp b/src/libs/utils/fsengine/fsenginehandler.cpp index 4580ebdcb57..2fbd853963f 100644 --- a/src/libs/utils/fsengine/fsenginehandler.cpp +++ b/src/libs/utils/fsengine/fsenginehandler.cpp @@ -220,18 +220,18 @@ bool FSEngineImpl::remove() bool FSEngineImpl::copy(const QString &newName) { - expected_str result = m_filePath.copyFile(FilePath::fromString(newName)); + Result result = m_filePath.copyFile(FilePath::fromString(newName)); if (!result) setError(QFile::CopyError, result.error()); - return result.has_value(); + return bool(result); } bool FSEngineImpl::rename(const QString &newName) { - auto result = m_filePath.renameFile(FilePath::fromString(newName)); + Result result = m_filePath.renameFile(FilePath::fromString(newName)); if (!result) setError(QFile::RenameError, result.error()); - return result.has_value(); + return bool(result); } bool FSEngineImpl::renameOverwrite(const QString &newName) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 0ae96b90799..0a18c72ef79 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -740,6 +740,26 @@ void Widget::show() access(this)->show(); } +bool Widget::isVisible() const +{ + return access(this)->isVisible(); +} + +bool Widget::isEnabled() const +{ + return access(this)->isEnabled(); +} + +void Widget::setVisible(bool visible) +{ + access(this)-> setVisible(visible); +} + +void Widget::setEnabled(bool enabled) +{ + access(this)->setEnabled(enabled); +} + void Widget::setNoMargins(int) { setContentsMargins(0, 0, 0, 0); diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index cbe29b55d02..5019f2e8232 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -231,6 +231,12 @@ public: QWidget *emerge() const; void show(); + bool isVisible() const; + bool isEnabled() const; + + void setVisible(bool); + void setEnabled(bool); + void setAutoFillBackground(bool); void setLayout(const Layout &layout); void setSize(int, int); diff --git a/src/libs/utils/savefile.cpp b/src/libs/utils/savefile.cpp index 65f9fa41a41..9ccdf1cea52 100644 --- a/src/libs/utils/savefile.cpp +++ b/src/libs/utils/savefile.cpp @@ -197,7 +197,7 @@ bool SaveFile::commit() } } - expected_str renameResult = m_tempFile->filePath().renameFile(finalFileName); + Result renameResult = m_tempFile->filePath().renameFile(finalFileName); if (!renameResult) { // 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 diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index 080bb8a3820..340f29d6f51 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -176,6 +176,10 @@ QColor StyleHelper::borderColor(bool lightColored) QColor StyleHelper::toolBarBorderColor() { + if (const QColor sepColor = creatorColor(Theme::FancyToolBarSeparatorColor); + sepColor == creatorColor(Theme::SplitterColor)) + return sepColor; // QTCREATORBUG-31682: Unify all separating line colors if two are the same + const QColor base = baseColor(); return QColor::fromHsv(base.hue(), base.saturation() , diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 94a52d5148e..60b549a7f2a 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -27,7 +27,6 @@ add_qtc_plugin(Android androidqmltoolingsupport.cpp androidqmltoolingsupport.h androidqtversion.cpp androidqtversion.h androidrunconfiguration.cpp androidrunconfiguration.h - androidruncontrol.cpp androidruncontrol.h androidrunner.cpp androidrunner.h androidrunnerworker.cpp androidrunnerworker.h androidsdkdownloader.cpp androidsdkdownloader.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index de16bda375c..6618e7c9cfb 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -55,8 +55,6 @@ QtcPlugin { "androidqtversion.h", "androidrunconfiguration.cpp", "androidrunconfiguration.h", - "androidruncontrol.cpp", - "androidruncontrol.h", "androidrunner.cpp", "androidrunner.h", "androidrunnerworker.cpp", diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 8ed611b19c4..ef1a93d7577 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -679,7 +679,7 @@ static bool copyFileIfNewer(const FilePath &sourceFilePath, if (!destinationFilePath.parentDir().ensureWritableDir()) return false; - expected_str result = sourceFilePath.copyFile(destinationFilePath); + Result result = sourceFilePath.copyFile(destinationFilePath); QTC_ASSERT_EXPECTED(result, return false); return true; } diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 5f860134f8f..232a3e5f590 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -13,7 +13,7 @@ #include "androidqmltoolingsupport.h" #include "androidqtversion.h" #include "androidrunconfiguration.h" -#include "androidruncontrol.h" +#include "androidrunner.h" #include "androidsettingswidget.h" #include "androidtoolchain.h" #include "androidtr.h" diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index 33ce4caa9ed..3b7da499440 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -100,7 +100,7 @@ class AndroidRunConfigurationFactory : public RunConfigurationFactory public: AndroidRunConfigurationFactory() { - registerRunConfiguration("Qt4ProjectManager.AndroidRunConfiguration:"); + registerRunConfiguration(Android::Constants::ANDROID_RUNCONFIG_ID); addSupportedTargetDeviceType(Android::Constants::ANDROID_DEVICE_TYPE); } }; diff --git a/src/plugins/android/androidruncontrol.cpp b/src/plugins/android/androidruncontrol.cpp deleted file mode 100644 index 023e14525c3..00000000000 --- a/src/plugins/android/androidruncontrol.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (C) 2016 BogDan Vatra -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "androidruncontrol.h" - -#include "androidconstants.h" -#include "androidglobal.h" -#include "androidrunconfiguration.h" -#include "androidrunner.h" - -#include - -#include - -using namespace ProjectExplorer; - -namespace Android::Internal { - -class AndroidRunSupport final : public AndroidRunner -{ -public: - explicit AndroidRunSupport(RunControl *runControl); - ~AndroidRunSupport() override; -}; - -AndroidRunSupport::AndroidRunSupport(RunControl *runControl) - : AndroidRunner(runControl) -{ - runControl->setIcon(Utils::Icons::RUN_SMALL_TOOLBAR); -} - -AndroidRunSupport::~AndroidRunSupport() -{ - stop(); -} - -class AndroidRunWorkerFactory final : public RunWorkerFactory -{ -public: - AndroidRunWorkerFactory() - { - setProduct(); - addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); - addSupportedRunConfig(Constants::ANDROID_RUNCONFIG_ID); - } -}; - -void setupAndroidRunWorker() -{ - static AndroidRunWorkerFactory theAndroidRunWorkerFactory; -} - -} // Android::Internal diff --git a/src/plugins/android/androidruncontrol.h b/src/plugins/android/androidruncontrol.h deleted file mode 100644 index 9c6fee8f251..00000000000 --- a/src/plugins/android/androidruncontrol.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (C) 2016 BogDan Vatra -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -namespace Android::Internal { - -void setupAndroidRunWorker(); - -} // Android::Internal diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index fa6dc5a415f..b72ab54f477 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -5,6 +5,7 @@ #include "androidrunner.h" #include "androidavdmanager.h" +#include "androidconstants.h" #include "androiddevice.h" #include "androidmanager.h" #include "androidrunnerworker.h" @@ -12,8 +13,11 @@ #include #include + #include + #include +#include #include #include @@ -31,6 +35,7 @@ namespace Android::Internal { AndroidRunner::AndroidRunner(RunControl *runControl) : RunWorker(runControl) { + runControl->setIcon(Utils::Icons::RUN_SMALL_TOOLBAR); setId("AndroidRunner"); static const int metaTypes[] = { qRegisterMetaType>("QList"), @@ -101,7 +106,6 @@ void AndroidRunner::start() runnerRecipe(glueStorage) }; m_taskTreeRunner.start(recipe); - m_packageName = AndroidManager::packageName(target); } void AndroidRunner::stop() @@ -110,8 +114,6 @@ void AndroidRunner::stop() return; emit canceled(); - appendMessage(Tr::tr("Android target \"%1\" terminated.").arg(m_packageName), - Utils::NormalMessageFormat); } void AndroidRunner::qmlServerPortReady(Port port) @@ -155,4 +157,20 @@ void AndroidRunner::remoteStdErr(const QString &output) m_outputParser.processOutput(output); } +class AndroidRunWorkerFactory final : public RunWorkerFactory +{ +public: + AndroidRunWorkerFactory() + { + setProduct(); + addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); + addSupportedRunConfig(Constants::ANDROID_RUNCONFIG_ID); + } +}; + +void setupAndroidRunWorker() +{ + static AndroidRunWorkerFactory theAndroidRunWorkerFactory; +} + } // namespace Android::Internal diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 0a6d6a0fedf..748b3879d00 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -46,7 +46,8 @@ private: Utils::ProcessHandle m_pid; QmlDebug::QmlOutputParser m_outputParser; Tasking::TaskTreeRunner m_taskTreeRunner; - QString m_packageName; }; +void setupAndroidRunWorker(); + } // namespace Android::Internal diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index abc56ea13a1..4033a86d2ce 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -581,10 +581,11 @@ static ExecutableItem postDoneRecipe(const Storage &storage) const auto onDone = [storage] { storage->m_processPID = -1; storage->m_processUser = -1; - if (!storage->m_glue->wasCancelled()) { - storage->m_glue->setFinished(Tr::tr("Android target \"%1\" died.") - .arg(storage->m_packageName)); - } + const QString package = storage->m_packageName; + const QString message = storage->m_glue->wasCancelled() + ? Tr::tr("Android target \"%1\" terminated.").arg(package) + : Tr::tr("Android target \"%1\" died.").arg(package); + storage->m_glue->setFinished(message); }; return Group { diff --git a/src/plugins/android/androidsignaloperation.cpp b/src/plugins/android/androidsignaloperation.cpp index 0b44f3d5f60..8f0fbd2a7e6 100644 --- a/src/plugins/android/androidsignaloperation.cpp +++ b/src/plugins/android/androidsignaloperation.cpp @@ -1,99 +1,73 @@ // 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 "androidconfigurations.h" #include "androidsignaloperation.h" +#include "androidconfigurations.h" + #include -#include +using namespace Tasking; using namespace Utils; +using namespace std::chrono_literals; -namespace Android { -namespace Internal { +namespace Android::Internal { -AndroidSignalOperation::AndroidSignalOperation() - : m_adbPath(AndroidConfig::adbToolPath()) - , m_timeout(new QTimer(this)) -{ - m_timeout->setInterval(5000); - connect(m_timeout, &QTimer::timeout, this, &AndroidSignalOperation::handleTimeout); -} - -AndroidSignalOperation::~AndroidSignalOperation() = default; - -bool AndroidSignalOperation::handleCrashMessage() -{ - if (m_adbProcess->exitStatus() == QProcess::NormalExit) - return false; - m_errorMessage = QLatin1String(" adb process exit code: ") + QString::number(m_adbProcess->exitCode()); - const QString adbError = m_adbProcess->errorString(); - if (!adbError.isEmpty()) - m_errorMessage += QLatin1String(" adb process error: ") + adbError; - return true; -} - -void AndroidSignalOperation::adbFindRunAsFinished() -{ - QTC_ASSERT(m_state == RunAs, return); - m_timeout->stop(); - - handleCrashMessage(); - const QString runAs = QString::fromLatin1(m_adbProcess->readAllRawStandardOutput()); - m_adbProcess.release()->deleteLater(); - if (runAs.isEmpty() || !m_errorMessage.isEmpty()) { - m_errorMessage.prepend(QLatin1String("Cannot find User for process: ") - + QString::number(m_pid)); - m_state = Idle; - emit finished(m_errorMessage); - } else { - startAdbProcess(Kill, {m_adbPath, {"shell", "run-as", runAs, "kill", - QString("-%1").arg(m_signal), QString::number(m_pid)}}, - [this] { adbKillFinished(); }); - } -} - -void AndroidSignalOperation::adbKillFinished() -{ - QTC_ASSERT(m_state == Kill, return); - m_timeout->stop(); - - if (!handleCrashMessage()) - m_errorMessage = QString::fromLatin1(m_adbProcess->readAllRawStandardError()); - m_adbProcess.release()->deleteLater(); - if (!m_errorMessage.isEmpty()) - m_errorMessage.prepend(QLatin1String("Cannot kill process: ") + QString::number(m_pid)); - m_state = Idle; - emit finished(m_errorMessage); -} - -void AndroidSignalOperation::handleTimeout() -{ - m_adbProcess.reset(); - m_timeout->stop(); - m_state = Idle; - m_errorMessage = QLatin1String("adb process timed out"); - emit finished(m_errorMessage); -} +AndroidSignalOperation::AndroidSignalOperation() = default; void AndroidSignalOperation::signalOperationViaADB(qint64 pid, int signal) { - QTC_ASSERT(m_state == Idle, return); - m_pid = pid; - m_signal = signal; - startAdbProcess(RunAs, {m_adbPath, {"shell", "cat", QString("/proc/%1/cmdline").arg(m_pid)}}, - [this] { adbFindRunAsFinished(); }); -} + struct InternalStorage { + FilePath adbPath; + QString runAs = {}; + QString errorMessage = {}; + }; -void AndroidSignalOperation::startAdbProcess(State state, const Utils::CommandLine &commandLine, - FinishHandler handler) -{ - m_state = state; - m_timeout->start(); - m_adbProcess.reset(new Process); - connect(m_adbProcess.get(), &Process::done, this, handler); - m_adbProcess->setCommand(commandLine); - m_adbProcess->start(); + const Storage storage({AndroidConfig::adbToolPath()}); + + const auto onCatSetup = [storage, pid](Process &process) { + process.setCommand({storage->adbPath, {"shell", "cat", QString("/proc/%1/cmdline").arg(pid)}}); + }; + const auto onCatDone = [storage, pid](const Process &process, DoneWith result) { + if (result == DoneWith::Success) { + storage->runAs = process.stdOut(); + if (!storage->runAs.isEmpty()) + return true; + storage->errorMessage = QLatin1String("Cannot find User for process: ") + + QString::number(pid); + } else if (result == DoneWith::Error) { + storage->errorMessage = QLatin1String(" adb process exit code: ") + + QString::number(process.exitCode()); + const QString adbError = process.errorString(); + if (!adbError.isEmpty()) + storage->errorMessage += QLatin1String(" adb process error: ") + adbError; + } else { + storage->errorMessage = QLatin1String("adb process timed out"); + } + return false; + }; + + const auto onKillSetup = [storage, pid, signal](Process &process) { + process.setCommand({storage->adbPath, {"shell", "run-as", storage->runAs, "kill", + QString("-%1").arg(signal), QString::number(pid)}}); + }; + const auto onKillDone = [storage, pid](const Process &process, DoneWith result) { + if (result == DoneWith::Error) { + storage->errorMessage = QLatin1String("Cannot kill process: ") + QString::number(pid) + + process.stdErr(); + } else if (result == DoneWith::Cancel) { + storage->errorMessage = QLatin1String("adb process timed out"); + } + }; + + const auto onDone = [this, storage] { emit finished(storage->errorMessage); }; + + const Group recipe { + ProcessTask(onCatSetup, onCatDone).withTimeout(5s), + ProcessTask(onKillSetup, onKillDone).withTimeout(5s), + onGroupDone(onDone) + }; + m_taskTreeRunner.start(recipe); } void AndroidSignalOperation::killProcess(qint64 pid) @@ -114,5 +88,4 @@ void AndroidSignalOperation::interruptProcess(qint64 pid) signalOperationViaADB(pid, 2); } -} // Internal -} // Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidsignaloperation.h b/src/plugins/android/androidsignaloperation.h index 53c1d61a899..6387bd77fe3 100644 --- a/src/plugins/android/androidsignaloperation.h +++ b/src/plugins/android/androidsignaloperation.h @@ -5,16 +5,13 @@ #include -#include -#include +#include -namespace Android { -namespace Internal { +namespace Android::Internal { class AndroidSignalOperation : public ProjectExplorer::DeviceProcessSignalOperation { public: - ~AndroidSignalOperation() override; void killProcess(qint64 pid) override; void killProcess(const QString &filePath) override; void interruptProcess(qint64 pid) override; @@ -23,32 +20,11 @@ protected: explicit AndroidSignalOperation(); private: - enum State { - Idle, - RunAs, - Kill - }; - - using FinishHandler = std::function; - - bool handleCrashMessage(); - void adbFindRunAsFinished(); - void adbKillFinished(); - void handleTimeout(); - void signalOperationViaADB(qint64 pid, int signal); - void startAdbProcess(State state, const Utils::CommandLine &commandLine, FinishHandler handler); - Utils::FilePath m_adbPath; - std::unique_ptr m_adbProcess; - QTimer *m_timeout; - - State m_state = Idle; - qint64 m_pid = 0; - int m_signal = 0; + Tasking::TaskTreeRunner m_taskTreeRunner; friend class AndroidDevice; }; -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/appstatisticsmonitor/idataprovider.cpp b/src/plugins/appstatisticsmonitor/idataprovider.cpp index 23d443c76e2..0d5d8a2fe8c 100644 --- a/src/plugins/appstatisticsmonitor/idataprovider.cpp +++ b/src/plugins/appstatisticsmonitor/idataprovider.cpp @@ -329,14 +329,36 @@ private: }; #endif +// ------------------------- NullDataProvider -------------------------------- + +class NullDataProvider : public IDataProvider +{ +public: + NullDataProvider(qint64 pid, QObject *parent = nullptr) + : IDataProvider(pid, parent) + {} + + double getCpuConsumption() + { + return 0.0; + } + + double getMemoryConsumption() + { + return 0.0; + } +}; + IDataProvider *createDataProvider(qint64 pid) { #ifdef Q_OS_WIN return new WindowsDataProvider(pid); #elif defined(Q_OS_MACOS) return new MacDataProvider(pid); -#else // Q_OS_LINUX +#elif defined(Q_OS_LINUX) return new LinuxDataProvider(pid); +#else + return new NullDataProvider(pid); #endif } diff --git a/src/plugins/autotest/qtest/datataglocatorfilter.cpp b/src/plugins/autotest/qtest/datataglocatorfilter.cpp index e6a436666ce..54569efea43 100644 --- a/src/plugins/autotest/qtest/datataglocatorfilter.cpp +++ b/src/plugins/autotest/qtest/datataglocatorfilter.cpp @@ -15,34 +15,35 @@ #include +using namespace Core; +using namespace Tasking; +using namespace Utils; + namespace Autotest::Internal { -static void linkAcceptor(const Utils::Link &link) +static void linkAcceptor(const Link &link) { if (link.hasValidTarget()) - Core::EditorManager::openEditorAt(link); + EditorManager::openEditorAt(link); } -using LinkAcceptor = std::function; +using LinkAcceptor = std::function; -static Core::LocatorMatcherTasks dataTagMatchers(const LinkAcceptor &acceptor) +static LocatorMatcherTasks dataTagMatchers(const LinkAcceptor &acceptor) { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, acceptor] { - const QString input = storage->input(); + const auto onSetup = [acceptor] { + const LocatorStorage &storage = *LocatorStorage::storage(); + const QString input = storage.input(); const TestTreeItem *qtTestRoot = theQtTestFramework().rootNode(); if (!qtTestRoot) return; - Core::LocatorFilterEntries entries; + LocatorFilterEntries entries; qtTestRoot->forAllChildItems([&entries, &input, acceptor = acceptor](TestTreeItem *it) { if (it->type() != TestTreeItem::TestDataTag) return; if (it->name().contains(input)) { - Core::LocatorFilterEntry entry; + LocatorFilterEntry entry; entry.displayName = it->data(0, Qt::DisplayRole).toString(); { const TestTreeItem *parent = it->parentItem(); @@ -52,18 +53,18 @@ static Core::LocatorMatcherTasks dataTagMatchers(const LinkAcceptor &acceptor) entry.displayExtra = grandParent->name() + "::" + parent->name(); } } - entry.linkForEditor = std::make_optional(it->data(0, LinkRole).value()); + entry.linkForEditor = std::make_optional(it->data(0, LinkRole).value()); entry.acceptor = [link = entry.linkForEditor, acceptor = acceptor] { if (link) acceptor(*link); - return Core::AcceptResult(); + return AcceptResult(); }; entries.append(entry); } }); - storage->reportOutput(entries); + storage.reportOutput(entries); }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } DataTagLocatorFilter::DataTagLocatorFilter() @@ -79,7 +80,7 @@ DataTagLocatorFilter::DataTagLocatorFilter() setEnabled(ProjectManager::startupProject()); } -Core::LocatorMatcherTasks DataTagLocatorFilter::matchers() +LocatorMatcherTasks DataTagLocatorFilter::matchers() { return dataTagMatchers(&linkAcceptor); } diff --git a/src/plugins/axivion/CMakeLists.txt b/src/plugins/axivion/CMakeLists.txt index a08aa434284..e427a425c58 100644 --- a/src/plugins/axivion/CMakeLists.txt +++ b/src/plugins/axivion/CMakeLists.txt @@ -1,14 +1,13 @@ add_qtc_plugin(Axivion PLUGIN_DEPENDS Core Debugger ProjectExplorer TextEditor - DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils qtkeychain + DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils SOURCES axivion.qrc axivionperspective.cpp axivionperspective.h axivionplugin.cpp axivionplugin.h axivionsettings.cpp axivionsettings.h axiviontr.h - credentialquery.h credentialquery.cpp dashboard/dto.cpp dashboard/dto.h dashboard/concat.cpp dashboard/concat.h dashboard/error.h dashboard/error.cpp diff --git a/src/plugins/axivion/axivion.qbs b/src/plugins/axivion/axivion.qbs index 671b292d9c5..f61fa928407 100644 --- a/src/plugins/axivion/axivion.qbs +++ b/src/plugins/axivion/axivion.qbs @@ -9,7 +9,6 @@ QtcPlugin { Depends { name: "ProjectExplorer" } Depends { name: "TextEditor" } Depends { name: "Utils" } - Depends { name: "qtkeychain" } Depends { name: "Qt.widgets" } Depends { name: "Qt.network" } @@ -22,8 +21,6 @@ QtcPlugin { "axivionsettings.cpp", "axivionsettings.h", "axiviontr.h", - "credentialquery.cpp", - "credentialquery.h", "dynamiclistmodel.cpp", "dynamiclistmodel.h", "issueheaderview.cpp", diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 79fe71c770f..6ec2eca29f0 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -6,10 +6,10 @@ #include "axivionperspective.h" #include "axivionsettings.h" #include "axiviontr.h" -#include "credentialquery.h" #include "dashboard/dto.h" #include "dashboard/error.h" +#include #include #include #include diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 9112c728497..1c15d4979d0 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -269,7 +269,7 @@ const QList AxivionSettings::validPathMappings() const 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-]+$)"); + 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) { @@ -279,7 +279,7 @@ static bool hostValid(const QString &host) } return true; } - return (host == "localhost") || dn.match(host).hasMatch(); + return dn.match(host).hasMatch(); } static bool isUrlValid(const QString &in) @@ -388,17 +388,17 @@ AxivionSettingsWidget::AxivionSettingsWidget() auto addButton = new QPushButton(Tr::tr("Add..."), this); m_edit = new QPushButton(Tr::tr("Edit..."), this); m_remove = new QPushButton(Tr::tr("Remove"), this); - Column{ - Row{ - Form{Tr::tr("Default dashboard server:"), m_dashboardServers, br}, + Column { + Row { + Form { Tr::tr("Default dashboard server:"), m_dashboardServers, br }, st, - Column{addButton, m_edit, st, m_remove}, + Column { addButton, m_edit, st, m_remove }, }, Space(10), br, - Row{settings().highlightMarks}, - st} - .attachTo(this); + Row {settings().highlightMarks }, + st + }.attachTo(this); connect(addButton, &QPushButton::clicked, this, [this] { // add an empty item unconditionally diff --git a/src/plugins/beautifier/beautifiertool.cpp b/src/plugins/beautifier/beautifiertool.cpp index 2914b5c58c0..9e55cf18363 100644 --- a/src/plugins/beautifier/beautifiertool.cpp +++ b/src/plugins/beautifier/beautifiertool.cpp @@ -150,7 +150,7 @@ AbstractSettings::AbstractSettings(const QString &name, const QString &ending) command.setSettingsKey("command"); command.setExpectedKind(PathChooser::ExistingCommand); command.setCommandVersionArguments({"--version"}); - command.setPromptDialogTitle(BeautifierTool::msgCommandPromptDialogTitle("Clang Format")); + command.setPromptDialogTitle(BeautifierTool::msgCommandPromptDialogTitle("ClangFormat")); command.setValidatePlaceHolder(true); command.addOnChanged(this, [this] { m_version = {}; version(); }); diff --git a/src/plugins/beautifier/clangformat/clangformat.cpp b/src/plugins/beautifier/clangformat/clangformat.cpp index 14c7313503f..7a250d6b94a 100644 --- a/src/plugins/beautifier/clangformat/clangformat.cpp +++ b/src/plugins/beautifier/clangformat/clangformat.cpp @@ -54,8 +54,8 @@ public: : AbstractSettings(SETTINGS_NAME, ".clang-format") { command.setDefaultValue("clang-format"); - command.setPromptDialogTitle(BeautifierTool::msgCommandPromptDialogTitle("Clang Format")); - command.setLabelText(Tr::tr("Clang Format command:")); + command.setPromptDialogTitle(BeautifierTool::msgCommandPromptDialogTitle("ClangFormat")); + command.setLabelText(Tr::tr("ClangFormat command:")); usePredefinedStyle.setSettingsKey("usePredefinedStyle"); usePredefinedStyle.setDefaultValue(true); @@ -530,7 +530,7 @@ public: ClangFormatSettingsPage() { setId("ClangFormat"); - setDisplayName(Tr::tr("Clang Format")); + setDisplayName(Tr::tr("ClangFormat")); setCategory(Constants::OPTION_CATEGORY); setWidgetCreator([] { return new ClangFormatSettingsPageWidget; }); } diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 18fd250a982..f2f66fa29e3 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -24,6 +24,7 @@ using namespace Core; using namespace LanguageClient; using namespace LanguageServerProtocol; using namespace ProjectExplorer; +using namespace Tasking; using namespace TextEditor; using namespace Utils; @@ -171,31 +172,25 @@ static void filterCurrentResults(QPromise &promise, const LocatorStorage & [](const Entry &entry) { return entry.entry; })); } -static LocatorMatcherTask currentDocumentMatcher() +static ExecutableItem currentDocumentMatcher() { - using namespace Tasking; - - Storage storage; Storage resultStorage; - const auto onQuerySetup = [=](CurrentDocumentSymbolsRequest &request) { - Q_UNUSED(request) - }; const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequest &request) { *resultStorage = request.currentDocumentSymbolsData(); }; - const auto onFilterSetup = [=](Async &async) { - async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage, + const auto onFilterSetup = [resultStorage](Async &async) { + async.setConcurrentCallData(filterCurrentResults, *LocatorStorage::storage(), *resultStorage, TextDocument::currentTextDocument()->plainText()); }; const Group root { resultStorage, - CurrentDocumentSymbolsRequestTask(onQuerySetup, onQueryDone, CallDoneIf::Success), + CurrentDocumentSymbolsRequestTask({}, onQueryDone, CallDoneIf::Success), AsyncTask(onFilterSetup) }; - return {root, storage}; + return root; } LocatorMatcherTasks ClangdCurrentDocumentFilter::matchers() diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index 7134ecd2e37..86bca4e40d4 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -375,9 +375,11 @@ public: private: void slotImportClicked() final { - const FilePath filePath = - FileUtils::getOpenFilePath(this, Tr::tr("Import Code Format"), {}, - Tr::tr("Clang Format (*clang-format*);;All files (*)")); + const FilePath filePath = FileUtils::getOpenFilePath( + this, + Tr::tr("Import Code Format"), + {}, + Tr::tr("ClangFormat (*clang-format*);;All files (*)")); if (!filePath.isEmpty()) { QString name = QInputDialog::getText( this, @@ -407,7 +409,7 @@ private: this, Tr::tr("Export Code Format"), FileUtils::homePath(), - Tr::tr("Clang Format (*clang-format*);;All files (*)")); + Tr::tr("ClangFormat (*clang-format*);;All files (*)")); if (!filePath.isEmpty()) { FilePath clangFormatFile = filePathToCurrentSettings(currentPreferences); clangFormatFile.copyFile(filePath); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index cccc08d4b59..31d0a4bbc8d 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -1946,7 +1946,7 @@ void CMakeBuildConfiguration::setBuildPresetToBuildSteps(const ProjectExplorer:: // Leave only the first build step enabled if (i > 0) - cbs->setEnabled(false); + cbs->setStepEnabled(false); } } diff --git a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp index a827190d185..2b5edbe7224 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp @@ -187,72 +187,31 @@ class CMakeKitAspectImpl final : public KitAspect { public: CMakeKitAspectImpl(Kit *kit, const KitAspectFactory *factory) - : KitAspect(kit, factory), m_comboBox(createSubWidget()) + : KitAspect(kit, factory) { setManagingPage(Constants::Settings::TOOLS_ID); - m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy()); - m_comboBox->setToolTip(factory->description()); + const auto sortModel = new CMakeToolSortModel(this); sortModel->setSourceModel(new CMakeToolListModel(*kit, this)); - m_comboBox->setModel(sortModel); - - refresh(); - - connect(m_comboBox, &QComboBox::currentIndexChanged, - this, &CMakeKitAspectImpl::currentCMakeToolChanged); + auto getter = [](const Kit &k) { return CMakeKitAspect::cmakeToolId(&k).toSetting(); }; + auto setter = [](Kit &k, const QVariant &id) { + CMakeKitAspect::setCMakeTool(&k, Id::fromSetting(id)); + }; + auto resetModel = [](QAbstractItemModel &model) { + static_cast(model).reset(); + }; + setListAspectSpec( + {sortModel, + std::move(getter), + std::move(setter), + std::move(resetModel), + CMakeToolTreeItem::IdRole}); CMakeToolManager *cmakeMgr = CMakeToolManager::instance(); connect(cmakeMgr, &CMakeToolManager::cmakeAdded, this, &CMakeKitAspectImpl::refresh); connect(cmakeMgr, &CMakeToolManager::cmakeRemoved, this, &CMakeKitAspectImpl::refresh); connect(cmakeMgr, &CMakeToolManager::cmakeUpdated, this, &CMakeKitAspectImpl::refresh); } - - ~CMakeKitAspectImpl() override - { - delete m_comboBox; - } - -private: - // KitAspectWidget interface - void makeReadOnly() override { m_comboBox->setEnabled(false); } - - void addToInnerLayout(Layouting::Layout &builder) override - { - addMutableAction(m_comboBox); - builder.addItem(m_comboBox); - } - - void refresh() override - { - const GuardLocker locker(m_ignoreChanges); - - const auto sortModel = static_cast(m_comboBox->model()); - sortModel->reset(); - sortModel->sort(0); - m_comboBox->setCurrentIndex(indexOf(CMakeKitAspect::cmakeToolId(m_kit))); - } - - int indexOf(Id id) - { - for (int i = 0; i < m_comboBox->count(); ++i) { - if (id == Id::fromSetting(m_comboBox->itemData(i, CMakeToolTreeItem::IdRole))) - return i; - } - - return m_comboBox->count() - 1; - } - - void currentCMakeToolChanged(int index) - { - if (m_ignoreChanges.isLocked()) - return; - - const Id id = Id::fromSetting(m_comboBox->itemData(index, CMakeToolTreeItem::IdRole)); - CMakeKitAspect::setCMakeTool(m_kit, id); - } - - Guard m_ignoreChanges; - QComboBox *m_comboBox; }; CMakeKitAspectFactory::CMakeKitAspectFactory() @@ -434,7 +393,7 @@ private: void refresh() override { - CMakeTool *const tool = CMakeKitAspect::cmakeTool(m_kit); + CMakeTool *const tool = CMakeKitAspect::cmakeTool(kit()); if (tool != m_currentTool) m_currentTool = tool; diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 9dc375d22c6..c3712e06979 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -19,6 +19,7 @@ using namespace Core; using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; namespace CMakeProjectManager::Internal { @@ -29,12 +30,9 @@ using BuildAcceptor = std::function; static LocatorMatcherTasks cmakeMatchers(const BuildAcceptor &acceptor) { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, acceptor] { - const QString input = storage->input(); + const auto onSetup = [acceptor] { + const LocatorStorage &storage = *LocatorStorage::storage(); + const QString input = storage.input(); const QRegularExpression regexp = ILocatorFilter::createRegExp(input, ILocatorFilter::caseSensitivity(input)); if (!regexp.isValid()) @@ -90,10 +88,10 @@ static LocatorMatcherTasks cmakeMatchers(const BuildAcceptor &acceptor) } } } - storage->reportOutput( + storage.reportOutput( std::accumulate(std::begin(entries), std::end(entries), LocatorFilterEntries())); }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } static void setupFilter(ILocatorFilter *filter) diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index eddbd316f37..5db7fb3362e 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -1,5 +1,5 @@ add_qtc_plugin(Core - DEPENDS Qt::PrintSupport Qt::Qml Qt::Sql Qt::Gui Qt::GuiPrivate TerminalLib + DEPENDS Qt::PrintSupport Qt::Qml Qt::Sql Qt::Gui Qt::GuiPrivate TerminalLib qtkeychain PUBLIC_DEPENDS Aggregation ExtensionSystem Utils SOURCES actionmanager/actioncontainer.cpp @@ -29,6 +29,8 @@ add_qtc_plugin(Core coreplugin.cpp coreplugin.h coreplugintr.h + credentialquery.cpp + credentialquery.h designmode.cpp designmode.h dialogs/addtovcsdialog.cpp diff --git a/src/plugins/coreplugin/actionsfilter.cpp b/src/plugins/coreplugin/actionsfilter.cpp index 8b5f23df71f..a2b8e129866 100644 --- a/src/plugins/coreplugin/actionsfilter.cpp +++ b/src/plugins/coreplugin/actionsfilter.cpp @@ -24,6 +24,7 @@ #include #include +using namespace Tasking; using namespace Utils; static const char lastTriggeredC[] = "LastTriggeredActions"; @@ -174,11 +175,7 @@ static void matches(QPromise &promise, const LocatorStorage &storage, LocatorMatcherTasks ActionsFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [this, storage](Async &async) { + const auto onSetup = [this](Async &async) { m_entries.clear(); m_indexes.clear(); QList processedMenus; @@ -186,15 +183,16 @@ LocatorMatcherTasks ActionsFilter::matchers() for (QAction* action : menuBarActions()) collectEntriesForAction(action, {}, processedMenus); collectEntriesForCommands(); - if (storage->input().simplified().isEmpty()) { - storage->reportOutput(m_entries); + const LocatorStorage &storage = *LocatorStorage::storage(); + if (storage.input().simplified().isEmpty()) { + storage.reportOutput(m_entries); return SetupResult::StopWithSuccess; } - async.setConcurrentCallData(matches, *storage, m_entries); + async.setConcurrentCallData(matches, storage, m_entries); return SetupResult::Continue; }; - return {{AsyncTask(onSetup), storage}}; + return {AsyncTask(onSetup)}; } LocatorFilterEntry::Acceptor ActionsFilter::acceptor(const ActionFilterEntryData &data) const diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index 41edaff0de7..96316a9c9df 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -16,6 +16,7 @@ QtcPlugin { Depends { name: "Utils" } Depends { name: "Aggregation" } Depends { name: "TerminalLib" } + Depends { name: "qtkeychain" } cpp.dynamicLibraries: { if (qbs.targetOS.contains("windows")) @@ -43,6 +44,8 @@ QtcPlugin { "coreplugin.cpp", "coreplugin.h", "coreplugintr.h", + "credentialquery.cpp", + "credentialquery.h", "designmode.cpp", "designmode.h", "diffservice.cpp", diff --git a/src/plugins/axivion/credentialquery.cpp b/src/plugins/coreplugin/credentialquery.cpp similarity index 96% rename from src/plugins/axivion/credentialquery.cpp rename to src/plugins/coreplugin/credentialquery.cpp index f183c083736..92c1ddfa359 100644 --- a/src/plugins/axivion/credentialquery.cpp +++ b/src/plugins/coreplugin/credentialquery.cpp @@ -8,7 +8,7 @@ using namespace QKeychain; using namespace Tasking; -namespace Axivion::Internal { +namespace Core { CredentialQueryTaskAdapter::~CredentialQueryTaskAdapter() = default; @@ -51,4 +51,4 @@ void CredentialQueryTaskAdapter::start() job->start(); } -} // Axivion::Internal +} // Core diff --git a/src/plugins/axivion/credentialquery.h b/src/plugins/coreplugin/credentialquery.h similarity index 86% rename from src/plugins/axivion/credentialquery.h rename to src/plugins/coreplugin/credentialquery.h index d8a958ab53e..22ec24921f5 100644 --- a/src/plugins/axivion/credentialquery.h +++ b/src/plugins/coreplugin/credentialquery.h @@ -3,13 +3,15 @@ #pragma once +#include "core_global.h" + #include -namespace Axivion::Internal { +namespace Core { enum class CredentialOperation { Get, Set, Delete }; -class CredentialQuery +class CORE_EXPORT CredentialQuery { public: void setOperation(CredentialOperation operation) { m_operation = operation; } @@ -30,7 +32,7 @@ private: friend class CredentialQueryTaskAdapter; }; -class CredentialQueryTaskAdapter final : public Tasking::TaskAdapter +class CORE_EXPORT CredentialQueryTaskAdapter final : public Tasking::TaskAdapter { private: ~CredentialQueryTaskAdapter(); @@ -40,4 +42,4 @@ private: using CredentialQueryTask = Tasking::CustomTask; -} // Axivion::Internal +} // Core diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp index dee9ebe6409..828f396433e 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -42,8 +42,8 @@ #include -const int kInitialWidth = 750; -const int kInitialHeight = 450; +const int kInitialWidth = 800; +const int kInitialHeight = 500; const int kMaxMinimumWidth = 250; const int kMaxMinimumHeight = 250; diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index b5f719f4a22..1b6af89db22 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -187,7 +187,7 @@ bool FileUtils::renameFile(const FilePath &orgFilePath, const FilePath &newFileP if (vc && vc->supportsOperation(IVersionControl::MoveOperation)) result = vc->vcsMove(orgFilePath, newFilePath); if (!result) // The moving via vcs failed or the vcs does not support moving, fall back - result = orgFilePath.renameFile(newFilePath).has_value(); + result = bool(orgFilePath.renameFile(newFilePath)); if (result) { DocumentManager::renamedFile(orgFilePath, newFilePath); updateHeaderFileGuardIfApplicable(orgFilePath, newFilePath, handleGuards); diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index 2d997dd020a..a1c8bcbc7fb 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -10,6 +10,7 @@ #include #include +using namespace Tasking; using namespace Utils; namespace Core { @@ -25,12 +26,9 @@ CommandLocator::CommandLocator(Id id, const QString &displayName, const QString LocatorMatcherTasks CommandLocator::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, commands = m_commands] { - const QString input = storage->input(); + const auto onSetup = [commands = m_commands] { + const LocatorStorage &storage = *LocatorStorage::storage(); + const QString input = storage.input(); const Qt::CaseSensitivity inputCaseSensitivity = caseSensitivity(input); LocatorFilterEntries goodEntries; LocatorFilterEntries betterEntries; @@ -63,9 +61,9 @@ LocatorMatcherTasks CommandLocator::matchers() goodEntries.append(entry); } } - storage->reportOutput(betterEntries + goodEntries); + storage.reportOutput(betterEntries + goodEntries); }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } } // namespace Core diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 629099207ed..5feeae26592 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -18,6 +18,7 @@ #include #include +using namespace Tasking; using namespace Utils; namespace Core::Internal { @@ -40,12 +41,9 @@ ExecuteFilter::~ExecuteFilter() LocatorMatcherTasks ExecuteFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [this, storage] { - const QString input = storage->input(); + const auto onSetup = [this] { + const LocatorStorage &storage = *LocatorStorage::storage(); + const QString input = storage.input(); LocatorFilterEntries entries; if (!input.isEmpty()) { // avoid empty entry LocatorFilterEntry entry; @@ -69,9 +67,9 @@ LocatorMatcherTasks ExecuteFilter::matchers() others.append(entry); } } - storage->reportOutput(entries + others); + storage.reportOutput(entries + others); }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } void ExecuteFilter::acceptCommand(const QString &cmd) diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index 86811e55b0b..1389c9169bb 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -13,6 +13,8 @@ #include +using namespace Tasking; + namespace Core::Internal { ExternalToolsFilter::ExternalToolsFilter() @@ -27,12 +29,9 @@ ExternalToolsFilter::ExternalToolsFilter() LocatorMatcherTasks ExternalToolsFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage] { - const QString input = storage->input(); + const auto onSetup = [] { + const LocatorStorage &storage = *LocatorStorage::storage(); + const QString input = storage.input(); LocatorFilterEntries bestEntries; LocatorFilterEntries betterEntries; @@ -77,10 +76,10 @@ LocatorMatcherTasks ExternalToolsFilter::matchers() return AcceptResult(); }; - storage->reportOutput(bestEntries + betterEntries + goodEntries - + LocatorFilterEntries{configEntry}); + storage.reportOutput(bestEntries + betterEntries + goodEntries + + LocatorFilterEntries{configEntry}); }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } } // Core::Internal diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 6b484635e40..2bc451dcf70 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -31,6 +31,7 @@ #include #include +using namespace Tasking; using namespace Utils; namespace Core::Internal { @@ -304,17 +305,13 @@ static void matches(QPromise &promise, const LocatorStorage &storage, LocatorMatcherTasks FileSystemFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, includeHidden = m_includeHidden, shortcut = shortcutString()] + const auto onSetup = [includeHidden = m_includeHidden, shortcut = shortcutString()] (Async &async) { - async.setConcurrentCallData(matches, *storage, shortcut, + async.setConcurrentCallData(matches, *LocatorStorage::storage(), shortcut, DocumentManager::fileDialogInitialDirectory(), includeHidden); }; - return {{AsyncTask(onSetup), storage}}; + return {AsyncTask(onSetup)}; } class FileSystemFilterOptions : public QDialog diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 371a679d030..ee5e88451e7 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -291,6 +291,14 @@ void LocatorStorage::reportOutput(const LocatorFilterEntries &outputData) const d->reportOutput(outputData); } +// Please note the thread_local keyword below guarantees a separate instance per thread. +static thread_local Storage s_locatorStorage = {}; + +Storage &LocatorStorage::storage() +{ + return s_locatorStorage; +} + void LocatorStorage::finalize() const { QTC_ASSERT(d, return); @@ -366,16 +374,16 @@ void LocatorMatcher::start() const auto onTaskTreeSetup = [iterator, input = d->m_input, collectorStorage](TaskTree &taskTree) { const std::shared_ptr deduplicator = collectorStorage->m_deduplicator; - const Storage storage = iterator->storage; - const auto onSetup = [storage, input, index = iterator.iteration(), deduplicator] { - *storage = std::make_shared(input, index, deduplicator); + const auto onSetup = [input, index = iterator.iteration(), deduplicator] { + *LocatorStorage::storage() + = std::make_shared(input, index, deduplicator); }; taskTree.setRecipe({ finishAllAndSuccess, - storage, + LocatorStorage::storage(), onGroupSetup(onSetup), - iterator->task, - onGroupDone([storage] { storage->finalize(); }) + *iterator, + onGroupDone([] { LocatorStorage::storage()->finalize(); }) }); }; @@ -1357,12 +1365,11 @@ static void filter(QPromise &promise, const LocatorStor 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 +ExecutableItem LocatorFileCache::matcher() const { - Storage storage; std::weak_ptr weak = d; - const auto onSetup = [storage, weak](Async &async) { + const auto onSetup = [weak](Async &async) { auto that = weak.lock(); if (!that) // LocatorMatcher is running after *this LocatorFileCache was destructed. return SetupResult::StopWithSuccess; @@ -1372,7 +1379,7 @@ LocatorMatcherTask LocatorFileCache::matcher() const // no provider is set or it returned empty generator that->bumpExecutionId(); - async.setConcurrentCallData(&filter, *storage, *that); + async.setConcurrentCallData(&filter, *LocatorStorage::storage(), *that); return SetupResult::Continue; }; const auto onDone = [weak](const Async &async) { @@ -1392,7 +1399,7 @@ LocatorMatcherTask LocatorFileCache::matcher() const that->update(async.result()); }; - return {AsyncTask(onSetup, onDone, CallDoneIf::Success), storage}; + return AsyncTask(onSetup, onDone, CallDoneIf::Success); } } // Core diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 368f0313814..399631873c7 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -126,6 +126,8 @@ public: LocatorStorage() = default; QString input() const; void reportOutput(const LocatorFilterEntries &outputData) const; + // Only use it from inside the bodies of Task handlers. + static Tasking::Storage &storage(); private: friend class LocatorMatcher; @@ -134,18 +136,7 @@ private: std::shared_ptr d; }; -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(). - Tasking::GroupItem task = Tasking::Group{}; - - // When constructing the task, don't place the storage inside the task above. - Tasking::Storage storage; -}; - -using LocatorMatcherTasks = QList; +using LocatorMatcherTasks = QList; using LocatorMatcherTaskCreator = std::function; class LocatorMatcherPrivate; @@ -315,7 +306,7 @@ public: std::optional filePaths() const; static FilePathsGenerator filePathsGenerator(const Utils::FilePaths &filePaths); - LocatorMatcherTask matcher() const; + Tasking::ExecutableItem matcher() const; using MatchedEntries = std::array; static Utils::FilePaths processFilePaths(const QFuture &future, diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index c63271bb8df..c4c174d7822 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -366,15 +366,15 @@ JavaScriptFilter::~JavaScriptFilter() = default; LocatorMatcherTasks JavaScriptFilter::matchers() { - Storage storage; if (!m_javaScriptEngine) m_javaScriptEngine.reset(new JavaScriptEngine); QPointer engine = m_javaScriptEngine.get(); - const auto onSetup = [storage, engine] { + const auto onSetup = [engine] { + const LocatorStorage &storage = *LocatorStorage::storage(); if (!engine) return SetupResult::StopWithError; - if (storage->input().trimmed().isEmpty()) { + if (storage.input().trimmed().isEmpty()) { LocatorFilterEntry entry; entry.displayName = Tr::tr("Reset Engine"); entry.acceptor = [engine] { @@ -385,21 +385,22 @@ LocatorMatcherTasks JavaScriptFilter::matchers() } return AcceptResult(); }; - storage->reportOutput({entry}); + storage.reportOutput({entry}); return SetupResult::StopWithSuccess; } return SetupResult::Continue; }; - const auto onJavaScriptSetup = [storage, engine](JavaScriptRequest &request) { + const auto onJavaScriptSetup = [engine](JavaScriptRequest &request) { request.setEngine(engine); - request.setEvaluateData(storage->input()); + request.setEvaluateData(LocatorStorage::storage()->input()); }; - const auto onJavaScriptDone = [storage](const JavaScriptRequest &request, DoneWith result) { + const auto onJavaScriptDone = [](const JavaScriptRequest &request, DoneWith result) { + const LocatorStorage &storage = *LocatorStorage::storage(); if (result != DoneWith::Success) { LocatorFilterEntry entry; entry.displayName = request.output().m_output; - storage->reportOutput({entry}); + storage.reportOutput({entry}); return; } const auto acceptor = [](const QString &clipboardContents) { @@ -408,7 +409,7 @@ LocatorMatcherTasks JavaScriptFilter::matchers() return AcceptResult(); }; }; - const QString input = storage->input(); + const QString input = storage.input(); const QString output = request.output().m_output; const QString expression = input + " = " + output; @@ -423,7 +424,7 @@ LocatorMatcherTasks JavaScriptFilter::matchers() copyExpressionEntry.displayName = Tr::tr("Copy to clipboard: %1").arg(expression); copyExpressionEntry.acceptor = acceptor(expression); - storage->reportOutput({entry, copyResultEntry, copyExpressionEntry}); + storage.reportOutput({entry, copyResultEntry, copyExpressionEntry}); }; const Group root { @@ -431,7 +432,7 @@ LocatorMatcherTasks JavaScriptFilter::matchers() JavaScriptRequestTask(onJavaScriptSetup, onJavaScriptDone) }; - return {{root, storage}}; + return {root}; } } // namespace Core::Internal diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp index fa44d967e67..ee24a262438 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp @@ -9,6 +9,7 @@ #include +using namespace Tasking; using namespace Utils; namespace Core::Internal { @@ -26,12 +27,9 @@ LocatorFiltersFilter::LocatorFiltersFilter(): LocatorMatcherTasks LocatorFiltersFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, icon = m_icon] { - if (!storage->input().isEmpty()) + const auto onSetup = [icon = m_icon] { + const LocatorStorage &storage = *LocatorStorage::storage(); + if (!storage.input().isEmpty()) return; QMap uniqueFilters; @@ -60,9 +58,9 @@ LocatorMatcherTasks LocatorFiltersFilter::matchers() entries.append(entry); } } - storage->reportOutput(entries); + storage.reportOutput(entries); }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } } // Core::Internal diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index ede24d5b892..b080894fcb2 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -70,15 +70,13 @@ static void matchEditors(QPromise &promise, const LocatorStorage &storage, LocatorMatcherTasks OpenDocumentsFilter::matchers() { - Storage storage; - - const auto onSetup = [storage](Async &async) { + const auto onSetup = [](Async &async) { const QList editorsData = Utils::transform(DocumentModel::entries(), [](const DocumentModel::Entry *e) { return Entry{e->filePath(), e->displayName()}; }); - async.setConcurrentCallData(matchEditors, *storage, editorsData); + async.setConcurrentCallData(matchEditors, *LocatorStorage::storage(), editorsData); }; - return {{AsyncTask(onSetup), storage}}; + return {AsyncTask(onSetup)}; } } // namespace Core::Internal diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index bcc685c9532..78fdf895fcf 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -24,6 +24,7 @@ #include #include +using namespace Tasking; using namespace Utils; namespace Core::Internal { @@ -176,16 +177,12 @@ static void matches(QPromise &promise, LocatorMatcherTasks SpotlightLocatorFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, - command = m_command, + const auto onSetup = [command = m_command, insensArgs = m_arguments, sensArgs = m_caseSensitiveArguments, sortResults = m_sortResults](Async &async) { - const Link link = Link::fromString(storage->input(), true); + const LocatorStorage &storage = *LocatorStorage::storage(); + const Link link = Link::fromString(storage.input(), true); const FilePath input = link.targetFilePath; if (input.isEmpty()) return SetupResult::StopWithSuccess; @@ -196,11 +193,11 @@ LocatorMatcherTasks SpotlightLocatorFilter::matchers() ? insensArgs : sensArgs; const CommandLine cmd(FilePath::fromString(command), expander->expand(args), CommandLine::Raw); - async.setConcurrentCallData(matches, *storage, cmd, sortResults); + async.setConcurrentCallData(matches, storage, cmd, sortResults); return SetupResult::Continue; }; - return {{AsyncTask(onSetup), storage}}; + return {AsyncTask(onSetup)}; } bool SpotlightLocatorFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.cpp b/src/plugins/coreplugin/locator/urllocatorfilter.cpp index 7457f0907cc..d96b6411ed6 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/urllocatorfilter.cpp @@ -18,6 +18,7 @@ #include #include +using namespace Tasking; using namespace Utils; namespace Core { @@ -163,12 +164,9 @@ UrlLocatorFilter::UrlLocatorFilter(const QString &displayName, Id id) LocatorMatcherTasks UrlLocatorFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, urls = remoteUrls()] { - const QString input = storage->input(); + const auto onSetup = [urls = remoteUrls()] { + const LocatorStorage &storage = *LocatorStorage::storage(); + const QString input = storage.input(); LocatorFilterEntries entries; for (const QString &url : urls) { const QString name = url.arg(input); @@ -182,9 +180,9 @@ LocatorMatcherTasks UrlLocatorFilter::matchers() entry.highlightInfo = {int(name.lastIndexOf(input)), int(input.length())}; entries.append(entry); } - storage->reportOutput(entries); + storage.reportOutput(entries); }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } const char kDisplayNameKey[] = "displayName"; diff --git a/src/plugins/coreplugin/session.cpp b/src/plugins/coreplugin/session.cpp index 5fa186e3e24..88e4749b51f 100644 --- a/src/plugins/coreplugin/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -351,9 +351,9 @@ bool SessionManager::deleteSession(const QString &session) FilePath sessionFile = sessionNameToFileName(session); if (!sessionFile.exists()) return false; - expected_str result = sessionFile.removeFile(); + Result result = sessionFile.removeFile(); QTC_CHECK_EXPECTED(result); - return result.has_value(); + return bool(result); } void SessionManager::deleteSessions(const QStringList &sessions) diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 7526d3dc9f9..b1e7c552e0a 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -19,13 +19,14 @@ using namespace Core; using namespace CPlusPlus; +using namespace Tasking; using namespace Utils; namespace CppEditor { using EntryFromIndex = std::function; -void matchesFor(QPromise &promise, const LocatorStorage &storage, +static void matchesFor(QPromise &promise, const LocatorStorage &storage, IndexItem::ItemType wantedType, const EntryFromIndex &converter) { const QString input = storage.input(); @@ -99,19 +100,15 @@ void matchesFor(QPromise &promise, const LocatorStorage &storage, LocatorFilterEntries())); } -LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex &converter) +static ExecutableItem locatorMatcher(IndexItem::ItemType type, const EntryFromIndex &converter) { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [=](Async &async) { - async.setConcurrentCallData(matchesFor, *storage, type, converter); + const auto onSetup = [type, converter](Async &async) { + async.setConcurrentCallData(matchesFor, *LocatorStorage::storage(), type, converter); }; - return {AsyncTask(onSetup), storage}; + return AsyncTask(onSetup); } -LocatorMatcherTask allSymbolsMatcher() +static ExecutableItem allSymbolsMatcher() { const auto converter = [](const IndexItem::Ptr &info) { LocatorFilterEntry filterEntry; @@ -129,7 +126,7 @@ LocatorMatcherTask allSymbolsMatcher() return locatorMatcher(IndexItem::All, converter); } -LocatorMatcherTask classMatcher() +static ExecutableItem classMatcher() { const auto converter = [](const IndexItem::Ptr &info) { LocatorFilterEntry filterEntry; @@ -145,7 +142,7 @@ LocatorMatcherTask classMatcher() return locatorMatcher(IndexItem::Class, converter); } -LocatorMatcherTask functionMatcher() +static ExecutableItem functionMatcher() { const auto converter = [](const IndexItem::Ptr &info) { QString name = info->symbolName(); @@ -166,7 +163,7 @@ LocatorMatcherTask functionMatcher() return locatorMatcher(IndexItem::Function, converter); } -QList itemsOfCurrentDocument(const FilePath ¤tFileName) +static QList itemsOfCurrentDocument(const FilePath ¤tFileName) { if (currentFileName.isEmpty()) return {}; @@ -188,7 +185,7 @@ QList itemsOfCurrentDocument(const FilePath ¤tFileName) return results; } -LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &match, +static LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &match, LocatorFilterEntry::HighlightInfo::DataType dataType) { const FuzzyMatcher::HighlightingPositions positions = @@ -197,7 +194,7 @@ LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &m return LocatorFilterEntry::HighlightInfo(positions.starts, positions.lengths, dataType); } -void matchesForCurrentDocument(QPromise &promise, const LocatorStorage &storage, +static void matchesForCurrentDocument(QPromise &promise, const LocatorStorage &storage, const FilePath ¤tFileName) { const QString input = storage.input(); @@ -290,25 +287,21 @@ void matchesForCurrentDocument(QPromise &promise, const LocatorStorage &st [](const Entry &entry) { return entry.entry; })); } -FilePath currentFileName() +static FilePath currentFileName() { IEditor *currentEditor = EditorManager::currentEditor(); return currentEditor ? currentEditor->document()->filePath() : FilePath(); } -LocatorMatcherTask currentDocumentMatcher() +static ExecutableItem currentDocumentMatcher() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [=](Async &async) { - async.setConcurrentCallData(matchesForCurrentDocument, *storage, currentFileName()); + const auto onSetup = [](Async &async) { + async.setConcurrentCallData(matchesForCurrentDocument, *LocatorStorage::storage(), currentFileName()); }; - return {AsyncTask(onSetup), storage}; + return AsyncTask(onSetup); } -using MatcherCreator = std::function; +using MatcherCreator = std::function; static MatcherCreator creatorForType(MatcherType type) { diff --git a/src/plugins/cppeditor/cpplocatorfilter_test.cpp b/src/plugins/cppeditor/cpplocatorfilter_test.cpp index a621d1c1103..ffb9eaa24f3 100644 --- a/src/plugins/cppeditor/cpplocatorfilter_test.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter_test.cpp @@ -28,7 +28,7 @@ QTC_DECLARE_MYTESTDATADIR("../../../tests/cpplocators/") class CppLocatorFilterTestCase : public CppEditor::Tests::TestCase { public: - CppLocatorFilterTestCase(const QList &matchers, + CppLocatorFilterTestCase(const LocatorMatcherTasks &matchers, const QString &fileName, const QString &searchText, const ResultDataList &expectedResults) @@ -54,7 +54,7 @@ class CppCurrentDocumentFilterTestCase : public CppEditor::Tests::TestCase { public: CppCurrentDocumentFilterTestCase(const FilePath &filePath, - const QList &matchers, + const LocatorMatcherTasks &matchers, const ResultDataList &expectedResults, const QString &searchText = QString()) { diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 00100592c5b..50ab3ba5d22 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -510,7 +510,7 @@ public: QAction m_abortAction{Tr::tr("Abort Debugging")}; QAction m_stepIntoAction{Tr::tr("Step Into")}; QAction m_stepOutAction{Tr::tr("Step Out")}; - QAction m_toggleEnableBreakpointsAction{Tr::tr("Disable all Breakpoints")}; + QAction m_toggleEnableBreakpointsAction{Tr::tr("Disable All Breakpoints")}; QAction m_runToLineAction{Tr::tr("Run to Line")}; // In the debug menu QAction m_runToSelectedFunctionAction{Tr::tr("Run to Selected Function")}; QAction m_jumpToLineAction{Tr::tr("Jump to Line")}; diff --git a/src/plugins/debugger/debuggerkitaspect.cpp b/src/plugins/debugger/debuggerkitaspect.cpp index e70ab1430cd..dc21b046062 100644 --- a/src/plugins/debugger/debuggerkitaspect.cpp +++ b/src/plugins/debugger/debuggerkitaspect.cpp @@ -20,8 +20,6 @@ #include #include -#include - #include using namespace ProjectExplorer; @@ -43,18 +41,6 @@ public: , m_kit(kit) {} - QModelIndex indexForId(const QVariant &id) const - { - // The "None" item always comes last - const auto noneIndex = [this] { return index(rowCount() - 1, 0); }; - - if (id.isNull()) - return noneIndex(); - const TreeItem *const item = findItemAtLevel<1>( - [id](TreeItem *item) { return item->data(0, DebuggerTreeItem::IdRole) == id; }); - return item ? indexForItem(item) : noneIndex(); - } - void reset() { clear(); @@ -83,12 +69,6 @@ class DebuggerItemSortModel : public SortModel public: DebuggerItemSortModel(QObject *parent) : SortModel(parent) {} - QModelIndex indexForId(const QVariant &id) const - { - return mapFromSource( - static_cast(sourceModel())->indexForId(id)); - } - void reset() { static_cast(sourceModel())->reset(); } private: @@ -135,58 +115,24 @@ public: { setManagingPage(ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID); - m_comboBox = createSubWidget(); - m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy()); - m_comboBox->setEnabled(true); const auto sortModel = new DebuggerItemSortModel(this); sortModel->setSourceModel(new DebuggerItemListModel(*workingCopy, this)); - m_comboBox->setModel(sortModel); - - refresh(); - m_comboBox->setToolTip(factory->description()); - connect(m_comboBox, &QComboBox::currentIndexChanged, this, [this] { - if (m_ignoreChanges.isLocked()) - return; - m_kit->setValue(DebuggerKitAspect::id(), currentId()); - }); - + auto getter = [](const Kit &k) { + if (const DebuggerItem * const item = DebuggerKitAspect::debugger(&k)) + return item->id(); + return QVariant(); + }; + auto setter = [](Kit &k, const QVariant &id) { k.setValue(DebuggerKitAspect::id(), id); }; + auto resetModel = [](QAbstractItemModel &model) { + static_cast(model).reset(); + }; + setListAspectSpec( + {sortModel, + std::move(getter), + std::move(setter), + std::move(resetModel), + DebuggerTreeItem::IdRole}); } - - ~DebuggerKitAspectImpl() override - { - delete m_comboBox; - } - -private: - void addToInnerLayout(Layouting::Layout &parent) override - { - addMutableAction(m_comboBox); - parent.addItem(m_comboBox); - } - - void makeReadOnly() override - { - KitAspect::makeReadOnly(); - m_comboBox->setEnabled(false); - } - - void refresh() override - { - const GuardLocker locker(m_ignoreChanges); - const auto sortModel = static_cast(m_comboBox->model()); - sortModel->reset(); - sortModel->sort(0); - const DebuggerItem * const item = DebuggerKitAspect::debugger(m_kit); - m_comboBox->setCurrentIndex(sortModel->indexForId(item ? item->id() : QVariant()).row()); - } - - QVariant currentId() const - { - return m_comboBox->itemData(m_comboBox->currentIndex(), DebuggerTreeItem::IdRole); - } - - Guard m_ignoreChanges; - QComboBox *m_comboBox; }; } // namespace Internal diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index c1e70eeda7c..50c4428d8e1 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -83,92 +83,27 @@ static QString noDebuggerInKitMessage() return Tr::tr("The kit does not have a debugger set."); } -class CoreUnpacker final : public RunWorker -{ -public: - CoreUnpacker(RunControl *runControl, const FilePath &coreFilePath) - : RunWorker(runControl), m_coreFilePath(coreFilePath) - {} - - FilePath coreFileName() const { return m_tempCoreFilePath; } - -private: - ~CoreUnpacker() final - { - if (m_tempCoreFile.isOpen()) - m_tempCoreFile.close(); - - m_tempCoreFilePath.removeFile(); - } - - void start() final - { - { - Utils::TemporaryFile tmp("tmpcore-XXXXXX"); - tmp.open(); - m_tempCoreFilePath = FilePath::fromString(tmp.fileName()); - } - - m_coreUnpackProcess.setWorkingDirectory(TemporaryDirectory::masterDirectoryFilePath()); - connect(&m_coreUnpackProcess, &Process::done, this, [this] { - if (m_coreUnpackProcess.error() == QProcess::UnknownError) { - reportStopped(); - return; - } - reportFailure("Error unpacking " + m_coreFilePath.toUserOutput()); - }); - - const QString msg = Tr::tr("Unpacking core file to %1"); - appendMessage(msg.arg(m_tempCoreFilePath.toUserOutput()), LogMessageFormat); - - if (m_coreFilePath.endsWith(".lzo")) { - m_coreUnpackProcess.setCommand({"lzop", {"-o", m_tempCoreFilePath.path(), - "-x", m_coreFilePath.path()}}); - reportStarted(); - m_coreUnpackProcess.start(); - return; - } - - if (m_coreFilePath.endsWith(".gz")) { - appendMessage(msg.arg(m_tempCoreFilePath.toUserOutput()), LogMessageFormat); - m_tempCoreFile.setFileName(m_tempCoreFilePath.path()); - m_tempCoreFile.open(QFile::WriteOnly); - connect(&m_coreUnpackProcess, &Process::readyReadStandardOutput, this, [this] { - m_tempCoreFile.write(m_coreUnpackProcess.readAllRawStandardOutput()); - }); - m_coreUnpackProcess.setCommand({"gzip", {"-c", "-d", m_coreFilePath.path()}}); - reportStarted(); - m_coreUnpackProcess.start(); - return; - } - - QTC_CHECK(false); - reportFailure("Unknown file extension in " + m_coreFilePath.toUserOutput()); - } - - QFile m_tempCoreFile; - FilePath m_coreFilePath; - FilePath m_tempCoreFilePath; - Process m_coreUnpackProcess; -}; - class DebuggerRunToolPrivate { public: - QPointer coreUnpacker; bool addQmlServerInferiorCommandLineArgumentIfNeeded = false; int snapshotCounter = 0; int engineStartsNeeded = 0; int engineStopsNeeded = 0; QString runId; + // Core unpacker + QFile m_tempCoreFile; + FilePath m_tempCoreFilePath; + Process m_coreUnpackProcess; + // Terminal Process terminalProc; DebuggerRunTool::AllowTerminal allowTerminal = DebuggerRunTool::DoAllowTerminal; // DebugServer Process debuggerServerProc; - Utils::ProcessHandle serverAttachPid; + ProcessHandle serverAttachPid; bool serverUseMulti = true; bool serverEssential = true; }; @@ -369,11 +304,6 @@ void DebuggerRunTool::setStartMessage(const QString &msg) void DebuggerRunTool::setCoreFilePath(const FilePath &coreFile, bool isSnapshot) { - if (coreFile.endsWith(".gz") || coreFile.endsWith(".lzo")) { - d->coreUnpacker = new CoreUnpacker(runControl(), coreFile); - addStartDependency(d->coreUnpacker); - } - m_runParameters.coreFile = coreFile; m_runParameters.isSnapshot = isSnapshot; } @@ -405,6 +335,63 @@ void DebuggerRunTool::addSearchDirectory(const Utils::FilePath &dir) void DebuggerRunTool::start() { + startCoreFileSetupIfNeededAndContinueStartup(); +} + +void DebuggerRunTool::startCoreFileSetupIfNeededAndContinueStartup() +{ + const FilePath coreFile = m_runParameters.coreFile; + if (!coreFile.endsWith(".gz") && !coreFile.endsWith(".lzo")) { + continueAfterCoreFileSetup(); + return; + } + + { + TemporaryFile tmp("tmpcore-XXXXXX"); + tmp.open(); + d->m_tempCoreFilePath = FilePath::fromString(tmp.fileName()); + } + + d->m_coreUnpackProcess.setWorkingDirectory(TemporaryDirectory::masterDirectoryFilePath()); + connect(&d->m_coreUnpackProcess, &Process::done, this, [this] { + if (d->m_coreUnpackProcess.error() == QProcess::UnknownError) { + m_runParameters.coreFile = d->m_tempCoreFilePath; + continueAfterCoreFileSetup(); + return; + } + reportFailure("Error unpacking " + m_runParameters.coreFile.toUserOutput()); + }); + + const QString msg = Tr::tr("Unpacking core file to %1"); + appendMessage(msg.arg(d->m_tempCoreFilePath.toUserOutput()), LogMessageFormat); + + if (coreFile.endsWith(".lzo")) { + d->m_coreUnpackProcess.setCommand({"lzop", {"-o", d->m_tempCoreFilePath.path(), + "-x", coreFile.path()}}); + d->m_coreUnpackProcess.start(); + return; + } + + if (coreFile.endsWith(".gz")) { + d->m_tempCoreFile.setFileName(d->m_tempCoreFilePath.path()); + d->m_tempCoreFile.open(QFile::WriteOnly); + connect(&d->m_coreUnpackProcess, &Process::readyReadStandardOutput, this, [this] { + d->m_tempCoreFile.write(d->m_coreUnpackProcess.readAllRawStandardOutput()); + }); + d->m_coreUnpackProcess.setCommand({"gzip", {"-c", "-d", coreFile.path()}}); + d->m_coreUnpackProcess.start(); + return; + } + + QTC_CHECK(false); + reportFailure("Unknown file extension in " + coreFile.toUserOutput()); +} + +void DebuggerRunTool::continueAfterCoreFileSetup() +{ + if (d->m_tempCoreFile.isOpen()) + d->m_tempCoreFile.close(); + startTerminalIfNeededAndContinueStartup(); } @@ -497,9 +484,6 @@ void DebuggerRunTool::continueAfterTerminalStart() // return; // } - if (d->coreUnpacker) - m_runParameters.coreFile = d->coreUnpacker->coreFileName(); - if (!fixupParameters()) return; @@ -978,6 +962,9 @@ void DebuggerRunTool::addSolibSearchDir(const QString &str) DebuggerRunTool::~DebuggerRunTool() { + if (d->m_tempCoreFilePath.exists()) + d->m_tempCoreFilePath.removeFile(); + if (m_runParameters.isSnapshot && !m_runParameters.coreFile.isEmpty()) m_runParameters.coreFile.removeFile(); diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index 4caf61112d4..4a2898fc3cd 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -111,6 +111,9 @@ private: void handleEngineStarted(Internal::DebuggerEngine *engine); void handleEngineFinished(Internal::DebuggerEngine *engine); + void startCoreFileSetupIfNeededAndContinueStartup(); + void continueAfterCoreFileSetup(); + void startTerminalIfNeededAndContinueStartup(); void continueAfterTerminalStart(); diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index 937c77b8e19..cc1b5ce3ebc 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -232,7 +232,7 @@ void AttachCoreDialog::accepted() const expected_str resultPath = pattern.createTempFile(); if (!resultPath) return make_unexpected(resultPath.error()); - const expected_str result = srcPath.copyFile(resultPath.value()); + const Result result = srcPath.copyFile(resultPath.value()); if (!result) return make_unexpected(result.error()); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index aecf3dd82ba..78cbfa32e55 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -582,7 +582,7 @@ DockerDevice::DockerDevice() return make_unexpected(cmdBridgePath.error()); auto fAccess = std::make_unique(d); - expected_str initResult; + Result initResult = Result::Ok; if (!cmdBridgePath->isSameDevice(Docker::Internal::settings().dockerBinaryPath())) { initResult = fAccess->deployAndInit(Core::ICore::libexecPath(), rootPath()); } else { diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index 15ccea6b1ba..a044c961590 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -171,6 +171,8 @@ public: constexpr static QSize dividerS{1, 16}; constexpr static TextFormat itemNameTF {Theme::Token_Text_Default, UiElement::UiElementH6}; + constexpr static TextFormat releaseStatusTF + {Theme::Token_Notification_Alert, UiElement::UiElementLabelSmall}; constexpr static TextFormat countTF {Theme::Token_Text_Default, UiElement::UiElementLabelSmall, Qt::AlignCenter | Qt::TextDontClip}; @@ -190,23 +192,23 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { - // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+---------+ - // | | | | (ExPaddingGapL) | | | - // | | | +-----------------------------+---------+--------+---------+-----------+ | | - // | | | | |(HGapXxs)||(HGapXxs)|| | | - // | | | +-----------------------------+---------+--------+---------+-----------+ | | - // | | | | (VGapXxs) | | | - // | | | +--------+--------+--------------+--------+--------+---------+---------+ | | - // |(ExPaddingGapL)| |(ExPaddingGapL)||(HGapXs)|(h16)|(HGapXs)||(HGapXxs)||(ExPaddingGapL)|(gapSize)| - // | |(50x50)| +--------+--------+--------------+--------+--------+---------+---------+ | | - // | | | | (VGapXxs) | | | - // | | | +----------------------------------------------------------------------+ | | - // | | | | | | | - // | | | +----------------------------------------------------------------------+ | | - // | | | | (ExPaddingGapL) | | | - // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+---------+ - // | (gapSize) | - // +----------------------------------------------------------------------------------------------------------------------------------------+ + // +---------------+-------+---------------+-----------------------------------------------------------------------------------+---------------+---------+ + // | | | | (ExPaddingGapL) | | | + // | | | +----------+---------+---------------+---------+--------------+---------+-----------+ | | + // | | | ||(HGapXxs)||(HGapXxs)||(HGapXxs)|| | | + // | | | +----------+---------+---------------+---------+--------------+---------+-----------+ | | + // | | | | (VGapXxs) | | | + // | | | +---------------------+--------+--------------+--------+--------+---------+---------+ | | + // |(ExPaddingGapL)| |(ExPaddingGapL)| |(HGapXs)|(h16)|(HGapXs)||(HGapXxs)||(ExPaddingGapL)|(gapSize)| + // | |(50x50)| +---------------------+--------+--------------+--------+--------+---------+---------+ | | + // | | | | (VGapXxs) | | | + // | | | +-----------------------------------------------------------------------------------+ | | + // | | | | | | | + // | | | +-----------------------------------------------------------------------------------+ | | + // | | | | (ExPaddingGapL) | | | + // +---------------+-------+---------------+-----------------------------------------------------------------------------------+---------------+---------+ + // | (gapSize) | + // +-----------------------------------------------------------------------------------------------------------------------------------------------------+ const QRect bgRGlobal = option.rect.adjusted(0, 0, -gapSize, -gapSize); const QRect bgR = bgRGlobal.translated(-option.rect.topLeft()); @@ -267,6 +269,10 @@ public: const QPixmap icon = itemIcon(index, SizeSmall); painter->drawPixmap(iconBgR.topLeft(), icon); } + { + const QPixmap badge = itemBadge(index, SizeSmall); + painter->drawPixmap(bgR.topLeft(), badge); + } if (isPack) { constexpr int circleSize = 18; constexpr int circleOverlap = 3; // Protrusion from lower right corner of iconRect @@ -286,16 +292,40 @@ public: QRect effectiveR = itemNameR; if (showState) effectiveR.setRight(stateR.left() - HGapXxs - 1); + const QString releaseStatus = statusDisplayString(index); + const bool showReleaseStatus = !releaseStatus.isEmpty(); + + if (showReleaseStatus) { + const QFont releaseStatusF = releaseStatusTF.font(); + const int releaseStatusAdv = + QFontMetrics(releaseStatusF).horizontalAdvance(releaseStatus) + + (showState ? ExVPaddingGapXl - HGapXxs + : HGapXxs); + effectiveR.setWidth(effectiveR.width() - releaseStatusAdv); + } + painter->setPen(itemNameTF.color()); painter->setFont(itemNameTF.font()); const QString titleElided = painter->fontMetrics().elidedText(itemName, Qt::ElideRight, effectiveR.width()); painter->drawText(effectiveR, itemNameTF.drawTextFlags, titleElided); + + if (showReleaseStatus) { + const int titleElidedAdv = painter->fontMetrics().horizontalAdvance(titleElided); + const QRect releaseStatusR(effectiveR.x() + titleElidedAdv + HGapXxs, + effectiveR.y(), 1, effectiveR.height() - 1); + painter->setPen(releaseStatusTF.color()); + painter->setFont(releaseStatusTF.font()); + painter->drawText(releaseStatusR, releaseStatusTF.drawTextFlags, releaseStatus); + } } if (showState) { - static const QIcon checkmark = Icon({{":/extensionmanager/images/checkmark.png", - stateTF.themeColor}}, Icon::Tint).icon(); - checkmark.paint(painter, checkmarkR); + const FilePath checkmarkMask = ":/extensionmanager/images/checkmark.png"; + static const QIcon enabled = Icon({{checkmarkMask, Theme::Token_Accent_Muted}}, + Icon::Tint).icon(); + static const QIcon disabled = Icon({{checkmarkMask, stateTF.themeColor}}, + Icon::Tint).icon(); + (state == InstalledEnabled ? enabled : disabled).paint(painter, checkmarkR); painter->setPen(stateTF.color()); painter->setFont(stateTF.font()); painter->drawText(stateR, stateTF.drawTextFlags, stateString); @@ -518,6 +548,7 @@ ExtensionsBrowser::ExtensionsBrowser(ExtensionsModel *model, QWidget *parent) Tr::tr("Filter by: %1")); d->filterChooser->addItems(Utils::transform(SortFilterProxyModel::filterOptions(), &SortFilterProxyModel::FilterOption::displayName)); + d->filterChooser->hide(); // TODO: Unhide when ready. See QTCREATORBUG-31751 d->sortChooser = new OptionChooser(":/extensionmanager/images/sort.png", Tr::tr("Sort by: %1")); d->sortChooser->addItems(Utils::transform(SortFilterProxyModel::sortOptions(), @@ -549,11 +580,11 @@ ExtensionsBrowser::ExtensionsBrowser(ExtensionsModel *model, QWidget *parent) customMargins(0, VPaddingM, extraListViewWidth() + gapSize, VPaddingM), }, Row { - d->filterChooser, - Space(HGapS), d->sortChooser, + d->filterChooser, st, settingsToolButton, + spacing(HGapS), customMargins(0, 0, extraListViewWidth() + gapSize, 0), }, d->extensionsView, @@ -587,7 +618,7 @@ ExtensionsBrowser::ExtensionsBrowser(ExtensionsModel *model, QWidget *parent) d->sortFilterProxyModel, &SortFilterProxyModel::setSortOption); connect(d->filterChooser, &OptionChooser::currentIndexChanged, d->sortFilterProxyModel, &SortFilterProxyModel::setFilterOption); - connect(settingsToolButton, &QAbstractButton::pressed, this, []() { + connect(settingsToolButton, &QAbstractButton::clicked, this, []() { ICore::showOptionsDialog(Constants::EXTENSIONMANAGER_SETTINGSPAGE_ID); }); connect(&settings(), &AspectContainer::changed, this, [this]() { @@ -697,6 +728,8 @@ QLabel *tfLabel(const TextFormat &tf, bool singleLine) return label; } +const int iconRectRounding = 4; + QPixmap itemIcon(const QModelIndex &index, Size size) { const QSize iconBgS = size == SizeSmall ? iconBgSizeSmall : iconBgSizeBig; @@ -727,7 +760,6 @@ QPixmap itemIcon(const QModelIndex &index, Size size) const ItemType itemType = index.data(RoleItemType).value(); const QIcon &icon = (itemType == ItemTypePack) ? (size == SizeSmall ? packS : packB) : (size == SizeSmall ? extensionS : extensionB); - const int iconRectRounding = 4; const qreal iconOpacityDisabled = 0.6; QPainter p(&pixmap); @@ -741,4 +773,33 @@ QPixmap itemIcon(const QModelIndex &index, Size size) return pixmap; } +QPixmap itemBadge(const QModelIndex &index, [[maybe_unused]] Size size) +{ + const QString badgeText = index.data(RoleBadge).toString(); + if (badgeText.isNull()) + return {}; + + constexpr TextFormat badgeTF + {Theme::Token_Basic_White, UiElement::UiElementLabelSmall}; + + const QFont font = badgeTF.font(); + const int textWidth = QFontMetrics(font).horizontalAdvance(badgeText); + const QSize badgeS(ExPaddingGapM + textWidth + ExPaddingGapM, + ExPaddingGapS + badgeTF.lineHeight() + ExPaddingGapS); + const QRect badgeR(QPoint(), badgeS); + const qreal dpr = qApp->devicePixelRatio(); + QPixmap pixmap(badgeS * dpr); + pixmap.fill(Qt::transparent); + pixmap.setDevicePixelRatio(dpr); + + QPainter p(&pixmap); + WelcomePageHelpers::drawCardBackground(&p, badgeR, + creatorColor(Theme::Token_Notification_Neutral), + Qt::NoPen, iconRectRounding); + p.setFont(font); + p.setPen(badgeTF.color()); + p.drawText(badgeR, Qt::AlignCenter, badgeText); + return pixmap; +} + } // ExtensionManager::Internal diff --git a/src/plugins/extensionmanager/extensionsbrowser.h b/src/plugins/extensionmanager/extensionsbrowser.h index 0b4254e02cd..620c581de71 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.h +++ b/src/plugins/extensionmanager/extensionsbrowser.h @@ -50,5 +50,6 @@ enum Size { SizeBig, }; QPixmap itemIcon(const QModelIndex &index, Size size); +QPixmap itemBadge(const QModelIndex &index, Size size); } // ExtensionManager::Internal diff --git a/src/plugins/extensionmanager/extensionsmodel.cpp b/src/plugins/extensionmanager/extensionsmodel.cpp index b3d63073f90..bea38dd368f 100644 --- a/src/plugins/extensionmanager/extensionsmodel.cpp +++ b/src/plugins/extensionmanager/extensionsmodel.cpp @@ -49,7 +49,7 @@ public: void ExtensionsModelPrivate::addUnlistedLocalPlugins() { QStringList responseExtensions; - for (const QJsonValueConstRef &responseItem : responseItems) + for (const QJsonValueConstRef &responseItem : qAsConst(responseItems)) responseExtensions << responseItem.toObject().value("id").toString(); localPlugins.clear(); @@ -114,7 +114,7 @@ QVariant ExtensionsModelPrivate::dataFromRemotePlugin(const QJsonObject &json, i const QJsonArray sources = json.value("sources").toArray(); const QString thisPlatform = customOsTypeToString(HostOsInfo::hostOs()); const QString thisArch = QSysInfo::currentCpuArchitecture(); - for (const QJsonValue source : sources) { + for (const QJsonValue &source : sources) { const QJsonObject sourceObject = source.toObject(); const QJsonObject platform = sourceObject.value("platform").toObject(); if (platform.isEmpty() // Might be a Lua plugin @@ -150,11 +150,14 @@ QVariant ExtensionsModelPrivate::dataFromRemoteExtension(int index, int role) co case RoleName: return json.value("display_name"); case RoleDownloadCount: - return json.value("downloads"); + break; // TODO: Reinstate download numbers when they have more substance + // return json.value("downloads"); case RoleId: return json.value(EXTENSION_KEY_ID); case RoleDateUpdated: return QDate::fromString(json.value("updated_at").toString(), Qt::ISODate); + case RoleStatus: + return json.value("status"); case RoleTags: return json.value("tags").toVariant().toStringList(); case RoleVendor: @@ -239,6 +242,13 @@ int ExtensionsModel::rowCount([[maybe_unused]] const QModelIndex &parent) const return d->responseItems.count() + d->localPlugins.count(); } +static QString badgeText(const QModelIndex &index) +{ + if (index.data(RoleDownloadUrl).isNull()) + return {}; + return Tr::tr("New"); +} + ExtensionState extensionState(const QModelIndex &index) { if (index.data(RoleItemType) != ItemTypeExtension) @@ -264,10 +274,16 @@ static QString searchText(const QModelIndex &index) QVariant ExtensionsModel::data(const QModelIndex &index, int role) const { - if (role == RoleExtensionState) + switch (role) { + case RoleBadge: + return badgeText(index); + case RoleExtensionState: return extensionState(index); - if (role == RoleSearchText) + case RoleSearchText: return searchText(index); + default: + break; + } const bool isRemoteExtension = index.row() < d->responseItems.count(); const int itemIndex = index.row() - (isRemoteExtension ? 0 : d->responseItems.count()); @@ -282,8 +298,8 @@ QModelIndex ExtensionsModel::indexOfId(const QString &extensionId) const if (localIndex >= 0) return index(d->responseItems.count() + localIndex); - for (int remoteIndex = 0; const QJsonValueConstRef vlaue : d->responseItems) { - if (vlaue.toObject().value(EXTENSION_KEY_ID) == extensionId) + for (int remoteIndex = 0; const QJsonValueConstRef &value : std::as_const(d->responseItems)) { + if (value.toObject().value(EXTENSION_KEY_ID) == extensionId) return index(remoteIndex); ++remoteIndex; } @@ -324,4 +340,10 @@ PluginSpec *pluginSpecForId(const QString &pluginId) return findOrDefault(PluginManager::plugins(), equal(&PluginSpec::id, pluginId)); } +QString statusDisplayString(const QModelIndex &index) +{ + const QString statusString = index.data(RoleStatus).toString(); + return statusString != "published" ? statusString : QString(); +} + } // ExtensionManager::Internal diff --git a/src/plugins/extensionmanager/extensionsmodel.h b/src/plugins/extensionmanager/extensionsmodel.h index eb3d289630c..87b4a6d73b6 100644 --- a/src/plugins/extensionmanager/extensionsmodel.h +++ b/src/plugins/extensionmanager/extensionsmodel.h @@ -27,7 +27,9 @@ enum ExtensionState { enum Role { RoleName = Qt::UserRole, + RoleBadge, RoleCopyright, + RoleDateUpdated, RoleDependencies, RoleDescriptionLong, RoleDescriptionShort, @@ -39,8 +41,8 @@ enum Role { RoleLicense, RolePlatforms, RolePlugins, - RoleDateUpdated, RoleSearchText, + RoleStatus, RoleTags, RoleVendor, RoleVendorId, @@ -65,6 +67,7 @@ private: QString customOsTypeToString(Utils::OsType osType); ExtensionSystem::PluginSpec *pluginSpecForId(const QString &pluginId); +QString statusDisplayString(const QModelIndex &index); #ifdef WITH_TESTS QObject *createExtensionsModelTest(); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 7739782c204..ea60ac555a2 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -647,6 +647,11 @@ public: GitLogConfig(bool fileRelated, GitEditorWidget *editor) : GitBaseConfig(editor) { + QAction *allBranchesButton = + addToggleButton(QStringList{"--all"}, + Tr::tr("All"), + Tr::tr("Show log for all local branches.")); + mapSetting(allBranchesButton, &settings().allBranches); QAction *firstParentButton = addToggleButton({"-m", "--first-parent"}, Tr::tr("First Parent"), @@ -944,7 +949,7 @@ void GitClient::updateModificationInfos() {'?', IVCF::UnmanagedState}, }; - const IVCF &modification = std::max(gitStates.value(line.at(0), IVCF::NoModification), + const IVCF modification = std::max(gitStates.value(line.at(0), IVCF::NoModification), gitStates.value(line.at(1), IVCF::NoModification)); if (modification != IVCF::NoModification) diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index daabb4dac1f..1021fbddb61 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -113,6 +113,7 @@ GitSettings::GitSettings() colorLog.setSettingsKey("ColorLog"); colorLog.setDefaultValue(true); + allBranches.setSettingsKey("AllBranches"); firstParent.setSettingsKey("FirstParent"); followRenames.setSettingsKey("FollowRenames"); diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h index 97a2ab787fb..6844b8e2029 100644 --- a/src/plugins/git/gitsettings.h +++ b/src/plugins/git/gitsettings.h @@ -33,6 +33,7 @@ public: Utils::FilePathAspect repositoryBrowserCmd{this}; Utils::BoolAspect graphLog{this}; Utils::BoolAspect colorLog{this}; + Utils::BoolAspect allBranches{this}; Utils::BoolAspect firstParent{this}; Utils::BoolAspect followRenames{this}; Utils::IntegerAspect lastResetIndex{this}; diff --git a/src/plugins/git/instantblame.cpp b/src/plugins/git/instantblame.cpp index 63e892a34ca..29eeaaecedb 100644 --- a/src/plugins/git/instantblame.cpp +++ b/src/plugins/git/instantblame.cpp @@ -407,6 +407,10 @@ void InstantBlame::perform() const CommitInfo info = parseBlameOutput(output.split('\n'), filePath, line, m_author); m_blameMark.reset(new BlameMark(filePath, line, info)); + static const QString uncommittedHash(40, '0'); + if (info.hash == uncommittedHash) + return; + // Get line diff: `git log -n 1 -p -L47,47:README.md a5c4c34c9ab4` const QString origLineString = QString("%1,%1").arg(info.originalLine); const QString fileLineRange = "-L" + origLineString + ":" + info.originalFileName; diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 2820c634a3d..e78bb37439e 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -82,9 +82,7 @@ static void matches(QPromise &promise, const LocatorStorage &storag LocatorMatcherTasks HelpIndexFilter::matchers() { - Storage storage; - - const auto onSetup = [this, storage](Async &async) { + const auto onSetup = [this](Async &async) { if (m_needsUpdate) { m_needsUpdate = false; LocalHelpManager::setupGuiHelpEngine(); @@ -92,18 +90,19 @@ LocatorMatcherTasks HelpIndexFilter::matchers() m_lastIndicesCache.clear(); m_lastEntry.clear(); } - const QStringList cache = m_lastEntry.isEmpty() || !storage->input().contains(m_lastEntry) + const LocatorStorage &storage = *LocatorStorage::storage(); + const QStringList cache = m_lastEntry.isEmpty() || !storage.input().contains(m_lastEntry) ? m_allIndicesCache : m_lastIndicesCache; - async.setConcurrentCallData(matches, *storage, cache, m_icon); + async.setConcurrentCallData(matches, storage, cache, m_icon); }; - const auto onDone = [this, storage](const Async &async) { + const auto onDone = [this](const Async &async) { if (async.isResultAvailable()) { m_lastIndicesCache = async.result(); - m_lastEntry = storage->input(); + m_lastEntry = LocatorStorage::storage()->input(); } }; - return {{AsyncTask(onSetup, onDone, CallDoneIf::Success), storage}}; + return {AsyncTask(onSetup, onDone, CallDoneIf::Success)}; } void HelpIndexFilter::invalidateCache() diff --git a/src/plugins/incredibuild/commandbuilderaspect.cpp b/src/plugins/incredibuild/commandbuilderaspect.cpp index ea071123330..4655cde53e6 100644 --- a/src/plugins/incredibuild/commandbuilderaspect.cpp +++ b/src/plugins/incredibuild/commandbuilderaspect.cpp @@ -104,7 +104,7 @@ void CommandBuilderAspectPrivate::tryToMigrate() for (Utils::Id stepId : migratableSteps) { if (BuildStep *bs = m_buildStep->stepList()->firstStepWithId(stepId)) { m_activeCommandBuilder = p; - bs->setEnabled(false); + bs->setStepEnabled(false); m_buildStep->project()->saveSettings(); return; } diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index 67a008ab074..e5685e296bc 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -381,7 +381,7 @@ bool applyDocumentChange(const Client *client, const DocumentChange &change) } } } - return oldPath.renameFile(newPath).has_value(); + return bool(oldPath.renameFile(newPath)); } else if (const auto deleteOperation = std::get_if(&change)) { const FilePath filePath = deleteOperation->uri().toFilePath(client->hostPathMapper()); if (const std::optional options = deleteOperation->options()) { @@ -390,7 +390,7 @@ bool applyDocumentChange(const Client *client, const DocumentChange &change) if (filePath.isDir() && options->recursive().value_or(false)) return filePath.removeRecursively(); } - return filePath.removeFile().has_value(); + return bool(filePath.removeFile()); } return false; } diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 4fb8cea19a2..5dc90ad5b32 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -15,11 +15,12 @@ using namespace Core; using namespace LanguageServerProtocol; +using namespace Tasking; using namespace Utils; namespace LanguageClient { -void filterResults(QPromise &promise, const LocatorStorage &storage, Client *client, +static void filterResults(QPromise &promise, const LocatorStorage &storage, Client *client, const QList &results, const QList &filter) { const auto doFilter = [&](const SymbolInformation &info) { @@ -41,18 +42,15 @@ void filterResults(QPromise &promise, const LocatorStorage &storage, Clien storage.reportOutput(Utils::transform(filteredResults, generateEntry)); } -LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, +static ExecutableItem locatorMatcher(Client *client, int maxResultCount, const QList &filter) { - using namespace Tasking; - - Storage storage; Storage> resultStorage; - const auto onQuerySetup = [storage, client, maxResultCount](ClientWorkspaceSymbolRequest &request) { + const auto onQuerySetup = [client, maxResultCount](ClientWorkspaceSymbolRequest &request) { request.setClient(client); WorkspaceSymbolParams params; - params.setQuery(storage->input()); + params.setQuery(LocatorStorage::storage()->input()); if (maxResultCount > 0) params.setLimit(maxResultCount); request.setParams(params); @@ -64,11 +62,12 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, *resultStorage = result->toList(); }; - const auto onFilterSetup = [storage, resultStorage, client, filter](Async &async) { + const auto onFilterSetup = [resultStorage, client, filter](Async &async) { const QList results = *resultStorage; if (results.isEmpty()) return SetupResult::StopWithSuccess; - async.setConcurrentCallData(filterResults, *storage, client, results, filter); + async.setConcurrentCallData(filterResults, *LocatorStorage::storage(), client, results, + filter); return SetupResult::Continue; }; @@ -77,20 +76,20 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, ClientWorkspaceSymbolRequestTask(onQuerySetup, onQueryDone, CallDoneIf::Success), AsyncTask(onFilterSetup) }; - return {root, storage}; + return root; } -LocatorMatcherTask allSymbolsMatcher(Client *client, int maxResultCount) +static ExecutableItem allSymbolsMatcher(Client *client, int maxResultCount) { return locatorMatcher(client, maxResultCount, {}); } -LocatorMatcherTask classMatcher(Client *client, int maxResultCount) +static ExecutableItem classMatcher(Client *client, int maxResultCount) { return locatorMatcher(client, maxResultCount, {SymbolKind::Class, SymbolKind::Struct}); } -LocatorMatcherTask functionMatcher(Client *client, int maxResultCount) +static ExecutableItem functionMatcher(Client *client, int maxResultCount) { return locatorMatcher(client, maxResultCount, {SymbolKind::Method, SymbolKind::Function, SymbolKind::Constructor}); @@ -112,33 +111,28 @@ static void filterCurrentResults(QPromise &promise, const LocatorStorage & docSymbolModifier)); } -LocatorMatcherTask currentDocumentMatcher() +static ExecutableItem currentDocumentMatcher() { - using namespace Tasking; - - Storage storage; Storage resultStorage; - const auto onQuerySetup = [](CurrentDocumentSymbolsRequest &request) { - Q_UNUSED(request) - }; const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequest &request) { *resultStorage = request.currentDocumentSymbolsData(); }; - const auto onFilterSetup = [storage, resultStorage](Async &async) { - async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage); + const auto onFilterSetup = [resultStorage](Async &async) { + async.setConcurrentCallData(filterCurrentResults, *LocatorStorage::storage(), + *resultStorage); }; const Group root { resultStorage, - CurrentDocumentSymbolsRequestTask(onQuerySetup, onQueryDone, CallDoneIf::Success), + CurrentDocumentSymbolsRequestTask({}, onQueryDone, CallDoneIf::Success), AsyncTask(onFilterSetup) }; - return {root, storage}; + return root; } -using MatcherCreator = std::function; +using MatcherCreator = std::function; static MatcherCreator creatorForType(MatcherType type) { diff --git a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp index 82f4a091dc2..ebc1e522fad 100644 --- a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp +++ b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include #include @@ -18,6 +20,7 @@ #include #include +#include #include #include @@ -207,6 +210,8 @@ public: TransportType m_transportType{TransportType::StdIO}; std::function(CommandLine &)> m_cmdLineCallback; std::function(QString &)> m_initOptionsCallback; + sol::function m_asyncInitOptions; + bool m_isUpdatingAsyncOptions{false}; AspectContainer *m_aspects{nullptr}; QString m_name; Utils::Id m_settingsTypeId; @@ -324,6 +329,13 @@ public: &LanguageClientManager::clientRemoved, this, &LuaClientWrapper::onClientRemoved); + + if (auto asyncInit = options.get>( + "initializationOptionsAsync")) { + m_asyncInitOptions = *asyncInit; + QMetaObject::invokeMethod( + this, &LuaClientWrapper::updateAsyncOptions, Qt::QueuedConnection); + } } void onClientRemoved(Client *c, bool unexpected) @@ -462,6 +474,25 @@ public: clients.front()->sendMessage(request); } + void updateAsyncOptions() + { + if (m_isUpdatingAsyncOptions) + return; + QTC_ASSERT(m_asyncInitOptions, return); + m_isUpdatingAsyncOptions = true; + std::function cb = guardedCallback(this, [this](sol::object options) { + if (options.is()) + m_initializationOptions = ::Lua::toJsonString(options.as()); + else if (options.is()) + m_initializationOptions = options.as(); + + emit optionsChanged(); + m_isUpdatingAsyncOptions = false; + }); + + ::Lua::Async::start(m_asyncInitOptions, cb); + } + void updateOptions() { if (m_cmdLineCallback) { @@ -479,6 +510,8 @@ public: // optionsChanged() needs to be called for it as well, but only once per updateOptions() emit optionsChanged(); } + if (m_asyncInitOptions) + updateAsyncOptions(); } static CommandLine cmdFromTable(const sol::table &tbl) diff --git a/src/plugins/lua/CMakeLists.txt b/src/plugins/lua/CMakeLists.txt index 51fc92496ee..7bc0aa2efbd 100644 --- a/src/plugins/lua/CMakeLists.txt +++ b/src/plugins/lua/CMakeLists.txt @@ -4,7 +4,6 @@ add_qtc_plugin(Lua PUBLIC_DEFINES LUA_AVAILABLE SOURCES bindings/action.cpp - bindings/async.cpp bindings/async.h bindings/core.cpp bindings/fetch.cpp @@ -49,7 +48,9 @@ if(TARGET Lua) qt_add_resources(Lua lua_script_rcc PREFIX "/lua" FILES + scripts/async.lua scripts/ilua.lua + scripts/inspect.lua ) set_source_files_properties(luauibindings.cpp PROPERTY SKIP_AUTOMOC ON PROPERTY SKIP_AUTOGEN ON) diff --git a/src/plugins/lua/bindings/gui.cpp b/src/plugins/lua/bindings/gui.cpp index ca26c77d8d5..9a5c2de6700 100644 --- a/src/plugins/lua/bindings/gui.cpp +++ b/src/plugins/lua/bindings/gui.cpp @@ -430,6 +430,10 @@ void setupGuiModule() &Widget::activateWindow, "close", &Widget::close, + "visible", + sol::property(&Widget::isVisible, &Widget::setVisible), + "enabled", + sol::property(&Widget::isEnabled, &Widget::setEnabled), sol::base_classes, sol::bases()); diff --git a/src/plugins/lua/bindings/project.cpp b/src/plugins/lua/bindings/project.cpp index 8c8099c75fb..e140ca92790 100644 --- a/src/plugins/lua/bindings/project.cpp +++ b/src/plugins/lua/bindings/project.cpp @@ -28,15 +28,28 @@ void setupProjectModule() sol::table result = lua.create_table(); + result.new_usertype( + "Kit", + sol::no_constructor, + "supportedPlatforms", + [](Kit *kit) { + const auto set = kit->supportedPlatforms(); + return QList(set.constBegin(), set.constEnd()); + }); + result.new_usertype( "RunConfiguration", sol::no_constructor, "runnable", - sol::property(&RunConfiguration::runnable)); + sol::property(&RunConfiguration::runnable), + "kit", + sol::property(&RunConfiguration::kit)); result.new_usertype( "Project", sol::no_constructor, + "displayName", + sol::property(&Project::displayName), "directory", sol::property(&Project::projectDirectory), "activeRunConfiguration", @@ -53,7 +66,8 @@ void setupProjectModule() }; result["runStartupProject"] = - [guard](const sol::optional &runnable) { + [guard](const sol::optional &runnable, + const sol::optional &displayName) { auto project = ProjectManager::instance()->startupProject(); if (!project) throw sol::error("No startup project"); @@ -72,6 +86,9 @@ void setupProjectModule() rc->setEnvironment(runnable->environment); } + if (displayName) + rc->setDisplayName(displayName.value()); + BuildForRunConfigStatus status = BuildManager::potentiallyBuildForRunConfig( runConfiguration); @@ -96,9 +113,32 @@ void setupProjectModule() } }; + result["stopRunConfigurationsByName"] = + [](const QString &displayName, const std::optional &force) -> int { + const auto runControls = ProjectExplorerPlugin::instance()->allRunControls(); + + int stoppedCount = 0; + for (const auto rc : runControls) { + if (rc && rc->displayName() == displayName) { + stoppedCount++; + + if (force.has_value() && force.value()) { + rc->forceStop(); + } else { + rc->initiateStop(); + } + } + } + + return stoppedCount; + }; + result["RunMode"] = lua.create_table_with( "Normal", Constants::NORMAL_RUN_MODE, "Debug", Constants::DEBUG_RUN_MODE); + result["Platforms"] = lua.create_table_with( + "Desktop", Utils::Id(Constants::DESKTOP_DEVICE_TYPE)); + return result; }); diff --git a/src/plugins/lua/bindings/qt.cpp b/src/plugins/lua/bindings/qt.cpp index 733eac85a4d..1eff2211dec 100644 --- a/src/plugins/lua/bindings/qt.cpp +++ b/src/plugins/lua/bindings/qt.cpp @@ -5,10 +5,14 @@ #include "utils.h" +#include + #include #include #include #include +#include +#include namespace Lua::Internal { @@ -27,29 +31,27 @@ void setupQtModule() "currentCompletion", &QCompleter::currentCompletion, "completionMode", - sol::property(&QCompleter::completionMode, - [](QCompleter *c, QCompleter::CompletionMode mode) { - c->setCompletionMode(mode); - }), + sol::property( + &QCompleter::completionMode, + [](QCompleter *c, QCompleter::CompletionMode mode) { c->setCompletionMode(mode); }), "onActivated", sol::property([guard = pluginSpec](QCompleter &obj, sol::function callback) { - QObject::connect(&obj, - QOverload::of(&QCompleter::activated), - guard->connectionGuard.get(), - [callback](const QString &arg) { - void_safe_call(callback, arg); - });}) - ); + QObject::connect( + &obj, + QOverload::of(&QCompleter::activated), + guard->connectionGuard.get(), + [callback](const QString &arg) { void_safe_call(callback, arg); }); + })); qt.new_usertype( "QClipboard", - sol::call_constructor, - &QApplication::clipboard, + sol::no_constructor, "text", - sol::property([](QClipboard &self) { return self.text(); }, - [](QClipboard &self, const QString &value) { self.setText(value); }) - ); + sol::property( + [](QClipboard &self) { return self.text(); }, + [](QClipboard &, const QString &text) { Utils::setClipboardAndSelection(text); })); + qt["clipboard"] = &QApplication::clipboard; mirrorEnum(qt, QMetaEnum::fromType(), "QCompleterCompletionMode"); @@ -110,6 +112,48 @@ void setupQtModule() "NoSort", QDir::NoSort ) ); + + qt["QFileDevice"] = lua.create_table_with( + "Permission", lua.create_table_with( + "ReadOwner", QFileDevice::ReadOwner, + "ReadUser", QFileDevice::ReadUser, + "ReadGroup", QFileDevice::ReadGroup, + "ReadOther", QFileDevice::ReadOther, + "WriteOwner", QFileDevice::WriteOwner, + "WriteUser", QFileDevice::WriteUser, + "WriteGroup", QFileDevice::WriteGroup, + "WriteOther", QFileDevice::WriteOther, + "ExeOwner", QFileDevice::ExeOwner, + "ExeUser", QFileDevice::ExeUser, + "ExeGroup", QFileDevice::ExeGroup, + "ExeOther", QFileDevice::ExeOther + ) + ); + + qt["QStandardPaths"] = lua.create_table_with( + "StandardLocation", lua.create_table_with( + "DesktopLocation", QStandardPaths::DesktopLocation, + "DocumentsLocation", QStandardPaths::DocumentsLocation, + "FontsLocation", QStandardPaths::FontsLocation, + "ApplicationsLocation", QStandardPaths::ApplicationsLocation, + "MusicLocation", QStandardPaths::MusicLocation, + "MoviesLocation", QStandardPaths::MoviesLocation, + "PicturesLocation", QStandardPaths::PicturesLocation, + "TempLocation", QStandardPaths::TempLocation, + "HomeLocation", QStandardPaths::HomeLocation, + "AppLocalDataLocation", QStandardPaths::AppLocalDataLocation, + "CacheLocation", QStandardPaths::CacheLocation, + "GenericDataLocation", QStandardPaths::GenericDataLocation, + "RuntimeLocation", QStandardPaths::RuntimeLocation, + "ConfigLocation", QStandardPaths::ConfigLocation, + "DownloadLocation", QStandardPaths::DownloadLocation, + "GenericCacheLocation", QStandardPaths::GenericCacheLocation, + "GenericConfigLocation", QStandardPaths::GenericConfigLocation, + "AppDataLocation", QStandardPaths::AppDataLocation, + "AppConfigLocation", QStandardPaths::AppConfigLocation, + "PublicShareLocation", QStandardPaths::PublicShareLocation, + "TemplatesLocation", QStandardPaths::TemplatesLocation + )); // clang-format on return qt; diff --git a/src/plugins/lua/bindings/qtcprocess.cpp b/src/plugins/lua/bindings/qtcprocess.cpp index d5a02440590..0aa6ccfa9b3 100644 --- a/src/plugins/lua/bindings/qtcprocess.cpp +++ b/src/plugins/lua/bindings/qtcprocess.cpp @@ -60,6 +60,7 @@ void setupProcessModule() const auto stdOut = parameter.get>("stdout"); const auto stdErr = parameter.get>("stderr"); const auto stdIn = parameter.get>("stdin"); + const auto onFinished = parameter.get>("onFinished"); auto p = std::make_unique(); @@ -86,6 +87,16 @@ void setupProcessModule() }); // clang-format on } + + if (onFinished) { + // clang-format off + QObject::connect(p.get(), &Process::done, + p.get(), + [p = p.get(), cb = *onFinished]() { + void_safe_call(cb); + }); + // clang-format on + } return p; }; diff --git a/src/plugins/lua/bindings/utils.cpp b/src/plugins/lua/bindings/utils.cpp index efd5a73a74c..0937950dcc0 100644 --- a/src/plugins/lua/bindings/utils.cpp +++ b/src/plugins/lua/bindings/utils.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -93,6 +94,10 @@ void setupUtilsModule() utils["pid"] = QCoreApplication::applicationPid(); + utils.new_usertype( + "Id", + sol::no_constructor); + auto hostOsInfoType = utils.new_usertype("HostOsInfo"); hostOsInfoType["isWindowsHost"] = &HostOsInfo::isWindowsHost; hostOsInfoType["isMacHost"] = &HostOsInfo::isMacHost; @@ -161,7 +166,15 @@ void setupUtilsModule() "resolvePath", sol::overload( [](const FilePath &p, const QString &path) { return p.resolvePath(path); }, - [](const FilePath &p, const FilePath &path) { return p.resolvePath(path); })); + [](const FilePath &p, const FilePath &path) { return p.resolvePath(path); }), + "permissions", + [](FilePath& p) { + return static_cast(p.permissions().toInt()); + }, + "setPermissions", + [](FilePath& p, QFileDevice::Permission permissions) { + p.setPermissions(static_cast(permissions)); + }); utils["FilePath"]["dirEntries_cb"] = utils["__dirEntries_cb__"]; utils["FilePath"]["dirEntries"] = wrap(utils["__dirEntries_cb__"]); @@ -169,6 +182,34 @@ void setupUtilsModule() utils["FilePath"]["searchInPath_cb"] = utils["__searchInPath_cb__"]; utils["FilePath"]["searchInPath"] = wrap(utils["__searchInPath_cb__"]); + utils["standardLocations"] = [](QStandardPaths::StandardLocation location) { + const auto locationsStrings = QStandardPaths::standardLocations( + static_cast(location)); + + QList locationsPaths; + std::transform(locationsStrings.constBegin(), locationsStrings.constEnd(), + std::back_inserter(locationsPaths), &FilePath::fromString); + return locationsPaths; + }; + utils["standardLocation"] = + [](QStandardPaths::StandardLocation location) -> sol::optional { + const auto paths = QStandardPaths::standardLocations( + static_cast(location)); + if (paths.isEmpty()) + return sol::nullopt; + + return FilePath::fromString(paths.first()); + }; + utils["writableLocation"] = + [](QStandardPaths::StandardLocation location) -> sol::optional { + const auto path = QStandardPaths::writableLocation( + static_cast(location)); + if (path.isEmpty()) + return sol::nullopt; + + return FilePath::fromString(path); + }; + utils.new_usertype( "CommandLine", sol::call_constructor, diff --git a/src/plugins/lua/lua.qbs b/src/plugins/lua/lua.qbs index 65b4205332a..5e6298387af 100644 --- a/src/plugins/lua/lua.qbs +++ b/src/plugins/lua/lua.qbs @@ -39,7 +39,6 @@ QtcPlugin { files: [ "action.cpp", - "async.cpp", "core.cpp", "fetch.cpp", "gui.cpp", diff --git a/src/plugins/lua/luaengine.cpp b/src/plugins/lua/luaengine.cpp index a13c0fd8474..dca1bb25733 100644 --- a/src/plugins/lua/luaengine.cpp +++ b/src/plugins/lua/luaengine.cpp @@ -72,7 +72,9 @@ QObject *ScriptPluginSpec::setup( "name", sol::property([](ScriptPluginSpec &self) { return self.name; }), "pluginDirectory", - sol::property([pluginLocation]() { return pluginLocation; })); + sol::property([pluginLocation]() { return pluginLocation; }), + "appDataPath", + sol::property([appDataPath]() { return appDataPath; })); auto guardObject = std::make_unique(); auto guardObjectPtr = guardObject.get(); @@ -169,6 +171,23 @@ void registerProvider(const QString &packageName, const PackageProvider &provide d->m_providers[packageName] = provider; } +void registerProvider(const QString &packageName, const FilePath &path) +{ + registerProvider(packageName, [path](sol::state_view lua) -> sol::object { + auto content = path.fileContents(); + if (!content) + throw sol::error(content.error().toStdString()); + + sol::protected_function_result res + = lua.script(content->data(), path.fileName().toStdString()); + if (!res.valid()) { + sol::error err = res; + throw err; + } + return res.get(0); + }); +} + void autoRegister(const std::function ®isterFunction) { d->m_autoProviders.append(registerFunction); diff --git a/src/plugins/lua/luaengine.h b/src/plugins/lua/luaengine.h index 81efef952e3..36cd6f10e47 100644 --- a/src/plugins/lua/luaengine.h +++ b/src/plugins/lua/luaengine.h @@ -51,6 +51,7 @@ LUA_EXPORT Utils::expected_str prepareSetup( sol::state_view lua, const LuaPluginSpec &pluginSpec); LUA_EXPORT void registerProvider(const QString &packageName, const PackageProvider &provider); +LUA_EXPORT void registerProvider(const QString &packageName, const Utils::FilePath &path); LUA_EXPORT void autoRegister(const std::function ®isterFunction); LUA_EXPORT void registerHook( QString name, const std::function &hookProvider); diff --git a/src/plugins/lua/luaplugin.cpp b/src/plugins/lua/luaplugin.cpp index 56518230bd7..a1821094500 100644 --- a/src/plugins/lua/luaplugin.cpp +++ b/src/plugins/lua/luaplugin.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,6 @@ using namespace ExtensionSystem; namespace Lua::Internal { void setupActionModule(); -void setupAsyncModule(); void setupCoreModule(); void setupFetchModule(); void setupGuiModule(); @@ -79,7 +79,7 @@ public: { auto label = new QLabel(parent); const QString text = index.data().toString(); - label->setText(text); + label->setText(text.startsWith("__ERROR__") ? text.mid(9) : text); label->setFont(option.font); label->setTextInteractionFlags( Qt::TextInteractionFlag::TextSelectableByMouse @@ -88,6 +88,29 @@ public: label->setSelection(0, text.size()); return label; } + + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) + const override + { + QStyleOptionViewItem opt = option; + initStyleOption(&opt, index); + + bool isError = opt.text.startsWith("__ERROR__"); + + if (isError) + opt.text = opt.text.mid(9); + + if (opt.state & QStyle::State_Selected) { + painter->fillRect(opt.rect, opt.palette.highlight()); + painter->setPen(opt.palette.highlightedText().color()); + } else if (isError) { + painter->setPen(creatorColor(Theme::Token_Notification_Danger)); + } else { + painter->setPen(opt.palette.text().color()); + } + + painter->drawText(opt.rect, opt.displayAlignment, opt.text); + } }; class LuaReplView : public QListView @@ -136,6 +159,7 @@ public: m_model.setStringList(m_model.stringList() << msgs); scrollToBottom(); }; + lua["LuaCopyright"] = LUA_COPYRIGHT; sol::table async = lua.script("return require('async')", "_ilua_").get(); sol::function wrap = async["wrap"]; @@ -254,8 +278,10 @@ public: { setupLuaEngine(this); + registerProvider("async", ":/lua/scripts/async.lua"); + registerProvider("inspect", ":/lua/scripts/inspect.lua"); + setupActionModule(); - setupAsyncModule(); setupCoreModule(); setupFetchModule(); setupGuiModule(); diff --git a/src/plugins/lua/meta/gui.lua b/src/plugins/lua/meta/gui.lua index 1d7f04c4678..9b34883f1b6 100644 --- a/src/plugins/lua/meta/gui.lua +++ b/src/plugins/lua/meta/gui.lua @@ -12,6 +12,8 @@ gui.layout = {} ---The base class of all widget classes, an empty widget itself. ---@class Widget : Object +---@field visible bool Whether the widget is visible or not. +---@field enabled bool Whether the widget is enabled or not. gui.widget = {} ---@alias LayoutChild string|BaseAspect|Layout|Widget|function diff --git a/src/plugins/lua/meta/lsp.lua b/src/plugins/lua/meta/lsp.lua index 37a3c2671e5..10c42c6e68b 100644 --- a/src/plugins/lua/meta/lsp.lua +++ b/src/plugins/lua/meta/lsp.lua @@ -11,6 +11,7 @@ local lsp = {} ---@field languageFilter LanguageFilter The language filter deciding which files to open with the language server. ---@field startBehavior? "AlwaysOn"|"RequiresFile"|"RequiresProject" ---@field initializationOptions? function|table|string The initialization options to pass to the language server, either a JSON string, a table, or a function that returns either. +---@field initializationOptionsAsync? function A callback that will return the initialization options as a JSON String or a table. Inside the callback you can use Async functions. ---@field settings? AspectContainer The settings object to associate with the language server. ---@field onStartFailed? function This callback is called when client failed to start. ---@field showInSettings? boolean Whether the client should show up in the general Language Server list. diff --git a/src/plugins/lua/meta/process.lua b/src/plugins/lua/meta/process.lua index 017524fc7cd..21c2a7127d2 100644 --- a/src/plugins/lua/meta/process.lua +++ b/src/plugins/lua/meta/process.lua @@ -24,6 +24,7 @@ process.Process = {} ---@field stdin? string The input to write to stdin. ---@field stdout? function The callback to call when the process writes to stdout. ---@field stderr? function The callback to call when the process writes to stderr. +---@field onFinished? function () The callback to call when the process finishes. process.ProcessParameters = {} ---Creates a new process object. diff --git a/src/plugins/lua/meta/project.lua b/src/plugins/lua/meta/project.lua index 9254e7a7ef6..37f5881c447 100644 --- a/src/plugins/lua/meta/project.lua +++ b/src/plugins/lua/meta/project.lua @@ -9,11 +9,25 @@ project.RunMode { Debug = "RunConfiguration.DebugRunMode", } +---@enum Platforms +project.Platforms { + Desktop = 0, +} + +---@class Kit +project.Kit = {} + +---Returns the list of supported platforms (device types) for this kit. +---@return [Id] The list of supported platforms (device types) for this kit. +function project.Kit:supportedPlatforms() end + ---@class RunConfiguration ---@field runnable ProcessRunData +---@field kit Kit project.RunConfiguration = {} ---@class Project +---@field displayName string The display name of the project. ---@field directory FilePath The directory of the project. project.Project = {} @@ -33,6 +47,13 @@ function project.canRunStartupProject(runMode) end ---Starts the active run configuration of the current startup project. It will be build first if necessary. ---@param runnable? ProcessRunData Override the run configuration with the specified runnable. -function project.runStartupProject(runnable) end +---@param displayName? string Override the run configuration display name with the provided name. +function project.runStartupProject(runnable, displayName) end + +---Stops any configuration with display names equal to the provided name. +---@param displayName string The name for projects to stop. +---@param force? boolean Whether to close project forcefully (false assumeed if not provided). +---@return int Number of stopped configurations. +function project.stopRunConfigurationsByName(displayName, force) end return project diff --git a/src/plugins/lua/meta/qt.lua b/src/plugins/lua/meta/qt.lua index 6adaa261fc3..7543302c600 100644 --- a/src/plugins/lua/meta/qt.lua +++ b/src/plugins/lua/meta/qt.lua @@ -11,27 +11,28 @@ qt.CompleterCompletionMode = { UnfilteredPopupCompletion = 2, }; ----Creates QCompleter. ---@class QCompleter ---@field completionMode CompleterCompletionMode The completion mode. local QCompleter = {} +---Creates a new Completer. +---@param params string[] The list of suggestions. +---@return QCompleter completer The new Completer. +function qt.QCompleter.create(params) end + ---Returns current completion. ---@return string function qt.QCompleter:currentCompletion() end +---@param callback function The function to be called when user choice is selected from popup. +function qt.QCompleter.onActivated(callback) end ----@param params string list A list of suggestions. ----@return QCompleter Created Completer. -function qt.QCompleter.create(params) end +---@class QClipboard A Lua wrapper for the Qt `QClipboard` class. +---@field text string The text content of the clipboard. Gets or sets the text content of the clipboard. +qt.QClipboard = {} ----@param function The function to be called when user choice is selected from popup. -function qt.QCompleter.onActivated(function) end - ----@class QClipboard ---- A Lua wrapper for the Qt `QClipboard` class. - -qt.QClipboard() Creates QClipboard object, which is a singleton instance of the system clipboard. ----@field text The text content of the clipboard. Gets or sets the text content of the clipboard. +---Returns the global clipboard object. +---@return QClipboard globalClipboard The global clipboard object. +function qt.clipboard() end ---@enum TextElideMode qt.TextElideMode = { @@ -92,4 +93,49 @@ qt.QDirIterator = { } } +qt.QFileDevice = { + ---@enum Permission + Permission = { + ReadOwner = 0, + ReadUser = 0, + ReadGroup = 0, + ReadOther = 0, + WriteOwner = 0, + WriteUser = 0, + WriteGroup = 0, + WriteOther = 0, + ExeOwner = 0, + ExeUser = 0, + ExeGroup = 0, + ExeOther = 0, + } +} + +qt.QStandardPaths = { + ---@enum StandardLocation + StandardLocation = { + DesktopLocation = 0, + DocumentsLocation = 0, + FontsLocation = 0, + ApplicationsLocation = 0, + MusicLocation = 0, + MoviesLocation = 0, + PicturesLocation = 0, + TempLocation = 0, + HomeLocation = 0, + AppLocalDataLocation = 0, + CacheLocation = 0, + GenericDataLocation = 0, + RuntimeLocation = 0, + ConfigLocation = 0, + DownloadLocation = 0, + GenericCacheLocation = 0, + GenericConfigLocation = 0, + AppDataLocation = 0, + AppConfigLocation = 0, + PublicShareLocation = 0, + TemplatesLocation = 0, + } +} + return qt diff --git a/src/plugins/lua/meta/qtc.lua b/src/plugins/lua/meta/qtc.lua index f5eb17ab3e1..2db56b3394c 100644 --- a/src/plugins/lua/meta/qtc.lua +++ b/src/plugins/lua/meta/qtc.lua @@ -3,6 +3,7 @@ ---@class PluginSpec ---@field name string The name of the plugin. ---@field pluginDirectory FilePath The directory of the plugin. +---@field appDataPath FilePath The application data directory of the plugin. PluginSpec = {} ---The global qtc object defined in the Lua plugin. ---@class qtc diff --git a/src/plugins/lua/meta/utils.lua b/src/plugins/lua/meta/utils.lua index adccb82525c..9e526370710 100644 --- a/src/plugins/lua/meta/utils.lua +++ b/src/plugins/lua/meta/utils.lua @@ -18,6 +18,9 @@ function utils.waitms_cb(ms, callback) end ---@return QString Arbitrary UUID string. function utils.createUuid() end +---@class Id +utils.Id = {} + ---@class FilePath utils.FilePath = {} @@ -89,6 +92,29 @@ function utils.FilePath:completeSuffix() end ---@return boolean function utils.FilePath:isAbsolutePath() end +---Returns the complete OR-ed together combination of permissions for the file. +---@return Permission +function utils.FilePath:permissions() end + +---Sets permissions for the file. +---@param permissions Permission The complete OR-ed together combination of permissions for the file. +function utils.FilePath:setPermissions() end + +---Returns the list of paths for the given standard location. +---@param location StandardLocation The standard location to get paths for. +---@return [FilePath] The list of paths for the given standard location. +function utils.standardLocations(location) end + +---Returns the first available paths for the given standard location. +---@param location StandardLocation The standard location to get the path for. +---@return FilePath|nil The first available paths for the given standard location or nil if no location is available. +function utils.standardLocation(location) end + +---Returns the writable paths for the given standard location. +---@param location StandardLocation The standard location to get path for. +---@return FilePath|nil The writable paths for the given standard location or nil if no writable location is available. +function utils.writableLocation(location) end + ---@class CommandLine ---@field command FilePath The command to execute. ---@field arguments string[] The arguments to pass to the command. diff --git a/src/plugins/lua/bindings/ASYNC-LICENSE.txt b/src/plugins/lua/scripts/ASYNC-LICENSE.txt similarity index 100% rename from src/plugins/lua/bindings/ASYNC-LICENSE.txt rename to src/plugins/lua/scripts/ASYNC-LICENSE.txt diff --git a/share/qtcreator/lua-plugins/luatests/INSPECT-LICENSE.txt b/src/plugins/lua/scripts/INSPECT-LICENSE.txt similarity index 100% rename from share/qtcreator/lua-plugins/luatests/INSPECT-LICENSE.txt rename to src/plugins/lua/scripts/INSPECT-LICENSE.txt diff --git a/src/plugins/lua/bindings/async.cpp b/src/plugins/lua/scripts/async.lua similarity index 74% rename from src/plugins/lua/bindings/async.cpp rename to src/plugins/lua/scripts/async.lua index 54868af6f0b..7958ea5d8af 100644 --- a/src/plugins/lua/bindings/async.cpp +++ b/src/plugins/lua/scripts/async.lua @@ -1,11 +1,3 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "../luaengine.h" - -namespace Lua::Internal { - -static const char *async_source = R"( -- From: https://github.com/ms-jpq/lua-async-await -- Licensed under MIT local co = coroutine @@ -70,13 +62,15 @@ end -- sugar over coroutine local await = function(defer) local _, isMain = coroutine.running() - assert(not isMain, "a.wait was called outside of a running coroutine. You need to start one using a.sync(my_function)() first") + assert(not isMain, + "a.wait was called outside of a running coroutine. You need to start one using a.sync(my_function)() first") assert(type(defer) == "function", "type error :: expected func :: was: " .. type(defer)) return co.yield(defer) end local await_all = function(defer) local _, isMain = coroutine.running() - assert(not isMain, "a.wait_all was called outside of a running coroutine. You need to start one using a.sync(my_function)() first") + assert(not isMain, + "a.wait_all was called outside of a running coroutine. You need to start one using a.sync(my_function)() first") assert(type(defer) == "table", "type error :: expected table") return co.yield(join(defer)) end @@ -86,14 +80,3 @@ return { wait_all = await_all, wrap = wrap, } -)"; - -void setupAsyncModule() -{ - registerProvider("async", [](sol::state_view lua) -> sol::object { - sol::protected_function_result res = lua.script(async_source, "async.cpp"); - return res.get(0); - }); -} - -} // namespace Lua::Internal diff --git a/src/plugins/lua/scripts/ilua.lua b/src/plugins/lua/scripts/ilua.lua index 3efaf0b788a..0918a249088 100644 --- a/src/plugins/lua/scripts/ilua.lua +++ b/src/plugins/lua/scripts/ilua.lua @@ -1,359 +1,61 @@ --- ilua.lua --- A more friendly Lua interactive prompt --- doesn't need '=' --- will try to print out tables recursively, subject to the pretty_print_limit value. --- Steve Donovan, 2007 --- -local pretty_print_limit = 20 -local max_depth = 7 -local table_clever = true -local prompt = '> ' -local verbose = false -local strict = true --- suppress strict warnings -_ = true - --- imported global functions -local sub = string.sub -local match = string.match -local find = string.find -local push = table.insert -local pop = table.remove -local append = table.insert -local concat = table.concat -local floor = math.floor -local write = io.write -local read = io.read - -local collisions = {} -local G_LIB = {} -local declared = {} -local line_handler_fn, global_handler_fn -local print_handlers = {} - -ilua = {} -local num_prec -local num_all - -local jstack = {} - -local function oprint(...) - print(...) -end - -local function join(tbl, delim, limit, depth) - if not limit then limit = pretty_print_limit end - if not depth then depth = max_depth end - local n = #tbl - local res = '' - local k = 0 - -- very important to avoid disgracing ourselves with circular referencs... - if #jstack > depth then - return "..." - end - for i, t in ipairs(jstack) do - if tbl == t then - return "" - end - end - push(jstack, tbl) - -- this is a hack to work out if a table is 'list-like' or 'map-like' - -- you can switch it off with ilua.table_options {clever = false} - local is_list - if table_clever then - local index1 = n > 0 and tbl[1] - local index2 = n > 1 and tbl[2] - is_list = index1 and index2 - end - if is_list then - for i, v in ipairs(tbl) do - res = res .. delim .. val2str(v) - k = k + 1 - if k > limit then - res = res .. " ... " - break - end - end - else - for key, v in pairs(tbl) do - if type(key) == 'number' then - key = '[' .. tostring(key) .. ']' - else - key = tostring(key) - end - res = res .. delim .. key .. '=' .. val2str(v) - k = k + 1 - if k > limit then - res = res .. " ... " - break - end - end - end - pop(jstack) - return sub(res, 2) -end - - -function val2str(val) - local tp = type(val) - if print_handlers[tp] then - local s = print_handlers[tp](val) - return s or '?' - end - if tp == 'function' then - return tostring(val) - elseif tp == 'table' then - if val.__tostring then - return tostring(val) - else - return '{' .. join(val, ',') .. '}' - end - elseif tp == 'string' then - return "'" .. val .. "'" - elseif tp == 'number' then - -- we try only to apply floating-point precision for numbers deemed to be floating-point, - -- unless the 3rd arg to precision() is true. - if num_prec and (num_all or floor(val) ~= val) then - return num_prec:format(val) - else - return tostring(val) - end - else - return tostring(val) - end -end - -function _pretty_print(...) - local arg = table.pack(...) - for i, val in ipairs(arg) do - oprint(val2str(val)) - end - _G['_'] = arg[1] -end - -function compile(line) - if verbose then oprint(line) end - local f, err = load(line, 'local') - return err, f -end - -function evaluate(chunk) - local ok, res = pcall(chunk) - if not ok then - return res - end - return nil -- meaning, fine! -end - -function eval_lua(line) - -- is the line handler interested? - if line_handler_fn then - line = line_handler_fn(line) - -- returning nil here means that the handler doesn't want - -- Lua to see the string - if not line then return end - end - -- is it an expression? - local err, chunk = compile('_pretty_print(' .. line .. ')') - if err then - -- otherwise, a statement? - err, chunk = compile(line) - end - -- if compiled ok, then evaluate the chunk - if not err then - err = evaluate(chunk) - end - -- if there was any error, print it out - if err then - oprint(err) - end -end - -local function quit(code, msg) - io.stderr:write(msg, '\n') - os.exit(code) -end - --- functions available in scripts -function ilua.precision(len, prec, all) - if not len then - num_prec = nil - else - num_prec = '%' .. len .. '.' .. prec .. 'f' - end - num_all = all -end - -function ilua.table_options(t) - if t.limit then pretty_print_limit = t.limit end - if t.depth then max_depth = t.depth end - if t.clever ~= nil then table_clever = t.clever end -end - --- inject @tbl into the global namespace -function ilua.import(tbl, dont_complain, lib) - lib = lib or '' - if type(tbl) == 'table' then - for k, v in pairs(tbl) do - local key = rawget(_G, k) - -- NB to keep track of collisions! - if key and k ~= '_M' and k ~= '_NAME' and k ~= '_PACKAGE' and k ~= '_VERSION' then - append(collisions, { k, lib, G_LIB[k] }) - end - _G[k] = v - G_LIB[k] = lib - end - end - if not dont_complain and #collisions > 0 then - for i, coll in ipairs(collisions) do - local name, lib, oldlib = coll[1], coll[2], coll[3] - write('warning: ', lib, '.', name, ' overwrites ') - if oldlib then - write(oldlib, '.', name, '\n') - else - write('global ', name, '\n') - end - end - end -end - -function ilua.print_handler(name, handler) - print_handlers[name] = handler -end - -function ilua.line_handler(handler) - line_handler_fn = handler -end - -function ilua.global_handler(handler) - global_handler_fn = handler -end - -function ilua.print_variables() - for name, v in pairs(declared) do - print(name, type(_G[name])) - end -end - --- --- strict.lua --- checks uses of undeclared global variables --- All global variables must be 'declared' through a regular assignment --- (even assigning nil will do) in a main chunk before being used --- anywhere. --- -local function set_strict() - local mt = getmetatable(_G) - if mt == nil then - mt = {} - setmetatable(_G, mt) - end - - local function what() - local d = debug.getinfo(3, "S") - return d and d.what or "C" - end - - mt.__newindex = function(t, n, v) - declared[n] = true - rawset(t, n, v) - end - - mt.__index = function(t, n) - if not declared[n] and what() ~= "C" then - local lookup = global_handler_fn and global_handler_fn(n) - if not lookup then - error("variable '" .. n .. "' is not declared", 2) - else - return lookup - end - end - return rawget(t, n) - end -end - ---- Initial operations which may not succeed! --- try to bring in any ilua configuration file; don't complain if this is unsuccessful -pcall(function() - require 'ilua-defs' -end) - --- process command-line parameters -if arg then - local i = 1 - - local function parm_value(opt, parm, def) - local val = parm:sub(3) - if #val == 0 then - i = i + 1 - if i > #arg then - if not def then - quit(-1, "expecting parameter for option '-" .. opt .. "'") - else - return def - end - end - val = arg[i] - end - return val - end - - while i <= #arg do - local v = arg[i] - local opt = v:sub(1, 1) - if opt == '-' then - opt = v:sub(2, 2) - if opt == 'h' then - quit(0, "ilua (-l lib) (-L lib) (lua files)") - elseif opt == 'l' then - require(parm_value(opt, v)) - elseif opt == 'L' then - local lib = parm_value(opt, v) - local tbl = require(lib) - -- we cannot always trust require to return the table! - if type(tbl) ~= 'table' then - tbl = _G[lib] - end - ilua.import(tbl, true, lib) - elseif opt == 't' or opt == 'T' then - local file - if opt == 'T' then - file = 'ilua_' .. os.date('%y_%m_%d_%H_%M') .. '.log' - else - file = parm_value(opt, v, "ilua.log") - end - print('saving transcript "' .. file .. '"') - elseif opt == 's' then - strict = false - elseif opt == 'v' then - verbose = true - end - else -- a plain file to be executed immediately - dofile(v) - end - i = i + 1 - end -end - -print 'ILUA: Lua 5.4.6 Copyright (C) 1994-2007 Lua.org, PUC-Rio' - --- any import complaints? -ilua.import() - --- enable 'not declared' error -if strict then - set_strict() -end - local a = require('async') +local inspect = require('inspect') -a.sync(function() - local line = a.wait(readline(prompt)) +local prompt = '> ' - while line do - ---if line == 'quit' then break end - eval_lua(line) - ---saveline(line) - line = a.wait(readline(prompt)) +local function errHandler(err) + return debug.traceback(err, 2) +end + +---Returns the number of arguments and a table with the arguments +---We need this because select('#', ...) is the only way to figure out the number of arguments +---because #table will not count nil values +---@return integer nArguments The number of arguments provided to wrap(...) +---@return table arguments The arguments packed a table +local function wrap(...) return select('#', ...), { ... } end + +local function eval(code) + if #code == 0 then + return end + + --We load the code once as is, and once by adding a return statement in front of it + local asFunc, errFunc = load(code) + local asReturn = load('return ' .. code) + --If the code with return statement did not compile we will use the code without it + if not asReturn then + --If the code without the return did not compile either we print an error + if not asFunc then + print("__ERROR__" .. errFunc) + return + end + asReturn = asFunc + end + + --We call the compiled code in protected mode, which will capture and errors thrown by it. + local numberOfReturnValues, result = wrap(xpcall(asReturn, errHandler)) + + --result[1] contains true or false depending on whether the function ran successfully + if not result[1] then + print("__ERROR__" .. result[2]) + --numberOfReturnValues is the real number of values returned from xpcall + elseif numberOfReturnValues > 1 then + --We concatenate all the return values into a single string + local str = "" + --Skip the first value which is the boolean from xpcall + for i = 2, numberOfReturnValues do + str = str .. inspect(result[i]) .. '\t' + end + print(str) + end +end + +print(LuaCopyright) + +--Main Loop +a.sync(function() + repeat + local input = a.wait(readline(prompt)) + eval(input) + until false end)() diff --git a/share/qtcreator/lua-plugins/luatests/inspect.lua b/src/plugins/lua/scripts/inspect.lua similarity index 100% rename from share/qtcreator/lua-plugins/luatests/inspect.lua rename to src/plugins/lua/scripts/inspect.lua diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp index 4cc819d8b73..a77bbd570b2 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 Tasking; using namespace Utils; MacroLocatorFilter::MacroLocatorFilter() @@ -28,12 +29,9 @@ MacroLocatorFilter::MacroLocatorFilter() LocatorMatcherTasks MacroLocatorFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, icon = m_icon] { - const QString input = storage->input(); + const auto onSetup = [icon = m_icon] { + const LocatorStorage &storage = *LocatorStorage::storage(); + const QString input = storage.input(); const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(input); const QMap ¯os = MacroManager::macros(); LocatorFilterEntries goodEntries; @@ -69,7 +67,7 @@ LocatorMatcherTasks MacroLocatorFilter::matchers() goodEntries.append(filterEntry); } } - storage->reportOutput(betterEntries + goodEntries); + storage.reportOutput(betterEntries + goodEntries); }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } diff --git a/src/plugins/mcusupport/mcubuildstep.cpp b/src/plugins/mcusupport/mcubuildstep.cpp index 3da8ee80759..706c3e6a2a8 100644 --- a/src/plugins/mcusupport/mcubuildstep.cpp +++ b/src/plugins/mcusupport/mcubuildstep.cpp @@ -198,7 +198,7 @@ void MCUBuildStepFactory::updateDeployStep(ProjectExplorer::Target *target, bool } else { if (!step) return; - step->setEnabled(enabled); + step->setStepEnabled(enabled); } } diff --git a/src/plugins/mesonprojectmanager/toolkitaspectwidget.cpp b/src/plugins/mesonprojectmanager/toolkitaspectwidget.cpp index 7f28ebea5ab..bcf4bcf48f2 100644 --- a/src/plugins/mesonprojectmanager/toolkitaspectwidget.cpp +++ b/src/plugins/mesonprojectmanager/toolkitaspectwidget.cpp @@ -49,8 +49,8 @@ private: { const auto id = [this] { if (m_type == ToolType::Meson) - return MesonToolKitAspect::mesonToolId(m_kit); - return NinjaToolKitAspect::ninjaToolId(m_kit); + return MesonToolKitAspect::mesonToolId(kit()); + return NinjaToolKitAspect::ninjaToolId(kit()); }(); m_toolsComboBox->setCurrentIndex(indexOf(id)); } @@ -107,9 +107,9 @@ void MesonToolKitAspectImpl::setCurrentToolIndex(int index) return; const Id id = Id::fromSetting(m_toolsComboBox->itemData(index)); if (m_type == ToolType::Meson) - MesonToolKitAspect::setMesonTool(m_kit, id); + MesonToolKitAspect::setMesonTool(kit(), id); else - NinjaToolKitAspect::setNinjaTool(m_kit, id); + NinjaToolKitAspect::setNinjaTool(kit(), id); } int MesonToolKitAspectImpl::indexOf(const Id &id) diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 580cfdd699f..7e6be34f7c3 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -295,7 +295,7 @@ MacroExpander *BuildConfiguration::macroExpander() const bool BuildConfiguration::createBuildDirectory() { - const bool result = buildDirectory().ensureWritableDir().has_value(); + const bool result = bool(buildDirectory().ensureWritableDir()); buildDirectoryAspect()->validateInput(); return result; } diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp index db194b2551a..75df07a1167 100644 --- a/src/plugins/projectexplorer/buildmanager.cpp +++ b/src/plugins/projectexplorer/buildmanager.cpp @@ -964,7 +964,7 @@ bool BuildManager::buildLists(const QList &bsls, const QStringL const QString name = displayNameForStepId(list->id()); const QList steps = list->steps(); for (BuildStep *step : steps) - buildItems.append({step, step->enabled(), name}); + buildItems.append({step, step->stepEnabled(), name}); d->m_isDeploying = d->m_isDeploying || list->id() == Constants::BUILDSTEPS_DEPLOY; } @@ -977,7 +977,7 @@ bool BuildManager::buildLists(const QList &bsls, const QStringL void BuildManager::appendStep(BuildStep *step, const QString &name) { - buildQueueAppend({{step, step->enabled(), name}}); + buildQueueAppend({{step, step->stepEnabled(), name}}); } template diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 19eb143d245..e614e1f9f18 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -129,14 +129,14 @@ QWidget *BuildStep::createConfigWidget() void BuildStep::fromMap(const Store &map) { - m_enabled = map.value(buildStepEnabledKey, true).toBool(); + m_stepEnabled = map.value(buildStepEnabledKey, true).toBool(); ProjectConfiguration::fromMap(map); } void BuildStep::toMap(Store &map) const { ProjectConfiguration::toMap(map); - map.insert(buildStepEnabledKey, m_enabled); + map.insert(buildStepEnabledKey, m_stepEnabled); } BuildConfiguration *BuildStep::buildConfiguration() const @@ -235,12 +235,12 @@ QVariant BuildStep::data(Id id) const return {}; } -void BuildStep::setEnabled(bool b) +void BuildStep::setStepEnabled(bool b) { - if (m_enabled == b) + if (m_stepEnabled == b) return; - m_enabled = b; - emit enabledChanged(); + m_stepEnabled = b; + emit stepEnabledChanged(); } BuildStepList *BuildStep::stepList() const @@ -248,9 +248,9 @@ BuildStepList *BuildStep::stepList() const return m_stepList; } -bool BuildStep::enabled() const +bool BuildStep::stepEnabled() const { - return m_enabled; + return m_stepEnabled; } BuildStepFactory::BuildStepFactory() diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h index 75184892abd..a7ac8b3f2bc 100644 --- a/src/plugins/projectexplorer/buildstep.h +++ b/src/plugins/projectexplorer/buildstep.h @@ -43,8 +43,8 @@ public: void fromMap(const Utils::Store &map) override; void toMap(Utils::Store &map) const override; - bool enabled() const; - void setEnabled(bool b); + bool stepEnabled() const; + void setStepEnabled(bool b); BuildStepList *stepList() const; @@ -90,6 +90,8 @@ signals: void addOutput(const QString &string, OutputFormat format, OutputNewlineSetting newlineSetting = DoAppendNewline); + void stepEnabledChanged(); + void progress(int percentage, const QString &message); protected: @@ -112,7 +114,7 @@ private: ProjectConfiguration *projectConfiguration() const; BuildStepList * const m_stepList; - bool m_enabled = true; + bool m_stepEnabled = true; bool m_immutable = false; bool m_widgetExpandedByDefault = true; std::optional m_wasExpanded; diff --git a/src/plugins/projectexplorer/buildstepspage.cpp b/src/plugins/projectexplorer/buildstepspage.cpp index 21fb4c20932..0971de90eaa 100644 --- a/src/plugins/projectexplorer/buildstepspage.cpp +++ b/src/plugins/projectexplorer/buildstepspage.cpp @@ -153,7 +153,7 @@ BuildStepsWidgetData::BuildStepsWidgetData(BuildStep *s) : detailsWidget->setWidget(widget); toolWidget = new ToolWidget(detailsWidget); - toolWidget->setBuildStepEnabled(step->enabled()); + toolWidget->setBuildStepEnabled(step->stepEnabled()); detailsWidget->setToolWidget(toolWidget); detailsWidget->setContentsMargins(0, 0, 0, 0); @@ -239,8 +239,8 @@ void BuildStepListWidget::addBuildStep(int pos) s->detailsWidget->setSummaryText(s->step->summaryText()); }); - connect(s->step, &BuildStep::enabledChanged, this, [s] { - s->toolWidget->setBuildStepEnabled(s->step->enabled()); + connect(s->step, &BuildStep::stepEnabledChanged, this, [s] { + s->toolWidget->setBuildStepEnabled(s->step->stepEnabled()); }); @@ -314,8 +314,8 @@ void BuildStepListWidget::updateBuildStepButtonsState() connect(s->toolWidget, &ToolWidget::disabledClicked, this, [s] { BuildStep *bs = s->step; - bs->setEnabled(!bs->enabled()); - s->toolWidget->setBuildStepEnabled(bs->enabled()); + bs->setStepEnabled(!bs->stepEnabled()); + s->toolWidget->setBuildStepEnabled(bs->stepEnabled()); }); s->toolWidget->setRemoveEnabled(!m_buildStepList->at(i)->isImmutable()); connect(s->toolWidget, &ToolWidget::removeClicked, diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp index 6b98866135a..52c5b73f024 100644 --- a/src/plugins/projectexplorer/buildsystem.cpp +++ b/src/plugins/projectexplorer/buildsystem.cpp @@ -141,26 +141,11 @@ void BuildSystem::requestDelayedParse() requestParseHelper(1000); } -void BuildSystem::requestParseWithCustomDelay(int delayInMs) -{ - requestParseHelper(delayInMs); -} - void BuildSystem::cancelDelayedParseRequest() { d->m_delayedParsingTimer.stop(); } -void BuildSystem::setParseDelay(int delayInMs) -{ - d->m_delayedParsingTimer.setInterval(delayInMs); -} - -int BuildSystem::parseDelay() const -{ - return d->m_delayedParsingTimer.interval(); -} - bool BuildSystem::isParsing() const { return d->m_isParsing; diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h index f18cbbbea71..1681f28e5f3 100644 --- a/src/plugins/projectexplorer/buildsystem.h +++ b/src/plugins/projectexplorer/buildsystem.h @@ -56,10 +56,7 @@ public: void requestParse(); void requestDelayedParse(); - void requestParseWithCustomDelay(int delayInMs = 1000); void cancelDelayedParseRequest(); - void setParseDelay(int delayInMs); - int parseDelay() const; bool isParsing() const; bool hasParsingData() const; diff --git a/src/plugins/projectexplorer/kitaspects.cpp b/src/plugins/projectexplorer/kitaspects.cpp index cef78fb2a25..7f0deaf75a0 100644 --- a/src/plugins/projectexplorer/kitaspects.cpp +++ b/src/plugins/projectexplorer/kitaspects.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include #include +#include + using namespace Utils; namespace ProjectExplorer { @@ -71,13 +74,13 @@ private: void refresh() override { if (!m_ignoreChanges.isLocked()) - m_chooser->setFilePath(SysRootKitAspect::sysRoot(m_kit)); + m_chooser->setFilePath(SysRootKitAspect::sysRoot(kit())); } void pathWasChanged() { const GuardLocker locker(m_ignoreChanges); - SysRootKitAspect::setSysRoot(m_kit, m_chooser->filePath()); + SysRootKitAspect::setSysRoot(kit(), m_chooser->filePath()); } PathChooser *m_chooser; @@ -197,47 +200,36 @@ class DeviceTypeKitAspectImpl final : public KitAspect { public: DeviceTypeKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) - : KitAspect(workingCopy, factory), m_comboBox(createSubWidget()) + : KitAspect(workingCopy, factory) { - for (IDeviceFactory *factory : IDeviceFactory::allDeviceFactories()) - m_comboBox->addItem(factory->displayName(), factory->deviceType().toSetting()); - m_comboBox->setToolTip(factory->description()); - refresh(); - connect(m_comboBox, &QComboBox::currentIndexChanged, - this, &DeviceTypeKitAspectImpl::currentTypeChanged); + using ItemData = std::pair; + const auto model = new ListModel(this); + model->setDataAccessor([](const ItemData &d, int column, int role) -> QVariant { + if (column != 0) + return {}; + if (role == Qt::DisplayRole) + return d.first; + if (role == Qt::UserRole) + return d.second.toSetting(); + return {}; + }); + const auto sortModel = new SortModel(this); + sortModel->setSourceModel(model); + auto getter = [](const Kit &k) { return DeviceTypeKitAspect::deviceTypeId(&k).toSetting(); }; + auto setter = [](Kit &k, const QVariant &type) { + DeviceTypeKitAspect::setDeviceTypeId(&k, Id::fromSetting(type)); + }; + auto resetModel = [](QAbstractItemModel &m) { + // FIXME: Change to parameter-less signature. + auto model = static_cast *>( + static_cast(m).sourceModel()); + model->clear(); + for (IDeviceFactory *factory : IDeviceFactory::allDeviceFactories()) + model->appendItem(std::make_pair(factory->displayName(), factory->deviceType())); + }; + setListAspectSpec( + {sortModel, std::move(getter), std::move(setter), std::move(resetModel), Qt::UserRole}); } - - ~DeviceTypeKitAspectImpl() override { delete m_comboBox; } - -private: - void addToInnerLayout(Layouting::Layout &builder) override - { - addMutableAction(m_comboBox); - builder.addItem(m_comboBox); - } - - void makeReadOnly() override { m_comboBox->setEnabled(false); } - - void refresh() override - { - Id devType = DeviceTypeKitAspect::deviceTypeId(m_kit); - if (!devType.isValid()) - m_comboBox->setCurrentIndex(-1); - for (int i = 0; i < m_comboBox->count(); ++i) { - if (m_comboBox->itemData(i) == devType.toSetting()) { - m_comboBox->setCurrentIndex(i); - break; - } - } - } - - void currentTypeChanged(int idx) - { - Id type = idx < 0 ? Id() : Id::fromSetting(m_comboBox->itemData(idx)); - DeviceTypeKitAspect::setDeviceTypeId(m_kit, type); - } - - QComboBox *m_comboBox; }; } // namespace Internal @@ -368,12 +360,12 @@ private: void makeReadOnly() override { m_comboBox->setEnabled(false); } - Id settingsPageItemToPreselect() const override { return DeviceKitAspect::deviceId(m_kit); } + Id settingsPageItemToPreselect() const override { return DeviceKitAspect::deviceId(kit()); } void refresh() override { - m_model->setTypeFilter(DeviceTypeKitAspect::deviceTypeId(m_kit)); - m_comboBox->setCurrentIndex(m_model->indexOf(DeviceKitAspect::device(m_kit))); + m_model->setTypeFilter(DeviceTypeKitAspect::deviceTypeId(kit())); + m_comboBox->setCurrentIndex(m_model->indexOf(DeviceKitAspect::device(kit()))); } void modelAboutToReset() @@ -392,7 +384,7 @@ private: { if (m_ignoreChanges.isLocked()) return; - DeviceKitAspect::setDeviceId(m_kit, m_model->deviceId(m_comboBox->currentIndex())); + DeviceKitAspect::setDeviceId(kit(), m_model->deviceId(m_comboBox->currentIndex())); } Guard m_ignoreChanges; @@ -660,7 +652,7 @@ private: } m_model->setFilter(blackList); - m_comboBox->setCurrentIndex(m_model->indexOf(BuildDeviceKitAspect::device(m_kit))); + m_comboBox->setCurrentIndex(m_model->indexOf(BuildDeviceKitAspect::device(kit()))); } void modelAboutToReset() @@ -679,7 +671,7 @@ private: { if (m_ignoreChanges.isLocked()) return; - BuildDeviceKitAspect::setDeviceId(m_kit, m_model->deviceId(m_comboBox->currentIndex())); + BuildDeviceKitAspect::setDeviceId(kit(), m_model->deviceId(m_comboBox->currentIndex())); } Guard m_ignoreChanges; @@ -922,7 +914,7 @@ private: void editEnvironmentChanges() { - MacroExpander *expander = m_kit->macroExpander(); + MacroExpander *expander = kit()->macroExpander(); EnvironmentDialog::Polisher polisher = [expander](QWidget *w) { VariableChooser::addSupportForChildWidgets(w, expander); }; @@ -941,12 +933,12 @@ private: else if (enforcesMSVCEnglish(*changes)) m_vslangCheckbox->setChecked(true); } - EnvironmentKitAspect::setEnvironmentChanges(m_kit, *changes); + EnvironmentKitAspect::setEnvironmentChanges(kit(), *changes); } EnvironmentItems envWithoutMSVCEnglishEnforcement() const { - EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(m_kit); + EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(kit()); if (HostOsInfo::isWindowsHost()) changes.removeAll(forceMSVCEnglishItem()); @@ -961,15 +953,15 @@ private: m_vslangCheckbox->setToolTip(Tr::tr("Either switches MSVC to English or keeps the language and " "just forces UTF-8 output (may vary depending on the used MSVC " "compiler).")); - if (enforcesMSVCEnglish(EnvironmentKitAspect::environmentChanges(m_kit))) + if (enforcesMSVCEnglish(EnvironmentKitAspect::environmentChanges(kit()))) m_vslangCheckbox->setChecked(true); connect(m_vslangCheckbox, &QCheckBox::clicked, this, [this](bool checked) { - EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(m_kit); + EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(kit()); if (!checked && changes.indexOf(forceMSVCEnglishItem()) >= 0) changes.removeAll(forceMSVCEnglishItem()); if (checked && changes.indexOf(forceMSVCEnglishItem()) < 0) changes.append(forceMSVCEnglishItem()); - EnvironmentKitAspect::setEnvironmentChanges(m_kit, changes); + EnvironmentKitAspect::setEnvironmentChanges(kit(), changes); }); } diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index d6544c130c3..899acddae5e 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -29,7 +29,9 @@ #include +#include #include +#include #include #include #include @@ -767,6 +769,17 @@ KitAspect::~KitAspect() delete m_mutableAction; } +void KitAspect::refresh() +{ + if (!m_listAspectSpec) + return; + const GuardLocker locker(m_ignoreChanges); + m_listAspectSpec->resetModel(*m_listAspectSpec->model); + m_listAspectSpec->model->sort(0); + const QVariant itemId = m_listAspectSpec->getter(*kit()); + m_comboBox->setCurrentIndex(m_comboBox->findData(itemId, m_listAspectSpec->itemRole)); +} + void KitAspect::makeStickySubWidgetsReadOnly() { if (!m_kit->isSticky(m_factory->id())) @@ -778,6 +791,45 @@ void KitAspect::makeStickySubWidgetsReadOnly() makeReadOnly(); } +void KitAspect::makeReadOnly() +{ + if (m_comboBox) + m_comboBox->setEnabled(false); +} + +void KitAspect::addToInnerLayout(Layouting::Layout &parentItem) +{ + if (m_comboBox) { + addMutableAction(m_comboBox); + parentItem.addItem(m_comboBox); + } +} + +void KitAspect::setListAspectSpec(ListAspectSpec &&listAspectSpec) +{ + m_listAspectSpec = std::move(listAspectSpec); + + m_comboBox = createSubWidget(); + m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy()); + m_comboBox->setEnabled(true); + m_comboBox->setModel(m_listAspectSpec->model); + + refresh(); + + const auto updateTooltip = [this] { + m_comboBox->setToolTip( + m_comboBox->itemData(m_comboBox->currentIndex(), Qt::ToolTipRole).toString()); + }; + updateTooltip(); + connect(m_comboBox, &QComboBox::currentIndexChanged, this, [this, updateTooltip] { + if (m_ignoreChanges.isLocked()) + return; + updateTooltip(); + m_listAspectSpec->setter( + *kit(), m_comboBox->itemData(m_comboBox->currentIndex(), m_listAspectSpec->itemRole)); + }); +} + void KitAspect::addToLayoutImpl(Layouting::Layout &layout) { auto label = createSubWidget(m_factory->displayName() + ':'); diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h index e04b6755c83..a3aa5d8c669 100644 --- a/src/plugins/projectexplorer/kitmanager.h +++ b/src/plugins/projectexplorer/kitmanager.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -17,6 +18,11 @@ #include +QT_BEGIN_NAMESPACE +class QAbstractItemModel; +class QComboBox; +QT_END_NAMESPACE + namespace Utils { class Environment; class FilePath; @@ -108,7 +114,7 @@ public: KitAspect(Kit *kit, const KitAspectFactory *factory); ~KitAspect(); - virtual void refresh() = 0; + virtual void refresh(); void addToLayoutImpl(Layouting::Layout &layout) override; static QString msgManage(); @@ -122,15 +128,49 @@ public: void makeStickySubWidgetsReadOnly(); protected: - virtual void makeReadOnly() {} - virtual void addToInnerLayout(Layouting::Layout &parentItem) = 0; + virtual void makeReadOnly(); + virtual void addToInnerLayout(Layouting::Layout &parentItem); virtual Utils::Id settingsPageItemToPreselect() const { return {}; } + // Convenience for aspects that provide a list model from which one value can be chosen. + // It will be exposed via a QComboBox. + class ListAspectSpec + { + public: + using Getter = std::function; + using Setter = std::function; + using ResetModel = std::function; + + ListAspectSpec( + QAbstractItemModel *model, + Getter &&getter, + Setter &&setter, + ResetModel &&resetModel, + int itemRole) + : model(model) + , getter(std::move(getter)) + , setter(std::move(setter)) + , resetModel(std::move(resetModel)) + , itemRole(itemRole) + {} + + QAbstractItemModel *model; + Getter getter; + Setter setter; + ResetModel resetModel; + int itemRole; + }; + void setListAspectSpec(ListAspectSpec &&listAspectSpec); + +private: Kit *m_kit; const KitAspectFactory *m_factory; QAction *m_mutableAction = nullptr; Utils::Id m_managingPageId; QPushButton *m_manageButton = nullptr; + QComboBox *m_comboBox = nullptr; + std::optional m_listAspectSpec; + Utils::Guard m_ignoreChanges; }; class PROJECTEXPLORER_EXPORT KitManager final : public QObject diff --git a/src/plugins/projectexplorer/processstep.cpp b/src/plugins/projectexplorer/processstep.cpp index 6d495335978..d899fb5e4d1 100644 --- a/src/plugins/projectexplorer/processstep.cpp +++ b/src/plugins/projectexplorer/processstep.cpp @@ -19,6 +19,8 @@ namespace ProjectExplorer::Internal { const char PROCESS_COMMAND_KEY[] = "ProjectExplorer.ProcessStep.Command"; const char PROCESS_WORKINGDIRECTORY_KEY[] = "ProjectExplorer.ProcessStep.WorkingDirectory"; +const char PROCESS_WORKINGDIRECTORYRELATIVEBASE_KEY[] + = "ProjectExplorer.ProcessStep.WorkingDirectoryRelativeBasePath"; const char PROCESS_ARGUMENTS_KEY[] = "ProjectExplorer.ProcessStep.Arguments"; ProcessStep::ProcessStep(BuildStepList *bsl, Id id) @@ -38,10 +40,18 @@ ProcessStep::ProcessStep(BuildStepList *bsl, Id id) m_workingDirectory.setLabelText(Tr::tr("Working directory:")); m_workingDirectory.setExpectedKind(PathChooser::Directory); + m_workingDirRelativeBasePath.setSettingsKey(PROCESS_WORKINGDIRECTORYRELATIVEBASE_KEY); + m_workingDirRelativeBasePath.setValue(QString()); + m_workingDirRelativeBasePath.setVisible(false); + m_workingDirRelativeBasePath.setExpectedKind(PathChooser::Directory); + setWorkingDirectoryProvider([this] { const FilePath workingDir = m_workingDirectory(); + const FilePath relativeBasePath = m_workingDirRelativeBasePath(); if (workingDir.isEmpty()) return FilePath::fromString(fallbackWorkingDirectory()); + else if (workingDir.isRelativePath() && !relativeBasePath.isEmpty()) + return relativeBasePath.resolvePath(workingDir); return workingDir; }); @@ -69,9 +79,11 @@ void ProcessStep::setArguments(const QStringList &arguments) m_arguments.setValue(arguments.join(" ")); } -void ProcessStep::setWorkingDirectory(const Utils::FilePath &workingDirectory) +void ProcessStep::setWorkingDirectory( + const Utils::FilePath &workingDirectory, const Utils::FilePath &relativeBasePath) { m_workingDirectory.setValue(workingDirectory); + m_workingDirRelativeBasePath.setValue(relativeBasePath); } void ProcessStep::setupOutputFormatter(OutputFormatter *formatter) diff --git a/src/plugins/projectexplorer/processstep.h b/src/plugins/projectexplorer/processstep.h index 09ffe26420b..ff36ebb28c3 100644 --- a/src/plugins/projectexplorer/processstep.h +++ b/src/plugins/projectexplorer/processstep.h @@ -15,7 +15,9 @@ public: void setCommand(const Utils::FilePath &command); void setArguments(const QStringList &arguments); - void setWorkingDirectory(const Utils::FilePath &workingDirectory); + void setWorkingDirectory( + const Utils::FilePath &workingDirectory, + const Utils::FilePath &relativeBasePath = Utils::FilePath()); private: void setupOutputFormatter(Utils::OutputFormatter *formatter) final; @@ -23,6 +25,7 @@ private: Utils::FilePathAspect m_command{this}; Utils::StringAspect m_arguments{this}; Utils::FilePathAspect m_workingDirectory{this}; + Utils::FilePathAspect m_workingDirRelativeBasePath{this}; }; class ProcessStepFactory final : public BuildStepFactory diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 5ca9b57b3ee..d1a9f2af869 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -547,7 +547,7 @@ bool Project::copySteps(Target *sourceTarget, Target *newTarget) } for (RunConfiguration *sourceRc : sourceTarget->runConfigurations()) { - RunConfiguration *newRc = RunConfigurationFactory::clone(newTarget, sourceRc); + RunConfiguration *newRc = sourceRc->clone(newTarget); if (!newRc) { runconfigurationError << sourceRc->displayName(); continue; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 184c5cfd74a..adfd6bdd26d 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -4253,14 +4253,13 @@ static RunConfiguration *runConfigurationForDisplayName(const QString &displayNa }); } +using namespace Tasking; + static LocatorMatcherTasks runConfigurationMatchers(const RunAcceptor &acceptor) { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, acceptor] { - const QString input = storage->input(); + const auto onSetup = [acceptor] { + const LocatorStorage &storage = *LocatorStorage::storage(); + const QString input = storage.input(); const Target *target = ProjectManager::startupTarget(); if (!target) return; @@ -4280,9 +4279,9 @@ static LocatorMatcherTasks runConfigurationMatchers(const RunAcceptor &acceptor) entries.append(entry); } } - storage->reportOutput(entries); + storage.reportOutput(entries); }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } static void runAcceptor(RunConfiguration *config) diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index f5b858d141d..0c920487d90 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -148,6 +148,8 @@ RunConfiguration::RunConfiguration(Target *target, Utils::Id id) forceDisplayNameSerialization(); connect(target, &Target::parsingFinished, this, &RunConfiguration::update); + setMacroExpander(&m_expander); + m_expander.setDisplayName(Tr::tr("Run Settings")); m_expander.setAccumulating(true); m_expander.registerSubProvider([target] { @@ -356,6 +358,13 @@ void RunConfiguration::update() ProjectExplorerPlugin::updateRunActions(); } +RunConfiguration *RunConfiguration::clone(Target *parent) +{ + Store map; + toMap(map); + return RunConfigurationFactory::restore(parent, map); +} + BuildTargetInfo RunConfiguration::buildTargetInfo() const { BuildSystem *bs = target()->buildSystem(); @@ -656,13 +665,6 @@ RunConfiguration *RunConfigurationFactory::restore(Target *parent, const Store & return nullptr; } -RunConfiguration *RunConfigurationFactory::clone(Target *parent, RunConfiguration *source) -{ - Store map; - source->toMap(map); - return restore(parent, map); -} - const QList RunConfigurationFactory::creatorsForTarget(Target *parent) { QList items; diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index 113bc54426b..84b385330f0 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -172,7 +172,7 @@ public: void update(); - const Utils::MacroExpander *macroExpander() const { return &m_expander; } + virtual RunConfiguration *clone(Target *parent); protected: RunConfiguration(Target *target, Utils::Id id); @@ -233,7 +233,6 @@ public: virtual ~RunConfigurationFactory(); static RunConfiguration *restore(Target *parent, const Utils::Store &map); - static RunConfiguration *clone(Target *parent, RunConfiguration *source); static const QList creatorsForTarget(Target *parent); Utils::Id runConfigurationId() const { return m_runConfigurationId; } diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index bc4e1369bd5..a3081663bb5 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 @@ -157,15 +157,11 @@ WorkingDirectoryAspect::WorkingDirectoryAspect(AspectContainer *container) : BaseAspect(container) { setDisplayName(Tr::tr("Working Directory")); + setLabelText(Tr::tr("Working directory:")); setId("WorkingDirectoryAspect"); setSettingsKey("RunConfiguration.WorkingDirectory"); } -void WorkingDirectoryAspect::setMacroExpander(const MacroExpander *expander) -{ - m_macroExpander = expander; -} - void WorkingDirectoryAspect::setEnvironment(EnvironmentAspect *envAspect) { m_envAspect = envAspect; @@ -178,8 +174,8 @@ void WorkingDirectoryAspect::addToLayoutImpl(Layout &builder) { QTC_CHECK(!m_chooser); m_chooser = new PathChooser; - if (QTC_GUARD(m_macroExpander)) - m_chooser->setMacroExpander(m_macroExpander); + if (QTC_GUARD(macroExpander())) + m_chooser->setMacroExpander(macroExpander()); m_chooser->setHistoryCompleter(settingsKey()); m_chooser->setExpectedKind(Utils::PathChooser::Directory); m_chooser->setPromptDialogTitle(Tr::tr("Select Working Directory")); @@ -206,7 +202,10 @@ void WorkingDirectoryAspect::addToLayoutImpl(Layout &builder) m_chooser->setReadOnly(isReadOnly()); m_resetButton->setEnabled(!isReadOnly()); - builder.addItems({Tr::tr("Working directory:"), m_chooser.data(), m_resetButton.data()}); + registerSubWidget(m_chooser); + registerSubWidget(m_resetButton); + + addLabeledItems(builder, {m_chooser.data(), m_resetButton.data()}); } void WorkingDirectoryAspect::resetPath() @@ -250,8 +249,8 @@ FilePath WorkingDirectoryAspect::workingDirectory() const const Environment env = m_envAspect ? m_envAspect->environment() : Environment::systemEnvironment(); QString workingDir = m_workingDirectory.path(); - if (m_macroExpander) - workingDir = m_macroExpander->expandProcessArgs(workingDir); + if (auto expander = macroExpander()) + workingDir = expander->expandProcessArgs(workingDir); QString res = workingDir.isEmpty() ? QString() : QDir::cleanPath(env.expandVariables(workingDir)); @@ -314,12 +313,11 @@ ArgumentsAspect::ArgumentsAspect(AspectContainer *container) : BaseAspect(container) { setDisplayName(Tr::tr("Arguments")); + setLabelText(Tr::tr("Command line arguments:")); setId("ArgumentsAspect"); setSettingsKey("RunConfiguration.Arguments"); addDataExtractor(this, &ArgumentsAspect::arguments, &Data::arguments); - - m_labelText = Tr::tr("Command line arguments:"); } void ArgumentsAspect::setMacroExpander(const MacroExpander *expander) @@ -369,14 +367,6 @@ void ArgumentsAspect::setArguments(const QString &arguments) m_multiLineChooser->setPlainText(arguments); } -/*! - Sets the displayed label text to \a labelText. -*/ -void ArgumentsAspect::setLabelText(const QString &labelText) -{ - m_labelText = labelText; -} - /*! Adds a button to reset the main value of this aspect to the value computed by \a resetter. @@ -501,8 +491,9 @@ void ArgumentsAspect::addToLayoutImpl(Layout &builder) containerLayout->addWidget(m_resetButton); containerLayout->setAlignment(m_resetButton, Qt::AlignTop); } + registerSubWidget(container); - builder.addItems({m_labelText, container}); + addLabeledItem(builder, container); } /*! diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h index c27cb18f10a..5f5f2f5b45c 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.h +++ b/src/plugins/projectexplorer/runconfigurationaspects.h @@ -69,7 +69,6 @@ public: Utils::FilePath unexpandedWorkingDirectory() const; void setDefaultWorkingDirectory(const Utils::FilePath &defaultWorkingDirectory); Utils::PathChooser *pathChooser() const; - void setMacroExpander(const Utils::MacroExpander *expander); void setEnvironment(EnvironmentAspect *envAspect); private: @@ -83,7 +82,6 @@ private: Utils::FilePath m_defaultWorkingDirectory; QPointer m_chooser; QPointer m_resetButton; - const Utils::MacroExpander *m_macroExpander = nullptr; }; class PROJECTEXPLORER_EXPORT ArgumentsAspect : public Utils::BaseAspect @@ -100,7 +98,6 @@ public: QString unexpandedArguments() const; void setArguments(const QString &arguments); - void setLabelText(const QString &labelText); void setResetter(const std::function &resetter); void resetArguments(); void setMacroExpander(const Utils::MacroExpander *macroExpander); @@ -117,7 +114,6 @@ private: QWidget *setupChooser(); QString m_arguments; - QString m_labelText; QPointer m_chooser; QPointer m_multiLineChooser; QPointer m_multiLineButton; diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 14f2094c166..62b11f11570 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -298,9 +298,11 @@ public: bool useDebugChannel = false; bool useQmlChannel = false; bool usePerfChannel = false; + bool useWorkerChannel = false; QUrl debugChannel; QUrl qmlChannel; QUrl perfChannel; + QUrl workerChannel; }; class RunControlPrivate : public QObject, public RunControlPrivateData @@ -606,6 +608,8 @@ void RunControlPrivate::startPortsGathererIfNeededAndContinueStart() qmlChannel = getNextChannel(); if (usePerfChannel) perfChannel = getNextChannel(); + if (useWorkerChannel) + workerChannel = getNextChannel(); continueStart(); } else { @@ -700,6 +704,17 @@ QUrl RunControl::perfChannel() const return d->perfChannel; } +void RunControl::requestWorkerChannel() +{ + d->enablePortsGatherer(); + d->useWorkerChannel = true; +} + +QUrl RunControl::workerChannel() const +{ + return d->workerChannel; +} + void RunControlPrivate::continueStart() { checkState(RunControlState::Starting); diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 69bcf1cdc1d..3003e83fef0 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -258,6 +258,9 @@ public: bool usesPerfChannel() const; QUrl perfChannel() const; + void requestWorkerChannel(); + QUrl workerChannel() const; + signals: void appendMessage(const QString &msg, Utils::OutputFormat format); void aboutToStart(); diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.cpp b/src/plugins/projectexplorer/runsettingspropertiespage.cpp index ec18f68c603..c10870c2af0 100644 --- a/src/plugins/projectexplorer/runsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/runsettingspropertiespage.cpp @@ -210,7 +210,7 @@ void RunSettingsWidget::cloneRunConfiguration() if (name.isEmpty()) return; - RunConfiguration *newRc = RunConfigurationFactory::clone(m_target, activeRunConfiguration); + RunConfiguration *newRc = activeRunConfiguration->clone(m_target); if (!newRc) return; diff --git a/src/plugins/projectexplorer/toolchainkitaspect.cpp b/src/plugins/projectexplorer/toolchainkitaspect.cpp index 178eaa000eb..5cf7916094f 100644 --- a/src/plugins/projectexplorer/toolchainkitaspect.cpp +++ b/src/plugins/projectexplorer/toolchainkitaspect.cpp @@ -36,18 +36,6 @@ public: reset(); } - QModelIndex indexForBundleId(Id bundleId) const - { - if (!bundleId.isValid()) - return index(rowCount() - 1, 0); // The "no compiler" item always comes last - const TreeItem *const item = findItemAtLevel<1>( - [bundleId](TreeItem *item) { - const auto tcItem = static_cast(item); - return tcItem->bundle && tcItem->bundle->bundleId() == bundleId; - }); - return item ? indexForItem(item) : QModelIndex(); - } - void reset() { clear(); @@ -77,12 +65,6 @@ class ToolchainSortModel : public SortModel public: ToolchainSortModel(QObject *parent) : SortModel(parent) {} - QModelIndex indexForBundleId(Id bundleId) const - { - return mapFromSource( - static_cast(sourceModel())->indexForBundleId(bundleId)); - } - void reset() { static_cast(sourceModel())->reset(); } private: @@ -181,7 +163,7 @@ private: Id currentBundleId; for (const Id lang : lc) { - if (Toolchain * const currentTc = ToolchainKitAspect::toolchain(m_kit, lang)) { + if (Toolchain * const currentTc = ToolchainKitAspect::toolchain(kit(), lang)) { currentBundleId = currentTc->bundleId(); break; } @@ -214,15 +196,15 @@ private: return tc->language() == lang; }); if (tc) - ToolchainKitAspect::setToolchain(m_kit, tc); + ToolchainKitAspect::setToolchain(kit(), tc); else - ToolchainKitAspect::clearToolchain(m_kit, lang); + ToolchainKitAspect::clearToolchain(kit(), lang); } } int indexOf(QComboBox *cb, Id bundleId) { - return static_cast(cb->model())->indexForBundleId(bundleId).row(); + return cb->findData(bundleId.toSetting(), ToolchainTreeItem::BundleIdRole); } QWidget *m_mainWidget = nullptr; diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp index 4c3a29177bf..1d017f0efbd 100644 --- a/src/plugins/projectexplorer/toolchainoptionspage.cpp +++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp @@ -51,7 +51,7 @@ QVariant ToolchainTreeItem::data(int column, int role) const switch (role) { case Qt::DisplayRole: if (column == 0) - return bundle ? bundle->displayName() : Tr::tr(""); + return bundle ? bundle->displayName() : Tr::tr("None"); return bundle->typeDisplayName(); case Qt::ToolTipRole: { if (!bundle) diff --git a/src/plugins/projectexplorer/workspaceproject.cpp b/src/plugins/projectexplorer/workspaceproject.cpp index 61e2b4b6894..fbba5d3a556 100644 --- a/src/plugins/projectexplorer/workspaceproject.cpp +++ b/src/plugins/projectexplorer/workspaceproject.cpp @@ -209,9 +209,6 @@ void WorkspaceBuildSystem::reparse(bool force) FilePath workingDirectory = FilePath::fromUserInput( targetObject["workingDirectory"].toString()); - if (!workingDirectory.isDir()) - workingDirectory = FilePath::currentWorkingPath(); - const QString name = targetObject["name"].toString(); const FilePath executable = FilePath::fromUserInput( targetObject["executable"].toString()); @@ -235,6 +232,8 @@ void WorkspaceBuildSystem::reparse(bool force) if (force || oldFilters != m_filters) scan(target()->project()->projectDirectory()); + else + emitBuildSystemUpdated(); } void WorkspaceBuildSystem::triggerParsing() @@ -368,8 +367,8 @@ public: const BuildTargetInfo bti = buildTargetInfo(); executable.setLabelText(Tr::tr("Executable:")); - executable.setReadOnly(true); executable.setValue(bti.targetFilePath); + executable.setSettingsKey("Workspace.RunConfiguration.Executable"); auto argumentsAsString = [this]() { return CommandLine{ @@ -378,39 +377,48 @@ public: }; arguments.setLabelText(Tr::tr("Arguments:")); - arguments.setReadOnly(true); - arguments.setMacroExpander(macroExpander()); arguments.setArguments(argumentsAsString()); + arguments.setSettingsKey("Workspace.RunConfiguration.Arguments"); workingDirectory.setLabelText(Tr::tr("Working directory:")); - workingDirectory.setReadOnly(true); workingDirectory.setDefaultWorkingDirectory(bti.workingDirectory); + workingDirectory.setSettingsKey("Workspace.RunConfiguration.WorkingDirectory"); setCommandLineGetter([this] { - const BuildTargetInfo bti = buildTargetInfo(); - CommandLine cmdLine{ - macroExpander()->expand(bti.targetFilePath), - Utils::transform( - bti.additionalData.toMap()["arguments"].toStringList(), - [this](const QString &arg) { return macroExpander()->expand(arg); })}; - - return cmdLine; + return CommandLine(executable.effectiveBinary(), + arguments.arguments(), + CommandLine::Raw); }); setUpdater([this, argumentsAsString] { + if (enabled.value()) // skip the update for cloned run configurations + return; const BuildTargetInfo bti = buildTargetInfo(); executable.setValue(bti.targetFilePath); arguments.setArguments(argumentsAsString()); workingDirectory.setDefaultWorkingDirectory(bti.workingDirectory); }); + auto enabledUpdater = [this] { setEnabled(enabled.value()); }; + connect(&enabled, &BaseAspect::changed, this, enabledUpdater); + connect(this, &AspectContainer::fromMapFinished, this, enabledUpdater); connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); + enabledUpdater(); + enabled.setSettingsKey("Workspace.RunConfiguration.Enabled"); + } + + RunConfiguration *clone(Target *parent) override + { + RunConfiguration *result = RunConfiguration::clone(parent); + dynamic_cast(result)->enabled.setValue(true); + return result; } TextDisplay hint{this}; FilePathAspect executable{this}; ArgumentsAspect arguments{this}; WorkingDirectoryAspect workingDirectory{this}; + BoolAspect enabled{this}; }; class WorkspaceProjectRunConfigurationFactory : public RunConfigurationFactory @@ -455,9 +463,7 @@ public: FilePath wd = FilePath::fromUserInput(bs["workingDirectory"].toString()); if (wd.isEmpty()) wd = "%{ActiveProject:BuildConfig:Path}"; - else if (wd.isRelativePath()) - wd = project()->projectDirectory().resolvePath(wd); - step->setWorkingDirectory(wd); + step->setWorkingDirectory(wd, project()->projectDirectory()); steps->appendStep(step); } initializeExtraInfo(extraInfos); @@ -471,8 +477,11 @@ public: resetExtraInfo(); if (extraInfos["forSetup"].toBool()) { originalExtraInfo = extraInfos; + setEnabled(false); buildInfoResetConnection = connect( this, &BaseAspect::changed, this, &WorkspaceBuildConfiguration::resetExtraInfo); + for (BuildStep *step : buildSteps()->steps()) + step->setEnabled(false); } } @@ -501,6 +510,9 @@ public: { originalExtraInfo.reset(); disconnect(buildInfoResetConnection); + setEnabled(true); + for (auto step : buildSteps()->steps()) + step->setEnabled(true); } std::optional originalExtraInfo; diff --git a/src/plugins/python/pythonkitaspect.cpp b/src/plugins/python/pythonkitaspect.cpp index f4fd0a0f976..8bdc557d946 100644 --- a/src/plugins/python/pythonkitaspect.cpp +++ b/src/plugins/python/pythonkitaspect.cpp @@ -40,7 +40,7 @@ public: if (m_ignoreChanges.isLocked()) return; - PythonKitAspect::setPython(m_kit, m_comboBox->currentData().toString()); + PythonKitAspect::setPython(this->kit(), m_comboBox->currentData().toString()); }); connect(PythonSettings::instance(), &PythonSettings::interpretersChanged, @@ -62,7 +62,7 @@ public: for (const Interpreter &interpreter : PythonSettings::interpreters()) m_comboBox->addItem(interpreter.name, interpreter.id); - updateComboBox(PythonKitAspect::python(m_kit)); + updateComboBox(PythonKitAspect::python(kit())); emit changed(); // we need to emit changed here to update changes in the macro expander } diff --git a/src/plugins/qbsprojectmanager/qbskitaspect.cpp b/src/plugins/qbsprojectmanager/qbskitaspect.cpp index a708601e219..f9fd3e6ec14 100644 --- a/src/plugins/qbsprojectmanager/qbskitaspect.cpp +++ b/src/plugins/qbsprojectmanager/qbskitaspect.cpp @@ -89,7 +89,10 @@ public: QbsKitAspectFactory() { setId(QbsKitAspect::id()); - setDisplayName(Tr::tr("Additional Qbs Profile Settings")); + setDisplayName(Tr::tr("Qbs Profile Additions")); + setDescription(Tr::tr("Additional module properties to set in " + "the Qbs profile corresponding to this kit.\n" + "You will rarely need to do this.")); setPriority(22000); } diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index b3acf6847de..925b91c61f0 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -532,7 +532,7 @@ FilePath QbsBuildSystem::installRoot() if (dc) { const QList steps = dc->stepList()->steps(); for (const BuildStep * const step : steps) { - if (!step->enabled()) + if (!step->stepEnabled()) continue; if (const auto qbsInstallStep = qobject_cast(step)) return qbsInstallStep->installRoot(); diff --git a/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp b/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp index 896c0a35864..2f902e8f33f 100644 --- a/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp +++ b/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp @@ -50,13 +50,13 @@ private: void refresh() override { if (!m_ignoreChanges.isLocked()) - m_lineEdit->setText(QDir::toNativeSeparators(QmakeKitAspect::mkspec(m_kit))); + m_lineEdit->setText(QDir::toNativeSeparators(QmakeKitAspect::mkspec(kit()))); } void mkspecWasChanged(const QString &text) { const GuardLocker locker(m_ignoreChanges); - QmakeKitAspect::setMkspec(m_kit, text, QmakeKitAspect::MkspecSource::User); + QmakeKitAspect::setMkspec(kit(), text, QmakeKitAspect::MkspecSource::User); } QLineEdit *m_lineEdit = nullptr; diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index c8ae2c884e7..1f5e3ce5f98 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -68,8 +68,6 @@ using namespace Utils; namespace QmakeProjectManager { namespace Internal { -const int UPDATE_INTERVAL = 3000; - static Q_LOGGING_CATEGORY(qmakeBuildSystemLog, "qtc.qmake.buildsystem", QtWarningMsg); #define TRACE(msg) \ @@ -204,8 +202,6 @@ QmakeBuildSystem::QmakeBuildSystem(QmakeBuildConfiguration *bc) , m_qmakeVfs(new QMakeVfs) , m_cppCodeModelUpdater(ProjectUpdaterFactory::createCppProjectUpdater()) { - setParseDelay(0); - m_rootProFile = std::make_unique(this, projectFilePath()); connect(BuildManager::instance(), &BuildManager::buildQueueFinished, @@ -588,10 +584,11 @@ void QmakeBuildSystem::startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay) return; } - const int interval = qMin(parseDelay(), - delay == QmakeProFile::ParseLater ? UPDATE_INTERVAL : 0); - TRACE("interval: " << interval); - requestParseWithCustomDelay(interval); + TRACE("delay: " << delay); + switch (delay) { + case QmakeProFile::ParseNow: requestParse(); break; + case QmakeProFile::ParseLater: requestDelayedParse(); break; + } } void QmakeBuildSystem::incrementPendingEvaluateFutures() @@ -666,7 +663,6 @@ bool QmakeBuildSystem::wasEvaluateCanceled() void QmakeBuildSystem::asyncUpdate() { TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); - setParseDelay(UPDATE_INTERVAL); TRACE(""); if (m_invalidateQmakeVfsContents) { @@ -945,7 +941,7 @@ void QmakeBuildSystem::activeTargetWasChanged(Target *t) return; m_invalidateQmakeVfsContents = true; - scheduleUpdateAll(QmakeProFile::ParseLater); + scheduleUpdateAllNowOrLater(); } static void notifyChangedHelper(const FilePath &fileName, QmakeProFile *file) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp index d12d824ddc8..3b7524faa00 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp @@ -158,8 +158,8 @@ QString AssetsLibraryModel::addNewFolder(const QString &folderPath) { Utils::FilePath uniqueDirPath = Utils::FilePath::fromString(UniqueName::generatePath(folderPath)); - auto res = uniqueDirPath.ensureWritableDir(); - if (!res.has_value()) { + const Utils::Result res = uniqueDirPath.ensureWritableDir(); + if (!res) { qWarning() << __FUNCTION__ << res.error(); return {}; } diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 1cbb3e5edb3..2913a8e6f6d 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -269,7 +269,7 @@ QmlDesignerPlugin::~QmlDesignerPlugin() // INHERITED FROM ExtensionSystem::Plugin // //////////////////////////////////////////////////// -bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage/* = 0*/) +bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString * /*errorMessage*/) { if constexpr (isUsingQmlDesignerLite()) { if (!QmlDesignerBasePlugin::isLiteModeEnabled()) { diff --git a/src/plugins/qmljseditor/qmltaskmanager.cpp b/src/plugins/qmljseditor/qmltaskmanager.cpp index 5388b6d5522..7bb85d9acca 100644 --- a/src/plugins/qmljseditor/qmltaskmanager.cpp +++ b/src/plugins/qmljseditor/qmltaskmanager.cpp @@ -139,9 +139,6 @@ void QmlTaskManager::updateSemanticMessagesNow() void QmlTaskManager::updateMessagesNow(bool updateSemantic) { - // clear out the qmllint warnings when qmlls was disabled after being enabled - TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE); - // don't restart a small update if a big one is running if (!updateSemantic && m_updatingSemantic) return; diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index c6f8dfa4fd0..21915e7be92 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -12,6 +12,7 @@ using namespace Core; using namespace QmlJSTools::Internal; +using namespace Tasking; using namespace Utils; Q_DECLARE_METATYPE(LocatorData::Entry) @@ -74,13 +75,9 @@ static void matches(QPromise &promise, const LocatorStorage &storage, LocatorMatcherTasks QmlJSFunctionsFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage, entries = m_data->entries()](Async &async) { - async.setConcurrentCallData(matches, *storage, entries); + const auto onSetup = [entries = m_data->entries()](Async &async) { + async.setConcurrentCallData(matches, *LocatorStorage::storage(), entries); }; - return {{AsyncTask(onSetup), storage}}; + return {AsyncTask(onSetup)}; } diff --git a/src/plugins/qtapplicationmanager/appmanagercmakepackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagercmakepackagestep.cpp index 0f9ae37f712..18d2f476761 100644 --- a/src/plugins/qtapplicationmanager/appmanagercmakepackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagercmakepackagestep.cpp @@ -33,7 +33,7 @@ public: const auto updaterSlot = [step] { const TargetInformation targetInformation(step->target()); step->setBuildTargets({targetInformation.cmakeBuildTarget}); - step->setEnabled(!targetInformation.isBuiltin); + step->setStepEnabled(!targetInformation.isBuiltin); }; QObject::connect(step->target(), &Target::activeRunConfigurationChanged, step, updaterSlot); QObject::connect(step->target(), &Target::activeDeployConfigurationChanged, step, updaterSlot); diff --git a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp index 6263028a6e4..36bb6071db9 100644 --- a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp @@ -59,7 +59,7 @@ public: targetDirectory.setValue(targetInformation.runDirectory); targetDirectory.setDefaultValue(targetDirectory.value()); - setEnabled(!targetInformation.isBuiltin); + setStepEnabled(!targetInformation.isBuiltin); }; connect(target(), &Target::activeRunConfigurationChanged, this, updateAspects); diff --git a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp index 49ba78f669f..28c8a53945e 100644 --- a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp @@ -83,7 +83,7 @@ AppManagerInstallPackageStep::AppManagerInstallPackageStep(BuildStepList *bsl, I packageFile.setDefaultPathValue(packageFilePath); } - setEnabled(!targetInformation.isBuiltin); + setStepEnabled(!targetInformation.isBuiltin); }; connect(target(), &Target::activeRunConfigurationChanged, this, updateAspects); diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index 5f09c3aa636..90662a89d4c 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -139,7 +139,7 @@ static FilePath copyToAlternativeLocation(const FilePath &proFile, QMessageBox::NoButton); return {}; } else { - expected_str result = projectDir.copyRecursively(targetDir); + Result result = projectDir.copyRecursively(targetDir); if (result) { // set vars to new location diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index 09bf54015a3..344a88d3e77 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -23,8 +23,6 @@ #include #include -#include - using namespace ProjectExplorer; using namespace Utils; @@ -39,15 +37,6 @@ public: , m_kit(kit) {} - QModelIndex indexForQtId(int id) const - { - if (id == -1) - return index(rowCount() - 1, 0); // The "No Qt" item always comes last - const TreeItem *const item = findItemAtLevel<1>( - [id](TreeItem *item) { return static_cast(item)->uniqueId() == id; }); - return item ? indexForItem(item) : QModelIndex(); - } - void reset() { clear(); @@ -71,12 +60,6 @@ class QtVersionSortModel : public SortModel public: QtVersionSortModel(QObject *parent) : SortModel(parent) {} - QModelIndex indexForId(int id) const - { - return mapFromSource( - static_cast(sourceModel())->indexForQtId(id)); - } - void reset() { static_cast(sourceModel())->reset(); } private: @@ -112,70 +95,27 @@ public: { setManagingPage(Constants::QTVERSION_SETTINGS_PAGE_ID); - m_combo = createSubWidget(); - m_combo->setSizePolicy(QSizePolicy::Ignored, m_combo->sizePolicy().verticalPolicy()); const auto sortModel = new QtVersionSortModel(this); sortModel->setSourceModel(new QtVersionListModel(*k, this)); - m_combo->setModel(sortModel); - - refresh(); - - // FIXME: We want the tooltip for the current item (also for toolchains etc). - m_combo->setToolTip(ki->description()); - - connect(m_combo, &QComboBox::currentIndexChanged, this, [this] { - if (!m_ignoreChanges.isLocked()) - currentWasChanged(m_combo->currentIndex()); - }); + auto getter = [](const Kit &k) { return QtKitAspect::qtVersionId(&k); }; + auto setter = [](Kit &k, const QVariant &versionId) { + QtKitAspect::setQtVersionId(&k, versionId.toInt()); + }; + auto resetModel = [](QAbstractItemModel &model) { + static_cast(model).reset(); + }; + setListAspectSpec( + {sortModel, + std::move(getter), + std::move(setter), + std::move(resetModel), + QtVersionItem::IdRole}); connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) { if (k == kit()) refresh(); }); } - - ~QtKitAspectImpl() final - { - delete m_combo; - } - -private: - void makeReadOnly() final { m_combo->setEnabled(false); } - - void addToInnerLayout(Layouting::Layout &parent) override - { - addMutableAction(m_combo); - parent.addItem(m_combo); - } - - void refresh() final - { - const GuardLocker locker(m_ignoreChanges); - const auto sortModel = static_cast(m_combo->model()); - sortModel->reset(); - sortModel->sort(0); - m_combo->setCurrentIndex(sortModel->indexForId(QtKitAspect::qtVersionId(m_kit)).row()); - } - -private: - static QString itemNameFor(const QtVersion *v) - { - QTC_ASSERT(v, return QString()); - QString name = v->displayName(); - if (!v->isValid()) - name = Tr::tr("%1 (invalid)").arg(v->displayName()); - return name; - } - - void currentWasChanged(int idx) - { - const QAbstractItemModel * const model = m_combo->model(); - const int versionId = model->data(model->index(idx, 0), QtVersionItem::IdRole).toInt(); - QtKitAspect::setQtVersionId(m_kit, versionId); - } - - Guard m_ignoreChanges; - QComboBox *m_combo; }; } // namespace Internal diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 5ba6ff5c67a..e817495e363 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -166,7 +166,7 @@ QVariant QtVersionItem::data(int column, int role) const if (!version) { if (role == Qt::DisplayRole && column == 0) - return Tr::tr("No Qt"); + return Tr::tr("None"); if (role == IdRole) return -1; return TreeItem::data(column, role); @@ -230,7 +230,7 @@ QVariant QtVersionItem::data(int column, int role) const int QtVersionItem::uniqueId() const { if (const auto v = std::get_if(&m_version)) - return v ? (*v)->uniqueId() : -1; + return *v ? (*v)->uniqueId() : -1; return *std::get_if(&m_version); } diff --git a/src/plugins/remotelinux/genericdeploystep.cpp b/src/plugins/remotelinux/genericdeploystep.cpp index 936f55348bb..06318a2d5d3 100644 --- a/src/plugins/remotelinux/genericdeploystep.cpp +++ b/src/plugins/remotelinux/genericdeploystep.cpp @@ -78,9 +78,7 @@ private: GroupItem GenericDeployStep::mkdirTask(const Storage &storage) { - using ResultType = expected_str; - - const auto onSetup = [storage](Async &async) { + const auto onSetup = [storage](Async &async) { FilePaths remoteDirs; for (const FileToTransfer &file : *storage) remoteDirs << file.m_target.parentDir(); @@ -88,9 +86,9 @@ GroupItem GenericDeployStep::mkdirTask(const Storage &storage) FilePath::sort(remoteDirs); FilePath::removeDuplicates(remoteDirs); - async.setConcurrentCallData([remoteDirs](QPromise &promise) { + async.setConcurrentCallData([remoteDirs](QPromise &promise) { for (const FilePath &dir : remoteDirs) { - const expected_str result = dir.ensureWritableDir(); + const Result result = dir.ensureWritableDir(); promise.addResult(result); if (!result) promise.future().cancel(); @@ -98,7 +96,7 @@ GroupItem GenericDeployStep::mkdirTask(const Storage &storage) }); }; - const auto onError = [this](const Async &async) { + const auto onError = [this](const Async &async) { const int numResults = async.future().resultCount(); if (numResults == 0) { addErrorMessage( @@ -107,13 +105,13 @@ GroupItem GenericDeployStep::mkdirTask(const Storage &storage) } for (int i = 0; i < numResults; ++i) { - const ResultType result = async.future().resultAt(i); - if (!result.has_value()) + const Result result = async.future().resultAt(i); + if (!result) addErrorMessage(result.error()); } }; - return AsyncTask(onSetup, onError, CallDoneIf::Error); + return AsyncTask(onSetup, onError, CallDoneIf::Error); } static FileTransferMethod effectiveTransferMethodFor(const FileToTransfer &fileToTransfer, diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 558e31b6bdf..2c028034eb1 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1066,7 +1066,7 @@ LinuxDevice::LinuxDevice() }); addDeviceAction({Tr::tr("Open Remote Shell"), [](const IDevice::Ptr &device, QWidget *) { - expected_str result = device->openTerminal(Environment(), FilePath()); + Result result = device->openTerminal(Environment(), FilePath()); if (!result) QMessageBox::warning(nullptr, Tr::tr("Error"), result.error()); @@ -1567,18 +1567,18 @@ private: QHash m_batches; }; -static void createDir(QPromise> &promise, const FilePath &pathToCreate) +static void createDir(QPromise &promise, const FilePath &pathToCreate) { - const expected_str result = pathToCreate.ensureWritableDir(); + const Result result = pathToCreate.ensureWritableDir(); promise.addResult(result); if (!result) promise.future().cancel(); }; -static void copyFile(QPromise> &promise, const FileToTransfer &file) +static void copyFile(QPromise &promise, const FileToTransfer &file) { - const expected_str result = file.m_source.copyFile(file.m_target); + const Result result = file.m_source.copyFile(file.m_target); promise.addResult(result); if (!result) @@ -1606,13 +1606,13 @@ private: const LoopList iteratorParentDirs(QList(allParentDirs.cbegin(), allParentDirs.cend())); - const auto onCreateDirSetup = [iteratorParentDirs](Async> &async) { + const auto onCreateDirSetup = [iteratorParentDirs](Async &async) { async.setConcurrentCallData(createDir, *iteratorParentDirs); }; const auto onCreateDirDone = [this, - iteratorParentDirs](const Async> &async) { - const expected_str result = async.result(); + iteratorParentDirs](const Async &async) { + const Result result = async.result(); if (result) emit progress( Tr::tr("Created directory: \"%1\".\n").arg(iteratorParentDirs->toUserOutput())); @@ -1623,13 +1623,13 @@ private: const LoopList iterator(m_setup.m_files); const Storage counterStorage; - const auto onCopySetup = [iterator](Async> &async) { + const auto onCopySetup = [iterator](Async &async) { async.setConcurrentCallData(copyFile, *iterator); }; const auto onCopyDone = [this, iterator, counterStorage]( - const Async> &async) { - const expected_str result = async.result(); + const Async &async) { + const Result result = async.result(); int &counter = *counterStorage; ++counter; @@ -1648,12 +1648,12 @@ private: const Group recipe { For (iteratorParentDirs) >> Do { parallelIdealThreadCountLimit, - AsyncTask>(onCreateDirSetup, onCreateDirDone), + AsyncTask(onCreateDirSetup, onCreateDirDone), }, For (iterator) >> Do { parallelLimit(2), counterStorage, - AsyncTask>(onCopySetup, onCopyDone), + AsyncTask(onCopySetup, onCopyDone), }, }; diff --git a/src/plugins/scxmleditor/plugin_interface/tagtextitem.h b/src/plugins/scxmleditor/plugin_interface/tagtextitem.h index 4ffcdbb9426..0c940a8126c 100644 --- a/src/plugins/scxmleditor/plugin_interface/tagtextitem.h +++ b/src/plugins/scxmleditor/plugin_interface/tagtextitem.h @@ -55,7 +55,7 @@ private: QPointF m_movePoint; QPointF m_startPos; TextItem *m_textItem; - qreal m_maxWidth; + qreal m_maxWidth = -1.0; }; } // namespace PluginInterface diff --git a/src/plugins/squish/squishtesttreeview.cpp b/src/plugins/squish/squishtesttreeview.cpp index e6dd495aea9..6421b89593b 100644 --- a/src/plugins/squish/squishtesttreeview.cpp +++ b/src/plugins/squish/squishtesttreeview.cpp @@ -185,7 +185,7 @@ void SquishTestTreeItemDelegate::setEditorData(QWidget *editor, const QModelInde static bool copyScriptTemplates(const SuiteConf &suiteConf, const Utils::FilePath &destination) { - Utils::expected_str result = destination.ensureWritableDir(); + Utils::Result result = destination.ensureWritableDir(); QTC_ASSERT_EXPECTED(result, return false); const bool scripted = suiteConf.objectMapStyle() == "script"; diff --git a/src/plugins/squish/suiteconf.cpp b/src/plugins/squish/suiteconf.cpp index 03a93b6a172..9e6ebfdea5c 100644 --- a/src/plugins/squish/suiteconf.cpp +++ b/src/plugins/squish/suiteconf.cpp @@ -323,7 +323,7 @@ bool SuiteConf::ensureObjectMapExists() const return true; const Utils::FilePath objectMap = scripts.pathAppended("objectmap_template" + extension); - Utils::expected_str result = destinationObjectMap.parentDir().ensureWritableDir(); + Utils::Result result = destinationObjectMap.parentDir().ensureWritableDir(); QTC_ASSERT_EXPECTED(result, return false); result = objectMap.copyFile(destinationObjectMap); QTC_ASSERT_EXPECTED(result, return false); diff --git a/src/plugins/terminal/shellintegration.cpp b/src/plugins/terminal/shellintegration.cpp index 300da2aff20..11dce74eca3 100644 --- a/src/plugins/terminal/shellintegration.cpp +++ b/src/plugins/terminal/shellintegration.cpp @@ -172,7 +172,7 @@ void ShellIntegration::prepareProcess(Utils::Process &process) const FilePath rcPath = filesToCopy.bash.rcFile; const FilePath tmpRc = FilePath::fromUserInput( m_tempDir.filePath(filesToCopy.bash.rcFile.fileName())); - expected_str copyResult = rcPath.copyFile(tmpRc); + const Result copyResult = rcPath.copyFile(tmpRc); QTC_ASSERT_EXPECTED(copyResult, return); if (cmd.arguments() == "-l") @@ -181,7 +181,7 @@ void ShellIntegration::prepareProcess(Utils::Process &process) cmd = {cmd.executable(), {"--init-file", tmpRc.nativePath()}}; } else if (cmd.executable().baseName() == "zsh") { for (const FileToCopy &file : filesToCopy.zsh.files) { - const expected_str copyResult = file.source.copyFile( + const Result copyResult = file.source.copyFile( FilePath::fromUserInput(m_tempDir.filePath(file.destName))); QTC_ASSERT_EXPECTED(copyResult, return); } @@ -196,7 +196,7 @@ void ShellIntegration::prepareProcess(Utils::Process &process) const FilePath rcPath = filesToCopy.pwsh.script; const FilePath tmpRc = FilePath::fromUserInput( m_tempDir.filePath(filesToCopy.pwsh.script.fileName())); - expected_str copyResult = rcPath.copyFile(tmpRc); + const Result copyResult = rcPath.copyFile(tmpRc); QTC_ASSERT_EXPECTED(copyResult, return); cmd.addArgs(QString("-noexit -command try { . '%1' } catch {Write-Host \"Shell " @@ -207,7 +207,7 @@ void ShellIntegration::prepareProcess(Utils::Process &process) const FilePath rcPath = filesToCopy.clink.script; const FilePath tmpRc = FilePath::fromUserInput( m_tempDir.filePath(filesToCopy.clink.script.fileName())); - expected_str copyResult = rcPath.copyFile(tmpRc); + const Result copyResult = rcPath.copyFile(tmpRc); QTC_ASSERT_EXPECTED(copyResult, return); env.set("CLINK_HISTORY_LABEL", "QtCreator"); @@ -216,7 +216,7 @@ void ShellIntegration::prepareProcess(Utils::Process &process) FilePath xdgDir = FilePath::fromUserInput(m_tempDir.filePath("fish_xdg_data")); FilePath subDir = xdgDir.resolvePath(QString("fish/vendor_conf.d")); QTC_ASSERT(subDir.createDir(), return); - expected_str copyResult = filesToCopy.fish.script.copyFile( + const Result copyResult = filesToCopy.fish.script.copyFile( subDir.resolvePath(filesToCopy.fish.script.fileName())); QTC_ASSERT_EXPECTED(copyResult, return); diff --git a/src/plugins/texteditor/bookmarkfilter.cpp b/src/plugins/texteditor/bookmarkfilter.cpp index 0938a0e81b8..f03b9f21902 100644 --- a/src/plugins/texteditor/bookmarkfilter.cpp +++ b/src/plugins/texteditor/bookmarkfilter.cpp @@ -12,6 +12,7 @@ #include using namespace Core; +using namespace Tasking; using namespace Utils; namespace TextEditor::Internal { @@ -36,12 +37,11 @@ private: LocatorMatcherTasks BookmarkFilter::matchers() { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [this, storage] { storage->reportOutput(match(storage->input())); }; - return {{Sync(onSetup), storage}}; + const auto onSetup = [this] { + const LocatorStorage &storage = *LocatorStorage::storage(); + storage.reportOutput(match(storage.input())); + }; + return {Sync(onSetup)}; } LocatorFilterEntries BookmarkFilter::match(const QString &input) const diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp index b532313330c..3d2bf792060 100644 --- a/src/plugins/texteditor/linenumberfilter.cpp +++ b/src/plugins/texteditor/linenumberfilter.cpp @@ -8,6 +8,7 @@ #include using namespace Core; +using namespace Tasking; using namespace Utils; namespace TextEditor::Internal { @@ -29,12 +30,9 @@ public: private: LocatorMatcherTasks matchers() final { - using namespace Tasking; - - Storage storage; - - const auto onSetup = [storage] { - const QStringList lineAndColumn = storage->input().split(':'); + const auto onSetup = [] { + const LocatorStorage &storage = *LocatorStorage::storage(); + const QStringList lineAndColumn = storage.input().split(':'); int sectionCount = lineAndColumn.size(); int line = 0; int column = 0; @@ -64,10 +62,10 @@ private: EditorManager::activateEditor(editor); return AcceptResult(); }; - storage->reportOutput({entry}); + storage.reportOutput({entry}); } }; - return {{Sync(onSetup), storage}}; + return {Sync(onSetup)}; } }; diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index a7a7288d8ce..32fabea7fcd 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -177,7 +177,7 @@ TextMark::AnnotationRects TextMark::annotationRects(const QRectF &boundingRect, const qreal fadeOutOffset) const { AnnotationRects rects; - rects.text = lineAnnotation(); + rects.text = lineAnnotation().simplified(); if (rects.text.isEmpty()) return rects; rects.fadeInRect = boundingRect; diff --git a/src/plugins/valgrind/callgrind/callgrindcallmodel.cpp b/src/plugins/valgrind/callgrind/callgrindcallmodel.cpp index b341e29d5d1..c08256db2f1 100644 --- a/src/plugins/valgrind/callgrind/callgrindcallmodel.cpp +++ b/src/plugins/valgrind/callgrind/callgrindcallmodel.cpp @@ -5,7 +5,6 @@ #include "callgrindfunctioncall.h" #include "callgrindfunction.h" -#include "callgrindparsedata.h" #include "../valgrindtr.h" #include @@ -17,7 +16,7 @@ namespace Valgrind::Callgrind { class CallModel::Private { public: - const ParseData *m_data = nullptr; + ParseDataPtr m_data = nullptr; QList m_calls; int m_event = 0; const Function *m_function = nullptr; @@ -69,7 +68,7 @@ int CallModel::costEvent() const return d->m_event; } -void CallModel::setParseData(const ParseData *data) +void CallModel::setParseData(const ParseDataPtr &data) { if (d->m_data == data) return; @@ -80,7 +79,7 @@ void CallModel::setParseData(const ParseData *data) d->m_data = data; } -const ParseData *CallModel::parseData() const +ParseDataPtr CallModel::parseData() const { return d->m_data; } diff --git a/src/plugins/valgrind/callgrind/callgrindcallmodel.h b/src/plugins/valgrind/callgrind/callgrindcallmodel.h index 4b8e6f631e4..2bb0225ace7 100644 --- a/src/plugins/valgrind/callgrind/callgrindcallmodel.h +++ b/src/plugins/valgrind/callgrind/callgrindcallmodel.h @@ -5,6 +5,8 @@ #include "callgrindabstractmodel.h" +#include "callgrindparsedata.h" + #include namespace Valgrind::Callgrind { @@ -26,11 +28,11 @@ public: /// Only one cost event column will be shown, this decides which one it is. /// By default it is the first event in the @c ParseData, i.e. 0. - virtual int costEvent() const; - virtual void setCostEvent(int event); + int costEvent() const; + void setCostEvent(int event); - virtual void setParseData(const ParseData *data); - virtual const ParseData *parseData() const; + void setParseData(const ParseDataPtr &data); + ParseDataPtr parseData() const; void setCalls(const QList &calls, const Function *function); QList calls() const; diff --git a/src/plugins/valgrind/callgrind/callgrindcostitem.cpp b/src/plugins/valgrind/callgrind/callgrindcostitem.cpp index d6fa4f99013..8ae0b86190f 100644 --- a/src/plugins/valgrind/callgrind/callgrindcostitem.cpp +++ b/src/plugins/valgrind/callgrind/callgrindcostitem.cpp @@ -3,8 +3,8 @@ #include "callgrindcostitem.h" -#include "callgrindparsedata.h" #include "callgrindfunctioncall.h" +#include "callgrindparsedata.h" #include @@ -13,18 +13,18 @@ namespace Valgrind::Callgrind { class CostItem::Private { public: - Private(ParseData *data); + Private(const ParseData *data); ~Private(); QList m_positions; QList m_events; const FunctionCall *m_call = nullptr; - const ParseData *m_data = nullptr; + const ParseData *m_data; qint64 m_differingFileId = -1; }; -CostItem::Private::Private(ParseData *data) +CostItem::Private::Private(const ParseData *data) : m_positions(data->positions().size(), 0) , m_events(data->events().size(), 0) , m_data(data) @@ -36,9 +36,8 @@ CostItem::Private::~Private() delete m_call; } - //BEGIN CostItem -CostItem::CostItem(ParseData *data) +CostItem::CostItem(const ParseData *data) : d(new Private(data)) { } diff --git a/src/plugins/valgrind/callgrind/callgrindcostitem.h b/src/plugins/valgrind/callgrind/callgrindcostitem.h index 3cc54df1dab..6080d2fd52c 100644 --- a/src/plugins/valgrind/callgrind/callgrindcostitem.h +++ b/src/plugins/valgrind/callgrind/callgrindcostitem.h @@ -18,7 +18,7 @@ class CostItem public: /// @p data the file data this cost item was parsed in. /// required for decompression of string data like differing source file information - explicit CostItem(ParseData *data); + explicit CostItem(const ParseData *data); ~CostItem(); /** diff --git a/src/plugins/valgrind/callgrind/callgrinddatamodel.cpp b/src/plugins/valgrind/callgrind/callgrinddatamodel.cpp index a623a6a8c98..1122b2da28f 100644 --- a/src/plugins/valgrind/callgrind/callgrinddatamodel.cpp +++ b/src/plugins/valgrind/callgrind/callgrinddatamodel.cpp @@ -3,9 +3,8 @@ #include "callgrinddatamodel.h" -#include "callgrindparsedata.h" -#include "callgrindfunction.h" #include "callgrindcostitem.h" +#include "callgrindfunction.h" #include "../valgrindtr.h" #include @@ -21,7 +20,7 @@ class DataModel::Private public: void updateFunctions(); - const ParseData *m_data = nullptr; + ParseDataPtr m_data; int m_event = 0; bool m_verboseToolTips = true; bool m_cycleDetection = false; @@ -51,7 +50,7 @@ DataModel::~DataModel() delete d; } -void DataModel::setParseData(const ParseData *data) +void DataModel::setParseData(const ParseDataPtr &data) { if (d->m_data == data) return; @@ -73,7 +72,7 @@ bool DataModel::verboseToolTipsEnabled() const return d->m_verboseToolTips; } -const ParseData *DataModel::parseData() const +ParseDataPtr DataModel::parseData() const { return d->m_data; } diff --git a/src/plugins/valgrind/callgrind/callgrinddatamodel.h b/src/plugins/valgrind/callgrind/callgrinddatamodel.h index 136ea4a0d7f..176ed9a7394 100644 --- a/src/plugins/valgrind/callgrind/callgrinddatamodel.h +++ b/src/plugins/valgrind/callgrind/callgrinddatamodel.h @@ -5,12 +5,13 @@ #include "callgrindabstractmodel.h" +#include "callgrindparsedata.h" + #include namespace Valgrind::Callgrind { class Function; -class ParseData; class DataModel : public QAbstractItemModel { @@ -20,15 +21,15 @@ public: DataModel(); ~DataModel() override; - virtual void setParseData(const ParseData *data); - virtual const ParseData *parseData() const; + void setParseData(const ParseDataPtr &data); + ParseDataPtr parseData() const; void setVerboseToolTipsEnabled(bool enabled); bool verboseToolTipsEnabled() const; /// Only one cost event column will be shown, this decides which one it is. /// By default it is the first event in the @c ParseData, i.e. 0. - virtual int costEvent() const; + int costEvent() const; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; @@ -61,7 +62,7 @@ public: /// Only one cost event column will be shown, this decides which one it is. /// By default it is the first event in the @c ParseData, i.e. 0. - virtual void setCostEvent(int event); + void setCostEvent(int event); private: class Private; diff --git a/src/plugins/valgrind/callgrind/callgrindparsedata.cpp b/src/plugins/valgrind/callgrind/callgrindparsedata.cpp index d58450b9684..231e9dd32ea 100644 --- a/src/plugins/valgrind/callgrind/callgrindparsedata.cpp +++ b/src/plugins/valgrind/callgrind/callgrindparsedata.cpp @@ -116,8 +116,7 @@ void ParseData::Private::cycleDetection() ParseData::ParseData(const QString &fileName) : d(new Private(this, fileName)) -{ -} +{} ParseData::~ParseData() { diff --git a/src/plugins/valgrind/callgrind/callgrindparsedata.h b/src/plugins/valgrind/callgrind/callgrindparsedata.h index e6c7b0b8cb1..7f7e864ef47 100644 --- a/src/plugins/valgrind/callgrind/callgrindparsedata.h +++ b/src/plugins/valgrind/callgrind/callgrindparsedata.h @@ -109,4 +109,6 @@ private: Private *d; }; +using ParseDataPtr = std::shared_ptr; + } // namespace Valgrind::Callgrind diff --git a/src/plugins/valgrind/callgrind/callgrindparser.cpp b/src/plugins/valgrind/callgrind/callgrindparser.cpp index b2d4b166835..a9977f76cdc 100644 --- a/src/plugins/valgrind/callgrind/callgrindparser.cpp +++ b/src/plugins/valgrind/callgrind/callgrindparser.cpp @@ -110,22 +110,10 @@ static int parseNameShorthand(const char **current, const char *end) } -class Parser::Private +class ParserPrivate { - Parser *const q; public: - - explicit Private(Parser *qq) - : q(qq) - { - } - - ~Private() - { - delete data; - } - - void parse(const FilePath &filePath); + ParseDataPtr parse(const FilePath &filePath); void parseHeader(QIODevice *device); using NamePair = QPair; @@ -145,7 +133,7 @@ public: int addressValuesCount = 0; int costValuesCount = 0; - ParseData *data = nullptr; + std::shared_ptr data; Function *currentFunction = nullptr; qint64 lastObject = -1; qint64 lastFile = -1; @@ -172,19 +160,14 @@ public: QSet recursiveFunctions; }; -void Parser::Private::parse(const FilePath &filePath) +ParseDataPtr ParserPrivate::parse(const FilePath &filePath) { - // be sure to clean up existing data before re-allocating - // the callee might not have taken the parse data - delete data; - data = nullptr; - const QString path = filePath.path(); // FIXME: Works only accidentally for docker QFile file(path); if (!file.open(QIODevice::ReadOnly)) qWarning() << "Could not open file for parsing:" << filePath.toUserOutput(); - data = new ParseData(path); + data = std::make_shared(path); parseHeader(&file); while (!file.atEnd()) { const QByteArray line = file.readLine(); @@ -243,8 +226,7 @@ void Parser::Private::parse(const FilePath &filePath) // now accumulate callees for (Function *func : std::as_const(pendingFunctions)) func->finalize(); - - emit q->parserDataReady(); + return data; } inline QString getValue(const QByteArray &line, const int prefixLength) @@ -254,7 +236,7 @@ inline QString getValue(const QByteArray &line, const int prefixLength) return QString::fromLatin1(line.mid(prefixLength, line.length() - 1 - prefixLength).constData()); } -void Parser::Private::parseHeader(QIODevice *device) +void ParserPrivate::parseHeader(QIODevice *device) { QTC_ASSERT(device->isOpen(), return); QTC_ASSERT(device->isReadable(), return); @@ -311,7 +293,7 @@ void Parser::Private::parseHeader(QIODevice *device) } } -Parser::Private::NamePair Parser::Private::parseName(const char *begin, const char *end) +ParserPrivate::NamePair ParserPrivate::parseName(const char *begin, const char *end) { const char *current = begin; qint64 nameShorthand = -1; @@ -335,7 +317,7 @@ Parser::Private::NamePair Parser::Private::parseName(const char *begin, const ch * cfn means called function */ -void Parser::Private::dispatchLine(const QByteArray &line) +void ParserPrivate::dispatchLine(const QByteArray &line) { int lineEnding = line.endsWith("\r\n") ? 2 : 1; const char *const begin = line.constData(); @@ -418,7 +400,7 @@ void Parser::Private::dispatchLine(const QByteArray &line) } } -void Parser::Private::parseCostItem(const char *begin, const char *end) +void ParserPrivate::parseCostItem(const char *begin, const char *end) { QTC_ASSERT(currentFunction, return); @@ -426,7 +408,7 @@ void Parser::Private::parseCostItem(const char *begin, const char *end) const char *current = begin; QTC_ASSERT(currentDifferingFile == -1 || currentDifferingFile != currentFunction->fileId(), return); - auto costItem = new CostItem(data); + auto costItem = new CostItem(data.get()); costItem->setDifferingFile(currentDifferingFile); FunctionCall *call = nullptr; if (isParsingFunctionCall) { @@ -514,7 +496,7 @@ void Parser::Private::parseCostItem(const char *begin, const char *end) currentFunction->addCostItem(costItem); } -void Parser::Private::parseSourceFile(const char *begin, const char *end) +void ParserPrivate::parseSourceFile(const char *begin, const char *end) { NamePair name = parseName(begin, end); @@ -528,9 +510,9 @@ void Parser::Private::parseSourceFile(const char *begin, const char *end) currentDifferingFile = -1; } -void Parser::Private::parseFunction(const char *begin, const char *end) +void ParserPrivate::parseFunction(const char *begin, const char *end) { - currentFunction = new Function(data); + currentFunction = new Function(data.get()); currentFunction->setFile(lastFile); currentFunction->setObject(lastObject); @@ -544,7 +526,7 @@ void Parser::Private::parseFunction(const char *begin, const char *end) currentFunction->setName(name.first); } -void Parser::Private::parseDifferingSourceFile(const char *begin, const char *end) +void ParserPrivate::parseDifferingSourceFile(const char *begin, const char *end) { NamePair name = parseName(begin, end); @@ -560,7 +542,7 @@ void Parser::Private::parseDifferingSourceFile(const char *begin, const char *en currentDifferingFile = name.first; } -void Parser::Private::parseObjectFile(const char *begin, const char *end) +void ParserPrivate::parseObjectFile(const char *begin, const char *end) { NamePair name = parseName(begin, end); if (!name.second.isEmpty()) @@ -569,7 +551,7 @@ void Parser::Private::parseObjectFile(const char *begin, const char *end) lastObject = name.first; } -void Parser::Private::parseCalls(const char *begin, const char *end) +void ParserPrivate::parseCalls(const char *begin, const char *end) { const char *current = begin; bool ok; @@ -587,7 +569,7 @@ void Parser::Private::parseCalls(const char *begin, const char *end) isParsingFunctionCall = true; } -void Parser::Private::parseCalledFunction(const char *begin, const char *end) +void ParserPrivate::parseCalledFunction(const char *begin, const char *end) { NamePair name = parseName(begin, end); if (!name.second.isEmpty()) @@ -596,7 +578,7 @@ void Parser::Private::parseCalledFunction(const char *begin, const char *end) currentCallData.calledFunction = name.first; } -void Parser::Private::parseCalledSourceFile(const char *begin, const char *end) +void ParserPrivate::parseCalledSourceFile(const char *begin, const char *end) { NamePair name = parseName(begin, end); if (!name.second.isEmpty()) { @@ -608,7 +590,7 @@ void Parser::Private::parseCalledSourceFile(const char *begin, const char *end) currentCallData.calledFile = name.first; } -void Parser::Private::parseCalledObjectFile(const char *begin, const char *end) +void ParserPrivate::parseCalledObjectFile(const char *begin, const char *end) { NamePair name = parseName(begin, end); if (!name.second.isEmpty()) @@ -619,26 +601,10 @@ void Parser::Private::parseCalledObjectFile(const char *begin, const char *end) //BEGIN Parser -void Parser::parse(const Utils::FilePath &filePath) +ParseDataPtr parseDataFile(const Utils::FilePath &filePath) { - d->parse(filePath); -} - -Parser::Parser() - : d(new Private(this)) -{ -} - -Parser::~Parser() -{ - delete d; -} - -ParseData *Parser::takeData() -{ - ParseData *data = d->data; - d->data = nullptr; - return data; + ParserPrivate parser; + return parser.parse(filePath); } } // namespace Valgrind::Callgrind diff --git a/src/plugins/valgrind/callgrind/callgrindparser.h b/src/plugins/valgrind/callgrind/callgrindparser.h index 6355a5859e8..43058827047 100644 --- a/src/plugins/valgrind/callgrind/callgrindparser.h +++ b/src/plugins/valgrind/callgrind/callgrindparser.h @@ -3,14 +3,14 @@ #pragma once +#include "callgrindparsedata.h" + #include namespace Utils { class FilePath; } namespace Valgrind::Callgrind { -class ParseData; - /** * Parser for Valgrind --tool=callgrind output * most of the format is documented at http://kcachegrind.sourceforge.net/html/CallgrindFormat.html @@ -20,25 +20,7 @@ class ParseData; * the rest is assumed to be zero." * */ -class Parser : public QObject -{ - Q_OBJECT -public: - Parser(); - ~Parser() override; - - // get and take ownership of the parsing results. If this function is not called the repository - // will be destroyed when the parser is destroyed. Subsequent calls return null. - ParseData *takeData(); - void parse(const Utils::FilePath &filePath); - -signals: - void parserDataReady(); - -private: - class Private; - Private *const d; -}; +ParseDataPtr parseDataFile(const Utils::FilePath &filePath); } // namespace Valgrind::Callgrind diff --git a/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp b/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp index d9bad9daefc..4dbbdf23d82 100644 --- a/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp +++ b/src/plugins/valgrind/callgrind/callgrindproxymodel.cpp @@ -119,7 +119,7 @@ bool DataProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_ // check minimum inclusive costs DataModel *model = dataModel(); QTC_ASSERT(model, return false); // as always: this should never happen - const ParseData *data = model->parseData(); + const ParseDataPtr data = model->parseData(); QTC_ASSERT(data, return false); if (m_minimumInclusiveCostRatio != 0.0) { const quint64 totalCost = data->totalCost(0); diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index 8422bb01769..4d6c911df60 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -34,13 +34,7 @@ CallgrindToolRunner::CallgrindToolRunner(RunControl *runControl) connect(&m_runner, &ValgrindProcess::valgrindStarted, this, [this](qint64 pid) { m_pid = pid; }); - connect(&m_runner, &ValgrindProcess::done, this, [this] { - triggerParse(); - emit parserDataReady(this); - }); - connect(&m_parser, &Callgrind::Parser::parserDataReady, this, [this] { - emit parserDataReady(this); - }); + connect(&m_runner, &ValgrindProcess::done, this, &CallgrindToolRunner::triggerParse); m_valgrindRunnable = runControl->runnable(); @@ -117,11 +111,6 @@ void CallgrindToolRunner::setToggleCollectFunction(const QString &toggleCollectF m_argumentForToggleCollect = "--toggle-collect=" + toggleCollectFunction; } -Callgrind::ParseData *CallgrindToolRunner::takeParserData() -{ - return m_parser.takeData(); -} - void CallgrindToolRunner::showStatusMessage(const QString &message) { Debugger::showPermanentStatusMessage(message); @@ -253,7 +242,7 @@ void CallgrindToolRunner::triggerParse() if (!res) // failed to run callgrind return; showStatusMessage(Tr::tr("Parsing Profile Data...")); - m_parser.parse(m_hostOutputFile); + emit parserDataReady(parseDataFile(m_hostOutputFile)); }; // TODO: Store the handle and cancel on CallgrindToolRunner destructor? // TODO: Should d'tor of context object cancel the running task? diff --git a/src/plugins/valgrind/callgrindengine.h b/src/plugins/valgrind/callgrindengine.h index c0e5ce2a8b6..82db9bac378 100644 --- a/src/plugins/valgrind/callgrindengine.h +++ b/src/plugins/valgrind/callgrindengine.h @@ -23,8 +23,6 @@ public: void start() override; - Valgrind::Callgrind::ParseData *takeParserData(); - /// controller actions void dump() { run(Dump); } void reset() { run(ResetEventCounters); } @@ -52,7 +50,7 @@ protected: QString progressTitle() const override; signals: - void parserDataReady(CallgrindToolRunner *engine); + void parserDataReady(const Callgrind::ParseDataPtr &data); private: void showStatusMessage(const QString &message); @@ -83,7 +81,6 @@ private: Utils::FilePath m_valgrindOutputFile; // On the device that runs valgrind Utils::FilePath m_hostOutputFile; // On the device that runs creator - Callgrind::Parser m_parser; bool m_paused = false; QString m_argumentForToggleCollect; diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 15b74a5c5f4..3d3c42832c9 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -95,10 +95,9 @@ public: void setupRunner(CallgrindToolRunner *runner); - void setParseData(ParseData *data); CostDelegate::CostFormat costFormat() const; - void doClear(bool clearParseData); + void doClear(); void updateEventCombo(); signals: @@ -136,10 +135,10 @@ public: void calleeFunctionSelected(const QModelIndex &index); void callerFunctionSelected(const QModelIndex &index); void visualisationFunctionSelected(const Function *function); - void showParserResults(const ParseData *data); + void showParserResults(const ParseDataPtr &data); - void takeParserDataFromRunControl(CallgrindToolRunner *rc); - void takeParserData(ParseData *data); + void setParserData(const ParseDataPtr &data); + void doSetParseData(const ParseDataPtr &data); void engineFinished(); void editorOpened(IEditor *); @@ -385,7 +384,7 @@ CallgrindTool::CallgrindTool(QObject *parent) action->setToolTip(Tr::tr("Discard Data")); connect(action, &QAction::triggered, this, [this](bool) { clearTextMarks(); - doClear(true); + doClear(); }); // navigation @@ -494,10 +493,9 @@ CallgrindTool::~CallgrindTool() delete m_visualization; } -void CallgrindTool::doClear(bool clearParseData) +void CallgrindTool::doClear() { - if (clearParseData) // Crashed when done from destructor. - setParseData(nullptr); + doSetParseData({}); // clear filters if (m_filterProjectCosts) @@ -664,25 +662,20 @@ void CallgrindTool::visualisationFunctionSelected(const Function *function) selectFunction(function); } -void CallgrindTool::setParseData(ParseData *data) +void CallgrindTool::doSetParseData(const ParseDataPtr &data) { // we have new parse data, invalidate filters in the proxy model if (m_visualization) m_visualization->setFunction(nullptr); - // invalidate parse data in the data model - delete m_dataModel.parseData(); + // might happen if the user cancelled the profile run + // callgrind then sometimes produces empty callgrind.out.PID files + const ParseDataPtr newData = data && !data->events().isEmpty() ? data : ParseDataPtr(); - if (data && data->events().isEmpty()) { - // might happen if the user cancelled the profile run - // callgrind then sometimes produces empty callgrind.out.PID files - delete data; - data = nullptr; - } - m_lastFileName = data ? data->fileName() : QString(); - m_dataModel.setParseData(data); - m_calleesModel.setParseData(data); - m_callersModel.setParseData(data); + m_lastFileName = newData ? newData->fileName() : QString(); + m_dataModel.setParseData(newData); + m_calleesModel.setParseData(newData); + m_callersModel.setParseData(newData); if (m_eventCombo) updateEventCombo(); @@ -700,7 +693,7 @@ void CallgrindTool::updateEventCombo() m_eventCombo->clear(); - const ParseData *data = m_dataModel.parseData(); + const ParseDataPtr data = m_dataModel.parseData(); if (!data || data->events().isEmpty()) { m_eventCombo->hide(); return; @@ -716,7 +709,7 @@ void CallgrindTool::setupRunner(CallgrindToolRunner *toolRunner) { RunControl *runControl = toolRunner->runControl(); - connect(toolRunner, &CallgrindToolRunner::parserDataReady, this, &CallgrindTool::takeParserDataFromRunControl); + connect(toolRunner, &CallgrindToolRunner::parserDataReady, this, &CallgrindTool::setParserData); connect(runControl, &RunControl::stopped, this, &CallgrindTool::engineFinished); connect(this, &CallgrindTool::dumpRequested, toolRunner, &CallgrindToolRunner::dump); @@ -749,7 +742,7 @@ void CallgrindTool::setupRunner(CallgrindToolRunner *toolRunner) m_dumpAction->setEnabled(true); m_loadExternalLogFile->setEnabled(false); clearTextMarks(); - doClear(true); + doClear(); } void CallgrindTool::updateRunActions() @@ -783,7 +776,7 @@ void CallgrindTool::engineFinished() m_dumpAction->setEnabled(false); m_loadExternalLogFile->setEnabled(true); - const ParseData *data = m_dataModel.parseData(); + const ParseDataPtr data = m_dataModel.parseData(); if (data) showParserResults(data); else @@ -792,7 +785,7 @@ void CallgrindTool::engineFinished() setBusyCursor(false); } -void CallgrindTool::showParserResults(const ParseData *data) +void CallgrindTool::showParserResults(const ParseDataPtr &data) { QString msg; if (data) { @@ -876,17 +869,10 @@ void CallgrindTool::loadExternalLogFile() Debugger::showPermanentStatusMessage(Tr::tr("Parsing Profile Data...")); QCoreApplication::processEvents(); - Parser parser; - parser.parse(filePath); - takeParserData(parser.takeData()); + setParserData(parseDataFile(filePath)); } -void CallgrindTool::takeParserDataFromRunControl(CallgrindToolRunner *rc) -{ - takeParserData(rc->takeParserData()); -} - -void CallgrindTool::takeParserData(ParseData *data) +void CallgrindTool::setParserData(const ParseDataPtr &data) { showParserResults(data); @@ -895,9 +881,9 @@ void CallgrindTool::takeParserData(ParseData *data) // clear first clearTextMarks(); - doClear(true); + doClear(); + doSetParseData(data); - setParseData(data); const FilePath kcachegrindExecutable = globalSettings().kcachegrindExecutable(); const FilePath found = kcachegrindExecutable.searchInPath(); const bool kcachegrindExists = found.isExecutableFile(); diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index ef50ea58849..b666bd2f7d4 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -185,20 +185,7 @@ void MemcheckToolRunner::addToolArguments(CommandLine &cmd) const if (m_settings.showReachable()) cmd << "--show-reachable=yes"; - QString leakCheckValue; - switch (m_settings.leakCheckOnFinish()) { - case ValgrindSettings::LeakCheckOnFinishNo: - leakCheckValue = "no"; - break; - case ValgrindSettings::LeakCheckOnFinishYes: - leakCheckValue = "full"; - break; - case ValgrindSettings::LeakCheckOnFinishSummaryOnly: - default: - leakCheckValue = "summary"; - break; - } - cmd << "--leak-check=" + leakCheckValue; + cmd << "--leak-check=" + m_settings.leakCheckOnFinishOptionString(); for (const FilePath &file : m_settings.suppressions()) cmd << QString("--suppressions=%1").arg(file.path()); diff --git a/src/plugins/valgrind/valgrindprocess.cpp b/src/plugins/valgrind/valgrindprocess.cpp index 34bda25c5ab..23c84f4b487 100644 --- a/src/plugins/valgrind/valgrindprocess.cpp +++ b/src/plugins/valgrind/valgrindprocess.cpp @@ -70,45 +70,6 @@ public: }); } - void setupValgrindProcess(Process *process, const CommandLine &command) const { - CommandLine cmd = command; - cmd.addArgs(m_valgrindCommand.arguments(), CommandLine::Raw); - - // consider appending our options last so they override any interfering user-supplied - // options -q as suggested by valgrind manual - - if (cmd.executable().osType() == OsTypeMac) { - // May be slower to start but without it we get no filenames for symbols. - cmd.addArg("--dsymutil=yes"); - } - - cmd.addCommandLineAsArgs(m_debuggee.command); - - emit q->appendMessage(cmd.toUserOutput(), NormalMessageFormat); - - process->setCommand(cmd); - process->setWorkingDirectory(m_debuggee.workingDirectory); - process->setEnvironment(m_debuggee.environment); - process->setProcessChannelMode(m_channelMode); - process->setTerminalMode(m_useTerminal ? TerminalMode::Run : TerminalMode::Off); - - connect(process, &Process::started, this, [this, process] { - emit q->valgrindStarted(process->processId()); - }); - connect(process, &Process::done, this, [this, process] { - const bool success = process->result() == ProcessResult::FinishedWithSuccess; - if (!success) - emit q->processErrorReceived(process->errorString(), process->error()); - emit q->done(toDoneResult(success)); - }); - connect(process, &Process::readyReadStandardOutput, this, [this, process] { - emit q->appendMessage(process->readAllStandardOutput(), StdOutFormat); - }); - connect(process, &Process::readyReadStandardError, this, [this, process] { - emit q->appendMessage(process->readAllStandardError(), StdErrFormat); - }); - } - Group runRecipe() const; bool run(); @@ -183,7 +144,40 @@ Group ValgrindProcessPrivate::runRecipe() const }; const auto onProcessSetup = [this, storage](Process &process) { - setupValgrindProcess(&process, storage->m_valgrindCommand); + CommandLine cmd = storage->m_valgrindCommand; + cmd.addArgs(m_valgrindCommand.arguments(), CommandLine::Raw); + + // consider appending our options last so they override any interfering user-supplied + // options -q as suggested by valgrind manual + + if (cmd.executable().osType() == OsTypeMac) { + // May be slower to start but without it we get no filenames for symbols. + cmd.addArg("--dsymutil=yes"); + } + + cmd.addCommandLineAsArgs(m_debuggee.command); + + emit q->appendMessage(cmd.toUserOutput(), NormalMessageFormat); + + process.setCommand(cmd); + process.setWorkingDirectory(m_debuggee.workingDirectory); + process.setEnvironment(m_debuggee.environment); + process.setProcessChannelMode(m_channelMode); + process.setTerminalMode(m_useTerminal ? TerminalMode::Run : TerminalMode::Off); + + Process *processPtr = &process; + connect(processPtr, &Process::started, this, [this, processPtr] { + emit q->valgrindStarted(processPtr->processId()); + }); + connect(processPtr, &Process::readyReadStandardOutput, this, [this, processPtr] { + emit q->appendMessage(processPtr->readAllStandardOutput(), StdOutFormat); + }); + connect(processPtr, &Process::readyReadStandardError, this, [this, processPtr] { + emit q->appendMessage(processPtr->readAllStandardError(), StdErrFormat); + }); + }; + const auto onProcessDone = [this, storage](const Process &process) { + emit q->processErrorReceived(process.errorString(), process.error()); }; const auto isAddressValid = [this] { return !m_localServerAddress.isNull(); }; @@ -194,19 +188,19 @@ Group ValgrindProcessPrivate::runRecipe() const parser.setSocket(storage->m_xmlSocket.release()); }; - const auto onParserError = [this](const Parser &parser) { + const auto onParserDone = [this](const Parser &parser) { emit q->internalError(parser.errorString()); }; const Group root { - parallel, storage, xmlBarrier, If (isSetupValid) >> Then { - ProcessTask(onProcessSetup), + parallel, + ProcessTask(onProcessSetup, onProcessDone, CallDoneIf::Error), If (isAddressValid) >> Then { waitForBarrierTask(xmlBarrier), - ParserTask(onParserSetup, onParserError, CallDoneIf::Error) + ParserTask(onParserSetup, onParserDone, CallDoneIf::Error) } } >> Else { errorItem diff --git a/src/plugins/valgrind/valgrindsettings.cpp b/src/plugins/valgrind/valgrindsettings.cpp index 0113f00c5a9..2291c9aa76a 100644 --- a/src/plugins/valgrind/valgrindsettings.cpp +++ b/src/plugins/valgrind/valgrindsettings.cpp @@ -397,6 +397,17 @@ ValgrindSettings::ValgrindSettings(bool global) readSettings(); } +QString ValgrindSettings::leakCheckOnFinishOptionString() const +{ + switch (leakCheckOnFinish()) { + case ValgrindSettings::LeakCheckOnFinishNo: return "no"; + case ValgrindSettings::LeakCheckOnFinishYes: return "full"; + case ValgrindSettings::LeakCheckOnFinishSummaryOnly: + default: return "summary"; + } + return {}; +} + ValgrindSettings &globalSettings() { static ValgrindSettings theSettings{true}; diff --git a/src/plugins/valgrind/valgrindsettings.h b/src/plugins/valgrind/valgrindsettings.h index 6f12c341a52..ef081e565d8 100644 --- a/src/plugins/valgrind/valgrindsettings.h +++ b/src/plugins/valgrind/valgrindsettings.h @@ -70,6 +70,7 @@ public: Utils::StringAspect memcheckArguments{this}; Utils::IntegerAspect numCallers{this}; Utils::SelectionAspect leakCheckOnFinish{this}; + QString leakCheckOnFinishOptionString() const; Utils::BoolAspect showReachable{this}; Utils::BoolAspect trackOrigins{this}; Utils::BoolAspect filterExternalIssues{this}; diff --git a/src/plugins/webassembly/webassemblyrunconfiguration.cpp b/src/plugins/webassembly/webassemblyrunconfiguration.cpp index 664625669c6..62d96ae5f6d 100644 --- a/src/plugins/webassembly/webassemblyrunconfiguration.cpp +++ b/src/plugins/webassembly/webassemblyrunconfiguration.cpp @@ -205,7 +205,7 @@ public: EmrunRunWorker(RunControl *runControl) : SimpleTargetRunner(runControl) { - runControl->enablePortsGatherer(); + runControl->requestWorkerChannel(); setStartModifier([this, runControl] { const QString browserId = @@ -213,7 +213,7 @@ public: setCommandLine(emrunCommand(runControl->target(), runControl->buildKey(), browserId, - QString::number(runControl->findEndPoint().port()))); + QString::number(runControl->workerChannel().port()))); setEnvironment(runControl->buildEnvironment()); }); } diff --git a/src/tools/process_stub/main.cpp b/src/tools/process_stub/main.cpp index 3749333e460..1ab190b652d 100644 --- a/src/tools/process_stub/main.cpp +++ b/src/tools/process_stub/main.cpp @@ -254,8 +254,7 @@ void onInferiorStarted() // In debug mode we use the poll timer to send the pid. if (!debugMode) sendPid(inferiorId); -#else - +#elif defined(Q_OS_LINUX) if (debugMode) { qCInfo(log) << "Waiting for SIGTRAP from inferiors execve ..."; if (!waitFor(SIGTRAP)) @@ -271,12 +270,13 @@ void onInferiorStarted() qCInfo(log) << "Sending pid:" << inferiorId; sendPid(inferiorId); +#else + sendPid(inferiorId); #endif } void setupUnixInferior() { -#ifndef Q_OS_WIN if (debugMode) { qCInfo(log) << "Debug mode enabled"; #ifdef Q_OS_DARWIN @@ -287,7 +287,7 @@ void setupUnixInferior() // Suspend ourselves ... raise(SIGSTOP); }); -#else +#elif defined(Q_OS_LINUX) // PTRACE_TRACEME will stop execution of the child process as soon as execve is called. inferiorProcess.setChildProcessModifier([] { ptrace(PTRACE_TRACEME, 0, 0, 0); @@ -296,7 +296,6 @@ void setupUnixInferior() }); #endif } -#endif } void setupWindowsInferior() diff --git a/tests/auto/valgrind/callgrind/callgrindparsertests.cpp b/tests/auto/valgrind/callgrind/callgrindparsertests.cpp index 803189e4a8a..cc90f0b20ca 100644 --- a/tests/auto/valgrind/callgrind/callgrindparsertests.cpp +++ b/tests/auto/valgrind/callgrind/callgrindparsertests.cpp @@ -21,9 +21,10 @@ using namespace Valgrind::Callgrind; namespace { -static QString dataFile(const char *file) +static Utils::FilePath dataFile(const char *file) { - return QLatin1String(PARSERTESTS_DATA_DIR) + QLatin1String("/") + QLatin1String(file); + return Utils::FilePath::fromString( + QLatin1String(PARSERTESTS_DATA_DIR) + QLatin1String("/") + QLatin1String(file)); } void testCostItem(const CostItem *item, quint64 expectedPosition, quint64 expectedCost) @@ -80,17 +81,9 @@ void CallgrindParserTests::cleanup() { } -ParseData* parseDataFile(const QString &dataFile) -{ - Parser p; - p.parse(Utils::FilePath::fromString(dataFile)); - - return p.takeData(); -} - void CallgrindParserTests::testHeaderData() { - QScopedPointer data(parseDataFile(dataFile("simpleFunction.out"))); + const ParseDataPtr data(parseDataFile(dataFile("simpleFunction.out"))); QCOMPARE(data->command(), QLatin1String("ls")); QCOMPARE(data->creator(), QLatin1String("callgrind-3.6.0.SVN-Debian")); @@ -109,7 +102,7 @@ void CallgrindParserTests::testHeaderData() void CallgrindParserTests::testSimpleFunction() { - QScopedPointer data(parseDataFile(dataFile("simpleFunction.out"))); + const ParseDataPtr data(parseDataFile(dataFile("simpleFunction.out"))); QCOMPARE(data->functions().size(), 4); @@ -178,7 +171,7 @@ void CallgrindParserTests::testSimpleFunction() void CallgrindParserTests::testCallee() { - QScopedPointer data(parseDataFile(dataFile("calleeFunctions.out"))); + const ParseDataPtr data(parseDataFile(dataFile("calleeFunctions.out"))); QCOMPARE(data->functions().size(), 3); @@ -253,7 +246,7 @@ void CallgrindParserTests::testCallee() void CallgrindParserTests::testInlinedCalls() { - QScopedPointer data(parseDataFile(dataFile("inlinedFunctions.out"))); + const ParseDataPtr data(parseDataFile(dataFile("inlinedFunctions.out"))); QCOMPARE(data->functions().size(), 3); const Function *main = data->functions().first(); @@ -279,7 +272,7 @@ void CallgrindParserTests::testInlinedCalls() void CallgrindParserTests::testMultiCost() { - QScopedPointer data(parseDataFile(dataFile("multiCost.out"))); + const ParseDataPtr data(parseDataFile(dataFile("multiCost.out"))); QCOMPARE(data->functions().size(), 2); QCOMPARE(data->positions(), QStringList() << "line"); @@ -298,7 +291,7 @@ void CallgrindParserTests::testMultiCost() void CallgrindParserTests::testMultiPos() { - QScopedPointer data(parseDataFile(dataFile("multiPos.out"))); + const ParseDataPtr data(parseDataFile(dataFile("multiPos.out"))); QCOMPARE(data->functions().size(), 2); QCOMPARE(data->positions(), QStringList() << "line" << "memAddr"); @@ -316,7 +309,7 @@ void CallgrindParserTests::testMultiPos() void CallgrindParserTests::testMultiPosAndCost() { - QScopedPointer data(parseDataFile(dataFile("multiCostAndPos.out"))); + const ParseDataPtr data(parseDataFile(dataFile("multiCostAndPos.out"))); QCOMPARE(data->functions().size(), 2); QCOMPARE(data->positions(), QStringList() << "line" << "memAddr"); @@ -345,7 +338,7 @@ const Function *findFunction(const QString &needle, const QVector data(parseDataFile(dataFile("cycle.out"))); + const ParseDataPtr data(parseDataFile(dataFile("cycle.out"))); QCOMPARE(data->functions().size(), 4); const Function *main = data->functions().at(0); @@ -377,7 +370,7 @@ void CallgrindParserTests::testCycle() void CallgrindParserTests::testRecursiveCycle() { - QScopedPointer data(parseDataFile(dataFile("recursiveCycle.out"))); + const ParseDataPtr data(parseDataFile(dataFile("recursiveCycle.out"))); QCOMPARE(data->functions().size(), 5); const Function *main = findFunction(QLatin1String("main"), data->functions()); @@ -418,7 +411,7 @@ void CallgrindParserTests::testRecursiveCycle() void CallgrindParserTests::testRecursion() { - QScopedPointer data(parseDataFile(dataFile("recursion.out"))); + const ParseDataPtr data(parseDataFile(dataFile("recursion.out"))); QCOMPARE(data->functions().size(), 3); QCOMPARE(data->totalCost(0), quint64(35700972));