From 149dc93ee9da2b9b9d7093e78c50480daa3b2e91 Mon Sep 17 00:00:00 2001 From: Artur Twardy Date: Mon, 7 Oct 2024 21:51:17 +0200 Subject: [PATCH 001/989] Expose markdown in TextEdit Change-Id: Ic0bae0bacfced74eb4977b74a6bb4b59c95f99dd Reviewed-by: Marcus Tillmanns --- src/libs/utils/layoutbuilder.cpp | 5 +++++ src/libs/utils/layoutbuilder.h | 1 + src/plugins/lua/bindings/gui.cpp | 2 ++ src/plugins/lua/meta/gui.lua | 3 +++ 4 files changed, 11 insertions(+) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 0a18c72ef79..5d2147a3bef 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -879,6 +879,11 @@ TextEdit::TextEdit(std::initializer_list ps) apply(this, ps); } +QString TextEdit::markdown() const +{ + return access(this)->toMarkdown(); +} + void TextEdit::setText(const QString &text) { access(this)->setText(text); diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 5019f2e8232..b95c68ff04e 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -316,6 +316,7 @@ public: TextEdit(std::initializer_list ps); + QString markdown() const; void setText(const QString &); void setMarkdown(const QString &); void setReadOnly(bool); diff --git a/src/plugins/lua/bindings/gui.cpp b/src/plugins/lua/bindings/gui.cpp index 9a5c2de6700..ead579cbc9d 100644 --- a/src/plugins/lua/bindings/gui.cpp +++ b/src/plugins/lua/bindings/gui.cpp @@ -462,6 +462,8 @@ void setupGuiModule() sol::factories([guard](const sol::table &children) { return constructWidgetType(children, guard); }), + "markdown", + sol::property(&TextEdit::markdown), sol::base_classes, sol::bases()); diff --git a/src/plugins/lua/meta/gui.lua b/src/plugins/lua/meta/gui.lua index 9b34883f1b6..fc958d7ff39 100644 --- a/src/plugins/lua/meta/gui.lua +++ b/src/plugins/lua/meta/gui.lua @@ -130,6 +130,9 @@ function gui.Tab(options) end ---@class TextEdit : Widget local textEdit = {} +---@return string markdown Returns the content of the TextEdit as markdown +function textEdit:markdown() end + ---@param options WidgetOptions ---@return TextEdit function gui.TextEdit(options) end From 73d720eea582d28ede7804c59c317dfd3da4a2a9 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Tue, 24 Sep 2024 16:40:12 +0200 Subject: [PATCH 002/989] QtQuickApplication Template: add 6.8 to versions Allows to set 6.8 via the combobox, as `REQUIRES 6.8` adds nice features like nested QML Module support. Also remove the now unsupported Qt 6.4 version. Change-Id: I21e45ea9b41bd3955f2316ba648c532faf7c6560 Reviewed-by: Ulf Hermann Reviewed-by: Alessandro Portale --- .../templates/wizards/projects/qtquickapplication/wizard.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index c0746b7c5be..2c8a5af02f7 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -56,8 +56,8 @@ { "items": [ { "trKey": "Qt 6.2", "value": "6.2" }, - { "trKey": "Qt 6.4", "value": "6.4" }, - { "trKey": "Qt 6.5", "value": "6.5" } + { "trKey": "Qt 6.5", "value": "6.5" }, + { "trKey": "Qt 6.8", "value": "6.8" } ], "index": 2 } From c6a8b5844fd3dcb7bbc819c1aca6706a592ea45a Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 1 Oct 2024 14:16:18 -0700 Subject: [PATCH 003/989] Utils: Remove compat beginEntryList() The function it was overriding was removed in qtbase commit 4fecfcc867f8215defaa40b50f0340654a36b4c7. Amends commit 81d4e8a374230298cba64b05cf102aa0a65a66fc. Change-Id: I41b1f04c9fbd043cb178fffd5f30fb6edeed4945 Reviewed-by: Marcus Tillmanns Reviewed-by: Ahmad Samir --- src/libs/utils/fsengine/fixedlistfsengine.h | 7 ------- src/libs/utils/fsengine/fsenginehandler.cpp | 19 +------------------ 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/libs/utils/fsengine/fixedlistfsengine.h b/src/libs/utils/fsengine/fixedlistfsengine.h index 36d1df3db91..6696fa7a258 100644 --- a/src/libs/utils/fsengine/fixedlistfsengine.h +++ b/src/libs/utils/fsengine/fixedlistfsengine.h @@ -78,13 +78,6 @@ public: return std::make_unique(m_children, path, filters, filterNames); } - - IteratorUniquePtr beginEntryList(const QString &path, - QDir::Filters filters, - const QStringList &filterNames) override - { - return std::make_unique(m_children, path, filters, filterNames); - } #else Iterator *beginEntryList(QDir::Filters /*filters*/, const QStringList & /*filterNames*/) override { diff --git a/src/libs/utils/fsengine/fsenginehandler.cpp b/src/libs/utils/fsengine/fsenginehandler.cpp index 2fbd853963f..f48051bfe44 100644 --- a/src/libs/utils/fsengine/fsenginehandler.cpp +++ b/src/libs/utils/fsengine/fsenginehandler.cpp @@ -70,8 +70,6 @@ public: bool cloneTo(QAbstractFileEngine *target) final; #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) - IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters, - const QStringList &filterNames) final; IteratorUniquePtr beginEntryList( const QString &path, QDirListing::IteratorFlags filters, @@ -404,13 +402,9 @@ QAbstractFileEngine::IteratorUniquePtr FSEngineImpl::beginEntryList( return std::make_unique(std::move(paths), path, filters, filterNames); } -QAbstractFileEngine::IteratorUniquePtr FSEngineImpl::beginEntryList(const QString &path, - QDir::Filters filters, - const QStringList &filterNames) #else QAbstractFileEngine::Iterator *FSEngineImpl::beginEntryList(QDir::Filters filters, const QStringList &filterNames) -#endif { FilePaths paths{m_filePath.pathAppended(".")}; m_filePath.iterateDirectory( @@ -424,12 +418,9 @@ QAbstractFileEngine::Iterator *FSEngineImpl::beginEntryList(QDir::Filters filter }, {filterNames, filters}); -#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) - return std::make_unique(std::move(paths), path, filters, filterNames); -#else return new DirIterator(std::move(paths)); -#endif } +#endif qint64 FSEngineImpl::read(char *data, qint64 maxlen) { @@ -480,14 +471,6 @@ public: public: #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) - IteratorUniquePtr beginEntryList(const QString &path, - QDir::Filters filters, - const QStringList &filterNames) final - { - return std::make_unique( - QFSFileEngine::beginEntryList(path, filters, filterNames)); - } - IteratorUniquePtr beginEntryList( const QString &path, QDirListing::IteratorFlags filters, From 702f9f5b5dac850847fe805a64666ebb9232865e Mon Sep 17 00:00:00 2001 From: Artur Twardy Date: Mon, 7 Oct 2024 21:40:28 +0200 Subject: [PATCH 004/989] Lua: Fix for TextEditor widget positioning Position widget at cursor coordinates if widget fits in TextEditor viewport, otherwise move the widget to be fully visible on the view and tries not to cover the cursor. Enable option to fill the remanining viewport width. Adds utils function to convert sol::table to std::tuple Change-Id: I6d0f52e82b9380888259e36819e3cab127e8fddd Reviewed-by: Marcus Tillmanns Reviewed-by: hjk Reviewed-by: --- src/plugins/lua/bindings/texteditor.cpp | 85 +++++++++++++++++++------ src/plugins/lua/bindings/utils.h | 1 - src/plugins/lua/meta/texteditor.lua | 4 +- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/plugins/lua/bindings/texteditor.cpp b/src/plugins/lua/bindings/texteditor.cpp index 6c3f9e95d9b..0066b96fc54 100644 --- a/src/plugins/lua/bindings/texteditor.cpp +++ b/src/plugins/lua/bindings/texteditor.cpp @@ -5,6 +5,7 @@ #include "../luatr.h" #include +#include #include #include #include @@ -45,22 +46,65 @@ TextEditor::TextEditorWidget *getSuggestionReadyEditorWidget(TextEditor::TextDoc return widget; } -void addFloatingWidget(BaseTextEditor *editor, QWidget *widget, int position) +void fillRemainingViewportWidth(QWidget *widget, const QSize &viewportSize, const QMargins &margins) { - widget->setParent(editor->editorWidget()->viewport()); - const auto editorWidget = editor->editorWidget(); - - QTextCursor cursor = QTextCursor(editor->textDocument()->document()); - cursor.setPosition(position); - const QRect cursorRect = editorWidget->cursorRect(cursor); - - QPoint widgetPos = cursorRect.bottomLeft(); - widgetPos.ry() += (cursorRect.top() - cursorRect.bottom()) / 2; - - widget->move(widgetPos); - widget->show(); + int maxWidth = viewportSize.width() - margins.right() - widget->x(); + widget->setFixedWidth(maxWidth); } +QPoint getPositionOnViewport(const BaseTextEditor * const editor, const QWidget * const widget, + int basePostion, const QSize &viewportSize, const QMargins &margins) +{ + QTextCursor cursor = QTextCursor(editor->textDocument()->document()); + cursor.setPosition(basePostion); + + const QRect cursorRect = editor->editorWidget()->cursorRect(cursor); + QPoint widgetPosDefault = cursorRect.bottomLeft(); + + widgetPosDefault.ry() += (cursorRect.top() - cursorRect.bottom()) / 2; + + int fontSize = editor->textDocument()->fontSettings().fontSize(); + int maxX = viewportSize.width() - margins.right() - widget->width(); + int maxY = viewportSize.height() - widget->height() - fontSize; + + if (maxX < 0) { + qWarning() << QStringLiteral("Floating Widget positioning: x (%1) < 0. Widget will not " + "fit in the viewport. Viewport.width (%2), widget.width (%3), " + "widget margin.right (%4). Setting x to 0.") + .arg(maxX).arg(viewportSize.width()).arg(widget->width()).arg(margins.right()); + maxX = 0; + } + + if (maxY < 0) { + qWarning() << QStringLiteral("Floating Widget positioning: y (%1) < 0. Widget is too big" + "for the viewport. Viewport.height (%2), widget.height (%3)." + "Setting y to 0.") + .arg(maxY).arg(viewportSize.height()).arg(widget->height()); + maxY = 0; + } + + int x = widgetPosDefault.x() > maxX ? maxX : widgetPosDefault.x(); + int y = widgetPosDefault.y() + fontSize; + y = y > maxY ? maxY : y; + + return {x, y}; +} + +void addFloatingWidget(BaseTextEditor *editor, QWidget *widget, int pos, const QRect &margins, + bool fillWidth = false) +{ + QMargins widgetMargins{margins.left(), margins.top(), margins.width(), margins.height()}; + + widget->setParent(editor->editorWidget()->viewport()); + TextEditorWidget *editorWidget = editor->editorWidget(); + const QSize viewportSize = editorWidget->viewport()->size(); + + widget->move(getPositionOnViewport(editor, widget, pos, viewportSize, widgetMargins)); + if (fillWidth) + fillRemainingViewportWidth(widget, viewportSize, widgetMargins); + + widget->show(); +} } // namespace namespace Lua::Internal { @@ -234,17 +278,20 @@ void setupTextEditorModule() }, "addFloatingWidget", sol::overload( - [](const TextEditorPtr &textEditor, QWidget *widget, int position) { + [](const TextEditorPtr &textEditor, QWidget *widget, int position, + const QRect &margins, bool fillWidth) { QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid")); - addFloatingWidget(textEditor, widget, position); + addFloatingWidget(textEditor, widget, position, margins, fillWidth); }, - [](const TextEditorPtr &textEditor, Layouting::Widget *widget, int position) { + [](const TextEditorPtr &textEditor, Layouting::Widget *widget, int position, + const QRect &margins, bool fillWidth) { QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid")); - addFloatingWidget(textEditor, widget->emerge(), position); + addFloatingWidget(textEditor, widget->emerge(), position, margins, fillWidth); }, - [](const TextEditorPtr &textEditor, Layouting::Layout *layout, int position) { + [](const TextEditorPtr &textEditor, Layouting::Layout *layout, int position, + const QRect &margins, bool fillWidth = false) { QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid")); - addFloatingWidget(textEditor, layout->emerge(), position); + addFloatingWidget(textEditor, layout->emerge(), position, margins, fillWidth); }), "cursor", [](const TextEditorPtr &textEditor) { diff --git a/src/plugins/lua/bindings/utils.h b/src/plugins/lua/bindings/utils.h index a6b65c762d0..b42c5f85e72 100644 --- a/src/plugins/lua/bindings/utils.h +++ b/src/plugins/lua/bindings/utils.h @@ -49,5 +49,4 @@ inline void mirrorEnum(sol::table &target, QMetaEnum metaEnum, const QString &na for (int i = 0; i < metaEnum.keyCount(); ++i) widgetAttributes.set(metaEnum.key(i), metaEnum.value(i)); }; - } // namespace Lua::Internal diff --git a/src/plugins/lua/meta/texteditor.lua b/src/plugins/lua/meta/texteditor.lua index d4575c14cae..a11138f7ad2 100644 --- a/src/plugins/lua/meta/texteditor.lua +++ b/src/plugins/lua/meta/texteditor.lua @@ -100,7 +100,9 @@ function TextEditor:cursor() end ---text document and will be automatically managed to stay pined to that position. ---@param widget Widget|Layout The widget to be added as a floating widget. ---@param position integer The position in the document where the widget should appear. -function TextEditor:addFloatingWidget(widget, position) end +---@param margins integer[] Four integers, representing left, top, right, bottom margins +---@param fillWidth boolean If true, the widget will fill remaining space from its x position to size of the TextEditor viewport +function TextEditor:addFloatingWidget(widget, position, margins, fillWidth) end ---Checks if the current suggestion is locked. The suggestion is locked when the user can use it. ---@return boolean True if the suggestion is locked, false otherwise. From 7ca87766253d85979a8fe0e8c7858c6967545269 Mon Sep 17 00:00:00 2001 From: Artur Twardy Date: Tue, 8 Oct 2024 15:49:42 +0200 Subject: [PATCH 005/989] Lua: Expose LineEdit type to lua Change-Id: Icd74bd5c9af12bbf737fca29417d011f9c58de81 Reviewed-by: Marcus Tillmanns --- src/libs/utils/layoutbuilder.cpp | 47 +++++++++++++++++++++++++++ src/libs/utils/layoutbuilder.h | 20 ++++++++++++ src/plugins/lua/bindings/gui.cpp | 56 ++++++++++++++++++++++++++++++++ src/plugins/lua/meta/gui.lua | 12 +++++++ 4 files changed, 135 insertions(+) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 5d2147a3bef..3539e6fd2dd 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -6,6 +6,7 @@ #include "filepath.h" #include "icon.h" #include "qtcassert.h" +#include "fancylineedit.h" #include #include @@ -1096,6 +1097,52 @@ void addToLayout(Layout *layout, const Stretch &inner) lt->addStretch(inner.stretch); } +LineEdit::LineEdit(std::initializer_list ps) +{ + ptr = new Implementation; + apply(this, ps); +} + +QString LineEdit::text() const +{ + return access(this)->text(); +} + +void LineEdit::setRightSideIconPath(const Utils::FilePath &path) +{ + if (!path.isEmpty()) { + QIcon icon(path.toFSPathString()); + QTC_CHECK(!icon.isNull()); + access(this)->setButtonIcon(Utils::FancyLineEdit::Right, icon); + access(this)->setButtonVisible(Utils::FancyLineEdit::Right, !icon.isNull()); + } +} + +void LineEdit::setPlaceHolderText(const QString &text) +{ + access(this)->setPlaceholderText(text); +} + +void LineEdit::setCompleter(QCompleter *completer) +{ + access(this)->setSpecialCompleter(completer); +} + +void LineEdit::setMinimumHeight(int height) +{ + access(this)->setMinimumHeight(height); +} + +void LineEdit::onReturnPressed(const std::function &func) +{ + QObject::connect(access(this), &Utils::FancyLineEdit::returnPressed, func); +} + +void LineEdit::onRightSideIconClicked(const std::function &func) +{ + QObject::connect(access(this), &Utils::FancyLineEdit::rightButtonClicked, func); +} + // void createItem(LayoutItem *item, QWidget *t) // { // if (auto l = qobject_cast(t)) diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index b95c68ff04e..515773377fa 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -20,6 +20,7 @@ QT_BEGIN_NAMESPACE class QBoxLayout; +class QCompleter; class QFormLayout; class QGridLayout; class QGroupBox; @@ -41,6 +42,7 @@ QT_END_NAMESPACE namespace Utils { +class FancyLineEdit; class FilePath; } // Utils @@ -322,6 +324,24 @@ public: void setReadOnly(bool); }; +class QTCREATOR_UTILS_EXPORT LineEdit : public Widget +{ +public: + using Implementation = Utils::FancyLineEdit; + using I = Building::BuilderItem; + using Id = Implementation *; + + LineEdit(std::initializer_list ps); + + QString text() const; + void setRightSideIconPath(const Utils::FilePath &path); + void setPlaceHolderText(const QString &text); + void setCompleter(QCompleter *completer); + void setMinimumHeight(int height); + void onReturnPressed(const std::function &); + void onRightSideIconClicked(const std::function &); +}; + class QTCREATOR_UTILS_EXPORT Splitter : public Widget { public: diff --git a/src/plugins/lua/bindings/gui.cpp b/src/plugins/lua/bindings/gui.cpp index ead579cbc9d..f85ea59cc85 100644 --- a/src/plugins/lua/bindings/gui.cpp +++ b/src/plugins/lua/bindings/gui.cpp @@ -107,9 +107,54 @@ HAS_MEM_FUNC(setIconPath, hasSetIconPath); HAS_MEM_FUNC(setFlat, hasSetFlat); HAS_MEM_FUNC(setOpenExternalLinks, hasSetOpenExternalLinks); HAS_MEM_FUNC(setIconSize, hasSetIconSize); +HAS_MEM_FUNC(setRightSideIconPath, hasSetRightSideIconPath); +HAS_MEM_FUNC(setPlaceHolderText, hasSetPlaceHolderText); +HAS_MEM_FUNC(setCompleter, hasSetCompleter); +HAS_MEM_FUNC(setMinimumHeight, hasSetMinimumHeight); +HAS_MEM_FUNC(onReturnPressed, hasOnReturnPressed); +HAS_MEM_FUNC(onRightSideIconClicked, hasOnRightSideIconClicked); + template void setProperties(std::unique_ptr &item, const sol::table &children, QObject *guard) { + if constexpr (hasSetRightSideIconPath::value) { + const auto path = children.get>("rightSideIconPath"); + if (path) + item->setRightSideIconPath(*path); + } + + if constexpr (hasSetPlaceHolderText::value) { + const auto text = children.get>("placeHolderText"); + if (text) + item->setPlaceHolderText(*text); + } + + if constexpr (hasSetCompleter::value) { + const auto completer = children.get("completer"); + if (completer) + item->setCompleter(completer); + } + + if constexpr (hasSetMinimumHeight::value) { + const auto minHeight = children.get>("minimumHeight"); + if (minHeight) + item->setMinimumHeight(*minHeight); + } + + if constexpr (hasOnReturnPressed &)>::value) { + const auto callback = children.get>("onReturnPressed"); + if (callback) + { + item->onReturnPressed([func = *callback]() { void_safe_call(func); }); + } + } + + if constexpr (hasOnRightSideIconClicked &)>::value) { + const auto callback = children.get>("onRightSideIconClicked"); + if (callback) + item->onRightSideIconClicked([func = *callback]() { void_safe_call(func); }); + } + if constexpr (hasSetFlat::value) { const auto flat = children.get>("flat"); if (flat) @@ -467,6 +512,17 @@ void setupGuiModule() sol::base_classes, sol::bases()); + gui.new_usertype( + "LineEdit", + sol::call_constructor, + sol::factories([guard](const sol::table &children) { + return constructWidgetType(children, guard); + }), + "text", + sol::property(&LineEdit::text), + sol::base_classes, + sol::bases()); + gui.new_usertype( "SpinBox", sol::call_constructor, diff --git a/src/plugins/lua/meta/gui.lua b/src/plugins/lua/meta/gui.lua index fc958d7ff39..fc87f11b6f6 100644 --- a/src/plugins/lua/meta/gui.lua +++ b/src/plugins/lua/meta/gui.lua @@ -137,6 +137,18 @@ function textEdit:markdown() end ---@return TextEdit function gui.TextEdit(options) end +---A Single line text edit +---@class LineEdit : Widget +---@field rightSideIconPath? FilePath A path to icon +---@field placeHolderText? string A placeholder text for intput +---@field completer? QCompleter A QCompleter object. +---@field minimumHeight? int Minimum height of input +---@field onReturnPressed? function The function to be called when Enter is pressed +---@field onRightSideIconClicked? function The function to be called when right side icon is clicked +---@field text string Current text + +local lineEdit = {} + ---@class PushButton : Widget local pushButton = {} From 8f3a0ebabbb03d6d95a354ad648d3a55b5ff0214 Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Wed, 16 Oct 2024 15:07:20 +0200 Subject: [PATCH 006/989] Debugger: enable disable breakpoint by clicking Disabled breakpoints can be enabled by just clicking on them. Clicking an enabled breakpoint deletes it (just as before). Change-Id: I651fb0f333d717db245ae0d06fcdfa6888cf8e7d Reviewed-by: hjk --- src/plugins/debugger/breakhandler.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 5d0b25a3729..ad8be0e2f66 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -120,7 +120,10 @@ public: void clicked() final { QTC_ASSERT(m_bp, return); - m_bp->deleteGlobalOrThisBreakpoint(); + if (!m_bp->isEnabled()) + m_bp->setEnabled(true); + else + m_bp->deleteGlobalOrThisBreakpoint(); } public: @@ -183,7 +186,10 @@ public: void clicked() final { QTC_ASSERT(m_gbp, return); - m_gbp->removeBreakpointFromModel(); + if (!m_gbp->isEnabled()) + m_gbp->setEnabled(true); + else + m_gbp->removeBreakpointFromModel(); } public: From 1e4a744398bdaf13ce51391d9a35e73b591ecb32 Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Thu, 17 Oct 2024 12:01:51 +0200 Subject: [PATCH 007/989] Debugger: tl::expected and Utils::Result dumpers Added dumpers for `tl::expected` and `Utils::Result` utility classes. Added a basic test. Useless `enum` prefix from CDB enum types (e.g. `enum MyEnum`) will be discarded in tests (credits to @hjk). Note that the include path for the newly added test executable is based on `__FILE__` macro value so it might easily break if the sources are reorganized. Also creating a test for `Utils::Result` is practically impossible within current setup as it is not a header only class, so the test binary must actually link against the correct version of Utils library target. Fixes: QTCREATORBUG-31795 Change-Id: I7f9ccb92d0c59333a2dca4ba928ac991f1e5238b Reviewed-by: hjk --- share/qtcreator/debugger/creatortypes.py | 12 ++++ share/qtcreator/debugger/dumper.py | 6 +- share/qtcreator/debugger/misctypes.py | 34 ++++++++- tests/auto/debugger/tst_dumpers.cpp | 88 ++++++++++++++++++++++-- 4 files changed, 131 insertions(+), 9 deletions(-) diff --git a/share/qtcreator/debugger/creatortypes.py b/share/qtcreator/debugger/creatortypes.py index fe78253c039..968eb26a51c 100644 --- a/share/qtcreator/debugger/creatortypes.py +++ b/share/qtcreator/debugger/creatortypes.py @@ -369,3 +369,15 @@ def qdump__QmakeProjectManager__QmakePriFileNode(d, value): def qdump__QmakeProjectManager__QmakeProFileNode(d, value): qdump__ProjectExplorer__FolderNode(d, value) + + +def qdump__Utils__Result(d, value): + error, _pad, has_err = value.split('{QString}@b') + if has_err: + d.putExpandable() + d.putValue('Error') + if d.isExpanded(): + with Children(d): + d.putSubItem('message', error) + else: + d.putValue('Ok') diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index d4241160db6..ffd48af5f95 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -4052,7 +4052,7 @@ typename)) #self.warn('SEARCHING FOR MEMBER: %s IN %s' % (name, value.type.name)) members = self.value_members(value, True) #self.warn('MEMBERS: %s' % ', '.join(str(m.name) for m in members)) - base = None + bases = [] for member in members: #self.warn('CHECKING FIELD %s' % member.name) if member.type.code == TypeCode.Typedef: @@ -4061,9 +4061,9 @@ typename)) #self.warn('FOUND MEMBER 1: %s IN %s' % (name, value.type.name)) return member if member.isBaseClass: - base = member + bases.append(member) if self.isCdb: - if base is not None: + for base in bases: # self.warn("CHECKING BASE CLASS '%s' for '%s'" % (base.type.name, name)) res = self.value_member_by_name(base, name) if res is not None: diff --git a/share/qtcreator/debugger/misctypes.py b/share/qtcreator/debugger/misctypes.py index 9099f19a2f7..a07feea4319 100644 --- a/share/qtcreator/debugger/misctypes.py +++ b/share/qtcreator/debugger/misctypes.py @@ -1,7 +1,7 @@ # Copyright (C) 2016 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -from dumper import Children, SubItem +from dumper import Children, SubItem, DumperBase from utils import TypeCode, DisplayFormat import re @@ -586,3 +586,35 @@ def qdump__QtcDumperTest_String(d, value): second = d.hexdecode(d.putSubItem('second', value['second']).value) third = d.hexdecode(d.putSubItem('third', value['third']).value)[:-1] d.putValue(first + ', ' + second + ', ' + third) + + +def qdump__tl__expected(d: DumperBase, value: DumperBase.Value): + # There are issues with correct type handling for enums and pointer in CDB + # preventing type cast from working as expected in these cases + + has_value = False + val = {} + + try: + has_value = value["m_has_val"].integer() != 0 + val = value["m_val"] if has_value else value["m_unexpect"]["m_val"] + except: + okType = value.type[0] + errType = value.type[1] + + # Result and error (and a initialized flag) are packed into a union storage + largerType = max(okType, errType, key=lambda t: t.size()) + storage, has_value = value.split(f'{{{largerType.name}}}b') + val = storage.cast(okType.name) if has_value else storage.cast(errType.name) + + if has_value: + if val.type.name != 'void': + d.putExpandable() + d.putValue('Expected') + else: + d.putExpandable() + d.putValue('Unexpected') + + if d.isExpanded(): + with Children(d): + d.putSubItem('inner', val) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 02bed53c5a4..bf110533899 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -411,6 +411,7 @@ struct Type } } QString actualType = simplifyType(actualType0); + actualType.replace(QRegularExpression("\\benum\\b"), ""); actualType.replace(' ', ""); actualType.replace("const", ""); QString expectedType; @@ -418,6 +419,7 @@ struct Type expectedType = type; else expectedType = aliasName; + expectedType.replace(QRegularExpression("\\benum\\b"), ""); expectedType.replace(' ', ""); expectedType.replace("const", ""); expectedType.replace('@', context.nameSpace); @@ -770,14 +772,16 @@ struct XmlProfile {}; struct NimProfile {}; struct BigArrayProfile {}; +struct InternalProfile +{}; class Data { public: Data() {} - Data(const QString &includes, const QString &code, const QString &unused) - : includes(includes), code(code), unused(unused) + Data(const QString &preamble, const QString &code, const QString &unused) + : preamble(preamble), code(code), unused(unused) {} const Data &operator+(const Check &check) const @@ -824,7 +828,7 @@ public: const Data &operator+(const Profile &profile) const { profileExtra += QString::fromUtf8(profile.contents); - includes += QString::fromUtf8(profile.includes); + preamble += QString::fromUtf8(profile.includes); return *this; } @@ -1059,6 +1063,13 @@ public: return *this; } + const Data &operator+(InternalProfile) const + { + const auto parentDir = Utils::FilePath::fromUserInput(__FILE__).parentDir().path(); + profileExtra += "INCLUDEPATH += " + parentDir + "/../../../src/libs/3rdparty\n"; + return *this; + } + const Data &operator+(const ForceC &) const { language = Language::C; @@ -1108,7 +1119,7 @@ public: mutable QString dumperOptions; mutable QString profileExtra; mutable QString cmakelistsExtra; - mutable QString includes; + mutable QString preamble; mutable QString code; mutable QString unused; @@ -1594,7 +1605,7 @@ void tst_Dumpers::dumper() "\n}\n" "\n#endif" "\n" - "\n\n" + data.includes + + "\n\n" + data.preamble + "\n\n" + (data.useQHash ? "\n#include " "\n#include " @@ -8563,6 +8574,73 @@ void tst_Dumpers::dumper_data() + Check("dir.entryInfoList.1", "[1]", quoted(tempDir + "/.."), "@QFileInfo") % NoCdbEngine + Check("dir.entryList.0", "[0]", "\".\"", "@QString") % NoCdbEngine + Check("dir.entryList.1", "[1]", "\"..\"", "@QString") % NoCdbEngine; + + // clang-format off + QTest::newRow("tl__expected") << Data{ + R"( + #include + + #include + + enum class Test { + One, + Two, + }; + + enum class ErrCode : std::int8_t { + Good, + Bad, + }; + + class MyClass { + public: + MyClass(int x) : m_x{x} {} + + private: + int m_x = 42; + }; + + static constexpr auto global = 42; + )", + + R"( + const auto ok_void = tl::expected{}; + const auto ok_primitive = tl::expected{42}; + const auto ok_pointer = tl::expected{&global}; + const auto ok_enum = tl::expected{Test::Two}; + const auto ok_class = tl::expected{MyClass{10}}; + + const auto err_primitive = tl::expected{tl::make_unexpected(42)}; + const auto err_pointer = tl::expected{tl::make_unexpected(&global)}; + const auto err_enum = tl::expected{tl::make_unexpected(ErrCode::Bad)}; + const auto err_class = tl::expected{tl::make_unexpected(MyClass{10})}; + )", + + "&ok_void, &ok_primitive, &ok_pointer, &ok_enum, &ok_class, &err_primitive, " + "&err_pointer, &err_enum, &err_class" + } + + CoreProfile{} + + InternalProfile{} + + Check{"ok_void", "Expected", "tl::expected"} + + Check{"ok_primitive", "Expected", "tl::expected"} + + Check{"ok_primitive.inner", "42", "int"} + + Check{"ok_pointer", "Expected", "tl::expected"} + + Check{"ok_pointer.inner", "42", "int"} + + Check{"ok_enum", "Expected", "tl::expected"} + + Check{"ok_enum.inner", "Test::Two (1)", "Test"} % GdbEngine + + Check{"ok_enum.inner", "Two (1)", "Test"} % NoGdbEngine + + Check{"ok_class", "Expected", "tl::expected"} + + Check{"ok_class.inner.m_x", "10", "int"} + + Check{"err_primitive", "Unexpected", "tl::expected"} + + Check{"err_primitive.inner", "42", "int"} + + Check{"err_pointer", "Unexpected", "tl::expected"} + + Check{"err_pointer.inner", "42", "int"} + + Check{"err_enum", "Unexpected", "tl::expected"} + + Check{"err_enum.inner", "ErrCode::Bad (1)", "ErrCode"} % GdbEngine + + Check{"err_enum.inner", "Bad (1)", "ErrCode"} % NoGdbEngine + + Check{"err_class", "Unexpected", "tl::expected"} + + Check{"err_class.inner.m_x", "10", "int"}; + //clang-format on } int main(int argc, char *argv[]) From 5f8a31628bf58b06be55b3fbf742f5473601aa17 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 21 Oct 2024 09:15:14 +0200 Subject: [PATCH 008/989] ProjectExplorer: add icon setter to task Change-Id: Idbd9973a8a854fefe1259c8763bb414d9056e9d1 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/task.cpp | 5 +++++ src/plugins/projectexplorer/task.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp index bbec54f14f0..f7691754751 100644 --- a/src/plugins/projectexplorer/task.cpp +++ b/src/plugins/projectexplorer/task.cpp @@ -125,6 +125,11 @@ QIcon Task::icon() const return m_icon; } +void Task::setIcon(const QIcon &icon) +{ + m_icon = icon; +} + QString Task::formattedDescription(DescriptionTags tags, const QString &extraHeading) const { if (isNull()) diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h index 478898725cf..954db64ef3e 100644 --- a/src/plugins/projectexplorer/task.h +++ b/src/plugins/projectexplorer/task.h @@ -52,6 +52,7 @@ public: void setFile(const Utils::FilePath &file); QString description(DescriptionTags tags = WithSummary) const; QIcon icon() const; + void setIcon(const QIcon &icon); QString formattedDescription(DescriptionTags tags, const QString &extraHeading = {}) const; friend PROJECTEXPLORER_EXPORT bool operator==(const Task &t1, const Task &t2); From 0bc70fdac141cff05fe27e22f50bd910486cadee Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 21 Oct 2024 12:46:23 +0200 Subject: [PATCH 009/989] ProjectExplorer: Fix offset calculation of links inside tasks Change-Id: Id17c5855c1d674045d778778868abbe872b427aa Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/task.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp index f7691754751..7df36f1cfcc 100644 --- a/src/plugins/projectexplorer/task.cpp +++ b/src/plugins/projectexplorer/task.cpp @@ -136,7 +136,7 @@ QString Task::formattedDescription(DescriptionTags tags, const QString &extraHea return {}; QString text = description(tags); - const int offset = (tags & WithSummary) ? 0 : summary.size() + 1; + const int offset = (tags & WithSummary) ? summary.size() + 1 : 0; static const QString linkTagStartPlaceholder("__QTC_LINK_TAG_START__"); static const QString linkTagEndPlaceholder("__QTC_LINK_TAG_END__"); static const QString linkEndPlaceholder("__QTC_LINK_END__"); From 3fc9d4f862dfa056fe5b47ab1b32ca955f611bd1 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 21 Oct 2024 12:47:07 +0200 Subject: [PATCH 010/989] ProjectExplorer: Allow to open external URLs from tasks Change-Id: I33e94b8d3ddfae7323544c7d834a9ca8bb625478 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/taskwindow.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 35e382fe263..298ed4580ec 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -695,8 +696,14 @@ void TaskView::mouseReleaseEvent(QMouseEvent *e) const QString anchor = anchorAt(e->pos()); if (anchor == m_clickAnchor) { - Core::EditorManager::openEditorAt(OutputLineParser::parseLinkTarget(m_clickAnchor), {}, - Core::EditorManager::SwitchSplitIfAlreadyVisible); + if (OutputLineParser::isLinkTarget(m_clickAnchor)) { + EditorManager::openEditorAt( + OutputLineParser::parseLinkTarget(m_clickAnchor), + {}, + EditorManager::SwitchSplitIfAlreadyVisible); + } else { + QDesktopServices::openUrl(QUrl(m_clickAnchor)); + } } m_clickAnchor.clear(); } From 0a7b608ca97132a158e3219f55a0eac1f5746843 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 21 Oct 2024 09:16:26 +0200 Subject: [PATCH 011/989] LSP: Add Diagnostic.CodeDescription to the protocol implementation see https://microsoft.github.io/language-server-protocol/specifications/ lsp/3.17/specification/#codeDescription Change-Id: Id2f92f1aea73928306be413afda636dcec978cf7 Reviewed-by: Christian Kandeler --- src/libs/languageserverprotocol/jsonkeys.h | 2 ++ src/libs/languageserverprotocol/lsptypes.h | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/libs/languageserverprotocol/jsonkeys.h b/src/libs/languageserverprotocol/jsonkeys.h index 37894f166e9..a4ba26e11c8 100644 --- a/src/libs/languageserverprotocol/jsonkeys.h +++ b/src/libs/languageserverprotocol/jsonkeys.h @@ -34,6 +34,7 @@ constexpr Key codeActionKindKey{"codeActionKind"}; constexpr Key codeActionKindsKey{"codeActionKinds"}; constexpr Key codeActionLiteralSupportKey{"codeActionLiteralSupport"}; constexpr Key codeActionProviderKey{"codeActionProvider"}; +constexpr Key codeDescriptionKey{"codeDescription"}; constexpr Key codeKey{"code"}; constexpr Key codeLensKey{"codeLens"}; constexpr Key codeLensProviderKey{"codeLensProvider"}; @@ -99,6 +100,7 @@ constexpr Key greenKey{"green"}; constexpr Key hierarchicalDocumentSymbolSupportKey{"hierarchicalDocumentSymbolSupport"}; constexpr Key hoverKey{"hover"}; constexpr Key hoverProviderKey{"hoverProvider"}; +constexpr Key hrefKey{"href"}; constexpr Key idKey{"id"}; constexpr Key ignoreIfExistsKey{"ignoreIfExists"}; constexpr Key ignoreIfNotExistsKey{"ignoreIfNotExists"}; diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h index 6e25fcb49d0..07e56e7c34f 100644 --- a/src/libs/languageserverprotocol/lsptypes.h +++ b/src/libs/languageserverprotocol/lsptypes.h @@ -154,6 +154,17 @@ enum class DiagnosticSeverity }; +class LANGUAGESERVERPROTOCOL_EXPORT CodeDescription : public JsonObject +{ +public: + using JsonObject::JsonObject; + + QString href() const { return typedValue(hrefKey); } + void setHref(const QString &href) { insert(hrefKey, href); } + + bool isValid() const override { return contains(hrefKey); } +}; + class LANGUAGESERVERPROTOCOL_EXPORT Diagnostic : public JsonObject { public: @@ -188,6 +199,12 @@ public: { return typedValue(messageKey); } void setMessage(const QString &message) { insert(messageKey, message); } + std::optional codeDescription() const + { return optionalValue(codeDescriptionKey); } + void setCodeDescription(const CodeDescription &codeDescription) + { insert(codeDescriptionKey, codeDescription); } + void clearCodeDescription() { remove(codeDescriptionKey); } + bool isValid() const override { return contains(rangeKey) && contains(messageKey); } }; From 176f6ec032a183de2a1d20ea4fe2203413c4da8b Mon Sep 17 00:00:00 2001 From: Alexander Drozdov Date: Tue, 22 Oct 2024 15:08:48 +1000 Subject: [PATCH 012/989] ProjectExplorer: Display build configuration specific variables ...in the Deployment configuration. Useful items like Device:HostAddress and Device:KeyFiles are missed in the Deployment steps parameters. Related to 9b6bbc181b2e41e75fa0833ee48fb3696cec653d Change-Id: I11065b2c2a20f4549544e72034e22c5fced195aa Reviewed-by: hjk --- .../projectexplorer/deployconfiguration.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/deployconfiguration.cpp b/src/plugins/projectexplorer/deployconfiguration.cpp index 418873ca024..9fe084f187e 100644 --- a/src/plugins/projectexplorer/deployconfiguration.cpp +++ b/src/plugins/projectexplorer/deployconfiguration.cpp @@ -3,6 +3,7 @@ #include "deployconfiguration.h" +#include "buildconfiguration.h" #include "buildsteplist.h" #include "deploymentdataview.h" #include "kitaspects.h" @@ -12,7 +13,9 @@ #include "target.h" #include +#include #include +#include #include @@ -31,6 +34,15 @@ DeployConfiguration::DeployConfiguration(Target *target, Id id) { //: Default DeployConfiguration display name setDefaultDisplayName(Tr::tr("Deploy locally")); + + // Allow to use Device::SshPort, KeyFile and so on on the custom deployment steps + MacroExpander &expander = *macroExpander(); + expander.setDisplayName(Tr::tr("Run Settings")); + expander.setAccumulating(true); + expander.registerSubProvider([target] { + BuildConfiguration *bc = target->activeBuildConfiguration(); + return bc ? bc->macroExpander() : target->macroExpander(); + }); } BuildStepList *DeployConfiguration::stepList() @@ -47,7 +59,9 @@ QWidget *DeployConfiguration::createConfigWidget() { if (!m_configWidgetCreator) return nullptr; - return m_configWidgetCreator(this); + QWidget *widget = m_configWidgetCreator(this); + VariableChooser::addSupportForChildWidgets(widget, macroExpander()); + return widget; } void DeployConfiguration::toMap(Store &map) const From 0d667bbbfb931b19fe7f7940a3653af6b2ea703a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 23 Oct 2024 06:45:25 +0200 Subject: [PATCH 013/989] EffectComposer: Fix missing include Change-Id: I7128cd5b0690f230aacdf1e4efd2d39cf9ea908a Reviewed-by: Mahmoud Badri Reviewed-by: Ali Kianian --- src/plugins/effectcomposer/effectshaderscodeeditor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/effectcomposer/effectshaderscodeeditor.cpp b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp index 95fe30a54e6..c650eb3e7f7 100644 --- a/src/plugins/effectcomposer/effectshaderscodeeditor.cpp +++ b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp @@ -17,6 +17,8 @@ #include +#include + #include #include #include From 1d84d7080e76d9d50ac961afa55dd526294a0e5a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 23 Oct 2024 08:17:53 +0200 Subject: [PATCH 014/989] EffectComposer: Compile fix Amends 34f51df1ea2df8beb4091b48c0015771f02cf923 Change-Id: I28be7bccf78f5369432fda6594fc7afe3362721a Reviewed-by: Mahmoud Badri --- src/plugins/effectcomposer/effectshaderscodeeditor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/effectcomposer/effectshaderscodeeditor.cpp b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp index c650eb3e7f7..2413c94ddcb 100644 --- a/src/plugins/effectcomposer/effectshaderscodeeditor.cpp +++ b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include #include From 4ecdbbd78747e5e5a03c7ef4936bd8096566c723 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 21 Oct 2024 09:17:06 +0200 Subject: [PATCH 015/989] LanguageClient: show CodeDescription in Tasks Change-Id: Ia8a20c71d6af9f0168614ecddb4fc0ca4ecf7cbc Reviewed-by: Christian Kandeler --- .../languageclient/diagnosticmanager.cpp | 20 ++++++++++++------- src/plugins/projectexplorer/task.cpp | 9 +++++++++ src/plugins/projectexplorer/task.h | 1 + 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/plugins/languageclient/diagnosticmanager.cpp b/src/plugins/languageclient/diagnosticmanager.cpp index db63b5a3f96..c437a9f1be6 100644 --- a/src/plugins/languageclient/diagnosticmanager.cpp +++ b/src/plugins/languageclient/diagnosticmanager.cpp @@ -224,13 +224,19 @@ std::optional DiagnosticManager::createTask( } } - return Task(taskType, - taskText(diagnostic), - doc->filePath(), - diagnostic.range().start().line() + 1, - d->m_taskCategory, - icon, - Task::NoOptions); + Task task( + taskType, + taskText(diagnostic), + doc->filePath(), + diagnostic.range().start().line() + 1, + d->m_taskCategory, + icon, + Task::NoOptions); + + if (const std::optional codeDescription = diagnostic.codeDescription()) + task.addLinkDetail(codeDescription->href()); + + return task; } QString DiagnosticManager::taskText(const LanguageServerProtocol::Diagnostic &diagnostic) const diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp index 7df36f1cfcc..91788306b82 100644 --- a/src/plugins/projectexplorer/task.cpp +++ b/src/plugins/projectexplorer/task.cpp @@ -163,6 +163,15 @@ QString Task::formattedDescription(DescriptionTags tags, const QString &extraHea .arg(htmlExtraHeading, TextEditor::FontSettings::defaultFixedFontFamily(), text); } +void Task::addLinkDetail(const QString &link) +{ + details.append(link); + QTextCharFormat format; + format.setAnchor(true); + format.setAnchorHref(link); + formats << QTextLayout::FormatRange{0, int(link.length()), format}; +} + // // functions // diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h index 954db64ef3e..e026c1044b7 100644 --- a/src/plugins/projectexplorer/task.h +++ b/src/plugins/projectexplorer/task.h @@ -54,6 +54,7 @@ public: QIcon icon() const; void setIcon(const QIcon &icon); QString formattedDescription(DescriptionTags tags, const QString &extraHeading = {}) const; + void addLinkDetail(const QString &link); friend PROJECTEXPLORER_EXPORT bool operator==(const Task &t1, const Task &t2); friend PROJECTEXPLORER_EXPORT bool operator<(const Task &a, const Task &b); From b04271108cfca914991a248d4fe84755efca6036 Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Fri, 11 Oct 2024 11:09:10 +0200 Subject: [PATCH 016/989] Debugger: Tooltips in secondary windows Debugger tooltips are no longer unconditionally bound to the main editor window. They are now moved with the text editor window they appear in. Fixes: QTCREATORBUG-24109 Change-Id: I7fd34f0717a30ec8a86c37e8dd16c1ea9512e1b5 Reviewed-by: Eike Ziller --- .../debugger/debuggertooltipmanager.cpp | 158 ++++++++++++------ 1 file changed, 111 insertions(+), 47 deletions(-) diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index bdea5b9f1e6..5587c566390 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -67,10 +67,14 @@ class DebuggerToolTipManagerPrivate : public QObject { public: explicit DebuggerToolTipManagerPrivate(DebuggerEngine *engine); + ~DebuggerToolTipManagerPrivate() override; void slotTooltipOverrideRequested(TextEditor::TextEditorWidget *editorWidget, const QPoint &point, int pos, bool *handled); void slotEditorOpened(Core::IEditor *e); + void slotEditorAboutToClose(Core::IEditor *e); + void slotCurrentEditorAboutToChange(Core::IEditor *e); + void slotCurrentEditorChanged(Core::IEditor *e); void hideAllToolTips(); void purgeClosedToolTips(); @@ -99,7 +103,7 @@ public: public: DebuggerEngine *m_engine; - QList> m_tooltips; + std::map, QList>> m_tooltips; bool m_debugModeActive = false; }; @@ -745,14 +749,16 @@ DebuggerToolTipManager::~DebuggerToolTipManager() void DebuggerToolTipManagerPrivate::hideAllToolTips() { purgeClosedToolTips(); - for (DebuggerToolTipWidget *tooltip : std::as_const(m_tooltips)) - tooltip->hide(); + for (const auto &[editor, tooltips] : m_tooltips) { + for (DebuggerToolTipWidget *tooltip : std::as_const(tooltips)) + tooltip->hide(); + } } void DebuggerToolTipManagerPrivate::updateVisibleToolTips() { purgeClosedToolTips(); - if (m_tooltips.isEmpty()) + if (m_tooltips.empty()) return; if (!m_debugModeActive) { hideAllToolTips(); @@ -771,25 +777,25 @@ void DebuggerToolTipManagerPrivate::updateVisibleToolTips() return; } + TextEditorWidget *editorWidget = toolTipEditor->editorWidget(); // Reposition and show all tooltips of that file. - for (DebuggerToolTipWidget *tooltip : std::as_const(m_tooltips)) { - if (tooltip->context.fileName == filePath) - tooltip->positionShow(toolTipEditor->editorWidget()); - else - tooltip->hide(); + for (DebuggerToolTipWidget *tooltip : std::as_const(m_tooltips.at(editorWidget))) { + tooltip->positionShow(editorWidget); } } void DebuggerToolTipManager::updateToolTips() { d->purgeClosedToolTips(); - if (d->m_tooltips.isEmpty()) + if (d->m_tooltips.empty()) return; // Stack frame changed: All tooltips of that file acquire the engine, // all others release (arguable, this could be more precise?) - for (DebuggerToolTipWidget *tooltip : std::as_const(d->m_tooltips)) - tooltip->updateTooltip(); + for (const auto &[editor, tooltips] : d->m_tooltips) { + for (DebuggerToolTipWidget *tooltip : std::as_const(tooltips)) + tooltip->updateTooltip(); + } d->updateVisibleToolTips(); // Move tooltip when stepping in same file. } @@ -799,19 +805,23 @@ void DebuggerToolTipManager::deregisterEngine() d->purgeClosedToolTips(); - for (DebuggerToolTipWidget *tooltip : std::as_const(d->m_tooltips)) - if (tooltip->context.engineType == d->m_engine->objectName()) - tooltip->releaseEngine(); + for (const auto &[editor, tooltips] : d->m_tooltips) { + for (DebuggerToolTipWidget *tooltip : std::as_const(tooltips)) + if (tooltip->context.engineType == d->m_engine->objectName()) + tooltip->releaseEngine(); + } // FIXME: For now remove all. - for (DebuggerToolTipWidget *tooltip : std::as_const(d->m_tooltips)) - tooltip->destroy(); + for (const auto &[window, tooltips] : d->m_tooltips) { + for (DebuggerToolTipWidget *tooltip : std::as_const(tooltips)) + tooltip->destroy(); + } d->purgeClosedToolTips(); } bool DebuggerToolTipManager::hasToolTips() const { - return !d->m_tooltips.isEmpty(); + return !d->m_tooltips.empty(); } void DebuggerToolTipManagerPrivate::sessionAboutToChange() @@ -826,9 +836,11 @@ void DebuggerToolTipManager::closeAllToolTips() void DebuggerToolTipManagerPrivate::closeAllToolTips() { - for (DebuggerToolTipWidget *tooltip : std::as_const(m_tooltips)) { - if (tooltip) - tooltip->destroy(); + for (const auto &[editor, tooltips] : m_tooltips) { + for (DebuggerToolTipWidget *tooltip : std::as_const(tooltips)) { + if (tooltip) + tooltip->destroy(); + } } m_tooltips.clear(); } @@ -836,8 +848,10 @@ void DebuggerToolTipManagerPrivate::closeAllToolTips() void DebuggerToolTipManager::resetLocation() { d->purgeClosedToolTips(); - for (DebuggerToolTipWidget *tooltip : std::as_const(d->m_tooltips)) - tooltip->pin(); + for (const auto &[editor, tooltips] : d->m_tooltips) { + for (DebuggerToolTipWidget *tooltip : std::as_const(tooltips)) + tooltip->pin(); + } } DebuggerToolTipManagerPrivate::DebuggerToolTipManagerPrivate(DebuggerEngine *engine) @@ -850,6 +864,12 @@ DebuggerToolTipManagerPrivate::DebuggerToolTipManagerPrivate(DebuggerEngine *eng debugModeEntered(); } +DebuggerToolTipManagerPrivate::~DebuggerToolTipManagerPrivate() +{ + for (const auto &[editor, tooltips] : m_tooltips) + editor->window()->removeEventFilter(this); +} + void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested (TextEditorWidget *editorWidget, const QPoint &point, int pos, bool *handled) { @@ -876,8 +896,7 @@ void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested != CppEditor::ProjectFile::Unsupported; if (context.expression.isEmpty()) { - ToolTip::show(point, Tr::tr("No valid expression"), - DebuggerMainWindow::instance()); + ToolTip::show(point, Tr::tr("No valid expression"), editorWidget); *handled = true; return; } @@ -895,7 +914,7 @@ void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested auto reusable = [context](DebuggerToolTipWidget *tooltip) { return tooltip->context.isSame(context); }; - DebuggerToolTipWidget *tooltip = Utils::findOrDefault(m_tooltips, reusable); + DebuggerToolTipWidget *tooltip = Utils::findOrDefault(m_tooltips.at(editorWidget), reusable); if (tooltip) { DEBUG("REUSING LOCALS TOOLTIP"); tooltip->context.mousePosition = point; @@ -904,8 +923,8 @@ void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested DEBUG("CREATING LOCALS, WAITING..."); tooltip = new DebuggerToolTipWidget(m_engine, context); tooltip->setState(Acquired); - m_tooltips.push_back(tooltip); - ToolTip::show(point, tooltip, DebuggerMainWindow::instance()); + m_tooltips.at(editorWidget).push_back(tooltip); + ToolTip::show(point, tooltip, editorWidget); } DEBUG("SYNC IN STATE" << tooltip->state); tooltip->updateTooltip(); @@ -916,7 +935,7 @@ void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested auto reusable = [&context](DebuggerToolTipWidget *tooltip) { return tooltip->context.isSame(context); }; - DebuggerToolTipWidget *tooltip = Utils::findOrDefault(m_tooltips, reusable); + DebuggerToolTipWidget *tooltip = Utils::findOrDefault(m_tooltips.at(editorWidget), reusable); if (tooltip) { //tooltip->destroy(); @@ -927,13 +946,12 @@ void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested DEBUG("CREATING DELAYED."); tooltip = new DebuggerToolTipWidget(m_engine, context); tooltip->context.mousePosition = point; - m_tooltips.push_back(tooltip); + m_tooltips.at(editorWidget).push_back(tooltip); tooltip->setState(PendingUnshown); if (m_engine->canHandleToolTip(context)) { m_engine->updateItem(context.iname); } else { - ToolTip::show(point, Tr::tr("Expression too complex"), - DebuggerMainWindow::instance()); + ToolTip::show(point, Tr::tr("Expression too complex"), editorWidget); tooltip->destroy(); } } @@ -947,6 +965,7 @@ void DebuggerToolTipManagerPrivate::slotEditorOpened(IEditor *e) // Move tooltip along when scrolled. if (auto textEditor = qobject_cast(e)) { TextEditorWidget *widget = textEditor->editorWidget(); + m_tooltips.insert({widget, {}}); QObject::connect(widget->verticalScrollBar(), &QScrollBar::valueChanged, this, &DebuggerToolTipManagerPrivate::updateVisibleToolTips); QObject::connect(widget, &TextEditorWidget::tooltipOverrideRequested, @@ -954,18 +973,49 @@ void DebuggerToolTipManagerPrivate::slotEditorOpened(IEditor *e) } } +void DebuggerToolTipManagerPrivate::slotEditorAboutToClose(IEditor *e) +{ + if (auto textEditor = qobject_cast(e)) + m_tooltips.erase(textEditor->editorWidget()); +} + +void DebuggerToolTipManagerPrivate::slotCurrentEditorAboutToChange(Core::IEditor *e) +{ + if (auto textEditor = qobject_cast(e)) + textEditor->widget()->window()->removeEventFilter(this); +} + +void DebuggerToolTipManagerPrivate::slotCurrentEditorChanged(Core::IEditor *e) +{ + if (auto textEditor = qobject_cast(e)) + textEditor->widget()->window()->installEventFilter(this); +} + void DebuggerToolTipManagerPrivate::debugModeEntered() { // Hook up all signals in debug mode. if (!m_debugModeActive) { m_debugModeActive = true; - QWidget *topLevel = ICore::mainWindow()->topLevelWidget(); - topLevel->installEventFilter(this); EditorManager *em = EditorManager::instance(); connect(em, &EditorManager::currentEditorChanged, this, &DebuggerToolTipManagerPrivate::updateVisibleToolTips); connect(em, &EditorManager::editorOpened, this, &DebuggerToolTipManagerPrivate::slotEditorOpened); + connect( + em, + &EditorManager::editorAboutToClose, + this, + &DebuggerToolTipManagerPrivate::slotEditorAboutToClose); + connect( + em, + &EditorManager::currentEditorAboutToChange, + this, + &DebuggerToolTipManagerPrivate::slotCurrentEditorAboutToChange); + connect( + em, + &EditorManager::currentEditorChanged, + this, + &DebuggerToolTipManagerPrivate::slotCurrentEditorChanged); setupEditors(); } @@ -976,7 +1026,7 @@ void DebuggerToolTipManagerPrivate::setupEditors() for (IEditor *e : DocumentModel::editorsForOpenedDocuments()) slotEditorOpened(e); // Position tooltips delayed once all the editor placeholder layouting is done. - if (!m_tooltips.isEmpty()) + if (!m_tooltips.empty()) QTimer::singleShot(0, this, &DebuggerToolTipManagerPrivate::updateVisibleToolTips); } @@ -1005,24 +1055,31 @@ DebuggerToolTipContexts DebuggerToolTipManager::pendingTooltips() const StackFrame frame = d->m_engine->stackHandler()->currentFrame(); DebuggerToolTipContexts rc; d->purgeClosedToolTips(); - for (DebuggerToolTipWidget *tooltip : std::as_const(d->m_tooltips)) { - const DebuggerToolTipContext &context = tooltip->context; - if (context.iname.startsWith("tooltip") && context.matchesFrame(frame)) - rc.push_back(context); + for (const auto &[editor, tooltips] : d->m_tooltips) { + for (DebuggerToolTipWidget *tooltip : std::as_const(tooltips)) { + const DebuggerToolTipContext &context = tooltip->context; + if (context.iname.startsWith("tooltip") && context.matchesFrame(frame)) + rc.push_back(context); + } } return rc; } bool DebuggerToolTipManagerPrivate::eventFilter(QObject *o, QEvent *e) { - if (m_tooltips.isEmpty()) + if (m_tooltips.empty()) return false; switch (e->type()) { case QEvent::Move: { // Move along with parent (toplevel) const auto me = static_cast(e); const QPoint dist = me->pos() - me->oldPos(); purgeClosedToolTips(); - for (const QPointer &tooltip : std::as_const(m_tooltips)) { + QList> affectedTooltips; + for (auto &[editor, tooltips] : m_tooltips) { + if (editor->window() == o) + affectedTooltips.append(tooltips); + } + for (const QPointer &tooltip : std::as_const(affectedTooltips)) { if (tooltip && tooltip->isVisible()) tooltip->move(tooltip->pos() + dist); } @@ -1034,7 +1091,12 @@ bool DebuggerToolTipManagerPrivate::eventFilter(QObject *o, QEvent *e) const bool isMinimized = static_cast(o)->windowState() & Qt::WindowMinimized; if (wasMinimized != isMinimized) { purgeClosedToolTips(); - for (DebuggerToolTipWidget *tooltip : std::as_const(m_tooltips)) + QList> affectedTooltips; + for (auto &[editor, tooltips] : m_tooltips) { + if (editor->window() == o) + affectedTooltips.append(tooltips); + } + for (DebuggerToolTipWidget *tooltip : std::as_const(affectedTooltips)) tooltip->setVisible(!isMinimized); } break; @@ -1047,11 +1109,13 @@ bool DebuggerToolTipManagerPrivate::eventFilter(QObject *o, QEvent *e) void DebuggerToolTipManagerPrivate::purgeClosedToolTips() { - for (int i = m_tooltips.size(); --i >= 0; ) { - const QPointer tooltip = m_tooltips.at(i); - if (!tooltip) { - DEBUG("PURGE TOOLTIP, LEFT: " << m_tooltips.size()); - m_tooltips.removeAt(i); + for (auto &[editor, tooltips] : m_tooltips) { + for (int i = tooltips.size(); --i >= 0;) { + const QPointer tooltip = tooltips.at(i); + if (!tooltip) { + DEBUG("PURGE TOOLTIP, LEFT: " << m_tooltips.size()); + tooltips.removeAt(i); + } } } } From 5354e7e557364a0c4b47652fe1e295469ae19c33 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 24 Oct 2024 10:52:32 +0200 Subject: [PATCH 017/989] Debugger: Compactify new DebuggerToolTipManager code a bit Change-Id: I126a6159c5d82af03838da5fcb7dcf2d919d894f Reviewed-by: Eike Ziller --- .../debugger/debuggertooltipmanager.cpp | 49 +++++-------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index 5587c566390..162994008aa 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -72,9 +72,6 @@ public: void slotTooltipOverrideRequested(TextEditor::TextEditorWidget *editorWidget, const QPoint &point, int pos, bool *handled); void slotEditorOpened(Core::IEditor *e); - void slotEditorAboutToClose(Core::IEditor *e); - void slotCurrentEditorAboutToChange(Core::IEditor *e); - void slotCurrentEditorChanged(Core::IEditor *e); void hideAllToolTips(); void purgeClosedToolTips(); @@ -973,24 +970,6 @@ void DebuggerToolTipManagerPrivate::slotEditorOpened(IEditor *e) } } -void DebuggerToolTipManagerPrivate::slotEditorAboutToClose(IEditor *e) -{ - if (auto textEditor = qobject_cast(e)) - m_tooltips.erase(textEditor->editorWidget()); -} - -void DebuggerToolTipManagerPrivate::slotCurrentEditorAboutToChange(Core::IEditor *e) -{ - if (auto textEditor = qobject_cast(e)) - textEditor->widget()->window()->removeEventFilter(this); -} - -void DebuggerToolTipManagerPrivate::slotCurrentEditorChanged(Core::IEditor *e) -{ - if (auto textEditor = qobject_cast(e)) - textEditor->widget()->window()->installEventFilter(this); -} - void DebuggerToolTipManagerPrivate::debugModeEntered() { // Hook up all signals in debug mode. @@ -1001,22 +980,18 @@ void DebuggerToolTipManagerPrivate::debugModeEntered() this, &DebuggerToolTipManagerPrivate::updateVisibleToolTips); connect(em, &EditorManager::editorOpened, this, &DebuggerToolTipManagerPrivate::slotEditorOpened); - connect( - em, - &EditorManager::editorAboutToClose, - this, - &DebuggerToolTipManagerPrivate::slotEditorAboutToClose); - connect( - em, - &EditorManager::currentEditorAboutToChange, - this, - &DebuggerToolTipManagerPrivate::slotCurrentEditorAboutToChange); - connect( - em, - &EditorManager::currentEditorChanged, - this, - &DebuggerToolTipManagerPrivate::slotCurrentEditorChanged); - + connect(em, &EditorManager::editorAboutToClose, [this](IEditor *editor) { + if (auto textEditor = qobject_cast(editor)) + m_tooltips.erase(textEditor->editorWidget()); + }); + connect(em, &EditorManager::currentEditorAboutToChange, [this](IEditor *editor) { + if (auto textEditor = qobject_cast(editor)) + textEditor->widget()->window()->removeEventFilter(this); + }); + connect(em, &EditorManager::currentEditorChanged, [this](IEditor *editor) { + if (auto textEditor = qobject_cast(editor)) + textEditor->widget()->window()->installEventFilter(this); + }); setupEditors(); } } From a5a8450edc5249c2694bc6836b177873ecb1132b Mon Sep 17 00:00:00 2001 From: Andrii Batyiev Date: Thu, 24 Oct 2024 13:17:43 +0300 Subject: [PATCH 018/989] Do not re-enable Aspects in AspectContainer::registerAspect Change-Id: I36e13edb97094c401be9c52766cd6ed0feafe021 Reviewed-by: Marcus Tillmanns --- src/libs/utils/aspects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index bbebf7b26d8..7dc9bfb4b02 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -3194,7 +3194,7 @@ void AspectContainer::registerAspect(BaseAspect *aspect, bool takeOwnership) { aspect->setContainer(this); aspect->setAutoApply(isAutoApply()); - aspect->setEnabled(isEnabled()); + aspect->setEnabled(aspect->isEnabled() && isEnabled()); d->m_items.append(aspect); if (takeOwnership) d->m_ownedItems.append(aspect); From 090b540487c0d5e178a043f8df05d3bbc0b67bd5 Mon Sep 17 00:00:00 2001 From: Markus Redeker Date: Mon, 30 Sep 2024 16:41:30 +0200 Subject: [PATCH 019/989] Extend Coco plugin for QMake/CMake project instrumentation The Coco plugin now can also configure QMake and CMake projects for the use with Coco. (COCO-1782) * There is a new global preferences page to set the Coco directory. (But the plugin also searches automatically for the active Coco installation, so using the page should rarely be necessary.) * There is a project settings page where the code coverage can be configured, especially CoverageScanner options set. * Code coverage is enabled by changing the build settings of a project so that the build tool reads a special file at the beginning (cocoplugin.prf or cocoplugin.cmake), which replaces the normal compiler calls with calls of the Coco compiler wrappers. The CoverageScanner options are part of this file. * An additional, ficticious build step appears in the build menu of QMake and CMake projects, with a button to switch coverage on or off. * Added documentation * The class CMakeBuildSystem has been made publicly accessible and some member functions added so that the build settings chanbe chenged. [ChangeLog][coco] Added to the existing Coco plugin the ability to configure CMake and QMake projects for code coverage. Change-Id: I70a351b79b89bef3c25f81bb4b62ac59dc787645 Reviewed-by: Leena Miettinen Reviewed-by: hjk --- .../images/qtcreator-coco-buildstep.png | Bin 0 -> 6488 bytes .../images/qtcreator-coco-configpage.png | Bin 0 -> 16561 bytes doc/qtcreator/images/qtcreator-coco.png | Bin 5550 -> 7353 bytes doc/qtcreator/src/analyze/creator-coco.qdoc | 113 +++++- .../cmakeprojectmanager/builddirparameters.h | 6 +- .../cmakebuildconfiguration.cpp | 17 +- .../cmakebuildconfiguration.h | 12 +- .../cmakeprojectmanager/cmakebuildsystem.cpp | 5 +- .../cmakeprojectmanager/cmakebuildsystem.h | 19 +- src/plugins/coco/CMakeLists.txt | 48 ++- src/plugins/coco/Coco.json.in | 5 +- src/plugins/coco/coco.qbs | 45 ++- src/plugins/coco/cocobuild/buildsettings.cpp | 100 ++++++ src/plugins/coco/cocobuild/buildsettings.h | 67 ++++ .../coco/cocobuild/cmakemodificationfile.cpp | 91 +++++ .../coco/cocobuild/cmakemodificationfile.h | 32 ++ src/plugins/coco/cocobuild/cocobuildstep.cpp | 126 +++++++ src/plugins/coco/cocobuild/cocobuildstep.h | 59 +++ .../coco/cocobuild/cococmakesettings.cpp | 167 +++++++++ .../coco/cocobuild/cococmakesettings.h | 51 +++ .../coco/cocobuild/cocoprojectwidget.cpp | 336 ++++++++++++++++++ .../coco/cocobuild/cocoprojectwidget.h | 81 +++++ .../coco/cocobuild/cocoqmakesettings.cpp | 188 ++++++++++ .../coco/cocobuild/cocoqmakesettings.h | 56 +++ .../coco/cocobuild/modificationfile.cpp | 73 ++++ src/plugins/coco/cocobuild/modificationfile.h | 51 +++ .../coco/cocobuild/qmakefeaturefile.cpp | 105 ++++++ src/plugins/coco/cocobuild/qmakefeaturefile.h | 34 ++ src/plugins/coco/cocoplugin.cpp | 150 ++++++-- src/plugins/coco/cocoplugin.qrc | 10 + src/plugins/coco/cocoplugin_global.h | 12 + src/plugins/coco/cocopluginconstants.h | 23 ++ src/plugins/coco/common.cpp | 30 ++ src/plugins/coco/common.h | 14 + src/plugins/coco/files/cocoplugin-clang.cmake | 8 + src/plugins/coco/files/cocoplugin-gcc.cmake | 8 + .../coco/files/cocoplugin-visualstudio.cmake | 8 + src/plugins/coco/files/cocoplugin.cmake | 87 +++++ src/plugins/coco/files/cocoplugin.prf | 33 ++ src/plugins/coco/images/SquishCoco_48x48.png | Bin 0 -> 594 bytes .../coco/settings/cocoinstallation.cpp | 177 +++++++++ src/plugins/coco/settings/cocoinstallation.h | 39 ++ .../settings/cocoprojectsettingswidget.cpp | 40 +++ .../coco/settings/cocoprojectsettingswidget.h | 28 ++ src/plugins/coco/settings/globalsettings.cpp | 53 +++ src/plugins/coco/settings/globalsettings.h | 13 + .../coco/settings/globalsettingspage.cpp | 121 +++++++ .../coco/settings/globalsettingspage.h | 59 +++ 48 files changed, 2724 insertions(+), 76 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-coco-buildstep.png create mode 100644 doc/qtcreator/images/qtcreator-coco-configpage.png create mode 100644 src/plugins/coco/cocobuild/buildsettings.cpp create mode 100644 src/plugins/coco/cocobuild/buildsettings.h create mode 100644 src/plugins/coco/cocobuild/cmakemodificationfile.cpp create mode 100644 src/plugins/coco/cocobuild/cmakemodificationfile.h create mode 100644 src/plugins/coco/cocobuild/cocobuildstep.cpp create mode 100644 src/plugins/coco/cocobuild/cocobuildstep.h create mode 100644 src/plugins/coco/cocobuild/cococmakesettings.cpp create mode 100644 src/plugins/coco/cocobuild/cococmakesettings.h create mode 100644 src/plugins/coco/cocobuild/cocoprojectwidget.cpp create mode 100644 src/plugins/coco/cocobuild/cocoprojectwidget.h create mode 100644 src/plugins/coco/cocobuild/cocoqmakesettings.cpp create mode 100644 src/plugins/coco/cocobuild/cocoqmakesettings.h create mode 100644 src/plugins/coco/cocobuild/modificationfile.cpp create mode 100644 src/plugins/coco/cocobuild/modificationfile.h create mode 100644 src/plugins/coco/cocobuild/qmakefeaturefile.cpp create mode 100644 src/plugins/coco/cocobuild/qmakefeaturefile.h create mode 100644 src/plugins/coco/cocoplugin.qrc create mode 100644 src/plugins/coco/cocoplugin_global.h create mode 100644 src/plugins/coco/cocopluginconstants.h create mode 100644 src/plugins/coco/common.cpp create mode 100644 src/plugins/coco/common.h create mode 100644 src/plugins/coco/files/cocoplugin-clang.cmake create mode 100644 src/plugins/coco/files/cocoplugin-gcc.cmake create mode 100644 src/plugins/coco/files/cocoplugin-visualstudio.cmake create mode 100644 src/plugins/coco/files/cocoplugin.cmake create mode 100644 src/plugins/coco/files/cocoplugin.prf create mode 100644 src/plugins/coco/images/SquishCoco_48x48.png create mode 100644 src/plugins/coco/settings/cocoinstallation.cpp create mode 100644 src/plugins/coco/settings/cocoinstallation.h create mode 100644 src/plugins/coco/settings/cocoprojectsettingswidget.cpp create mode 100644 src/plugins/coco/settings/cocoprojectsettingswidget.h create mode 100644 src/plugins/coco/settings/globalsettings.cpp create mode 100644 src/plugins/coco/settings/globalsettings.h create mode 100644 src/plugins/coco/settings/globalsettingspage.cpp create mode 100644 src/plugins/coco/settings/globalsettingspage.h diff --git a/doc/qtcreator/images/qtcreator-coco-buildstep.png b/doc/qtcreator/images/qtcreator-coco-buildstep.png new file mode 100644 index 0000000000000000000000000000000000000000..66b21eee1e7eba0d8770e96301f5fd3cfa21bbd2 GIT binary patch literal 6488 zcmeAS@N?(olHy`uVBq!ia0y~yU|Pb!z%Y@6je&tdG;h^B1_lPk;vjb?hIQv;UNSH+ zu%tWsIx;Y9?C1WI$jZRLz**oCS*?YcQW5v|?%lpS$EF_m zXdIYuIGk^i0wd3pLk&hvvt*wdZn55;ckaOX1f8Te%qvdryno=3)A)WB z`;&_`zp*he9Ec6#^hoABZWa+UdmATL@=SNLCq0XrS*N-_*p*$$$iPsLV_W5+Z24aH zNu|-pyZ@grl{$!O4m+xIF$*7SL zTNrnD^TOEq;-NpcmHl2CdvCt_<)c1-w#tP>=WW-ySUEAhH1?^*>3+75s_4}(XPm6e z5d%ftEapoV8xG$w+wduUQd^T&Gt5jSSD#jAVe0igVzwnyVpLLod$|dR| zD!7X6%fYSx!m z>%L#vb^baN1H*#2VCDDb-Q%pzm*qdcRHr1JY1IUVQ%AQAQf62F?YXE!nM@w zZpGh8Q9h@CA9I}XeV$ulLjTPr6HEJ^*={|$nC<9JMg|6l$$t8#qWYhI82K`p#@|=> zdV2fq2Xni>nSw`dPM>VGJiKWG&$qt|KQ3SK$1^iSo`Hek^{)L_rq~2W@p%8<{7GQzKiLa!;~!m|-mj%^ z_|y1#>Jm2J`keh%EqTvgpITw_HEn0cGdI6w@!00Ff^2^Ys=1eV}2{@ zTb;#ez{tSBx44>LlYxPufPn>+T_r>qK|Hpj#t@z@gn|gVI)IFD6r8}sz>pAtq8=(W z^&j8M*Vos-RcByecu*i`Q;}eQm1W60F9rsNH-5=$zTdCEf9~P!{QbH|=kVNQ#$^f~ z3$RIT4Rw%ePqwtQJh{A3;}=d*N`v@tTlAjpXMN)A1}AYZfC#l|McVWepTO~&!_D8*Oxm;&7JL_)NyqF+LW!A zGS&9QmU}oqUEOx3S|CoL`-w&PrWsXbiVO@EdxC%dIVxTG*=>1x(f{t_pFXCaf4fUf zw)yns_>v88My%P9p;q$35cY3+b!-(g{CyA?`);_&h^Zlz&lZ!i}PDR#EaadmCu{(4BKIdmQ z4f~F}R?Y5He!On|y3-{#`?mgKW_Ym9`fs_Vb*E;S^}c*MwZ<=sBMv2{(qCx549DZgI`l z5^HIeY3ARbo?5c>_{!TVw#R)_H$Pe$e(QMb^eoNv?7xf*AJ!Q%K7IVWXd3TJd*RAo zU-sD;%b(k{@LziR$!Y25yAuCze(ry}{qxyh`tR&F-`+1c+hy^x2gTDDlypy@l_Z>U zqrXqXOL_Vl^^3EAs4elDo_=t~bN@-HGq=@V`+9!+uDmCfJ752La(~VD^DM3>yR80x zHshZB+~;w|y6V$5m#&;OioKzle|~yr^`=d6F6vHaKFRl9;zqZVJ;9qUGe*Jzw z^OaTqB6s;-s@`?5cJjWP`%ZI*%x*fD+k7dGF;h(9Nu!5<3GQWB;$W z*}qTU{(QWP)#UVT>c($X*SgVpZzKea-=t%|C~E> z+r{W+FhvaW7LCZcGWY#%d|aB=eYe%^QO`LHSW5x)4v8S`y{tp!KeB~ zh=|zvnzU_aqJLgK@I-KSO6g8@N28wm%I{rrE?uv;{iv>HDt%z(+Wzz3+{)_Owp_g4 zn|gYQ?U85q+jiw@r{Dg_$WZY8rNCeDqW?4bPD(GgpZ+`T=4D^onep+bzrI{~^O^_K zt(2E;%lB6)>ic~8^;O>L-3EW{rgQL3t>>yUH#LQR&R^Mn4V0m#U66QvcDA|nvUF|X z3ak5-%U7R|57}1v@#m{6cb~n9-1O(>OzZzisgF*T{QHtqS~hFx;+NNJ>dL~FsHd+^ z&#PmfwaV~$=fC433Lk%c&940LpmFZu+{O7zUVA&JB|K(TU|`4-=-qg){(r4?d;b2v z+eC`vCU% zV&L|hh3!`+zdXJDq;X&V{kW5dKTN!{d&cch|0hpxPyckpJDrh%p<$IR|4siVubzhN zsZ=pj0kwal-u{;idM`Y)qPTNX#}(PQ{->V;4Y$lMU35-=j^h8E#Aj3aelCCQ)z7qJ z(s8CuCVEm#4}a}B{X6aS#qneiv~x=&B*4V)ccHAh^$|5Ix3@uzS8zxcH2&kx7t z$&3sPJEHr(2VMRXbf`VNEaU&$7~e}rC$CQ0QJ=I;^U=A8L*5hhOYfdu>G31;Z1G|> zff|$Pp5IO!n0n&rEjOtIyGcKvq^joMHJ{QR`A@AsTy4Rg9^1-KDN3JB7Wut+esZ$< zqpi=xPiw#T-h4-+6-Pya{WGtKt>5jnld&}{aNznkYBwK;OTkuzcW z`bl!9etZgw^R@G2e(ciz$4Wl@s$w521H*%~+rGVTg<=4B~O^W?`l5Rgynm`B~9^se$xB*^A&H* zUaGy^w|>*~{z=cx=h~P|FlBu7XW{!Nw^i*If825A-?Jwv`Zl#$&#IU6GB6YzpR%Q;4e^S5hBe!+?+!q)AEsmIXLww<_KmWe(pC143)ATYv28IXU zRvnvjy!y0U_Ot1UhFka<7(Vp9lAZ7>VAH;W=G>6~a;x|*-`=lsq3JU(1H-#b_ZVNY z%hxE>|2!T4M&{SW=aF-_zp&=Hx_bZrzwbXiY?r@f3Cfa7%N>4gp8wb9->>WY)f_c# z%iEVe|9-yy-{zXnXU#udbeF%m6cjk#@2AhYQhvX7dd}*DlQvs_d-MDL|9yWxwA)W< z=a)ZK{eExybS4IdJ9$@U6t4z%-)@NIgW8!7+!P_*I1Ud+1_lESrXWz4sSB(G*29BH zt=PKX8PtcBiFz!5jGcjjp|4l58kb_2IrhI<7#JEBXaCvkFEwG8HX{SW2J56Xn_m4) zI3dS?=tDwmfN8>FIUcDM^B6N#o~x@D1glQ<@{%P-Mcg9Uk~U#cm3DL+?&p?PUmc$bTuo@?x;}DZGDA13HL(8R=4`tTJPt* zec#gnEw%JS$Oki5E_um1FH`7SB-c5OY(kZ z8%R}g&vyI0Gxk_vRsV+PYu2jW%`FViE#@uVqxY@geR=cKWtq~}d^h`#ysirPr(?OZ z`*98Pql`1tFS;ry7dPv$1}?j3UT1%-xYI4|?*!k6D^fokk-phKb9Mn=p3*t*dgu9@ zul=c=smt_n(TSSadrZ%ce{~h=nbz!7zimQ-@=IE6!Dm8#zjnS{d`;E1@unT`-b2~9mpnc5`D$`ed*1FPH`{k+ro9wB z9`*O>lXKhutSUNX#y7nz(e)CW&tG%a`BxvCKB`n%d`x!Lt5=cY*XM5k5^?VQ)_vW@ z`?sy%7}nNSwIW~nYRToFLBd{rzhnNLou*uHyJ6!`nJrtTqtpGY%P+qx%geguaQyW$ z-M
u)B>$HvWR{vz{j#q?Xbzo&jzxL%pGS7!ES-|shXxLIFKT(wPC_M_c~jk?vs zA8ju`it1mx(|5_1nzXw=>u1$p{v5VNeeslKyZ76!Tb8{vOVT^1FZFMRjbv|9=d=Cm z&hPhXX5U;pW9rJUg3BVNsohuE>-%(dPIvi{W7!_Je^%|z+0DMze6#QMgvj6vJ97s`pG{wz zo~(JX&3jg@#qqqlK+l4}|E!lgr|G`^d1X_q>eBoNGiPu8yCYI1(IAU2VYSa*mc?6g zUrf1He7n-vJjegF_1eo{YeTp4oPBw9+r+IUwln>FqffsVOB4QlbN;y}|4ZzHZ(IEd z>fyUGxA~E`+TMdROr&r3X03YN_xzZiX35^XTbKFI^iTd|_p8FckZ)4<%Hq9uuDrf; zHH1I+XI|Fg+E*JE>dL;gyYRWn@6u|^ZO6sR$$f>WuJrz5Gp;9#HVS=-+Ma5j*&p?K^&Z`OuBF!luC0#GoBsCuzOHN8 z8|LLbUv=*L*2l(6xH)~U-1~8QSMwY1JKM{*d|9-8R@=|q^>?=)bKxOJZS@_nzrgZ9N*kS5vv!kQt=Ibe)HGX`PIoI*R}K7rSAoptnjWYNpIX5JMRM5 z$1E*N?jvtQs@vae>dijBN?1j1vEM3Z&b3LOz0cK@PH9>+>-mJq z+<8l`yVtD=FPaz=@$A-St2xha)xJKpAnQ_gmh#q@vkquRsO_~alsI*1{*w5H>{*}g zyKY_gd)vW%Wj_1E_r7_NaJ^D?xm?ue(l?j(SAUv%%P#`kb0?edynRD6TWPa<4#pOHQG}!n*;@Ykt+f zDfn8slyP>q;?3~a2Gw<5r?-6jTz_C5qg|uBvaBJg?M#8y()Z z>`T;b57pSY^JfUX-q2zB?wJ0%Tg4Y3DWK|o?y98zm-*|a&n}s3p1Go(H+Ol~>Tj{- z=Y-sM@tZt*f9avCtl#-MpY8I|UuPM4Uwggc)UuiXHT>S$-ZWgj>~rAZ8cqLN-Oazx zEa%*FJekufetX-=1rkbE57-)Y&oU}iN!72PZ)SA+QS62HQm4M|VNbob{-Cna#N2nQ z*YDdjf7Y3>XDt~TF|%rfo0f}d7t8!CI{&%rtFe8o*bIp~f9I^xTE6`9ExYVfsh+17 zoZb_$b<~hreH1USBz7itY4Fxn~uhjdnj>FVnrbU!3J>Y3S9*C;9>}Zhty7OsO>D?unX4gum z7YEPEk6y0zdGBTO;+v-HZhu=jU1e_0ZN>GUtum#)e!ZX?KlkpwTJ!Bor)_)qZ2RNd z1<}!Emrh=hjec8Ma5`|^;-G4;u-%!vD)TJlc_+Qr^0R~q~b?=F?LCo3P*T0O5{w*5`xx<99)A30kTNS5qa`!;o% zbRl2fqSfpHt=vNbmNi^GdVkuQ#5UnR;WNzg7D!u^rMJ9*uKf8mB$u zcK$Eo{>@DPoq%x7(#4+Vu6!|4%xkZ`nmNCOZ>w&B`J5ST>(2A2z}v?R3=B8e!7aN5 z?Z~qO1Y341V9m-|zso(m!NaKqIVeM*6HfeR7Un#;a@&Ois-OXVPgg&ebxsLQ0FLB^ AjsO4v literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-coco-configpage.png b/doc/qtcreator/images/qtcreator-coco-configpage.png new file mode 100644 index 0000000000000000000000000000000000000000..ac48dcbbd81c6aa9f7f85f2b2a61402c6ff1914e GIT binary patch literal 16561 zcmeAS@N?(olHy`uVBq!ia0y~yV4B9jz_^-&je&uo>fiMz3=9m6#X;^)4C~IxykuZt zU`coMb!1@J*w6hZk(GggfwRCPvY3H^?=T269?xHq!oc9*=IP=XQW5v|u6K`ic-4)M z{gW1NbeB7Ode^q+jW>3*C2!1-Jn1CC!l|I>AXm_Eq(J<3+)YQG{4Fz8+@>W3W*?rZ zvt=W*%FUEJDbG21J~=Smb)Dd|WNNBds`PgyuV;z7-}ji#+W2Imkx=oz;N`3QL|1pY ze%dhm?%)5MSJpnS44wG(;~cGT38@?m3=A8VyWiQ*z`$@Ijzfo$fkA+!QI&y#p-Eu_ z3j>3LfVKUe$$xhL{^bAv^#7^(dq4lbGpSVm_lNnD_4Q1iYj_q^@f62IEoyqfw$x4xd?0B_lb_VT)y>uYZLmUgN{u5odH z{MEGkZcqOGl2`87P-&uA|ZhF+dD2DP0d;Wg^;L~=} zgKc-cGYdmZF*~Qu|D)^wZ24(lf8qJJE)}U=o)X)a+9u7^73zFeEPRQHA#d?s=F|Is zPk*;#We?j_{r~sOx9{WM{G=*!S>BHgW_!%!tDW<|&YQTD?`y8aq|JvLE2SP!<4(}J z9JsI7+$H|zcC(WAYo&ds=PeYrIiGXe>z~z~S^T!<&!%sEU16g&ZR@twrFxgM)`zFZ zn()U?^GZ4uF4KI>YQdN2arymGKcjB% zisP@hoBhsi+SNU$Q_ohu&MvO4>hM$P^GTSwJoMz^vYzdB+uX9N85#Nxe&1QIEoW2l zV3|?*`)&3Y*V=1-IbWZuQvZIwZW)Kx=I*$p<;gSGrak+AO2=QlEaNPj&*PP6)Nfi@ zFUi<`k^9`0n2;p%E$QE89@`YLR^?Ln`4=I})W0U$Z$6))_c2M8J2vmqHSVaGn;y+w z6VE(uUGv7x@~-*Bg(vG5vTm%L(S6J5^NMxe%atW(`fl3GKjpc~w8pr-kJlW1mS$y^ zE3)<3^5~_TdVJ)Jr@JRdzYCuJMj|U}Vy<}XwLtdW`@)uW*&W}qeqGhiGRuFv_Whg_ zo6m2*;BE9Wwb^}77k!MFQntE3@7DZh7wh!$>T}GuhyUHo%}^k*cH_c-cLMJI{r&xJ zi1E**|3fPOe#-y*?p3{gP5M{w{aoJ8sc+0S-dw#bv2tSjy6#D#GykeS$^3lc`plO$|F8YI zc6-G}-S2C?ZRhuvu9&)V!@hO3_VxQxcdd@w*Y+tY`s(7fHmmYyZu7kS;_JQ-&&t>J zuh0CMG}Wa}?%vKt`m+!Is@wbNU5-A(fz+2>!p(P*f9n7Hef^34z7O`_B>uhgtTsD# z%W^S4myU{I_}a9UI??V{Tf=?7m+Ke1TJLdwB6(UR@>I#JS!pv*8QFcT%By;EeYfuG zb&LLnTsPeNw9IZA`-FL?ZDdbv&~Tprxiy)a!ThLS<5Ir*>!$yg1UyTY&yy* zt2EBa=|t>q-0x~L@yMU_{CoDkd*cLC_13)1oHnh#aCOJq;MHoEmCk>i@79^Jsla~r zqirY6PJWAh#_xHf`uHcCGrJ;nelm+JPuq9qcR;0-6ia4-!5uUE#altqb+^r`B+Gi) zvb}1llI+VkW?z22YI^?hib)PAItWO{`rUOC@3=EC}Aax2HOx~c1$}xeHfuTWx zNKG9Mjj39fFFLR>f0yz-J1INOPVcn6#OXV_`#xS;*~6whGj2CC8-v5UY@>gz_1etu zO|AZKi!Sf3`T9NO3-^EDW$~q-!xR1=xWuaVGDUUu)atpNbK;ku@Of<@HuLGzc$ZCk zHcosRbF5B5(l=#e)CrZM&kPJP-u@n+UfZj$zJKkyv60RHe4`(SuHV`9+Ku_C9b;1N z?(=`9=+ymQfAWcO-aoE4k`c>{Y<*KKqEG6Sbx+|8Q~UR4WAw5~ZWDR#zS*j6&%p4Z zCMs?JzbP*9|8BjNY_t*j%{uMn&NG)I9<5V2^DSfA;U~$}Et?m9&bf7Q;forMy_@{) zbmo5D(tCVy(#@KfW!4{rKYx?=U4B(=*Rn0XtdC44UOx8m!7GFMdA`N>)|nSX@vZLf zGTD7i()M-C#T(mBJvIG)+wt?Ir?dRDIC^Y`xG^xq%sgM?_2~SJ z1D{Uk-QyFU?)>y|&Caj6Gyg@^#_qj-VSf4Lc)iP4YJ=XYmVTbP@Q2sE^)s|r6=lxZ zA9UM&`fIcM(_BtJsfv9bf8zW3>882Qr(euiTO56lagEfS{q^^Kb2oT|1x{HbmREK+ zCpGC@s7>+aU3*h(0!=QE?v?_M$eT42)VE9Y_|wtLTwzGZe^+ukhu^`1RipKUMYXzlkC zw`OE0xVdjvm;e9QT0gsHZ@m|#`v1lKHIM$Uyu8b9zS+J{zqGWro!{2|EdOTc(yCei zYNpNmv-tYv*Khv+iPtv#>?&3EuRitqi7KnK*llyYAJ4DZ8gXxzzw2I^yQw+rinpz^ ze1CS=qazI8BbIF{nVfxTY2@>-8MhRlg@~u`ZTY;j`_|e0r&Xluw*B5AXZn^=`n<1L zCEvs&>i5nz9A!3-%b)j7e&?2+3?oC;0<$HykuUyE?bJEG?)urUC;VpRIpmzW-KBEU z_`20Bndz>_Q%>*7eKlwE?=4%_rhc-TJ>&oDl-k&CyG*mG^%;l!FUw7pi(p__cSl(0 z<=?jWzkNHCYNH;VPxby9cjV;reYz{Zy{Y~B+UWnQ<*7xVT(+&-uCDU)kALd*o9Ab4 zIa~9`a(dfb^U7OaO!Kd=Ua_}1{>QA7->q+!%{q2+`DV}h`D*d!s>MIco#);4Dkpd1 zcd>8WI*Wxnm4!vVtxBBBd1KO2A76t>e#6JT&Y1p50$od_L#%VZY{zJMEdqpL>1JJ-NbmjHi{EVci^F345i( z+BFlFe#xA9v%Txi>(6=%UVFE1*`M%;Z}5u9p14@|HA z%+PRt+k58v&8MmT5hY1#&vxZReB;_xYx3aD6Z?YXYO%MMa{il~{A6yDq1$zB+O}y6 zBc`0%>8WFM`&r}XTi=G_Tbnn3+qSD!XU@k~)xK*DmA?E&%vWraLEyJdZx*pK zJm9MFJ+}YbE*|^;JvY2>r28~vPW$;i+He1xs?T@!&bYj_n#W%0V)`DreX;T^MV0H9 z?{8f{tElD~=j1-W>;pN|%U-Yg%=p$`MDBdo!^b%pH}?3snxt*nTkvn!#h6D&b*xW# zF`M(Iv{|j0b^6;x7x{?7-=?LFM}VI);3k^24Z};o0?lY9H6{UJyKQLg&nF_Wmi~ z&&n4Wp7ytkwKGYcmb*vJ?9?YQ{l91Jo0l*y_#SZXdEF@&+4brCk7^#?j?>S{-QBg$ zO8#8J(#Pve`Q>aT>@I)5YiG7!`&##vK4G>@OQfCWKbYsW<-vDNMh1t7*uqD>{5o$9 z{u)g@ddT)fkv6FG&*OhP(OII3|ApFioefv+hsbya-FYT{`c2r^FfCBEP$02=*Ktr? z@v!7*=WqKx%nS?+5=7P^N8+oxK{yt6l|38l3m0@6DShw2#*JArg@;@ia7Z$(e`^Nn8O9&GK!yO*p z+TQ5La>UkFo09Y%AM{wZayBaigF`-wqhksaW}YfBnQ%~{y7zhR=~+7xU;hkoySMFS zNyr=PRXv&8m&~5_yMLMYc7yBNbr={Jb{sko)VvMUWc@4b^lR49w2ho1lOL|xwI)>S zWXKbr?WWS_jx$?M-JBC|Jb%{INSzy#rn4-|%fs$HHI zo^{Q=(tk9W6knCeQQVV`6pM{CYAlDoc))P zfuTTkU7m)G)kKR~r?))aUc2a|lbEN9_wA=UmT%j$Xd%yKmu2g?P3AsxetxX&6C(q| zf>&JcH}<4#nsL%VQ-0gVy^}u|8rplcHMT8^{xm5f?cF_}*s`o=r|(^WcqC=RrH@Z% zvGdEFxVyXjZp`ldy3eyeo%FA}be55U;lZw7hwcA3|GX&wH_-h0I&Hr_hrm&GM+GGc zK&g*`ytW5f4VF<&lr;B7LvJ+nsL*SmM>2XN8o|fLY|aX*Yu-$B|Mos#W(|*dY{iEM zjd%7|Uq8FG`upATr{?va&7ZE_ey<2rn-tuw`LbAkYW&};@l*M0UpVJ^?p|k6xE|a| z+U^}b=Y%bBy(X6l^QEia@BRKnJN{?apPTdl&fN3=-|sxlDgX4YEVuirS@~w;@jH|9 zwmdC-WbrQlwiye9%<|@ceM{pU{y*UV=TP^ez3#+5r$1T0eLo&#mp?K8&&l~Gjvj6O z^Thw(lVjXkxs`J)`hMTu#>>cX{PlwU$v?lYuaB+!(Ow_%?#|A`tXte}J2Q9t*L|A2 z?R%E+txpz(GT*o7N;5I6TfTRF)vxC=_TM)4@3b_z$i0fMGtVhn&b;sOzhB!F86H$| zU7Gvp#p3>5nkE;&y{w)un_IaDWYaQUMuzMBk4uocj4XUQ=bwJL=>E1K{GXL=`RZ+p zUfSsDFU#AuUG|%`{n=B$zI0Dorhn@4(SN(ADNf10F-`Q|zo}(=kA5mXyLX;lN^{A! zpP}<_Gc?S8#b7&aqEB4){d?|9*KZcy{zGFX_nOXYe&>85f-@F`6dkH4aC zP`5z*BzOFr4xf0Fg`YMWKdt|@W$~QZ*O(ddy1hAczAk#q`#bY|FQ0XKvD>zNwL7-o za}J%o-MQ}Pg-4fkOZJrZ+ePjFkZH9`XKH5PzP@`K&TY{Z*p%e(f^_cyDp`c*R1 zFZtA21Pu-Yl%kW^Eg+sziyuBdi}D#;^kd^e3Ac8XGIII@Qd4STlBJ9|I}-B z`+TR3-U;n{d^be&Z^`-aX9`cQ;;vI=FTTB;Tvr!;NWZHlaQo`-T@WwoX>PDN-$#}E!=)5SjaVwKjh--WEba3t+}VV^BUtOXum!aQ+~^K>$22Wp?8j7Gn2hF zaa-#3f3deNy$h8;{5GB?_ht7o9^UW9Ru|9D7Ja^}mved7y}i!z?&eowUmi8iw6_(V zIc0Bq>dkpt)mgu{{8fuRzAXHgl*u#3dVhj@{!G59_N98y{b$ze8#7p03jdB(SigAh z)P-gF>)9@=ov^Og`gZF6^0($Mt;}jKT~EF!Y5)!*T{i8*zT$E=6$<6=@0Awct$SWx z=U(?~dHt=k3(vm)_wN0v^MB5q-?1}o%hRV97_#Nwf7`u4=J?;Qna&IcKECP_&i`RM z&7qfXYWy>2YX*ipO4aPstV))d|5+S+|Jy=c{*$&bi=3av-+8OvX3_V1aV*1wwAiDM@$b7%PotKf}`sI6#Pt)yx zNB(?fzCTlc$rrbf%<4ZM<^OMtiHSJ@Dw4Nvkwq$2uV22$|9-{yd)5AR|G(GYkF$`P zw0rBm_rLe~+kNcxKN0M2tJ-h-ZASF1-fcE^GRObEz0}6g@c4?TIvXcwwxq!NLx=?f z0|Q?lxay#Gli^5QXB--YFpxuU)6oj_7>kf zzT{`k?znXyY~q9$*!I6F{-ZWW{y^C`E}h3Wy~4C>&#FxGnB;1b|?ndB>LT=azAQRh6H7 z?DN}QJ6C<);n?xbX4(0V(uH*lw-YsF+*9r3JdI2oQ&qW)7%wFy>DBG?@H?aStax|U zOfRb|+)Le?btWJ4{J`z&Ey=ewXntQ=NAl*YyqiBd)t)@Q>`Ikge}BkddsgbcfBSh~ z|IdoYzghJx3(ns^?Nf!;;XOy$BI}ZcBSgR6+4b(L)h=7Dmp@W(DV_JKy}iyMdP}@= z@swv1RVIHcI3a(j?+p95OEm?*pDp7}5)KHhkbn0wHq$n-L`ph zSn0ldda1vD{(S8JdSBV@Yl{EBZjw9wlQG76HQV?1_sfH8&xUPuS)KAQ?d_g5Dqdk_ z7j@z~kECVpJ9qoqn(h*}?VX!-y>xH?+IDOG$~n28t#V&YSibgW$SZ}_HCL57&sc4b zPp-VR=6U$F^YP0!TVLB778ZOXbW7>Ht0r1s*M9hZ{#$0=ezB-+f97Nwc4wEayi&i> zYth%D%*tF_sms@ks-9}y3b}0b^!)X$Q*+ny+27gLbn?yfUoU&P`vbwf$@o5^fsh+k1TBeZBXK@6&11 z^X(SrM&A$nof~-0w^YN)XdQPd9gZ7O#!Dx@%QdZT8zxOR;tPZg#bOGMBv`1xh;cHd>#3Gpofh*4{sz3uwL(#><% zx`l1`w9?8G-ryX1GHLI=Z*g}2_nrA#Ykbvc%hKokotm>i)D=jC5!eb-L^5k9IOS!E^fe~Mi;XYb}}iR$gW+t1&!+RJ-z_x0e{ zwkE9E{?@zeON4f_{MmB-)z+hiA8*~ewQNrA@w3Y&dI-&~-Mia4>h(33%P+G2pWCzh z{P}NY>)x+6+kW$wQTVmv+isMt_`mJSb-(Aw4_qnDyT@=e?fK_VWz(W=y?#4s`Snu0 zsk2_q%B^O3&R)P9TbGb|uf+Lt+5BDA39mroF>1FqegB;U4ioE(UoN{Wdlxm$Z@Jp` zRbG`fzZjp^f7mKoczxIPoh4_U#~x$Zc3J7ds?5`y-D?jUh&Q^ZSgySrouNPFX06ZE z9|tceEdF!BOnlyosDD2zbWW!P#R!Dh%=TO(u4g`foo!*>i^5NOIXi#tTNTwd?Msiz z{R}&^uN^Au;%;8QwC&}**^gB>f9lMu-WavtBJ9+H%nI>?O?4|RMJ+Ece>Jaj+vP6KeA1YeJ2x)lbamWn|L6I0%e?Pa%L>=KQcY05sswU#dec5FJ#wRK^`sSge2PcCd(n}7Q6 z8P;9N_w=8)SylXW^9)*-t?lpFo_^<-M%>Y(7vgN~laKGZ{yM^U`C`9Sy63n33d^}z zC;P>2ms0)bQ(Y6bM(^d^67%f#{@H=E{CDQxOpDtsp1JDPr<&^A!`pIqoxU(9ZfQ(m z(zcVg7b)l7ezvtZW9`1a?R)Okne|3RMcLooXAyp9b<}pd+~gZuPJcO7x~u-Jj7FRJ z?910S{rz;OO_3txlR>{s!n){RI>wV=oskhIA!nPT`|N3eD_I%y{ z-d6Sv$yY_y`M%UYd$JDRpG{PL%PFv&=Iz~BhVN3Z%O;2S>Y1pkuvD!bj?2N7x%;{QXquMy$w8Q_{FUswEl$X235vi zSx|?5!O5`tOM(mx3^&A_A0qW$2@X0wDA!?RFt}I$zxL<3@_owpf8YE5q?zBYz&n3C zXkg$|v;B`|a8FtFZpPu+tKaW*NZ@4H@zq43>hoFiryGyUZ5F?9FyXw2?Bd1)LJS43_kO(={po~q|BVKYP${2`3qL;g*Wc02bd$bU zQ+tl}-9{FMJ5}%Z{a*Jr^RN}KNNGm3@U0KeUKi_uJdj{ea@*(j()SP4aw|4}wG>C0 zv3>ARmf^tK^1?zz`QJB=--+Q^c}C6n^Zy`|d8aIjjIW>BzVEB<&f@2Nv$MBdYkTRV zw%LpOM1_^vfBP-mJHKD@{`9GJcJDExw>dw)CNJ%KTd{O==Z$B3KF_iF|E6_MO4>V{ z?|Wvxv(sCcYb6evYkr{c?nLo<|5Pheec^>mHh+Dfs>3@WZc=rnL+Mn#cQ+3lXDf}W z|GaCB!rMpp?yyW<_trF6_(9mC+hI~avLZJ>`2OMe>iyl-`ZujI6fA51MHZ*Y>Vsw- z_;kB`Hhc<@lXJdM&Z#$TWk%@xJC#P!2`-OMzgW9wSH+JDzPX2Gw4*OPwvO|+d+FpQ zz9GIWKUE$yqm{S!Fi-3K$=2uX^}pR(fB4Y%cPBnq=1>0iV(*tty!$rI+m!zFp|}3Y zqnqQ-&)a|g);Fmosg)U9rY)17bpBNMnfi0b9^QYOV=MBGw|PD9^{`h-FD|_M>>PRP zVfNe1lH6(e>DRB{K5%0C?wdiS8M{y1pY}3wW}V{wdt0;T_1|yX`?)OZcKGRlZ_Vp; z&2wvxZ&`fz{8Pp6ag(NZ71lbR7F}BQyQco_#Wgv}Hx|~MytFny{km=B>fpWq@-pN4 z_N)Urzd%**$SI!Ol)upPCdE1@Ot(zmRfBMeV z_}7#5HoyH8cYYIZ%!cK^ZU4{VJP>!T?Y8!pf2Upvd^_rTKhB%i;Os`DpEj9H>o@WK ze)jfB<4m@cb@Qe^xVUuj+r_!TzG{eGyU4#%4;mG>vT;OVyw5R#qx@oR$M9B zZvW+{uJpUpr_4%oK{?}q;|}g^adUhpM8wSUUGVt=ztvgS+idn$F>yKR|7w5CN!b{7 z`r9?x&bG)4g*he)rR5v%P$NBi4F-h7_ezwt-S|C$+pPV(BG&i-Tea#glJXnsQG(%f{_ zx_1k&pI%|oaWPKm`=+}-6K!5^+r6XQUoMPk^0K$<+czCQd*$?z!@o*4v+1b4T6gs@ z>qPODoLbW-9i6IoqvX4n7-O=xwauOrw{GkgH|*B^+L(}Nkdj93dsYTridr!9Vw{fW`;&XW zcnUw*abQXE@8r_L{Aadv=Y6-kXBfJ3f==1Vs;Jle*ImxrrC*Dgp>`q8UYO&Sf_}Dm zZg2PW_o=p7Ubk0XQ>n~PSSoIC{buyb&Ust+PCFVyGE2czoVQ z+5X#(bN45zv#&q(=AO0C%+&KP%$22Pll5mlcsy^P+$;qxqv>Cc+v~jF^Gmhz>B;9Q zYd%loJS4UKdUl;Df8`I=pO>cZ`NH(`UHN|Pe)~M*%%|HQ-p;=>`Q{t%$jJA5wet7m zo=TRVRe5L1*M*!n?oBX{+pGTn`P}1g>-zui$P`}Na;^U7swLw2vtQXL+yB1P-+A`y zNBPaU+iJdwR;uPVf06z9anZXzPPxSggW_tRica6oIf3o`$#_BWn?d((ZC_|J;7Po6$4zW?^^{5@IMpTC`S{(k2?;p&LH-*)}8SMB+{EAN_B1+gu&yTw_R?h zgKD5#&tevUrh}cUlm312|9>UUMseHsj~CtLr>f7ZIP~u}dv1ksE~J)XP~d1ggt>wg zl*fo)f5agWvCK%8H^rb}{lzOffyI*iZboO*`dp%Cmg!_$O%2=_A1*chg4one3=9l0 z`~EU{i=SCCdFqS#GTYZ1PyDqs}{j9IrNCzV&D6G*$+Ngu8N$salsW zyR>bddM0VR$4rLwN9UOt7#@V(u-)KuK6TzPp?of->9Ou*TmYkel49B_cJVCSz}h>TD@8Q z|7LqFy50XjF*mL}N8|dnw>N_17#JGl*tBK$udDpKv%VeK#$yY0kzIIi{1dbXMK=RgHRKuHJ{h__X9}GmAWov`!~3zPqmWmCu6NX||=!6Ybv4yU!iPcA;#pXIb#qs^_b} z+hxsqX6n_ZCZF5!ZP$^F|2O#6?pxot$rR+P1@o`9mq+EFvJv~nI6Fiwo1ZyRdy6sy z!wskKIXmL}pNh`%pIl@iYrR;Ok-fw3i`n&5b-~vTe#wOD(w^_}Xl0>F14e<$N#a zq~2Zj_4kblWpU^JOwBc)UbrvEM6~|=PmB9yDszvXy}e=E|EZQK((iSqzSPJ+ziivB zEph#qZ~WQsH~o6Q|K&{rw@wu#ysO}IOa3`~ZSI4ub1O^tPH*1u{Ey;ycx7_Hw zvUl*iojW6LA9a7Hacf5?xCBx&SjA%fthqkvx%pcCqmx~xh1aO=nPoKNbHNN>S!Zb( ztJb^{3zLP*ewxRoefIvmp6$-Nro69b zwo5qO-?m5kR+5R_`mIL~-n#KkXzFj1Ww+aHk8deIa`t*|)cVS2sa<|5akKO}qf_#Y zR`6_mo*Qbb_H#nQHDfcm*E`pqmim^f?VMZ{^{1%*c3YV3-JE?9YjgH~UidylX!E^o z)$h$tTv{XZ`qW0*nflSGGqsOz3BUbgZ^!GGnXy{)1#K_S_q%Hu`DXFy(`F}b6?8wo zwB_xzr@3}*cE0DMuNUd9iPk^plYcej7}UGKczNujy- zyz5QoR=xi7_Rg1EJFh;OabEmELm2P7`}^N7`xUKn@l=h{`bn)bXC6(93Y$1r^LZ(c z-fYv$Y4^^3i&s&8IggK3{eJmv>DSVi=C`)Q zeg1NN_Rp+;xAuK~{8;z$-|n`PSHEdqI@1?AvF`D{W6O-ztPPhw6%xJd?fkRXE`{~} zOn>h1?NYHt{JP6O_gikSy|?b$oHL(SJPm&`^=mV<4z zzhtMssf~$UwoP;Wd3|@gxlaSd()X@;{quR&(-ku8@wWGUpJzl%X8m5Z^;7Bg$cdp# z*X({XdF|~QzF(JD?OW$#|NBpt_u{vAKFR+6$@FHqwja-xv8&`&#bed445H_mZC7KXu_eCsgYi50Y zV)m_|?3wlS;8;1;BqpEj9>2@J#DCANoO0va+SixG0&9|{KYjh_-c`Nb+X~Bk_Rcff zn%S}U?d^?14P)hB1Z zrLT*9o6G+0@5Sx8*D79S#{S8DyT>z}dynE@mGxWp`^Ub2Jn3uO@9lf0R80#vm32<9 zvzk=7M^id98F^Pbnu zoz5OAE$_EUULei7xY7UYl-p}J7{=e8_bdNqTbajQgZoZ*UGML$n(|xAb@HaZOruY2 zfz~s+oy+uIo@O<&x+6BzVdX#0*|)dU^;+s3c6npFc^YTe>+6ia6K$_#=LIe^w%jUz z=UMS>L&xyIYttTI+?cEJ@3Z^v)ODv^-r=VC zF`I(dBK~irW0;qGYA(;ye-!%6`C7`{WobLPjl6%d$Gh(f)Jae8tSgz3zu@NftBcAF zXHL5x_x$yD)32G`d(3z4)2orT-qwEU^~<9BN3K_OS-Bd`JYuGyfBT++{DGTCa}HOX z-7Iz`Ox~&^#lqxmZB(A|e6>lle*HAP;!v6B$8?)-BBzyffBoiD`}~&js;mG49EExWX7UEP1ry85ntCC$fv2cI&zHf=Z0+4i)Z_in3qU7J3=^7kjJ z>z|9BYHO!m4}Jae)=J&@>iP+h?{4Ypul{+$Y~^j%o4+1~W`CbEec!&Wsw>lOhsQZ+ z*GPx==WqRY^xy3j+a2rn2d&H9`z-SQH97D7yxGUE-QO2f{@!jyRoyn;Ywydm?p$9r zb)li{`k25yU7z1tU)uV1Us=xIUC;jf+57l?T;QkoIrn~U+;n_f#&n&t7U#|f|DUJ7 z*#CCOv)$KL-uiRx->=O56aVYVx##o0Jy8oYBRO(YEey*0co6L+**{aZy`Ss6 z<)hxZM>}L*$?Vn%FVXuhv>>C#3{#yZ`2beT4*g2gcJscHfqD ze=?jSef=zN{$_7m`^MWZKQW)KNYgL)8J{-ey8Xed*ZFI8ZzZnf&2I@=w!D+a_dy6} z+nLsd|E{Mz@>Dvlo!7it(^+NW@5>6uFR&f&D7z__%a$PD&Z*O_xGT_XNzU@S0?W*g zSj$h}n`4#RK5y^WqZ3MOd-b-~nk~D$r8e*7+SfOh?~J)M`%&)X@Gbs7OEga9x7SqJ z#A%;DX0~VDrQ(^(Z&g2f_IgWSV@qGxXDY|Pk?*eYFnBE~-S3_kd3axL zYKG5w+0`|bGb?pb+bMF-@8wQd8aYS0&U#ms-}BU&+Rp>lZ~Is+c>VI_T}y)RmhJws z{PLSQdfzWTO_ff`-Ep)q^H$mEPiFGY^Orqen{6q6ZSC~r;(a&m=00EXs+ebcmT~Nx z0VT=A&AjDXIHj zr`2z%7keH5Inr~=4AWoV|0r9_zxLX$=T*{s?p0l0?6w7)_C3(gznwO5jnZbD^V=ux z&%ga`>(i;9W=qYANMD*fA#7i6V53ji`ixM`N6Y^Fc`N-YTHinJ|GnIbxf!!_tor^{ z8ON_(FSk7E_wUms|8E&a-(K!vZ2ipjSMP7B*{3#ai_6sr&YdauI%nIoZCPjRt<5)0 zudcuK)N1bk*~Pb?zs)*-+NM9M&Nc3)UFyDnWm~^&(fhZp?4Evb^)FZHoEyvU7oN0R zzv}cAv!`EwK0UE~v(2eTYo?dl{*PHJGxhO<)z5dol*!e0&W+z1w(p&p_NG-+N~hOu zDxH1au|DeR^{Fq@=TFbg+%h+MU$T9C!|Cgy>T+coH5P0BtiAel)7#q#?SG=9ADi!4 z^(AKi^4a|pex&@(-($Aq^3J_QPy5g8KQ*m>U9C~uYf+gVq1kSC4KCU4l~bL2drG{> zY0t-9KKtTJlI)7k?9be_<@EJCQ*Lu!3W>^^arNT==zWDchksT+-k4!xGF`ivN846p zneFsiJxJ?oa(bpKE!n8YbHs>-$sx znJ-PAdDdmiaewtyCuhF>yx%Y{-`ZoV)Zg1_z0>DiJ9_`xx!EOK4@h6~|K#=i_m!`9 zdXf1*mVEqsar2&4FD0x#U!Hj8v1_HYd-~s5TV&X;&U)WgT;ePp-j{gaY;)$UvXieP zEz`?x9DlWeYcx`${XnfxeKKyt3N$^#uQWc@{IkAYnL>+ScFvQk zo|SvkESh`9zh{pp)n?w*UVkn*!!G-rn33@M;{~sOZIx-~eeQSH?s@rov*Jv#<#TH5 zpMjf^x~1zc==a6>FY{bu(Qo>93s2Wq?#PYn%-_eI0W~L&KR(5Lx@N|qZ(3nW9rHId zw$`0^QE(u0zCYXFY5P1>jO4YR_TIiU&+qX!>3b)B+I?$Qzr8%_oloWBZE-v97M#@k z`SVWQ;v;X8o38!g&Z(A;D=yn{JLXQ;Hk0+ig1wuiUa}sjexWc=SHiNI(bvf^2}?^t8QH~eSS72LvN1r=lt@R zo!8iYR>m)}{`=iXwl{U=3(Lu0+xoN_ckTSKG*W;1w@>`t3qQ@v-Ml&W()EVJSN*rY zt&KS|ecDlz`VDIdT2g^FQalW^L9v`^eU6mUqs! z)8}T!ehbWfzF_^IN15A=UrxI{_2$!=XE)W9hvLSG7Gqu$ms1o%NJ1on<3z`vk604X(|7EhUvQV zV*fgOV>AfzuPm-uYk#9~Y2JaIDfx{j+ZQs*$TX@JY`K&F{AEBQxIM7rS3z5?Devzj z>#z6cTuDs5XMZ47GGqJF*?Kk=9~|D@+xz+%0|P^YPxu@U@Ej&=4?XTy0k$2O8Glb( zGcYhXOy0JC&t(bFeocnkNgAMrh9hV$5Wa&#;nRP{i_3oI-ivy$mVtqR!PC{xWt~$( F69Bvei#=yX^O=aVL1_lPk;vjb?hIQv;UNSH+ zu%tWsIx;Y9?C1WI$jZRLz**oCSB9KB4DzLN%!)t(@I#XG}=PBX?KD^iwi(jCU(_B@{h7<-KUxx;1-a?&z=9d*W>( zwfv^Mt{8%@031i9y(`x{&xQNlJ6zoznnRA zZrAVsfoH$`zL{_T_v8ELmDOq8vu4i@=Gpo26!+mTFE78mu`#)FySSRqj0xetudWWi z99w>OY4AnwPFv;jzB9=Hxd1<<;`-huWI&9$P85_{;KX z6*lvBeY=%iYR168z|hu}dwW};p^X#+1H%G?4mR=Er66Gu1`b0828I9!g(D0M3=WL} z3tu)iGR|dTU|={9&}5keQhh+=@3-yyePhe-mRd=knYFKU&z4sq74vp};M@xea)!y< zwr%?$SGZ4!2V`QsQ*Hl`>%WBr5*Zj67SB7SUo-Jv`scK{r(90$`*3vs^_6d0<|)^` z($CI(aG24m`i;o0*T&l~CX23q*?B@goL*`C0KDVse?ssk0stO0)O?s7y z9x6g#I{j-7MHT&=={5P(DX-OkC#iau=rJ%b6uhcBFQHwZ(^7K(|V56 zT|=?%`+?nCvcKm=S^VVsb>_$Z#nt!YeE;97HGgZnuRpA2)2wBEw%zMyma*1W-BEve ze7D>p(YfUp{L5{9*!|@$+5Ra0|Mz=vaq-;~&a+W+RWGnQO$UC4PD>|2j{1ru!^8?`PK^_j|wn z#q9jOe(e1+i>80iUuJyVXHoHS-{mtOrw5$hc=yY-i`zs0Cad>f{MgukWtY6tj_-Gh z`L}N0{#vHF^!2qse}8`sL(z#fe?A`9lhIQDs^80L$tldLbK{(AS!N__S2)8?%3@)3%JZ++uz&9y0sP zvboPTe$T_H+Tp8mJ?8yPP)Ig2Dd%enN$DoXVux++wa%S*4z6fNc+j( zxB2zAxe~qSFH1NzKfvVk`@P@eR97f{c$8cJI{JRl&qt}=wUV17!}%I)d-UY?J@Kvw zC0_x{$|LT6a*N}>wJqNqo>O$q;&5@z_XBdb$_wP@{`kN$_s@$Zr=)dum%Y7|eX!#K zo1#;0)tN_)-nEx!i|YSgIz28ZRq0aNzK)ghLI3-#-(ApLWc_|maOE2{B~S_DX7;UM zi>=RG{)MeSUbwrzT+d#9QT6#B=BaaQ8GY@Nh5latc|GX=N9HS^5BlAzEHDrC**if^ zeul&E`_>M^-D($hJTflH&foXvss8E>>&2BSy2bUcY1SW!o+eNf;q(4l%#qV#g7d7) z*G-+idPdskQ;ZA@Ju-KS552Q|9HXhHt9y0z!6iTLFP`gvvG05Ji~Zt%TFmP9&eWS- zXt?(8>#A4Q+vd-^bI~XNOW6f|@jo->?c3BDcJ?3R-10}4O*4povLeJ|gd_8aX%rg03@wX7a^TY0dyW?2@eox8Q5rQ+_c(v_>%?ea=* z%sJ7i;cw^a>T1Q#z+m@J#=5NM+xz?L_gLHCtA1}g%c@js>Xa!jWD=B|{v2eNztAIT zT;gXDSNAh@&l*++1_c@SKAAu#9;1mIjV-S~GlD`x!6f-u&&BKmeK%C^TNXnD{=-*Q zP~bH198!L_EcElTRX>@wo{2tcIqRC}%Rei%S6n@@M08SI;*vWh>t`J=eST4E^<*2v z?YfU&#<_l8W0(4S`GWszwgiM;l*#gV^+aG&&Wy!zN}H#x5{sQAts9yqfAIIiJ8`1# zciKOE-Su}z-}xK8bvci-R-Sqhe$4*3ZNbXtFN{5Ti_etpIg|N7ruoai-M=>Gp59#l zy^i(jcZC!0vi7evWSf(Gl5N)H%RiUD&5b_PV_LvdsrZ+5zVm~}UQMfx_XIACE?(*P zLTSN1_c`+gvKwEotDJwYK3?Bfr*zTAplwYnPM*ovUYzG$eR@UDY2%|CriRTGYE9Xg zx-kBZ%I&oaH*J#2s@~t5b*iM$(ekRfo_f*ZdBO3HXKMnU9yoQ$r|cu=_FBQ_Hjnmq zi<@65?K;qWE@e{E*=OHoX)gP`_ry}Yz!s&symHC83)`xqmv#7wF8#h!*=g>c-5Vo% zCY|()J-J}%QrD;2TOw3npZWMf==tr|8C|EXlGEypL$8FtF5K{UP43OlTNj)zQ_XxN zF?;Vm^MhsOZ_5QHTD{tEtKIgwQpo+p`{`nTZR8()Qa^Tld29bnF7gk4}T&fqy zdOg>32iv*wmttbU+49ztr}Vg-cs0#+g&&u8MRd^h6RA(w^v$ax(;u!`x16g^BV(KN z>7493Ev=5-<^?&{ZlzzJ{rJJAtn}eX-yR)yc;2g3p;j@v z8#WZ*mD(M}ed={t`}VmH3(}`VJDm?Yzrxr**Iq&9?bZD)Ti+^{$#-?H{_1;5^4^&e zr6bA@H?4aAdPDT2S4;Or23DrUz1^yQd6FJKk9e2DP1aLQuB((zG8N4K{_XCGv(sOj z&q&_Xnr-YEq@ExCb$V`%td-_S=lCyb;li#M591J^L{_gd#$v%_u_U_wV8bdvir~E?)WG*KRj-kuF8G8w~u#hv)TSOxqD%Ye30

1(a1&}%8J zhh^n<-pUjHAMa**XPvHr+}q3b9&C?}EIN?R5HIjm^sLpA=btuQ;as0I`Hk+~<$FVA znL$$Tn@YqFr~zb0iJ-5Yyf zFhs3dwc_%ptYT-*tzQ);KB@MfCi`uR^?c{6Hf6sLx4Ulp?3^R~X$HH}bItyPHg#uz z-3f28cfV|L{

Q%TWiOd&ai9KRHlu-S?7jpWNl!&)fHV+&OiAk6-im(^;#FdG_2A zn18#-@ASrJMLVBZzpC*6^D6ya^x-*{e->o;dB6Dh^Imk$wg*0y0xQ$BrT!kzc|Pa- zHs<${%Z2ax2P>?u{8RXQa_XdAO4%=-oV0LtP0*HJVUx$7EZrpCTbS9s@|5nKHv4N* z-+b0R{o`SoZW82Nc_-s^_eRN=#*Tr;Cg;Atck@2j&R%&=usr>v6tCfw%3JS5XD02L zvG-Blx2~oAVgEwnHU*|E__e)q{~bs3=PTJ6zD4oomka#(x_^di+_Pz=ruJPwpRL%V zD9W_9$gVXjYE^Id>F+Mjzs;?g8U1U4)1o&wqh_5lzp!K90^?J2PWb+xBKSBrbK~b( z*mkyZcf14z0wdR7-dbyNKNiveU91Dno*U?z~d4c{49(#j|3KcgFtm|Nd;?csh4x z#_Yo7HbUC76ywr=%{h_Ib0>buJ+A-WPYxG$e%Kej;&GaKg7r1-!gqf=1J2ZBect7_ z`OWmJ*ZT6M>s}--oXpX(CgQj74&L6r3s-jXZ+gG?Xd3snsWusr$)TC|mYICKU3S3s z^_N4}SDL!ZEOgs#emeEy>#uenBz8yiMHcfay|HxvSyBG6%Cdj2_cyPS8QE8hmL7@n zQ}-;1_^MbcbTuSXJnHK5zm5&(^{+nspjfV`C;a~Evx{tjVa~p9W^UW1?JfUi>b9=- z+i&MM`zgz<`xY_v`l+c`PKUqYocuAZWZCw)+;V^0UG{BRYs0fov*bf?>YVwWPg9;3 z$11Bks(fB_T3S$e@2l2bJKoG|?W{Rp{^T;u`6}yC1J=yEkvHbGPeU;UR zjw{8<2i{vh(d_mvo6PbXrp$tgl_~y~E;nSm%Gy`$?YOcueqU1N*^_oI(O0;mJSz*m z@|L`DRh#_Pe+iGMY_+6qWbK)%dNZrN=3cm@hz^5sXo~j{>Joru*4JdeV;#c+`OIo zG^ezB*C(?rOQ!CSikx#Y>Gs*aHMfsXu{(9eJKkvdoQI98E^Pll`%0>5uGW_|dv4Tx zcy0egW~21Zhh-mP5Ad`W@g05ihBx@YWcB+;v?G)*Eescve%-2c@R@1a?CVduSL>-Q z)cEati=*;t_!8T-YfcDn6}|WPTa9^1OUd7Wln*-lusfSuES_vwRW72@@c=BdHCl<;UYQD7ZKcB?fi|MS2f+2c%o{)`+8Qj$CQ6R8V`v?RSKT1 zlV~|JeOt}8!`Ekj-8ApibkTa5>zNPgZYEYo6yK=J-O*R2Ah7+$vzhEyxBoJcx16XE4y81R6i&Y z-@0PQ)+Lu+vTm=OtN%!^cFofBX9~8|&byia_lvTVPp6C0QMtr--qF5YtRZSMdY7(I zJ96NIqloUX{$7&=OnGavir{6{a-F`v6!n?9bH_Qe|R3> z&HY>D?|J9vuMf08w*BO@h+VcvgXSDIS)L@~dG&L$y8Y7SKVtj?m(07qWY;?F+|a_> zE`PbZ_i~gaYL6rd#=2>4_7tc|jQnc+`^$}e;@=Ee^FofTc>PhxW?#(fTgP?HOmekv zoSyqPttb3#_hmLQzT2M{^#?BF)f6?f-XQz_Oznh?JC0|5OFaKwarWJ%G5r^}G=Be? zxV@jpa)E#A>9)9UMYp}aikh$;tIIu-)Mt3}w9?nF=ZsoqijDO%tbhHQRAc9!w9YK< zcCk!%!(Xrd<5SONd@eR+`z#aqyuWnLj0?9tt{bjO*}a`(XW!K7kDFPGzr473Wu9%d z&HL(SpN>iAFS)V!OkwBp2>aaIy-Qx*dYk&qME`B+w!-SEH$UBZS#f3C+>EZh3H^4J zoyRQi@5|l)^^Vxa{^@s{#4bKi`uYCV>h;eyHX87pjgOzC{*0}wgr&aUTw7?@8J$`9S*Oj>#tFLuv9wR&)_q=(xLChGOzkX+#cJpE9*bB+{c}# zq`%v-@}LHz)1QrpzJ6+rVv5`KQFVGyKrxB z_0)8o(x=5+l;?feSNr>llG2>jzExFKD^@IBs#<#1^!f{(3A~nq@|8~nzdm7RU{G$= z3|@92cl+ICHjfolw02})*L(H;eR$u=4EKHOb+%2OzNJYn=}*POR&hx0ZlQppTMQ!u z1A~Tw0C?E0!Jz}xtz}|T1dY;hakNNakqo+W=gyp{9R&;hm>3S6aINccs_Xjj!2{7J7bnZTW?&;xJ`NwJ6pPZ*> zW*Tqi;>?-hxz4Oa*@;J+iNTGvX!9JyWVg8e>^4Dy)*TB@DaGZPB^>rC+PYADg9<}J zNWqg6f`2xO$-B6yT$#grO|-KqKyk>KQ4L* z?ozWZTC$|2>m&O+kS7l*NcCJWVPKfUC3IEGCR1-}uV*a7AJ3rV)LUuETGE#3D?9?e z&hXOuk|@OMmLbK!z}DSSP%3_P>-;5?)l)N8Jy?3HX3ohp;q(=^vz}$%f5`j{WYPu~rI2;ub5%5NE)B1oE1MFftazjB zc_xiTt?1r*A5g9&(56w=_IM*Lkq*8ffpP6yTrtLW`YaWX{WuLL--mjZ3 zE;}X(T`aqM?#s63H_;VWPDfSAGB7yoQ<6u>vaEKsx_L4; zGRDWh@9vHzOYhw|)^pV@S>)-gwsu>l4_jv*tNMBN?ZIC+T&izwefg8I+2J=IKPdef zNQ7`$IqK$xhjKbwhVCdisNgx5Pq!l|rn+$1a`QzWH_z;BnY7yT_L8};Y;tFCAHKe? zA{!J9zAbw8etQ7=h)?i1IbXroKmb@ zfA++*eBZN@;jgy2{U|x2Z1(u?yG{G2Y@PC=%Ft`ev{x$*RvgUAoOH^$@`%p6w}o2U zZ(cNb{9${3ppBfrZqybJbw-ASlugCY{bpI0uk+(I{j@D#+4a`j_(G|;ocsIcrk$O& zH29v#wYJ0a4a`b57e01_4Cp8x+2UWne_#DRzpv~G?<39N zWh=ycj`hi|E^cn*o%0QJ_K7g$MMrLFEQ38)(#oL4>2G zmJ?J`7~m^L1hRL7qMgCv;EPvppk^-Gvs!pRXf%dFq)U6<*5(JNYh&yP=fBJtEZ)qU`+5 z1HJ^_p6q|Ak9+#%v(s;EKmK$7Khv*gcTe6|$Ebe)j>Gr-7t1Tn@48H%vd8nh-G-@N zS9VRY_2$pfU6^`WZ`q`MYro9CzsGfc^fsTX)$hd52mV(*oiQ^cB=v8}$M63pR+Pki zQ=j#0Rr%wi+YI-7m9bs%`|SJtj+95`ay+6p&ow4Go_DLNNajBqS7NO@YwhP>+b?eW zD}K@SNb2on7kSNNrr4>)e6v1zd1|$posaa+b&>8%GX?MFm8MC6l!xcU`emTemyy_RTFN7oS^v6wCdi+J8IN{pn}3|G8#gSDbfM+1mT3 z_e%Z8pr}>bcc<~jtKa`AHGRM9dHXLm)9=36V-{i;Z*P9j!)=>w?waWzwx&+A{jLzd zeqLte_3JCv{$HeYZu>g_lZEl?zil$9jjne-fBE{Auj}S$?Rz%=mQ`=wuCP3%+AUvK zE`M>BJ8#kKGet*dZ+ZC7Ol#-QG^0FUw_PPai{?(N7N73DE1!97p7z40r=Ne^yR3I! zO%Z$SidRct`(#J^=Bl24Iqm1tRd3(F|80B!d)~t>#T#b&-RFz?|M}~c?^8v$G`$x4 zn!9k>GP_y--(SD@{QstTb=#JHMEBrdpw|cS-x+ z&+fl${DpVd*GqO)ztsJM?=Ri{Y1dw%?SD_M4*7L9f0FWTw*|?!?s~0`+PyO8Wc`In zMsu(K=GuFyS~525n(ynnEqz_n{xnRRQv7e<*)OZ(zg|kUk8pZ=#r5^SY}v1RKg4&v v{Zt%sQ@Q`mV%GmZ&xahmt^Mk*&wu`$&+i_8Qak4bni2DK^>bP0l+XkKmWolM literal 5550 zcmeAS@N?(olHy`uVBq!ia0y~yV0^~Fz_5gaiGhLPteBKH1A}O(r;B4q#jUq<|Mtr~ ztv&G9`|3aTzZ(zgitgK7X*iWb-!m)2nc@ELpK&>p3!d-ZTf5VE-IP^KJ>_qUf>y6u zbue3d>MH9itA1SLI=X1$`2%u)E~w>-C~&)E9>{bOy0mIhN1KLkUH1OZn~cw&u`#xO zJ^SwMnSX1(I-WUe_xVoEe&f$K)92m%{LaczfW>i%O4-T!|Ly`Tj$djP;GBydind;HD)VtEJ}TIYwPQ; z*W>xuO`rPd(zYqJ->)t_Uz=R=XYEdL`#rx7$NzhAeE+Wpv+b*kf8ITQ^xWip`RcEa z>;GNUuU9(J^haXZo9y)Wx1PGZ^XloDqWjLOx>wmpz@^RU%Af50|D^4*v%|NoeRKcT zj<>UqZ|{%2_JYCo7c6T2 zZ(qLkl-b+YRlmH>{qz(owfmM^@b=A3?dyS)C!FJKQm8tA%dl3~`)2jL{lB07uX%fD zceeT7iu39F3~L_koqYfI(XD^>|NUrR_v6#m{}&?bjjVoGVav&{!MR>&09XxS8_M= z>xNBxYt6oQ%oJ`?*koatWK&o3{-(KI-RpnTm$A*;|NGHz{XeJO*T3Ii^M3yR&u6UX z*L-iBzAXRlp7#gMo#pJ+%%;n(N_a07`&?tTLPy-!t>2F4YDWLqd%C{hWBdOP&Hrov ztMC7{^25{osi{vNeE$CDF2CMMub&g{-?snl_bxhKuKM%D7m~d1k2^Xo$?TiXJYV9Y ze@Vr*lDIEts#|<}EDje<@fA37?)NU;?BhY(4zJa}^ZV=nf6uPh{rWU-{k^xt$GfJeRU#(H3>%rsk|t=G{B5Z^&X!{`~CxF=p3t=DUyGuRaF3PPT*ZpQi7H)8F&@ z{{EX9I8*oI+W)J|_X%aE=TK51{M{E-`$mT6Oy^Hn?LovMA5%MmWH?SrjK4*zuS{-xV_}h zMPW%dp*@c;m%r;x%$?G^iLvVYs+-0ZJ2uQXE#B4MFLTyl(t;(LCl}>R;hpekwVN96 zwD7+3a(0s{ReU|gQWxhmT+yyh`{wb?@ur5fg7m4lnKNzYRI2!bObS~6=F+EAU(Vz_ zn`jbfc8bko@22jhPglO2c}6+2%;~1Gf3De^8!@uCejbjA%HFXt?9I)|`fKtw{eRth zp=X_)=^gHu6qi}Eefpk+jnA@=(XDSCV6hotHZ0G)f%2*Ei@JM zFs?oHs)kD=di@)xjU^dbR%VOdto?lY*{4sfYmY7UlD_>;Wm4LvQ)b6H_m-bpwLFu5 z?xs^Gudm8e`tmg>KYdEWCg#j#0THtPjH$1u>dudxXJaBd`|_eUS(-cUy!M#Ysb!tS zlijB@btUKeC0(z-1zgNc`TY1ucmHj8~UAtVI z@cqieN#zsra^9UwxRI+=cH2|;(G%{~vv;rko(l1ym-&+mm%BN zb64EC#Vg8mo?Q5$_0rpT%ej4juTMJ^^Wp0QPj^qnM-8j;mln?Y8Pu^k^!j?%de&W~ zx-VK4UibRFnakc+6buxnY-M!`YTiPVAORwe~581Y@ch}mx#Yc{KtnP6-eRa{H zvj0cFw#^E;@@3cij8}JZmp)#<#N5|+t}=i52l1Cx0hbEzo9z+35T>7Ie1Brs_R#6; zS+92I*rk;R;L#)E8~+PCMP($m&{eRb02H7Bl%Y*GI1wKnelrYN!1&zfG> zo{e_eeEwd@wz4fRV%N`^a`y1!`uNf|{(Bpv3-5kDb2fQb+UXa5Th1TZvitg*Jsa}+ zyn3EKV>tCk^j+qaqV3W59vz*Pm>+iXz57>RjWD-`&JPk=ozoMPj$L`U_)WsXnyFuw zO0FsH{(Jqu+uP{5+kFcdR;-SjlQv7_QO;K3>rLO@F0{Vhv~1?wzz=Rmiq!?zy}1)q zSCeF9HkEf`@x>UuQ$KD*eOtR`>g>0vHG2ci!mq7neSExXYmV;pp8uk2zqP%4`>*@l zjN5V*+c)P2dd!NQd7961=UVfu-*2Px_1>ObGDq*%Ws^O^<^0iemwn6MsHYeir(bdW z&^3|9e@S`aH$To}eDU5t*(SAj^_zs&$>H0c%{{qx$ve(@%g?>lx_!UCe9Bs# z-B(^c^@{z$;MX!Y>Yv^{w_@SH08{@TX%!iHTF)P`p>ho z<8I%|oZP#AZfCLYSG;s3ZHZ=hN$cd$vIPMLy;fzi#b1@nTYmG`t~5RCH;yF-f)&qS zsPV6TZ1UN*rDtd8^>wVT6BqnCu_gMt(~FrOmV7?;%x?C_@0Y!9cJI8n@#75%uUxmk zG4~>0>h$+Nn|qS?{;6mEuRdum-`}hLceeDqa4UYjEsaZNPTgPkW+{J6`G@uL-LG#g zbia1$s@2(f|2IShxv#Qc*ZQ{pM1EpnVM>Y4XOCHuf!jXLTt4qd_oR|P2dkt`Pu+N4 zytrU;=(mlnM;}hSct$yMS=7x_@fFJpA}*GuF5exau{)nn@6@?9n|`J*WZ03#lY0KF zytI_uNt;P(r`&Ebyxfz4X`R&Dt0o2p8i)O7nw&70lpqtoIESIZ zq;V4?q9*gzg;i^IPuvCmeo)+h|L>i>=6Ak7$WN2<{BZ32o$gIPgQXfuK($yjf1mxN z)6eB?11rAt8+9&GU{ENZ6+;K=>}=|HPyD-L zhi8;C!IfcM>h!Q<%hHYem)zt`)xMwkq=tR&v)$|V-dE2}s@Y$3zs51-^OMOzDqqj~ zpIv{wXg~Ar-|;)9CRp8EaJMOgKT_#<;q19zj!fU~s!?51WoA~ts^)N2^5Zi(*0_t(D)Tk|&CIalV+hV1Dxe|Jyv zR)4#UPn+YEU))XZqfaNUoOxr;&KozX(r(7Y?F-0{soK<=TQ1~j9GNQpIQ#5PP3N5d z;davP^|^mvJ$u!${N}G;QU5h>S9pKEQ?MlZ=EcuVp6U=SOw(;+;Imz0arC{+PeYt}C}9&zjY3U1PZ1;c%JqlNGL7 zza#dU*jUO+M_)cx^fYL3*|EsVjoYqf#8_$CPfPidd;DnE#ZM_`<38l*o$WarK5u2U zl=ke|dsSPO%-pic*)&U@;r_$&_mXdOn=cu@$&m?9=85Z)*}43uW7pK=F9#x{+Y8cn zhEEUGIM1@({rgHvM>yu)lfChvj#UHnDs^^47Oi3Ug|1{pM#C@T4O?*Y4UTY3b9aekWb&yy$fE^Up^Yo`mH1#g{DKl&wB> z>iUrBbDwsL7T3P~qusl9xp%Ph)TqT}w<3a9?hU%XDM~NwEbDXC?b^k{t2f?FXY!bJ zS2C47eb-d>)Mt%3yP|6wmbJ*(6!*T{bN<-o_m^h<=3BD&D#vPP@6_FoK8Q!&-d`sC ze&W?HkN0Q$DaqdV&VAFoUiiJG5hmnUmkM{`9j`zka$tKE8JO>1#zV zU+&u3c`>dee$#LB`jC4fT5sP(i%d!jf3~T1KIg|6wr94<7cH%?I2Q{U z?o!96NqcuC=v<#SA??_vyEzN9&a_G(DylONoBs-+v$)q5X&*1ht<$DXJy!I1=cdaGzU|n#(BtRSs#v$n*FF_Xn`YlUn31r?(CquZCna(* z8O`pK!neJzJ1cAbd*1dRdRotU&7SP@-}b3?leKcc{MCuAzbBlkvw2z{w|sT;@{M&< za_!b~Ri}u*h~M9N%O_v;yq)?azXz&!?KCFyygS~@G+C(k!toggSN5M1U-B~{x41U< zvT?yj`?@P@dhT3(V7jRO)GeclFW#K_``xCJOC<99YUQbSe;vtK_~z)+_G4;E!FA{6 zZd)<`thM&sr=9Jeu7>~NT{HEp{MDzyrs+aY3jaU*bnyMAOO*u+c~yM>{n|L)Zrzf4 zkFCY?{cfw-PUK^K*}cE+&!wby2QPjE7p4CaY*)|kS*B3CVUXf8lS)X-$#F)l_lMTrkJQkf_oh`SO1)| zWoNUiFG#BT_TtW;!^OwJHN(4~huib^JZCs{PqJv|on#irEy6`tGuAJ=zwh~h<$QPa zC$mYq3H3bAp2Ev8K`p?Hf#DPz1H%+vhK5ZmS&=x53=FBvU_Piv*02e}hxO1ve2`uk zUjx092IWJ|W&p{_%gS;^xPsQ z4QU0_HinHoGLBtqef)RHo5#<$-#If~_}+ixt;eqY6rI9*;rl5) z5%2b8%O*eE@}uhYpG{vMcWL;TOpbVd+xZeta2bx>*ki#+tgd#{A)gS@12Pt zf0}4U+ikS2%+TVTwmP~u$~7|BDt@}?$&!7sDrXH+^LH~f9+~`ni^lG#R~`_@?wz9V z<0I$A5PTu^{HdU=dW$Bub|uc~GBH>br>i+TA~83^Z1pv%eQBNwnQfZYyG1Xklb@TOqP0h7jkrZ*N>gt4vj|#n=r_Oq*zjPz%;uBdCYl_cviB}mhEV<^zRk_08G7vI`GGTAv>P@tURsj#lfC)a zG4)9cD%R=ggA}9c4UU(ijo-RX@+iX|5E#p&t+Q~wr%Q;q_<9AV{XPou7CD+%HgTGQuYDu z9j6xLG}MKCOUf(Bu`%?^wJ`r8y?oBswn8(rSO30Nrm`h0&M~!~UT&VLr{1tca@89b ztp(45*6T@Xb3cFceC?!NQ@taap7O?DT%HWCs1(QoyzsbCQ;PkCWD4_>f#)R7Y&=9 zKkMh^?N5>OH1@e!8^<_>cY+kS?HPFvrR}*Clq`>)n9g{w?DyNt#>T}$pFiJB$@3Gs zv%mho!-;bHZ \uicontrol Coco with which you + can set the directory in which Coco is installed. But in most cases, the default + settings need not to be changed. + + \section1 Measure code coverage + + With the Coco plugin, it is possible to set up code coverage easily for Qt Creator + projects that are built with QMake or CMake. + + The general idea is that you take an existing build configuration, like "Debug", + clone it with a new name (like "DebugCoverage") and then use the plugin to + configure it for the use with Coco. Switching back and forth between coverage + and normal builds on the same build configuration is not recommended. + + \section2 Components of the plugin + + With the plugin enabled, C/C++ projects get + \list + \li A project settings menu at \uicontrol Projects > \uicontrol {Project settings} + > \uicontrol {Coco Code Coverage} with which you can enable and configure + code coverage. + \li In the Build Settings, an additional pseudo build step that shows whether + code coverage was enabled. There is also a button to directly disable or + enable code coverage from this build step. + + \image qtcreator-coco-buildstep.png {Ficticious build step for code coverage} + \endlist + + If code coverage is enabled, the plugin generates a \e {settings} file that is read + by the build tool before the other configuration files and which changes the + build process so that the Coco compiler wrappers are used instead of the original + compiler. The settings file is always located in the root directory of the + project sources. It also contains the coverage flags and possible overrides and + can be checked in into version control to preserve the settings. + + \section2 The Project settings page + + \image qtcreator-coco-configpage.png {Settings page} + + The pages for QMake and CMake projects do not differ very much. They contain: + \list + \li A checkbox to enable and disable code coverage. + \li A field to enter code coverage options. There are no settings that are + needed to enable code coverage. Below the field are buttons: + \list + \li \uicontrol {Exclude file...} to exclude a file from instrumentation + more easily. + \li \uicontrol {Exclude directory...} to exclude a directory from + instrumentation more easily. + \li \uicontrol Override to open another entry field in which you can + enter additional commands at the end of the settings file. It is + meant for special cases in which the usual configuration flags are + not enough. + \endlist + \li A button \uicontrol Revert to reload the coverage settings from the current + settings file. + \li A button \uicontrol Save or \uicontrol {Save & Re-configure} to write + the settings to the settings file and reconfigure the project, if + necessary. + \li A list with the project build settings that were changed by the plugin. + \endlist + + \section2 QMake projects + + The settings file is \c {cocoplugin.prf}. It is a QMake "feature file". + + For a command line build, \c {qmake} must be run with the additional options + \tt {CONFIG+=cocoplugin COCOPATH=\e{}}. It is also necessary + to set the environment variable \c {QMAKEFEATURES} to the directory in which + \c {cocoplugin.prf} is located. + + \section2 CMake projects + + The settings file is \c {cocoplugin.cmake}. It is a CMake cache preload script. + Apart from this file, the "compiler files" \c {cocoplugin-gcc.cmake}, + \c {cocoplugin-clang.cmake} and \c {cocoplugin-visualstudio.cmake} are created + in the same directory. They are needed for a command line build. + + In a command-line build, run CMake in the form + "\tt {cmake \e{} -C\e{}/cocoplugin-gcc.cmake}" + (if you are compiling with GCC). The file \c {cocoplugin-gcc.cmake} includes + then \c {cocoplugin.cmake}. + + If you use a compiler different from GCC, clang or Visual Studio, one of the + compiler files must be modified for the new compiler. + + \section1 Check code coverage + + With the help of Coco CoverageBrowser, you can analyze the test coverage by + loading an instrumentation database (a \c .csmes file), which was generated by + Coco CoverageScanner. + + \section2 Configure Coco \list 1 \li Go to \uicontrol Analyze > \uicontrol {Squish Coco}. \image qtcreator-coco.png {Coco CoverageBrowser and CSMes file} - \li In \uicontrol {CoverageBrowser}, enter the path to the Coco - coverage browser to use for analyzing a .csmes file. \li In \uicontrol CSMes, select the instrumentation database to load. \li Select \uicontrol Open to start CoverageBrowser. \li In CoverageBrowser, go to \uicontrol File > - \uicontrol {Load Execution Report} and select the .csexe for the + \uicontrol {Load Execution Report} and select the \c .csexe file for the coverage scan. \image coco-coveragebrowser-load-execution-report.png {Load Execution Report dialog} \li To keep the execution report, clear @@ -39,7 +130,7 @@ after the code in \uicontrol Edit mode. You can change the fonts and colors used for different types of results. - \section1 Changing Fonts and Colors + \section2 Changing Fonts and Colors To change the default fonts and colors, go to \preferences > \uicontrol {Text Editor} > \uicontrol {Font & Colors}. diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.h b/src/plugins/cmakeprojectmanager/builddirparameters.h index b73993eb37c..fc5c812bbd8 100644 --- a/src/plugins/cmakeprojectmanager/builddirparameters.h +++ b/src/plugins/cmakeprojectmanager/builddirparameters.h @@ -19,9 +19,11 @@ namespace ProjectExplorer { class Project; } -namespace CMakeProjectManager::Internal { - +namespace CMakeProjectManager { class CMakeBuildSystem; +} + +namespace CMakeProjectManager::Internal { class BuildDirParameters { diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 1c5e78980ab..c11aa6be18a 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -117,6 +117,8 @@ public: void setError(const QString &message); void setWarning(const QString &message); + void updateInitialCMakeArguments(); + private: void updateButtonState(); void updateAdvancedCheckBox(); @@ -135,7 +137,6 @@ private: void batchEditConfiguration(); void reconfigureWithInitialParameters(); - void updateInitialCMakeArguments(); void kitCMakeConfiguration(); void updateConfigureDetailsWidgetsSummary( const QStringList &configurationArguments = QStringList()); @@ -1838,7 +1839,19 @@ QString CMakeBuildSystem::warning() const NamedWidget *CMakeBuildConfiguration::createConfigWidget() { - return new CMakeBuildSettingsWidget(this); + m_configWidget = new CMakeBuildSettingsWidget(this); + return m_configWidget; +} + +void CMakeBuildConfiguration::updateInitialCMakeArguments() +{ + Q_ASSERT(m_configWidget); + m_configWidget->updateInitialCMakeArguments(); +} + +QStringList CMakeBuildConfiguration::initialCMakeOptions() const +{ + return initialCMakeArguments.allValues(); } CMakeConfig CMakeBuildConfiguration::signingFlags() const diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index 8a7d2bace4d..398b42ffa50 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -14,10 +14,10 @@ namespace CMakeProjectManager { class CMakeProject; +class CMakeBuildSystem; namespace Internal { -class CMakeBuildSystem; class CMakeBuildSettingsWidget; class CMakeProjectImporter; @@ -75,7 +75,7 @@ public: void setRestrictedBuildTarget(const QString &buildTarget); Utils::Environment configureEnvironment() const; - Internal::CMakeBuildSystem *cmakeBuildSystem() const; + CMakeBuildSystem *cmakeBuildSystem() const; QStringList additionalCMakeArguments() const; void setAdditionalCMakeArguments(const QStringList &args); @@ -90,6 +90,9 @@ public: QtSupport::QmlDebuggingAspect qmlDebugging{this}; Internal::ConfigureEnvironmentAspect configureEnv{this, this}; + void updateInitialCMakeArguments(); + QStringList initialCMakeOptions() const; + signals: void signingFlagsChanged(); void configureEnvironmentChanged(); @@ -105,11 +108,12 @@ private: void setBuildPresetToBuildSteps(const ProjectExplorer::Target *target); void filterConfigArgumentsFromAdditionalCMakeArguments(); - Internal::CMakeBuildSystem *m_buildSystem = nullptr; + CMakeBuildSystem *m_buildSystem = nullptr; + Internal::CMakeBuildSettingsWidget *m_configWidget = nullptr; QStringList m_unrestrictedBuildTargets; friend class Internal::CMakeBuildSettingsWidget; - friend class Internal::CMakeBuildSystem; + friend class CMakeBuildSystem; }; class CMAKE_EXPORT CMakeBuildConfigurationFactory diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 3547e96ed10..3d8d75eaa78 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -62,8 +62,9 @@ using namespace ProjectExplorer; using namespace TextEditor; using namespace Utils; +using namespace CMakeProjectManager::Internal; -namespace CMakeProjectManager::Internal { +namespace CMakeProjectManager { static Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg); @@ -2523,4 +2524,4 @@ ExtraCompiler *CMakeBuildSystem::findExtraCompiler(const ExtraCompilerFilter &fi return Utils::findOrDefault(m_extraCompilers, filter); } -} // CMakeProjectManager::Internal +} // CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 2b55097852d..2b6b3f79f2f 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -29,13 +29,11 @@ namespace CMakeProjectManager { class CMakeBuildConfiguration; class CMakeProject; -namespace Internal { - // -------------------------------------------------------------------- // CMakeBuildSystem: // -------------------------------------------------------------------- -class CMakeBuildSystem final : public ProjectExplorer::BuildSystem +class CMAKE_EXPORT CMakeBuildSystem final : public ProjectExplorer::BuildSystem { Q_OBJECT @@ -157,7 +155,7 @@ private: Utils::FilePaths *); bool addTsFiles(ProjectExplorer::Node *context, const Utils::FilePaths &filePaths, Utils::FilePaths *); - bool renameFile(CMakeTargetNode *context, + bool renameFile(Internal::CMakeTargetNode *context, const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath, bool &shouldRunCMake); @@ -175,10 +173,10 @@ private: }; void reparse(int reparseParameters); QString reparseParametersString(int reparseFlags); - void setParametersAndRequestParse(const BuildDirParameters ¶meters, + void setParametersAndRequestParse(const Internal::BuildDirParameters ¶meters, const int reparseParameters); - bool mustApplyConfigurationChangesArguments(const BuildDirParameters ¶meters) const; + bool mustApplyConfigurationChangesArguments(const Internal::BuildDirParameters ¶meters) const; // State handling: // Parser states: @@ -208,7 +206,7 @@ private: void wireUpConnections(); - void ensureBuildDirectory(const BuildDirParameters ¶meters); + void ensureBuildDirectory(const Internal::BuildDirParameters ¶meters); void stopParsingAndClearState(); void becameDirty(); @@ -243,7 +241,7 @@ private: ProjectExplorer::ProjectUpdater *m_cppCodeModelUpdater = nullptr; QList m_extraCompilers; QList m_buildTargets; - QSet m_cmakeFiles; + QSet m_cmakeFiles; QHash m_cmakeSymbolsHash; QHash m_dotCMakeFilesHash; QHash m_findPackagesFilesHash; @@ -254,9 +252,9 @@ private: QHash m_filesToBeRenamed; // Parsing state: - BuildDirParameters m_parameters; + Internal::BuildDirParameters m_parameters; int m_reparseParameters = REPARSE_DEFAULT; - FileApiReader m_reader; + Internal::FileApiReader m_reader; mutable bool m_isHandlingError = false; // CTest integration @@ -271,5 +269,4 @@ private: QString m_warning; }; -} // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/coco/CMakeLists.txt b/src/plugins/coco/CMakeLists.txt index bb5c5f165ac..71693fac7ad 100644 --- a/src/plugins/coco/CMakeLists.txt +++ b/src/plugins/coco/CMakeLists.txt @@ -1,7 +1,51 @@ add_qtc_plugin(Coco - PLUGIN_DEPENDS Core LanguageClient + PLUGIN_DEPENDS + QtCreator::Core + QtCreator::LanguageClient + QtCreator::ProjectExplorer + QtCreator::QmakeProjectManager + DEPENDS + QtCreator::CMakeProjectManager + QtCreator::ExtensionSystem SOURCES - cocolanguageclient.cpp cocolanguageclient.h + Coco.json.in + cocobuild/buildsettings.cpp + cocobuild/buildsettings.h + cocobuild/cmakemodificationfile.cpp + cocobuild/cmakemodificationfile.h + cocobuild/cococmakesettings.cpp + cocobuild/cococmakesettings.h + cocobuild/cocobuildstep.cpp + cocobuild/cocobuildstep.h + cocobuild/cocoprojectwidget.cpp + cocobuild/cocoprojectwidget.h + cocobuild/modificationfile.cpp + cocobuild/modificationfile.h + cocobuild/qmakefeaturefile.cpp + cocobuild/qmakefeaturefile.h + cocobuild/cocoqmakesettings.cpp + cocobuild/cocoqmakesettings.h + cocolanguageclient.cpp + cocolanguageclient.h cocoplugin.cpp + cocoplugin.qrc + cocoplugin_global.h + cocopluginconstants.h cocotr.h + common.cpp + common.h + files/cocoplugin-clang.cmake + files/cocoplugin-gcc.cmake + files/cocoplugin-visualstudio.cmake + files/cocoplugin.cmake + files/cocoplugin.prf + images/SquishCoco_48x48.png + settings/cocoinstallation.cpp + settings/cocoinstallation.h + settings/cocoprojectsettingswidget.cpp + settings/cocoprojectsettingswidget.h + settings/globalsettings.cpp + settings/globalsettings.h + settings/globalsettingspage.cpp + settings/globalsettingspage.h ) diff --git a/src/plugins/coco/Coco.json.in b/src/plugins/coco/Coco.json.in index 3c1b411b0b3..e9eb090aa42 100644 --- a/src/plugins/coco/Coco.json.in +++ b/src/plugins/coco/Coco.json.in @@ -15,9 +15,10 @@ "", "Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this plugin. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html." ], - "Description" : "Access the Coco CoverageBrowser.", + "Description" : "Configure Coco and access the results", "LongDescription" : [ - "View the results from the Coco CoverageBrowser to make tests more efficient and complete." + "Configure CMake and QMake projects for code coverage.", + "Highlight the source code according to the measured coverage." ], "Url" : "https://www.qt.io", "DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-coco.html", diff --git a/src/plugins/coco/coco.qbs b/src/plugins/coco/coco.qbs index 6e32634eaf4..abfe8e939f8 100644 --- a/src/plugins/coco/coco.qbs +++ b/src/plugins/coco/coco.qbs @@ -5,14 +5,57 @@ QtcPlugin { Depends { name: "Core" } Depends { name: "LanguageClient" } + Depends { name: "CMakeProjectManager" } + Depends { name: "ExtensionSystem" } + Depends { name: "ProjectExplorer" } + Depends { name: "QmakeProjectManager" } Depends { name: "TextEditor" } + Depends { name: "Utils" } Depends { name: "Qt"; submodules: ["widgets"] } files: [ - "cocoplugin.cpp", + "cocobuild/buildsettings.cpp", + "cocobuild/buildsettings.h", + "cocobuild/cmakemodificationfile.cpp", + "cocobuild/cmakemodificationfile.h", + "cocobuild/cocobuildstep.cpp", + "cocobuild/cocobuildstep.h", + "cocobuild/cococmakesettings.cpp", + "cocobuild/cococmakesettings.h", + "cocobuild/cocoprojectwidget.cpp", + "cocobuild/cocoprojectwidget.h", + "cocobuild/cocoprojectwidget.ui", + "cocobuild/cocoqmakesettings.cpp", + "cocobuild/cocoqmakesettings.h", + "cocobuild/modificationfile.cpp", + "cocobuild/modificationfile.h", + "cocobuild/qmakefeaturefile.cpp", + "cocobuild/qmakefeaturefile.h", "cocolanguageclient.cpp", "cocolanguageclient.h", + "cocoplugin.cpp", + "cocoplugin.qrc", + "cocoplugin_global.h", + "cocopluginconstants.h", + "cocotr.h", + "common.cpp", + "common.h", + "files/cocoplugin-clang.cmake", + "files/cocoplugin-gcc.cmake", + "files/cocoplugin-visualstudio.cmake", + "files/cocoplugin.cmake", + "files/cocoplugin.prf", + "images/SquishCoco_48x48.png", + "settings/cocoinstallation.cpp", + "settings/cocoinstallation.h", + "settings/cocoprojectsettingswidget.cpp", + "settings/cocoprojectsettingswidget.h", + "settings/globalsettings.cpp", + "settings/globalsettings.h", + "settings/globalsettingspage.cpp", + "settings/globalsettingspage.h", + "settings/globalsettingspage.ui", ] } diff --git a/src/plugins/coco/cocobuild/buildsettings.cpp b/src/plugins/coco/cocobuild/buildsettings.cpp new file mode 100644 index 00000000000..c905b6806d1 --- /dev/null +++ b/src/plugins/coco/cocobuild/buildsettings.cpp @@ -0,0 +1,100 @@ +// 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 "buildsettings.h" + +#include "cocobuildstep.h" +#include "cococmakesettings.h" +#include "cocoqmakesettings.h" +#include "modificationfile.h" + +#include +#include +#include + +namespace Coco::Internal { + +bool BuildSettings::supportsBuildConfig(const ProjectExplorer::BuildConfiguration &config) +{ + return config.id() == QmakeProjectManager::Constants::QMAKE_BC_ID + || config.id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID; +} + +BuildSettings *BuildSettings::createdFor(const ProjectExplorer::BuildConfiguration &config) +{ + if (config.id() == QmakeProjectManager::Constants::QMAKE_BC_ID) + return new CocoQMakeSettings{config.project()}; + else if (config.id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID) + return new CocoCMakeSettings{config.project()}; + else + return nullptr; +} + +BuildSettings::BuildSettings(ModificationFile &featureFile, ProjectExplorer::Project *project) + : m_featureFile{featureFile} + , m_project{*project} +{ + // Do not use m_featureFile in the constructor; it may not yet be valid. +} + +void BuildSettings::connectToBuildStep(CocoBuildStep *step) const +{ + connect( + activeTarget(), + &ProjectExplorer::Target::buildSystemUpdated, + step, + &CocoBuildStep::buildSystemUpdated); +} + +bool BuildSettings::enabled() const +{ + return m_enabled; +} + +const QStringList &BuildSettings::options() const +{ + return m_featureFile.options(); +} + +const QStringList &BuildSettings::tweaks() const +{ + return m_featureFile.tweaks(); +} + +bool BuildSettings::hasTweaks() const +{ + return !m_featureFile.tweaks().isEmpty(); +} + +QString BuildSettings::featureFilenName() const +{ + return m_featureFile.fileName(); +} + +QString BuildSettings::featureFilePath() const +{ + return m_featureFile.nativePath(); +} + +void BuildSettings::provideFile() +{ + if (!m_featureFile.exists()) + write("", ""); +} + +QString BuildSettings::tableRow(const QString &name, const QString &value) const +{ + return QString("%1%2").arg(name, value); +} + +void BuildSettings::setEnabled(bool enabled) +{ + m_enabled = enabled; +} + +ProjectExplorer::Target *BuildSettings::activeTarget() const +{ + return m_project.activeTarget(); +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/buildsettings.h b/src/plugins/coco/cocobuild/buildsettings.h new file mode 100644 index 00000000000..10cf8e96925 --- /dev/null +++ b/src/plugins/coco/cocobuild/buildsettings.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include + +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +namespace ProjectExplorer { +class BuildConfiguration; +class Project; +class Target; +} + +namespace Coco::Internal { + +class CocoBuildStep; +class CocoProjectWidget; +class ModificationFile; + +class BuildSettings : public QObject +{ + Q_OBJECT +public: + static bool supportsBuildConfig(const ProjectExplorer::BuildConfiguration &config); + static BuildSettings *createdFor(const ProjectExplorer::BuildConfiguration &config); + + explicit BuildSettings(ModificationFile &featureFile, ProjectExplorer::Project *project); + virtual ~BuildSettings() {} + + void connectToBuildStep(CocoBuildStep *step) const; + virtual void connectToProject(CocoProjectWidget *) const {} + virtual void read() = 0; + bool enabled() const; + virtual bool validSettings() const = 0; + virtual void setCoverage(bool on) = 0; + + virtual QString saveButtonText() const = 0; + virtual void reconfigure() {}; + virtual void stopReconfigure() {}; + virtual bool needsReconfigure() const { return false; } + + virtual QString configChanges() const = 0; + + const QStringList &options() const; + const QStringList &tweaks() const; + virtual QString projectDirectory() const = 0; + + bool hasTweaks() const; + QString featureFilenName() const; + QString featureFilePath() const; + + virtual void write(const QString &options, const QString &tweaks) = 0; + void provideFile(); + +protected: + QString tableRow(const QString &name, const QString &value) const; + void setEnabled(bool enabled); + ProjectExplorer::Target *activeTarget() const; + +private: + ModificationFile &m_featureFile; + ProjectExplorer::Project &m_project; + bool m_enabled = false; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cmakemodificationfile.cpp b/src/plugins/coco/cocobuild/cmakemodificationfile.cpp new file mode 100644 index 00000000000..9813e92be0c --- /dev/null +++ b/src/plugins/coco/cocobuild/cmakemodificationfile.cpp @@ -0,0 +1,91 @@ +// 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 "cmakemodificationfile.h" + +#include "cocopluginconstants.h" + +#include +#include +#include + +namespace Coco::Internal { + +using namespace ProjectExplorer; + +static const char flagsSetting[] = "set(coverage_flags_list\n"; +static const char tweaksLine[] = "# User-supplied settings follow here:\n"; + +CMakeModificationFile::CMakeModificationFile(Project *project) + : m_project{project} +{} + +QString CMakeModificationFile::fileName() const +{ + return QString(Constants::PROFILE_NAME) + ".cmake"; +} + +void CMakeModificationFile::setProjectDirectory(const Utils::FilePath &projectDirectory) +{ + setFilePath(projectDirectory.pathAppended(fileName())); +} + +QStringList CMakeModificationFile::defaultModificationFile() const +{ + return contentOf(":/cocoplugin/files/cocoplugin.cmake"); +} + +void CMakeModificationFile::read() +{ + clear(); + QStringList file = currentModificationFile(); + + { + QStringList options; + int i = file.indexOf(flagsSetting); + if (i != -1) { + i++; + while (i < file.size() && !file[i].startsWith(')')) { + options += file[i].trimmed(); + i++; + } + } + setOptions(options); + } + { + QStringList tweaks; + int i = file.indexOf(tweaksLine); + if (i != -1) { + i++; + while (i < file.size()) { + tweaks += file[i].chopped(1); + i++; + } + } + setTweaks(tweaks); + } +} + +void CMakeModificationFile::write() const +{ + QFile out(nativePath()); + out.open(QIODevice::WriteOnly | QIODevice::Text); + + QTextStream outStream(&out); + for (QString &line : defaultModificationFile()) { + outStream << line; + + if (line.startsWith(flagsSetting)) { + for (const QString &option : options()) { + QString line = " " + option + '\n'; + outStream << line; + } + } + } + for (const QString &line : tweaks()) + outStream << line << "\n"; + + out.close(); +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cmakemodificationfile.h b/src/plugins/coco/cocobuild/cmakemodificationfile.h new file mode 100644 index 00000000000..485c5fa4326 --- /dev/null +++ b/src/plugins/coco/cocobuild/cmakemodificationfile.h @@ -0,0 +1,32 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "modificationfile.h" + +namespace ProjectExplorer { +class Project; +} + +namespace Coco::Internal { + +class CMakeModificationFile : public ModificationFile +{ +public: + CMakeModificationFile(ProjectExplorer::Project *project); + + void read() override; + void write() const override; + + QString fileName() const override; + void setProjectDirectory(const Utils::FilePath &projectDirectory) override; + +protected: + QStringList defaultModificationFile() const override; + +private: + ProjectExplorer::Project *m_project; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cocobuildstep.cpp b/src/plugins/coco/cocobuild/cocobuildstep.cpp new file mode 100644 index 00000000000..6a71157e7b6 --- /dev/null +++ b/src/plugins/coco/cocobuild/cocobuildstep.cpp @@ -0,0 +1,126 @@ +// 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 "cocobuildstep.h" + +#include "cocopluginconstants.h" +#include "cocotr.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace Coco::Internal { + +using namespace ProjectExplorer; + +QMakeStepFactory::QMakeStepFactory() +{ + registerStep(Utils::Id{Constants::COCO_STEP_ID}); + setSupportedProjectType(QmakeProjectManager::Constants::QMAKEPROJECT_ID); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); + setRepeatable(false); +} + +CMakeStepFactory::CMakeStepFactory() +{ + registerStep(Utils::Id{Constants::COCO_STEP_ID}); + setSupportedProjectType(CMakeProjectManager::Constants::CMAKE_PROJECT_ID); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); + setRepeatable(false); +} + +CocoBuildStep *CocoBuildStep::create(BuildConfiguration *buildConfig) +{ + // The "new" command creates a small memory leak which we can tolerate. + return new CocoBuildStep( + new BuildStepList(buildConfig, Constants::COCO_STEP_ID), Utils::Id(Constants::COCO_STEP_ID)); +} + +CocoBuildStep::CocoBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id) + : BuildStep(bsl, id) + , m_reconfigureButton{new QPushButton} +{} + +bool CocoBuildStep::init() +{ + return true; +} + +void CocoBuildStep::buildSystemUpdated() +{ + updateDisplay(); +} + +void CocoBuildStep::onReconfigureButtonClicked() +{ + m_valid = !m_valid; + + setSummaryText(Tr::tr("Coco Code Coverage: Reconfiguring...")); + m_reconfigureButton->setEnabled(false); + m_buildSettings->setCoverage(m_valid); + m_buildSettings->provideFile(); + m_buildSettings->reconfigure(); +} + +QWidget *CocoBuildStep::createConfigWidget() +{ + connect( + m_reconfigureButton, + &QPushButton::clicked, + this, + &CocoBuildStep::onReconfigureButtonClicked); + + Layouting::Form builder; + builder.addRow({m_reconfigureButton, new QLabel}); + builder.setNoMargins(); + + return builder.emerge(); +} + +void CocoBuildStep::updateDisplay() +{ + CocoInstallation coco; + if (!coco.isValid()) { + setSummaryText("" + Tr::tr("Coco Code Coverage: No working Coco installation") + ""); + m_reconfigureButton->setEnabled(false); + return; + } + + m_valid = m_buildSettings->validSettings(); + + if (m_valid) { + setSummaryText("" + Tr::tr("Coco Code Coverage: Enabled") + ""); + m_reconfigureButton->setText(Tr::tr("Disable Coverage")); + } else { + setSummaryText(Tr::tr("Coco Code Coverage: Disabled")); + m_reconfigureButton->setText(Tr::tr("Enable Coverage")); + } + + m_reconfigureButton->setEnabled(true); +} + +void CocoBuildStep::display(BuildConfiguration *buildConfig) +{ + Q_ASSERT( m_buildSettings.isNull() ); + + m_buildSettings = BuildSettings::createdFor(*buildConfig); + m_buildSettings->read(); + m_buildSettings->connectToBuildStep(this); + + setImmutable(true); + updateDisplay(); +} + +Tasking::GroupItem CocoBuildStep::runRecipe() +{ + return Tasking::GroupItem({}); +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cocobuildstep.h b/src/plugins/coco/cocobuild/cocobuildstep.h new file mode 100644 index 00000000000..15b48565fbc --- /dev/null +++ b/src/plugins/coco/cocobuild/cocobuildstep.h @@ -0,0 +1,59 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "buildsettings.h" + +#include +#include +#include + +#include + +class QPushButton; + +namespace Coco::Internal { + +class QMakeStepFactory: public ProjectExplorer::BuildStepFactory +{ +public: + QMakeStepFactory(); +}; + +class CMakeStepFactory: public ProjectExplorer::BuildStepFactory +{ +public: + CMakeStepFactory(); +}; + +class CocoBuildStep : public ProjectExplorer::BuildStep +{ + Q_OBJECT +public: + static CocoBuildStep *create(ProjectExplorer::BuildConfiguration *buildConfig); + + CocoBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); + + bool init() override; + void display(ProjectExplorer::BuildConfiguration *buildConfig); + +public slots: + void buildSystemUpdated(); + +private slots: + void onReconfigureButtonClicked(); + +protected: + QWidget *createConfigWidget() override; + +private: + void updateDisplay(); + Tasking::GroupItem runRecipe() override; + + QPointer m_buildSettings; + bool m_valid; + QPushButton *m_reconfigureButton; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cococmakesettings.cpp b/src/plugins/coco/cocobuild/cococmakesettings.cpp new file mode 100644 index 00000000000..ceb3ec8012a --- /dev/null +++ b/src/plugins/coco/cocobuild/cococmakesettings.cpp @@ -0,0 +1,167 @@ +// 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 "cococmakesettings.h" + +#include "cocobuild/cocoprojectwidget.h" +#include "cocotr.h" +#include "common.h" + +#include +#include +#include + +using namespace ProjectExplorer; +using namespace CMakeProjectManager; + +namespace Coco::Internal { + +CocoCMakeSettings::CocoCMakeSettings(Project *project) + : BuildSettings{m_featureFile, project} + , m_featureFile{project} +{} + +CocoCMakeSettings::~CocoCMakeSettings() {} + +void CocoCMakeSettings::connectToProject(CocoProjectWidget *parent) const +{ + connect( + activeTarget(), &Target::buildSystemUpdated, parent, &CocoProjectWidget::buildSystemUpdated); + connect( + qobject_cast(activeTarget()->buildSystem()), + &CMakeProjectManager::CMakeBuildSystem::errorOccurred, + parent, + &CocoProjectWidget::configurationErrorOccurred); +} + +void CocoCMakeSettings::read() +{ + setEnabled(false); + if (Target *target = activeTarget()) { + if ((m_buildConfig = qobject_cast( + target->activeBuildConfiguration()))) { + m_featureFile.setProjectDirectory(m_buildConfig->project()->projectDirectory()); + m_featureFile.read(); + setEnabled(true); + } + } +} + +QString CocoCMakeSettings::initialCacheOption() const +{ + return QString("-C%1").arg(m_featureFile.nativePath()); +} + +bool CocoCMakeSettings::hasInitialCacheOption(const QStringList &args) const +{ + for (int i = 0; i < args.length(); ++i) { + if (args[i] == "-C" && i + 1 < args.length() && args[i + 1] == m_featureFile.nativePath()) + return true; + + if (args[i] == initialCacheOption()) + return true; + } + + return false; +} + +bool CocoCMakeSettings::validSettings() const +{ + return enabled() && m_featureFile.exists() + && hasInitialCacheOption(m_buildConfig->additionalCMakeArguments()); +} + +void CocoCMakeSettings::setCoverage(bool on) +{ + if (!enabled()) + return; + + auto values = m_buildConfig->initialCMakeOptions(); + QStringList args = Utils::filtered(values, [&](const QString &option) { + return !(option.startsWith("-C") && option.endsWith(featureFilenName())); + }); + + if (on) + args << QString("-C%1").arg(m_featureFile.nativePath()); + + m_buildConfig->setInitialCMakeArguments(args); +} + +QString CocoCMakeSettings::saveButtonText() const +{ + return Tr::tr("Save && Re-configure"); +} + +QString CocoCMakeSettings::configChanges() const +{ + return "" + + tableRow("Additional CMake options: ", maybeQuote(initialCacheOption())) + + tableRow("Initial cache script: ", maybeQuote(featureFilePath())) + "
"; +} + +void CocoCMakeSettings::reconfigure() +{ + if (!enabled()) + return; + + m_buildConfig->cmakeBuildSystem()->clearCMakeCache(); + m_buildConfig->updateInitialCMakeArguments(); + m_buildConfig->cmakeBuildSystem()->runCMake(); +} + +void Coco::Internal::CocoCMakeSettings::stopReconfigure() +{ + if (enabled()) + m_buildConfig->cmakeBuildSystem()->stopCMakeRun(); +} + +QString CocoCMakeSettings::projectDirectory() const +{ + if (enabled()) + return m_buildConfig->project()->projectDirectory().path(); + else + return ""; +} + +void CocoCMakeSettings::write(const QString &options, const QString &tweaks) +{ + m_featureFile.setOptions(options); + m_featureFile.setTweaks(tweaks); + m_featureFile.write(); + + writeToolchainFile(":/cocoplugin/files/cocoplugin-gcc.cmake"); + writeToolchainFile(":/cocoplugin/files/cocoplugin-clang.cmake"); + writeToolchainFile(":/cocoplugin/files/cocoplugin-visualstudio.cmake"); +} + +void CocoCMakeSettings::writeToolchainFile(const QString &internalPath) +{ + const Utils::FilePath projectDirectory = m_buildConfig->project()->projectDirectory(); + + QFile internalFile{internalPath}; + internalFile.open(QIODeviceBase::ReadOnly); + const QByteArray internalContent = internalFile.readAll(); + + const QString fileName = Utils::FilePath::fromString(internalPath).fileName(); + const Utils::FilePath toolchainPath{projectDirectory.pathAppended(fileName)}; + const QString toolchainNative = toolchainPath.nativePath(); + + if (toolchainPath.exists()) { + QFile currentFile{toolchainNative}; + currentFile.open(QIODeviceBase::ReadOnly); + + QByteArray currentContent = currentFile.readAll(); + if (internalContent == currentContent) + return; + + logSilently(Tr::tr("Overwrite file %1").arg(maybeQuote(toolchainNative))); + } else + logSilently(Tr::tr("Write file %1").arg(maybeQuote(toolchainNative))); + + QFile out{toolchainNative}; + out.open(QIODeviceBase::WriteOnly); + out.write(internalContent); + out.close(); +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cococmakesettings.h b/src/plugins/coco/cocobuild/cococmakesettings.h new file mode 100644 index 00000000000..8535744b9f7 --- /dev/null +++ b/src/plugins/coco/cocobuild/cococmakesettings.h @@ -0,0 +1,51 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "cocobuild/buildsettings.h" +#include "cocobuild/cmakemodificationfile.h" + +#include +#include + +namespace CMakeProjectManager { +class CMakeBuildConfiguration; +class CMakeConfig; +} + +namespace Coco::Internal { + +class CocoProjectWidget; + +class CocoCMakeSettings : public BuildSettings +{ + Q_OBJECT +public: + explicit CocoCMakeSettings(ProjectExplorer::Project *project); + ~CocoCMakeSettings() override; + + void connectToProject(CocoProjectWidget *parent) const override; + void read() override; + bool validSettings() const override; + void setCoverage(bool on) override; + + QString saveButtonText() const override; + QString configChanges() const override; + bool needsReconfigure() const override { return true; } + void reconfigure() override; + void stopReconfigure() override; + + QString projectDirectory() const override; + void write(const QString &options, const QString &tweaks) override; + +private: + bool hasInitialCacheOption(const QStringList &args) const; + QString initialCacheOption() const; + void writeToolchainFile(const QString &internalPath); + + CMakeProjectManager::CMakeBuildConfiguration *m_buildConfig; + CMakeModificationFile m_featureFile; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cocoprojectwidget.cpp b/src/plugins/coco/cocobuild/cocoprojectwidget.cpp new file mode 100644 index 00000000000..7cf55610eba --- /dev/null +++ b/src/plugins/coco/cocobuild/cocoprojectwidget.cpp @@ -0,0 +1,336 @@ +// 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 "cocoprojectwidget.h" + +#include "buildsettings.h" +#include "cocopluginconstants.h" +#include "cocotr.h" +#include "common.h" +#include "settings/globalsettingspage.h" + +#include +#include + +#include +#include + +using namespace ProjectExplorer; +using namespace Core; + +namespace Coco::Internal { + +CocoProjectWidget::CocoProjectWidget(Project *project, const BuildConfiguration &buildConfig) + : m_project{project} + , m_buildConfigurationName{buildConfig.displayName()} +{ + using namespace Layouting; + using namespace Utils; + + m_configerrorLabel.setVisible(false); + m_configerrorLabel.setIconType(InfoLabel::Error); + Label docLink( + QString( + "%1") + .arg(Tr::tr("Documentation"))); + docLink.setOpenExternalLinks(true); + m_optionEdit.setDisplayStyle(StringAspect::TextEditDisplay); + m_tweaksEdit.setDisplayStyle(StringAspect::TextEditDisplay); + m_revertButton.setText(Tr::tr("Revert")); + QFont bold; + bold.setBold(true); + m_saveButton.setFont(bold); + + m_coverageGroupbox + = {groupChecker(m_coverageGroupBoxEnabled.groupChecker()), + Column{ + Row{Tr::tr("CoverageScanner Options"), st, docLink}, + m_optionEdit, + Row{PushButton{ + text(Tr::tr("Exclude File...")), + onClicked([&] { onExcludeFileButtonClicked(); }, this)}, + PushButton{ + text(Tr::tr("Exclude Directory...")), + onClicked([&] { onExcludeDirButtonClicked(); }, this)}, + m_tweaksButton, + st}, + m_tweaksDescriptionLabel, + m_tweaksEdit, + Row{Tr::tr("These settings are stored in"), m_fileNameLabel, st}, + Group{title(Tr::tr("Changed Build Settings")), Column{m_changesText}}}}; + + Column{ + m_configerrorLabel, + m_coverageGroupbox, + Row{m_messageLabel, st, &m_revertButton, &m_saveButton}} + .attachTo(this); + + m_buildSettings = BuildSettings::createdFor(buildConfig); + m_buildSettings->connectToProject(this); + + readSelectionDir(); + reloadSettings(); + + m_fileNameLabel.setValue(m_buildSettings->featureFilePath()); + m_tweaksDescriptionLabel.setText( + Tr::tr("Code for the end of the file \"%1\" to override the built-in declarations." + " Only needed in special cases.") + .arg(m_buildSettings->featureFilenName())); + setTweaksVisible(m_buildSettings->hasTweaks()); + clearMessageLabel(); + + connect(&m_coverageGroupBoxEnabled, &BoolAspect::changed, this, &CocoProjectWidget::onCoverageGroupBoxClicked); + + connect(&m_optionEdit, &StringAspect::changed, this, &CocoProjectWidget::onTextChanged); + connect(&m_tweaksEdit, &StringAspect::changed, this, &CocoProjectWidget::onTextChanged); + m_tweaksButton.onClicked([&] { onTweaksButtonClicked(); }, this); + + connect(&m_revertButton, &QPushButton::clicked, this, &CocoProjectWidget::onRevertButtonClicked); + connect(&m_saveButton, &QPushButton::clicked, this, &CocoProjectWidget::onSaveButtonClicked); + + connect(GlobalSettingsPage::instance().widget(), &GlobalSettingsWidget::updateCocoDir, this, &CocoProjectWidget::reloadSettings); +} + +// Read the build settings again and show them in the widget. +void CocoProjectWidget::reloadSettings() +{ + m_buildSettings->read(); + m_coverageGroupBoxEnabled.setValue(m_buildSettings->validSettings(), Utils::BaseAspect::BeQuiet); + m_coverageGroupbox.setTitle( + Tr::tr("Enable code coverage for build configuration \"%1\"").arg(m_buildConfigurationName)); + + m_optionEdit.setValue(m_buildSettings->options().join('\n'), Utils::BaseAspect::BeQuiet); + m_tweaksEdit.setValue(m_buildSettings->tweaks().join('\n'), Utils::BaseAspect::BeQuiet); + + setState(configDone); + displayChanges(); + + const bool valid = m_coco.isValid(); + m_configerrorLabel.setVisible(!valid); + if (!valid) { + m_configerrorLabel.setText( + Tr::tr("Coco is not installed correctly: \"%1\"").arg(m_coco.errorMessage())); + } +} + +void CocoProjectWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event) + reloadSettings(); +} + +void CocoProjectWidget::buildSystemUpdated(ProjectExplorer::BuildSystem *bs) +{ + QString newBuildConfigurationName = bs->buildConfiguration()->displayName(); + + if (m_buildConfigurationName != newBuildConfigurationName) { + m_buildConfigurationName = newBuildConfigurationName; + logSilently(Tr::tr("Build Configuration changed to %1.").arg(newBuildConfigurationName)); + reloadSettings(); + } else if (m_configState == configRunning) + setState(configDone); +} + +void CocoProjectWidget::configurationErrorOccurred(const QString &error) +{ + Q_UNUSED(error) + + if (m_configState == configEdited) { + setMessageLabel(Utils::InfoLabel::Information, Tr::tr("Re-configuring stopped by user.")); + setState(configStopped); + } else { + // The variable error seems to contain no usable information. + setMessageLabel( + Utils::InfoLabel::Error, + Tr::tr("Error when configuring with \"%1\". " + "Check General Messages for more information.") + .arg(m_buildSettings->featureFilenName())); + setState(configDone); + } +} + +void CocoProjectWidget::setState(ConfigurationState state) +{ + m_configState = state; + + switch (m_configState) { + case configDone: + m_saveButton.setText(m_buildSettings->saveButtonText()); + m_saveButton.setEnabled(false); + m_revertButton.setEnabled(false); + break; + case configEdited: + m_saveButton.setText(m_buildSettings->saveButtonText()); + m_saveButton.setEnabled(true); + m_revertButton.setEnabled(true); + break; + case configRunning: + m_saveButton.setText(Tr::tr("Stop Re-configuring")); + m_saveButton.setEnabled(true); + m_revertButton.setEnabled(false); + break; + case configStopped: + m_saveButton.setText(Tr::tr("Re-configure")); + m_saveButton.setEnabled(true); + m_revertButton.setEnabled(false); + break; + } +} + +void CocoProjectWidget::readSelectionDir() +{ + QVariantMap settings = m_project->namedSettings(Constants::SETTINGS_NAME_KEY).toMap(); + + if (settings.contains(Constants::SELECTION_DIR_KEY)) + m_selectionDirectory = settings[Constants::SELECTION_DIR_KEY].toString(); + else + m_selectionDirectory = m_buildSettings->projectDirectory(); +} + +void CocoProjectWidget::writeSelectionDir(const QString &path) +{ + m_selectionDirectory = path; + + QVariantMap settings; + settings[Constants::SELECTION_DIR_KEY] = path; + + m_project->setNamedSettings(Constants::SETTINGS_NAME_KEY, settings); +} + +void CocoProjectWidget::setTweaksVisible(bool on) +{ + if (on) + m_tweaksButton.setText(Tr::tr("Override <<")); + else + m_tweaksButton.setText(Tr::tr("Override >>")); + + m_tweaksDescriptionLabel.setVisible(on); + m_tweaksEdit.setVisible(on); +} + +void CocoProjectWidget::setMessageLabel(const Utils::InfoLabel::InfoType type, const QString &text) +{ + m_messageLabel.setText(text); + m_messageLabel.setIconType(type); +} + +void CocoProjectWidget::clearMessageLabel() +{ + m_messageLabel.setText(""); + m_messageLabel.setIconType(Utils::InfoLabel::None); +} + +void Internal::CocoProjectWidget::onCoverageGroupBoxClicked() +{ + bool checked = m_coverageGroupBoxEnabled(); + + displayChanges(); + + if (!checked) { + m_buildSettings->setCoverage(false); + setState(configEdited); + return; + } + + if (!m_coco.isValid()) { + m_coverageGroupBoxEnabled.setValue(false, Utils::BaseAspect::BeQuiet); + + QMessageBox box; + box.setIcon(QMessageBox::Critical); + box.setText(Tr::tr("The Coco installation path is not set correctly.")); + box.addButton(QMessageBox::Cancel); + QPushButton *editButton = box.addButton(Tr::tr("Edit"), QMessageBox::AcceptRole); + box.exec(); + + if (box.clickedButton() == editButton) + Core::ICore::showOptionsDialog(Constants::COCO_SETTINGS_PAGE_ID); + + m_coverageGroupBoxEnabled.setValue(m_coco.isValid(), Utils::BaseAspect::BeQuiet); + } else + m_buildSettings->setCoverage(checked); + + setState(configEdited); +} + +void CocoProjectWidget::onSaveButtonClicked() +{ + if (m_configState == configRunning) { + logSilently(Tr::tr("Stop re-configuring")); + m_buildSettings->stopReconfigure(); + setState(configEdited); + return; + } + + QString options = m_optionEdit(); + QString tweaks = m_tweaksEdit(); + clearMessageLabel(); + + logSilently(Tr::tr("Write file \"%1\"").arg(m_buildSettings->featureFilePath())); + m_buildSettings->write(options, tweaks); + + if (m_buildSettings->needsReconfigure()) { + logSilently(Tr::tr("Re-configure")); + setState(configRunning); + m_buildSettings->reconfigure(); + } else + setState(configDone); +} + +void CocoProjectWidget::onRevertButtonClicked() +{ + clearMessageLabel(); + logSilently(Tr::tr("Reload file \"%1\"").arg(m_buildSettings->featureFilePath())); + reloadSettings(); +} + +void CocoProjectWidget::onTextChanged() +{ + setState(configEdited); +} + +void CocoProjectWidget::displayChanges() +{ + m_changesText.setValue(m_buildSettings->configChanges()); +} + +void CocoProjectWidget::addCocoOption(QString option) +{ + m_optionEdit.setValue(m_optionEdit() + "\n" + option); +} + +void CocoProjectWidget::onExcludeFileButtonClicked() +{ + QString fileName = QFileDialog::getOpenFileName( + this, Tr::tr("File to Exclude from Instrumentation"), m_selectionDirectory); + if (fileName.isEmpty()) + return; + + const auto fileNameInfo = Utils::FilePath::fromString(fileName); + addCocoOption("--cs-exclude-file-abs-wildcard=" + maybeQuote("*/" + fileNameInfo.fileName())); + + writeSelectionDir(fileNameInfo.path()); +} + +void CocoProjectWidget::onExcludeDirButtonClicked() +{ + QString path = QFileDialog::getExistingDirectory( + this, Tr::tr("Directory to Exclude from Instrumentation"), m_selectionDirectory); + if (path.isEmpty()) + return; + + const QString projectDir = m_buildSettings->projectDirectory(); + if (path.startsWith(projectDir)) + // Make it a relative path with "*/" at the beginnig. + path = "*/" + path.arg(path.mid(projectDir.size())); + + addCocoOption("--cs-exclude-file-abs-wildcard=" + maybeQuote(path)); + + writeSelectionDir(path); +} + +void Internal::CocoProjectWidget::onTweaksButtonClicked() +{ + setTweaksVisible(!m_tweaksEdit.isVisible()); +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cocoprojectwidget.h b/src/plugins/coco/cocobuild/cocoprojectwidget.h new file mode 100644 index 00000000000..b7f2cf4e12c --- /dev/null +++ b/src/plugins/coco/cocobuild/cocoprojectwidget.h @@ -0,0 +1,81 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "buildsettings.h" +#include "projectexplorer/buildconfiguration.h" +#include "settings/cocoinstallation.h" +#include +#include + +#include +#include +#include + +namespace ProjectExplorer { +class Project; +} + +namespace Coco::Internal { + +class CocoProjectWidget : public QWidget +{ + Q_OBJECT +public: + enum ConfigurationState { configDone, configEdited, configRunning, configStopped }; + + explicit CocoProjectWidget( + ProjectExplorer::Project *project, const ProjectExplorer::BuildConfiguration &buildConfig); + +protected: + void showEvent(QShowEvent *event) override; + +public slots: + void buildSystemUpdated(ProjectExplorer::BuildSystem *bs); + void configurationErrorOccurred(const QString &error); + +private slots: + void onCoverageGroupBoxClicked(); + + void onSaveButtonClicked(); + void onRevertButtonClicked(); + void onExcludeFileButtonClicked(); + void onExcludeDirButtonClicked(); + void onTweaksButtonClicked(); + + void onTextChanged(); + +private: + void displayChanges(); + void reloadSettings(); + void addCocoOption(QString option); + void setState(ConfigurationState state); + void readSelectionDir(); + void writeSelectionDir(const QString &path); + void setTweaksVisible(bool on); + void setMessageLabel(const Utils::InfoLabel::InfoType type, const QString &text); + void clearMessageLabel(); + + Utils::TextDisplay m_configerrorLabel; + Utils::BoolAspect m_coverageGroupBoxEnabled; + Layouting::Group m_coverageGroupbox{}; + Utils::StringAspect m_optionEdit; + Layouting::PushButton m_tweaksButton{}; + Utils::TextDisplay m_tweaksDescriptionLabel; + Utils::StringAspect m_tweaksEdit; + Utils::StringAspect m_fileNameLabel; + Utils::TextDisplay m_messageLabel; + QPushButton m_revertButton; + QPushButton m_saveButton; + Utils::StringAspect m_changesText; + + ProjectExplorer::Project *m_project; + QPointer m_buildSettings; + QString m_selectionDirectory; + ConfigurationState m_configState = configDone; + QString m_buildConfigurationName; + CocoInstallation m_coco; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cocoqmakesettings.cpp b/src/plugins/coco/cocobuild/cocoqmakesettings.cpp new file mode 100644 index 00000000000..c86b53ed2f7 --- /dev/null +++ b/src/plugins/coco/cocobuild/cocoqmakesettings.cpp @@ -0,0 +1,188 @@ +// 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 "cocoqmakesettings.h" + +#include "cocobuild/cocoprojectwidget.h" +#include "cocopluginconstants.h" +#include "cocotr.h" +#include "common.h" + +#include +#include +#include +#include +#include + +using namespace ProjectExplorer; + +namespace Coco::Internal { + +CocoQMakeSettings::CocoQMakeSettings(Project *project) + : BuildSettings{m_featureFile, project} +{} + +CocoQMakeSettings::~CocoQMakeSettings() {} + +void CocoQMakeSettings::read() +{ + setEnabled(false); + if (Target *target = activeTarget()) { + if ((m_buildConfig = qobject_cast(target->activeBuildConfiguration()))) { + if (BuildStepList *buildSteps = m_buildConfig->buildSteps()) { + if ((m_qmakeStep = buildSteps->firstOfType())) { + m_featureFile.setProjectDirectory(m_buildConfig->project()->projectDirectory()); + m_featureFile.read(); + setEnabled(true); + } + } + } + } +} + +QString configAssignment() +{ + static const QString assignment = QString("CONFIG+=") + Constants::PROFILE_NAME; + return assignment; +} + +static const char pathAssignmentPrefix[] = "COCOPATH="; +static const char featuresVar[] = "QMAKEFEATURES"; + +const QStringList CocoQMakeSettings::userArgumentList() const +{ + if (!enabled()) + return {}; + + Utils::ProcessArgs::ConstArgIterator it{m_qmakeStep->userArguments.unexpandedArguments()}; + QStringList result; + + while (it.next()) { + if (it.isSimple()) + result << it.value(); + } + + return result; +} + +Utils::Environment CocoQMakeSettings::buildEnvironment() const +{ + if (!enabled()) + return Utils::Environment(); + + Utils::Environment env = m_buildConfig->environment(); + env.modify(m_buildConfig->userEnvironmentChanges()); + return env; +} + +void CocoQMakeSettings::setQMakeFeatures() const +{ + if (!enabled()) + return; + + Utils::Environment env = buildEnvironment(); + + const QString projectDir = m_buildConfig->project()->projectDirectory().nativePath(); + if (env.value(featuresVar) != projectDir) { + // Bug in prependOrSet(): It does not recognize if QMAKEFEATURES contains a single path + // without a colon and then appends it twice. + env.prependOrSet(featuresVar, projectDir); + } + + Utils::EnvironmentItems diff = m_buildConfig->baseEnvironment().diff(env); + m_buildConfig->setUserEnvironmentChanges(diff); +} + +bool CocoQMakeSettings::environmentSet() const +{ + if (!enabled()) + return true; + + const Utils::Environment env = buildEnvironment(); + const Utils::FilePath projectDir = m_buildConfig->project()->projectDirectory(); + const QString nativeProjectDir = projectDir.nativePath(); + return env.value(featuresVar) == nativeProjectDir + || env.value(featuresVar).startsWith(nativeProjectDir + projectDir.pathListSeparator()); +} + +bool CocoQMakeSettings::validSettings() const +{ + const bool configured = userArgumentList().contains(configAssignment()); + return enabled() && configured && environmentSet() && m_featureFile.exists() + && cocoPathValid(); +} + +void CocoQMakeSettings::setCoverage(bool on) +{ + QString args = m_qmakeStep->userArguments.unexpandedArguments(); + Utils::ProcessArgs::ArgIterator it{&args}; + + while (it.next()) { + if (it.isSimple()) { + const QString value = it.value(); + if (value.startsWith(pathAssignmentPrefix) || value == configAssignment()) + it.deleteArg(); + } + } + if (on) { + it.appendArg(configAssignment()); + it.appendArg(pathAssignment()); + + setQMakeFeatures(); + m_featureFile.write(); + } + + m_qmakeStep->userArguments.setArguments(args); +} + +QString CocoQMakeSettings::saveButtonText() const +{ + return Tr::tr("Save"); +} + +QString CocoQMakeSettings::configChanges() const +{ + return "" + + tableRow( + "Additional qmake arguments: ", + maybeQuote(configAssignment()) + " " + maybeQuote(pathAssignment())) + + tableRow( + "Build environment: ", maybeQuote(QString(featuresVar) + "=" + projectDirectory())) + + tableRow("Feature File: ", maybeQuote(featureFilePath())) + "
"; +} + +QString CocoQMakeSettings::projectDirectory() const +{ + if (enabled()) + return m_buildConfig->project()->projectDirectory().nativePath(); + else + return ""; +} + +void CocoQMakeSettings::write(const QString &options, const QString &tweaks) +{ + m_featureFile.setOptions(options); + m_featureFile.setTweaks(tweaks); + m_featureFile.write(); +} + +QString CocoQMakeSettings::pathAssignment() const +{ + return pathAssignmentPrefix + m_coco.directory().toUserOutput(); +} + +bool CocoQMakeSettings::cocoPathValid() const +{ + Utils::ProcessArgs::ConstArgIterator it{m_qmakeStep->userArguments.unexpandedArguments()}; + + while (it.next()) { + if (it.isSimple()) { + const QString value = it.value(); + if (value.startsWith(pathAssignmentPrefix) && value != pathAssignment()) + return false; + } + } + return true; +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cocoqmakesettings.h b/src/plugins/coco/cocobuild/cocoqmakesettings.h new file mode 100644 index 00000000000..a081bb1e080 --- /dev/null +++ b/src/plugins/coco/cocobuild/cocoqmakesettings.h @@ -0,0 +1,56 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "buildsettings.h" +#include "qmakefeaturefile.h" +#include "settings/cocoinstallation.h" + +#include +#include + +#include +#include + +namespace QmakeProjectManager { +class QMakeStep; +class QmakeBuildConfiguration; +} + +namespace Coco::Internal { + +class CocoProjectWidget; + +class CocoQMakeSettings : public BuildSettings +{ + Q_OBJECT +public: + explicit CocoQMakeSettings(ProjectExplorer::Project *project); + ~CocoQMakeSettings() override; + + void read() override; + bool validSettings() const override; + void setCoverage(bool on) override; + + QString saveButtonText() const override; + QString configChanges() const override; + QString projectDirectory() const override; + void write(const QString &options, const QString &tweaks) override; + +private: + bool environmentSet() const; + QString pathAssignment() const; + const QStringList userArgumentList() const; + Utils::Environment buildEnvironment() const; + void setQMakeFeatures() const; + bool cocoPathValid() const; + + QmakeProjectManager::QmakeBuildConfiguration *m_buildConfig; + QmakeProjectManager::QMakeStep *m_qmakeStep; + + QMakeFeatureFile m_featureFile; + CocoInstallation m_coco; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/modificationfile.cpp b/src/plugins/coco/cocobuild/modificationfile.cpp new file mode 100644 index 00000000000..a8184021847 --- /dev/null +++ b/src/plugins/coco/cocobuild/modificationfile.cpp @@ -0,0 +1,73 @@ +// 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 "modificationfile.h" + +namespace Coco::Internal { + +static void cutTail(QStringList &list) +{ + while (!list.isEmpty() && list.last().trimmed().isEmpty()) + list.removeLast(); +} + +ModificationFile::ModificationFile() {} + +bool ModificationFile::exists() const +{ + return m_filePath.exists(); +} + +void ModificationFile::clear() +{ + m_options.clear(); + m_tweaks.clear(); +} + +QStringList ModificationFile::contentOf(const Utils::FilePath &filePath) const +{ + QFile resource(filePath.nativePath()); + resource.open(QIODevice::ReadOnly | QIODevice::Text); + QTextStream inStream(&resource); + + QStringList result; + QString line; + while (inStream.readLineInto(&line)) + result << line + '\n'; + return result; +} + +QStringList ModificationFile::currentModificationFile() const +{ + QStringList lines; + if (m_filePath.exists()) + lines = contentOf(m_filePath); + else + lines = defaultModificationFile(); + + return lines; +} + +void ModificationFile::setOptions(const QString &options) +{ + m_options = options.split('\n', Qt::SkipEmptyParts); +} + +void ModificationFile::setOptions(const QStringList &options) +{ + m_options = options; +} + +void ModificationFile::setTweaks(const QString &tweaks) +{ + m_tweaks = tweaks.split('\n', Qt::KeepEmptyParts); + cutTail(m_tweaks); +} + +void ModificationFile::setTweaks(const QStringList &tweaks) +{ + m_tweaks = tweaks; + cutTail(m_tweaks); +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/modificationfile.h b/src/plugins/coco/cocobuild/modificationfile.h new file mode 100644 index 00000000000..0f156ab2495 --- /dev/null +++ b/src/plugins/coco/cocobuild/modificationfile.h @@ -0,0 +1,51 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include + +namespace Coco::Internal { + +class ModificationFile +{ +public: + ModificationFile(); + + virtual void read() = 0; + virtual void write() const = 0; + + virtual void setProjectDirectory(const Utils::FilePath &projectDirectory) = 0; + + virtual QString fileName() const = 0; + QString nativePath() const { return m_filePath.nativePath(); } + bool exists() const; + + const QStringList &options() const { return m_options; } + void setOptions(const QString &options); + + const QStringList &tweaks() const { return m_tweaks; } + void setTweaks(const QString &tweaks); + +protected: + void clear(); + + virtual QStringList defaultModificationFile() const = 0; + QStringList contentOf(const Utils::FilePath &filePath) const; + QStringList currentModificationFile() const; + + void setFilePath(const Utils::FilePath &path) { m_filePath = path; } + + void setOptions(const QStringList &options); + void setTweaks(const QStringList &tweaks); + +private: + QStringList m_options; + QStringList m_tweaks; + + Utils::FilePath m_filePath; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/qmakefeaturefile.cpp b/src/plugins/coco/cocobuild/qmakefeaturefile.cpp new file mode 100644 index 00000000000..897cbaefa7b --- /dev/null +++ b/src/plugins/coco/cocobuild/qmakefeaturefile.cpp @@ -0,0 +1,105 @@ +// 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 "qmakefeaturefile.h" + +#include "cocopluginconstants.h" + +#include +#include +#include + +namespace Coco::Internal { + +static const char assignment[] = "COVERAGE_OPTIONS = \\\n"; +static const char tweaksLine[] = "# User-supplied settings follow here:\n"; + +static void cutTail(QStringList &list) +{ + while (!list.isEmpty() && list.last().trimmed().isEmpty()) + list.removeLast(); +} + +QMakeFeatureFile::QMakeFeatureFile() {} + +QString QMakeFeatureFile::fileName() const +{ + return QString(Constants::PROFILE_NAME) + ".prf"; +} + +void QMakeFeatureFile::setProjectDirectory(const Utils::FilePath &projectDirectory) +{ + setFilePath(projectDirectory.pathAppended(fileName())); +} + +QString QMakeFeatureFile::fromFileLine(const QString &line) const +{ + return line.chopped(2).trimmed().replace("\\\"", "\""); +} + +QString QMakeFeatureFile::toFileLine(const QString &option) const +{ + QString line = option.trimmed().replace("\"", "\\\""); + return " " + line + " \\\n"; +} + +void QMakeFeatureFile::read() +{ + clear(); + QStringList file = currentModificationFile(); + + { + QStringList options; + int i = file.indexOf(assignment); + if (i != -1) { + i++; + while (i < file.size() && file[i].endsWith("\\\n")) { + options += fromFileLine(file[i]); + i++; + } + } + setOptions(options); + } + { + QStringList tweaks; + int i = file.indexOf(tweaksLine); + if (i != -1) { + i++; + while (i < file.size()) { + tweaks += file[i].chopped(1); + i++; + } + } + setTweaks(tweaks); + } +} + +void QMakeFeatureFile::write() const +{ + QFile out(nativePath()); + out.open(QIODevice::WriteOnly | QIODevice::Text); + + QTextStream outStream(&out); + for (QString &line : defaultModificationFile()) { + outStream << line; + + if (line.startsWith(assignment)) { + for (const QString &option : options()) { + QString line = toFileLine(option); + if (!line.isEmpty()) + outStream << line; + } + } + } + for (const QString &line : tweaks()) + outStream << line << "\n"; + + out.close(); +} + +QStringList QMakeFeatureFile::defaultModificationFile() const +{ + return contentOf(":/cocoplugin/files/cocoplugin.prf"); +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/qmakefeaturefile.h b/src/plugins/coco/cocobuild/qmakefeaturefile.h new file mode 100644 index 00000000000..3c865a1a25d --- /dev/null +++ b/src/plugins/coco/cocobuild/qmakefeaturefile.h @@ -0,0 +1,34 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "modificationfile.h" + +#include + +#include +#include + +namespace Coco::Internal { + +class QMakeFeatureFile : public ModificationFile +{ +public: + QMakeFeatureFile(); + + void setProjectDirectory(const Utils::FilePath &projectDirectory) override; + void read() override; + void write() const override; + + QString fileName() const override; + +protected: + QStringList defaultModificationFile() const override; + +private: + QString fromFileLine(const QString &line) const; + QString toFileLine(const QString &option) const; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index 89047b84249..13b0d690e90 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -1,17 +1,25 @@ -// Copyright (C) 2022 The Qt Company Ltd. +// 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 "cocobuild/cocobuildstep.h" #include "cocolanguageclient.h" +#include "cocopluginconstants.h" #include "cocotr.h" +#include "settings/cocoprojectsettingswidget.h" +#include "settings/globalsettings.h" +#include "settings/globalsettingspage.h" #include #include #include +#include +#include +#include +#include #include #include - #include #include #include @@ -19,12 +27,17 @@ #include #include #include +#include +#include using namespace Core; using namespace Utils; namespace Coco { +using namespace ProjectExplorer; +using namespace Internal; + class CocoPlugin final : public ExtensionSystem::IPlugin { Q_OBJECT @@ -36,7 +49,7 @@ public: // FIXME: Kill m_client? } - void initialize() final + void initLanguageServer() { ActionBuilder(this, "Coco.startCoco") .setText("Squish Coco ...") @@ -50,53 +63,112 @@ public: m_client->shutdown(); m_client = nullptr; - QDialog dialog(ICore::dialogParent()); - dialog.setModal(true); - auto layout = new QFormLayout(); + CocoInstallation coco; + if (coco.isValid()) { + QDialog dialog(ICore::dialogParent()); + dialog.setModal(true); + auto layout = new QFormLayout(); - const Environment env = Environment::systemEnvironment(); - const FilePath squishCocoPath = FilePath::fromUserInput(env.value("SQUISHCOCO")); - const FilePath candidate = FilePath("coveragebrowser").searchInPath({squishCocoPath}, - FilePath::PrependToPath); + PathChooser csmesChoser; + csmesChoser.setHistoryCompleter("Coco.CSMes.history", true); + csmesChoser.setExpectedKind(PathChooser::File); + csmesChoser.setInitialBrowsePathBackup(PathChooser::homePath()); + csmesChoser.setPromptDialogFilter(Tr::tr("Coco instrumentation files (*.csmes)")); + csmesChoser.setPromptDialogTitle(Tr::tr("Select a Squish Coco Instrumentation File")); + layout->addRow(Tr::tr("CSMes file:"), &csmesChoser); + QDialogButtonBox buttons(QDialogButtonBox::Cancel | QDialogButtonBox::Open); + layout->addWidget(&buttons); + dialog.setLayout(layout); + dialog.resize(480, dialog.height()); - PathChooser cocoChooser; - if (!candidate.isEmpty()) - cocoChooser.setFilePath(candidate); - cocoChooser.setExpectedKind(PathChooser::Command); - cocoChooser.setPromptDialogTitle(Tr::tr("Select a Squish Coco CoverageBrowser Executable")); + QObject::connect(&buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + QObject::connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); - cocoChooser.setHistoryCompleter("Coco.CoverageBrowser.history", true); - layout->addRow(Tr::tr("CoverageBrowser:"), &cocoChooser); - PathChooser csmesChoser; - csmesChoser.setHistoryCompleter("Coco.CSMes.history", true); - csmesChoser.setExpectedKind(PathChooser::File); - csmesChoser.setInitialBrowsePathBackup(FileUtils::homePath()); - csmesChoser.setPromptDialogFilter(Tr::tr("Coco instrumentation files (*.csmes)")); - csmesChoser.setPromptDialogTitle(Tr::tr("Select a Squish Coco Instrumentation File")); - layout->addRow(Tr::tr("CSMes:"), &csmesChoser); - QDialogButtonBox buttons(QDialogButtonBox::Cancel | QDialogButtonBox::Open); - layout->addItem(new QSpacerItem(0, 20, QSizePolicy::Expanding, QSizePolicy::MinimumExpanding)); - layout->addWidget(&buttons); - dialog.setLayout(layout); - dialog.resize(480, dialog.height()); - - QObject::connect(&buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); - QObject::connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); - - if (dialog.exec() == QDialog::Accepted) { - const FilePath cocoPath = cocoChooser.filePath(); - const FilePath csmesPath = csmesChoser.filePath(); - if (cocoPath.isExecutableFile() && csmesPath.exists()) { - m_client = new CocoLanguageClient(cocoPath, csmesPath); - m_client->start(); + if (dialog.exec() == QDialog::Accepted) { + const FilePath cocoPath = coco.coverageBrowserPath(); + const FilePath csmesPath = csmesChoser.filePath(); + if (cocoPath.isExecutableFile() && csmesPath.exists()) { + m_client = new CocoLanguageClient(cocoPath, csmesPath); + m_client->start(); + } } + } else { + QMessageBox msg; + msg.setText(Tr::tr("No valid CoverageScanner found.")); + QPushButton *configButton = msg.addButton(Tr::tr("Configure"), QMessageBox::AcceptRole); + msg.setStandardButtons(QMessageBox::Cancel); + msg.exec(); + + if (msg.clickedButton() == configButton) + Core::ICore::showOptionsDialog(Constants::COCO_SETTINGS_PAGE_ID); } } + bool initialize(const QStringList &arguments, QString *errorString); + void addEntryToProjectSettings(); + private: + static void addBuildStep(ProjectExplorer::Target *target); + + QMakeStepFactory m_qmakeStepFactory; + CMakeStepFactory m_cmakeStepFactory; + CocoLanguageClient *m_client = nullptr; }; +void CocoPlugin::addBuildStep(Target *target) +{ + for (BuildConfiguration *config : target->buildConfigurations()) { + if (BuildSettings::supportsBuildConfig(*config)) { + BuildStepList *steps = config->buildSteps(); + + if (!steps->contains(Constants::COCO_STEP_ID)) + steps->insertStep(0, CocoBuildStep::create(config)); + + steps->firstOfType()->display(config); + } + } +} + +bool CocoPlugin::initialize(const QStringList &arguments, QString *errorString) +{ + Q_UNUSED(arguments) + Q_UNUSED(errorString) + + GlobalSettings::read(); + GlobalSettingsPage::instance().widget(); + addEntryToProjectSettings(); + + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [&](Project *project) { + if (Target *target = project->activeTarget()) + addBuildStep(target); + + connect(project, &Project::addedTarget, this, [](Target *target) { + addBuildStep(target); + }); + }); + + initLanguageServer(); + + return true; +} + +void CocoPlugin::addEntryToProjectSettings() +{ + auto panelFactory = new ProjectPanelFactory; + panelFactory->setPriority(50); + panelFactory->setDisplayName(tr("Coco Code Coverage")); + panelFactory->setSupportsFunction([](Project *project) { + if (Target *target = project->activeTarget()) { + if (BuildConfiguration *abc = target->activeBuildConfiguration()) + return BuildSettings::supportsBuildConfig(*abc); + } + return false; + }); + panelFactory->setCreateWidgetFunction( + [](Project *project) { return new CocoProjectSettingsWidget(project); }); +} + } // namespace Coco #include "cocoplugin.moc" diff --git a/src/plugins/coco/cocoplugin.qrc b/src/plugins/coco/cocoplugin.qrc new file mode 100644 index 00000000000..bb52bda91b1 --- /dev/null +++ b/src/plugins/coco/cocoplugin.qrc @@ -0,0 +1,10 @@ + + + images/SquishCoco_48x48.png + files/cocoplugin.prf + files/cocoplugin.cmake + files/cocoplugin-clang.cmake + files/cocoplugin-gcc.cmake + files/cocoplugin-visualstudio.cmake + + diff --git a/src/plugins/coco/cocoplugin_global.h b/src/plugins/coco/cocoplugin_global.h new file mode 100644 index 00000000000..b89de4ccaea --- /dev/null +++ b/src/plugins/coco/cocoplugin_global.h @@ -0,0 +1,12 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#if defined(COCO_LIBRARY) +# define COCOPLUGINSHARED_EXPORT Q_DECL_EXPORT +#else +# define COCOPLUGINSHARED_EXPORT Q_DECL_IMPORT +#endif diff --git a/src/plugins/coco/cocopluginconstants.h b/src/plugins/coco/cocopluginconstants.h new file mode 100644 index 00000000000..8fd36ee3bce --- /dev/null +++ b/src/plugins/coco/cocopluginconstants.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace Coco { +namespace Constants { + +const char ACTION_ID[] = "coco.Action"; +const char MENU_ID[] = "coco.Menu"; +const char COCO_STEP_ID[] = "Cocoplugin.BuildStep"; + +const char PROFILE_NAME[] = "cocoplugin"; // Name of the Coco profile file + +const char COCO_SETTINGS_GROUP[] = "Coco"; +const char COCO_SETTINGS_PAGE_ID[] = "A.CocoOptions"; + +// Project settings +const char SETTINGS_NAME_KEY[] = "CocoProjectSettings"; +const char SELECTION_DIR_KEY[] = "SelectionDir"; + +} // namespace Constants +} // namespace Coco diff --git a/src/plugins/coco/common.cpp b/src/plugins/coco/common.cpp new file mode 100644 index 00000000000..e822e6eb7b7 --- /dev/null +++ b/src/plugins/coco/common.cpp @@ -0,0 +1,30 @@ +// 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 "common.h" + +#include "cocopluginconstants.h" + +#include + +QString maybeQuote(const QString &str) +{ + if ((str.contains(' ') || str.contains('\t')) && !str.startsWith('"')) + return '"' + str + '"'; + else + return str; +} + +void logSilently(const QString &msg) +{ + static const QString prefix = QString{"[%1] "}.arg(Coco::Constants::PROFILE_NAME); + + Core::MessageManager::writeSilently(prefix + msg); +} + +void logFlashing(const QString &msg) +{ + static const QString prefix = QString{"[%1] "}.arg(Coco::Constants::PROFILE_NAME); + + Core::MessageManager::writeFlashing(prefix + msg); +} diff --git a/src/plugins/coco/common.h b/src/plugins/coco/common.h new file mode 100644 index 00000000000..fde75dc617e --- /dev/null +++ b/src/plugins/coco/common.h @@ -0,0 +1,14 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef COMMON_H +#define COMMON_H + +#include + +QString maybeQuote(const QString &str); + +void logSilently(const QString &msg); +void logFlashing(const QString &msg); + +#endif // COMMON_H diff --git a/src/plugins/coco/files/cocoplugin-clang.cmake b/src/plugins/coco/files/cocoplugin-clang.cmake new file mode 100644 index 00000000000..697b87465e0 --- /dev/null +++ b/src/plugins/coco/files/cocoplugin-clang.cmake @@ -0,0 +1,8 @@ +# Created by the Coco Qt Creator plugin. Do not edit! + +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_AR ar) +set(CMAKE_LINKER clang) + +include(cocoplugin.cmake) diff --git a/src/plugins/coco/files/cocoplugin-gcc.cmake b/src/plugins/coco/files/cocoplugin-gcc.cmake new file mode 100644 index 00000000000..1271c3115a3 --- /dev/null +++ b/src/plugins/coco/files/cocoplugin-gcc.cmake @@ -0,0 +1,8 @@ +# Created by the Coco Qt Creator plugin. Do not edit! + +set(CMAKE_C_COMPILER gcc) +set(CMAKE_CXX_COMPILER g++) +set(CMAKE_AR ar) +set(CMAKE_LINKER gcc) + +include(cocoplugin.cmake) diff --git a/src/plugins/coco/files/cocoplugin-visualstudio.cmake b/src/plugins/coco/files/cocoplugin-visualstudio.cmake new file mode 100644 index 00000000000..d72f74db882 --- /dev/null +++ b/src/plugins/coco/files/cocoplugin-visualstudio.cmake @@ -0,0 +1,8 @@ +# Created by the Coco Qt Creator plugin. Do not edit! + +set(CMAKE_C_COMPILER cl) +set(CMAKE_CXX_COMPILER cl) +set(CMAKE_AR lib) +set(CMAKE_LINKER link) + +include(cocoplugin.cmake) diff --git a/src/plugins/coco/files/cocoplugin.cmake b/src/plugins/coco/files/cocoplugin.cmake new file mode 100644 index 00000000000..78ea51de860 --- /dev/null +++ b/src/plugins/coco/files/cocoplugin.cmake @@ -0,0 +1,87 @@ +# Created by the Coco Qt Creator plugin. Do not edit! + +set(coverage_flags_list +) +list(JOIN coverage_flags_list " " coverage_flags) + +foreach(var IN ITEMS CMAKE_C_COMPILER CMAKE_CXX_COMPILER) + if(NOT DEFINED ${var}) + message(FATAL_ERROR "Variable ${var} must be defined.") + endif() +endforeach() + +set(CMAKE_C_FLAGS_INIT "${coverage_flags}" + CACHE STRING "Coverage flags for the C compiler." FORCE) +set(CMAKE_CXX_FLAGS_INIT "${coverage_flags}" + CACHE STRING "Coverage flags for the C++ compiler." FORCE) +set(CMAKE_EXE_LINKER_FLAGS_INIT "${coverage_flags}" + CACHE STRING "Coverage flags for the linker." FORCE) +set(CMAKE_SHARED_LINKER_FLAGS_INIT "${coverage_flags}" + CACHE STRING "Coverage flags to link shared libraries." FORCE) +set(CMAKE_STATIC_LINKER_FLAGS_INIT "${coverage_flags}" + CACHE STRING "Coverage flags to link static libraries." FORCE) + +if (DEFINED ENV{SQUISHCOCO}) + set(cocopath $ENV{SQUISHCOCO}) +else() + find_file(cocopath SquishCoco + PATHS "$ENV{HOME}" /opt/ "/Applications" + REQUIRED + NO_DEFAULT_PATH + ) +endif() + +if(CMAKE_HOST_APPLE) + set(wrapperdir "${cocopath}/") +elseif(CMAKE_HOST_UNIX) + set(wrapperdir "${cocopath}/bin/") +elseif(MINGW) + set(wrapperdir "${cocopath}\\bin\\") +else() + set(wrapperdir "${cocopath}\\" ) +endif() + +get_filename_component(c_compiler ${CMAKE_C_COMPILER} NAME) +find_program(code_coverage_c_compiler cs${c_compiler} + PATHS ${wrapperdir} + REQUIRED NO_DEFAULT_PATH) +set(CMAKE_C_COMPILER "${code_coverage_c_compiler}" + CACHE FILEPATH "CoverageScanner wrapper for C compiler" FORCE) + +get_filename_component(cxx_compiler ${CMAKE_CXX_COMPILER} NAME) +find_program(code_coverage_cxx_compiler cs${cxx_compiler} + PATHS ${wrapperdir} + REQUIRED NO_DEFAULT_PATH) +set(CMAKE_CXX_COMPILER "${code_coverage_cxx_compiler}" + CACHE FILEPATH "CoverageScanner wrapper for C++ compiler" FORCE) + +if(DEFINED CMAKE_LINKER) + get_filename_component(linker_prog ${CMAKE_LINKER} NAME) + find_program(code_coverage_linker cs${linker_prog} + PATHS ${wrapperdir} + REQUIRED NO_DEFAULT_PATH) + set(CMAKE_LINKER "${code_coverage_linker}" + CACHE FILEPATH "CoverageScanner wrapper for linker" FORCE) +elseif(${c_compiler} STREQUAL "cl.exe") # special case for Visual Studio + find_program(code_coverage_linker "cslink.exe" + PATHS ${wrapperdir} + REQUIRED NO_DEFAULT_PATH) + set(CMAKE_LINKER "${code_coverage_linker}" + CACHE FILEPATH "CoverageScanner wrapper for linker" FORCE) +endif() + +if(DEFINED CMAKE_AR) + get_filename_component(ar_prog ${CMAKE_AR} NAME) + find_program(code_coverage_ar cs${ar_prog} + PATHS ${wrapperdir} + REQUIRED NO_DEFAULT_PATH) + set(CMAKE_AR "${code_coverage_ar}" + CACHE FILEPATH "CoverageScanner wrapper for ar" FORCE) +endif() + +mark_as_advanced( + cocopath + code_coverage_c_compiler code_coverage_cxx_compiler code_coverage_linker code_coverage_ar +) + +# User-supplied settings follow here: diff --git a/src/plugins/coco/files/cocoplugin.prf b/src/plugins/coco/files/cocoplugin.prf new file mode 100644 index 00000000000..b68c2c671da --- /dev/null +++ b/src/plugins/coco/files/cocoplugin.prf @@ -0,0 +1,33 @@ +# Created by the Coco plugin. Do not edit! + +COVERAGE_OPTIONS = \ + +defineReplace(toCoco) { + cmd = $$1 + path = $$take_first(cmd) + prog = $$basename(path) + + return(cs$$prog $$cmd) +} + +isEmpty(COCOPATH): error(The variable COCOPATH must be set) + +macos: wrapperdir = $$COCOPATH +else: unix: wrapperdir = $$COCOPATH/bin +else: win32: { + win32-arm-msvc*|win32-x86-msvc*: wrapperdir = $$COCOPATH/visualstudio + else: win32-arm64-msvc*|win32-x64-msvc*: wrapperdir = $$COCOPATH/visualstudio_x64 + else: wrapperdir = $$COCOPATH +} + +QMAKE_CFLAGS += $$COVERAGE_OPTIONS +QMAKE_CXXFLAGS += $$COVERAGE_OPTIONS +QMAKE_LFLAGS += $$COVERAGE_OPTIONS + +QMAKE_AR = $$wrapperdir/$$toCoco($$QMAKE_AR) +QMAKE_CC = $$wrapperdir/$$toCoco($$QMAKE_CC) +QMAKE_CXX = $$wrapperdir/$$toCoco($$QMAKE_CXX) +QMAKE_LINK = $$wrapperdir/$$toCoco($$QMAKE_LINK) +QMAKE_LINK_SHLIB_CMD = $$wrapperdir/$$toCoco($$QMAKE_LINK_SHLIB_CMD) + +# User-supplied settings follow here: diff --git a/src/plugins/coco/images/SquishCoco_48x48.png b/src/plugins/coco/images/SquishCoco_48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..74a68a1727c9257c5d62005b940d91b5bf679303 GIT binary patch literal 594 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F$mbIO@o>nPIdPh>vfk#|v0@cRXRLX8`1dvQ{l3@jdw(%<6YGK7 z-<4-d-;QIAWAf+JcR!H!`chovJi9$i6Y_o-8F=nE%*?~=Eq>_dDG@`4mv)uTxqA5$ ze>djjUC}T)FMRUu4VS(WEkj4;pKe0`HdanZiD5e9dDZdXq=hTY6&}6S%2f8Q%h@(P zQSQm%?XB*wbEPF-NI$837W$yEN$r*Lm47T+X^p3LJLzx!p;W?GGV7=PMZOho)&eZI zubO6kowR=I!h!`!Vm0OqWCMIPWPZrj^1JZ9Z3y3Uu0nka^Qwz{EUs(gl6LQURynuK z!Sw%j=A9d7I+)#Dx$bve?7Jh2`Fhgh*f*V=_w(g^Q;-S%GB4V0Wp>W}TYCO=)guRU zj+XUoTbNgM{^5MV7NX4PUdmzrhf7y*hS%gDPyQ@tZ8(zXTqt(l!r|u%&W_@nyS9X% ztBY{Gx^UM~M!RX!b87M#zlk#*5ZQQVMWD}eA>nu89|DT5ZMk8ax9j1`WXsCJ_*%y~ u=_g$i`gZSkI^@MX=X`|D#?smXZuL#83pf6dw_;#mVDNPHb6Mw<&;$U=ru8cT literal 0 HcmV?d00001 diff --git a/src/plugins/coco/settings/cocoinstallation.cpp b/src/plugins/coco/settings/cocoinstallation.cpp new file mode 100644 index 00000000000..77d466eed3e --- /dev/null +++ b/src/plugins/coco/settings/cocoinstallation.cpp @@ -0,0 +1,177 @@ +// 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 "cocoinstallation.h" + +#include "cocotr.h" +#include "common.h" +#include "globalsettings.h" + +#include +#include + +#include +#include +#include + +namespace Coco::Internal { + +struct CocoInstallationPrivate +{ + Utils::FilePath cocoPath; + bool isValid = false; + QString errorMessage = Tr::tr("Error: Coco installation directory not set. (This can't happen.)"); +}; + +CocoInstallationPrivate *CocoInstallation::d = nullptr; + +CocoInstallation::CocoInstallation() +{ + if (!d) + d = new CocoInstallationPrivate; +} + +Utils::FilePath CocoInstallation::directory() const +{ + return d->cocoPath; +} + +Utils::FilePath CocoInstallation::coverageBrowserPath() const +{ + QString browserPath; + + if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost()) + browserPath = "bin/coveragebrowser"; + else + browserPath = "coveragebrowser.exe"; + + return d->cocoPath.resolvePath(browserPath); +} + +void CocoInstallation::setDirectory(const Utils::FilePath &dir) +{ + if (isCocoDirectory(dir)) { + d->cocoPath = dir; + d->isValid = true; + d->errorMessage = ""; + verifyCocoDirectory(); + } + else { + d->cocoPath = Utils::FilePath(); + d->isValid = false; + d->errorMessage + = Tr::tr("Error: Coco installation directory not found at \"%1\".").arg(dir.nativePath()); + } +} + +Utils::FilePath CocoInstallation::coverageScannerPath(const Utils::FilePath &cocoDir) const +{ + QString scannerPath; + + if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost()) + scannerPath = "bin/coveragescanner"; + else + scannerPath = "coveragescanner.exe"; + + return cocoDir.resolvePath(scannerPath); +} + +bool CocoInstallation::isCocoDirectory(const Utils::FilePath &cocoDir) const +{ + return coverageScannerPath(cocoDir).exists(); +} + +void CocoInstallation::logError(const QString &msg) +{ + logFlashing(msg); + d->isValid = false; + d->errorMessage = msg; +} + +bool CocoInstallation::verifyCocoDirectory() +{ + QString coveragescanner = coverageScannerPath(d->cocoPath).nativePath(); + + QProcess proc; + proc.setProgram(coveragescanner); + proc.setArguments({"--cs-help"}); + proc.start(); + + if (!proc.waitForStarted()) { + logError(Tr::tr("Error: Coveragescanner at \"%1\" did not start.").arg(coveragescanner)); + return false; + } + + if (!proc.waitForFinished()) { + logError(Tr::tr("Error: Coveragescanner at \"%1\" did not finish.").arg(coveragescanner)); + return false; + } + + QString result = QString::fromLatin1(proc.readAll()); + static const QRegularExpression linebreak("\n|\r\n|\r"); + QStringList lines = result.split(linebreak, Qt::SkipEmptyParts); + + const qsizetype n = lines.size(); + if (n >= 2 && lines[n - 2].startsWith("Version:") && lines[n - 1].startsWith("Date:")) { + logSilently(Tr::tr("Valid CoverageScanner found at \"%1\":").arg(coveragescanner)); + logSilently(" " + lines[n - 2]); + logSilently(" " + lines[n - 1]); + return true; + } else { + logError( + Tr::tr("Error: Coveragescanner at \"%1\" did not run correctly.").arg(coveragescanner)); + for (const QString &l : lines) { + logSilently(l); + } + return false; + } +} + +bool CocoInstallation::isValid() const +{ + return d->isValid; +} + +QString CocoInstallation::errorMessage() const +{ + return d->errorMessage; +} + +void CocoInstallation::tryPath(const QString &path) +{ + if (d->isValid) + return; + + const auto fpath = Utils::FilePath::fromString(path); + const QString nativePath = fpath.nativePath(); + if (isCocoDirectory(fpath)) { + logSilently(Tr::tr("Found Coco directory \"%1\".").arg(nativePath)); + setDirectory(fpath); + GlobalSettings::save(); + } else + logSilently(Tr::tr("Checked Coco directory \"%1\".").arg(nativePath)); +} + +QString CocoInstallation::envVar(const QString &var) const +{ + return QProcessEnvironment::systemEnvironment().value(var); +} + +void CocoInstallation::findDefaultDirectory() +{ + if (Utils::HostOsInfo::isMacHost()) + tryPath("/Applications/SquishCoco"); + else if (Utils::HostOsInfo::isAnyUnixHost()) { + tryPath((Utils::FileUtils::homePath() / "SquishCoco").nativePath()); + tryPath("/opt/SquishCoco"); + } else { + tryPath(envVar("SQUISHCOCO")); + QStringList homeDirs = QStandardPaths::standardLocations(QStandardPaths::HomeLocation); + if (!homeDirs.isEmpty()) + tryPath(homeDirs[0] + "/squishcoco"); + tryPath(envVar("ProgramFiles") + "\\squishcoco"); + tryPath(envVar("ProgramFiles(x86)") + "\\squishcoco"); + } +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/settings/cocoinstallation.h b/src/plugins/coco/settings/cocoinstallation.h new file mode 100644 index 00000000000..73d83bf704d --- /dev/null +++ b/src/plugins/coco/settings/cocoinstallation.h @@ -0,0 +1,39 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +class QString; + +namespace Coco::Internal { + +struct CocoInstallationPrivate; + +// Borg pattern: There are many instances of this class, but all are the same. +class CocoInstallation +{ +public: + CocoInstallation(); + + Utils::FilePath directory() const; + Utils::FilePath coverageBrowserPath() const; + void setDirectory(const Utils::FilePath &dir); + void findDefaultDirectory(); + + bool isValid() const; + QString errorMessage() const; + +private: + Utils::FilePath coverageScannerPath(const Utils::FilePath &cocoDir) const; + void logError(const QString &msg); + bool isCocoDirectory(const Utils::FilePath &cocoDir) const; + bool verifyCocoDirectory(); + void tryPath(const QString &path); + QString envVar(const QString &var) const; + + static CocoInstallationPrivate *d; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/settings/cocoprojectsettingswidget.cpp b/src/plugins/coco/settings/cocoprojectsettingswidget.cpp new file mode 100644 index 00000000000..8e6f10cc5ec --- /dev/null +++ b/src/plugins/coco/settings/cocoprojectsettingswidget.cpp @@ -0,0 +1,40 @@ +// 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 "cocoprojectsettingswidget.h" + +#include "cocobuild/cocoprojectwidget.h" +#include "cocopluginconstants.h" + +#include +#include +#include +#include +#include + +#include + +namespace Coco::Internal { + +CocoProjectSettingsWidget::CocoProjectSettingsWidget(ProjectExplorer::Project *project) + : m_layout{new QVBoxLayout} +{ + setUseGlobalSettingsCheckBoxVisible(false); + setGlobalSettingsId(Constants::COCO_SETTINGS_PAGE_ID); + + if (auto *target = project->activeTarget()) { + auto abc = target->activeBuildConfiguration(); + + if (abc->id() == QmakeProjectManager::Constants::QMAKE_BC_ID + || abc->id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID) + m_layout->addWidget(new CocoProjectWidget(project, *abc)); + } + setLayout(m_layout); +} + +CocoProjectSettingsWidget::~CocoProjectSettingsWidget() +{ + delete m_layout; +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/settings/cocoprojectsettingswidget.h b/src/plugins/coco/settings/cocoprojectsettingswidget.h new file mode 100644 index 00000000000..c201a55ece7 --- /dev/null +++ b/src/plugins/coco/settings/cocoprojectsettingswidget.h @@ -0,0 +1,28 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include + +namespace ProjectExplorer { +class Project; +} + +namespace Coco::Internal { + +class CocoProjectSettingsWidget : public ProjectExplorer::ProjectSettingsWidget +{ + Q_OBJECT + +public: + explicit CocoProjectSettingsWidget(ProjectExplorer::Project *project); + ~CocoProjectSettingsWidget(); + +private: + QVBoxLayout *m_layout; +}; + +} // namespace Coco::Internal diff --git a/src/plugins/coco/settings/globalsettings.cpp b/src/plugins/coco/settings/globalsettings.cpp new file mode 100644 index 00000000000..594355964ee --- /dev/null +++ b/src/plugins/coco/settings/globalsettings.cpp @@ -0,0 +1,53 @@ +// 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 "globalsettings.h" + +#include "cocoinstallation.h" +#include "cocopluginconstants.h" + +#include +#include + +#include +#include + +namespace Coco::Internal { +namespace GlobalSettings { + +static const char DIRECTORY[] = "CocoDirectory"; + +void read() +{ + CocoInstallation coco; + bool directoryInSettings = false; + + Utils::QtcSettings *s = Core::ICore::settings(); + s->beginGroup(Constants::COCO_SETTINGS_GROUP); + const QStringList keys = s->allKeys(); + for (const QString &keyString : keys) { + Utils::Key key(keyString.toLatin1()); + if (key == DIRECTORY) { + coco.setDirectory(Utils::FilePath::fromUserInput(s->value(key).toString())); + directoryInSettings = true; + } else + s->remove(key); + } + s->endGroup(); + + if (!directoryInSettings) + coco.findDefaultDirectory(); + + GlobalSettings::save(); +} + +void save() +{ + Utils::QtcSettings *s = Core::ICore::settings(); + s->beginGroup(Constants::COCO_SETTINGS_GROUP); + s->setValue(DIRECTORY, CocoInstallation().directory().toUserOutput()); + s->endGroup(); +} + +} // namespace GlobalSettings +} // namespace Coco::Internal diff --git a/src/plugins/coco/settings/globalsettings.h b/src/plugins/coco/settings/globalsettings.h new file mode 100644 index 00000000000..e57f7e790f3 --- /dev/null +++ b/src/plugins/coco/settings/globalsettings.h @@ -0,0 +1,13 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace Coco::Internal { +namespace GlobalSettings { + +void read(); +void save(); + +} // namespace GlobalSettings +} // namespace Coco::Internal diff --git a/src/plugins/coco/settings/globalsettingspage.cpp b/src/plugins/coco/settings/globalsettingspage.cpp new file mode 100644 index 00000000000..b4eda76d0ba --- /dev/null +++ b/src/plugins/coco/settings/globalsettingspage.cpp @@ -0,0 +1,121 @@ +// 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 "globalsettingspage.h" + +#include "cocoinstallation.h" +#include "cocopluginconstants.h" +#include "cocotr.h" +#include "globalsettings.h" + +#include +#include + +namespace Coco::Internal { + +GlobalSettingsWidget::GlobalSettingsWidget(QFrame *parent) + : QFrame(parent) +{ + m_cocoPathAspect.setDefaultPathValue(m_coco.directory()); + m_cocoPathAspect.setExpectedKind(Utils::PathChooser::ExistingDirectory); + m_cocoPathAspect.setPromptDialogTitle(Tr::tr("Coco Installation Directory")); + + connect( + &m_cocoPathAspect, + &Utils::FilePathAspect::changed, + this, + &GlobalSettingsWidget::onCocoPathChanged); + + using namespace Layouting; + Form{ + Column{ + Row{Tr::tr("Coco Directory"), m_cocoPathAspect}, + Row{m_messageLabel}} + }.attachTo(this); +} + +void GlobalSettingsWidget::onCocoPathChanged() +{ + if (!verifyCocoDirectory(m_cocoPathAspect())) + m_cocoPathAspect.setValue(m_previousCocoDir, Utils::BaseAspect::BeQuiet); +} + +bool GlobalSettingsWidget::verifyCocoDirectory(const Utils::FilePath &cocoDir) +{ + m_coco.setDirectory(cocoDir); + m_messageLabel.setText(m_coco.errorMessage()); + if (m_coco.isValid()) + m_messageLabel.setIconType(Utils::InfoLabel::None); + else + m_messageLabel.setIconType(Utils::InfoLabel::Error); + return m_coco.isValid(); +} + +void GlobalSettingsWidget::apply() +{ + if (!verifyCocoDirectory(widgetCocoDir())) + return; + + m_coco.setDirectory(widgetCocoDir()); + GlobalSettings::save(); + + emit updateCocoDir(); +} + +void GlobalSettingsWidget::cancel() +{ + m_coco.setDirectory(m_previousCocoDir); +} + +void GlobalSettingsWidget::setVisible(bool visible) +{ + QFrame::setVisible(visible); + m_previousCocoDir = m_coco.directory(); +} + +Utils::FilePath GlobalSettingsWidget::widgetCocoDir() const +{ + return Utils::FilePath::fromUserInput(m_cocoPathAspect.value()); +} + +GlobalSettingsPage::GlobalSettingsPage() + : m_widget(nullptr) +{ + setId(Constants::COCO_SETTINGS_PAGE_ID); + setDisplayName(QCoreApplication::translate("Coco", "Coco")); + setCategory("I.Coco"); // Category I contains also the C++ settings. + setDisplayCategory(QCoreApplication::translate("Coco", "Coco")); + setCategoryIconPath(":/cocoplugin/images/SquishCoco_48x48.png"); +} + +GlobalSettingsPage &GlobalSettingsPage::instance() +{ + static GlobalSettingsPage instance; + return instance; +} + +GlobalSettingsWidget *GlobalSettingsPage::widget() +{ + if (!m_widget) + m_widget = new GlobalSettingsWidget; + return m_widget; +} + +void GlobalSettingsPage::apply() +{ + if (m_widget) + m_widget->apply(); +} + +void GlobalSettingsPage::cancel() +{ + if (m_widget) + m_widget->cancel(); +} + +void GlobalSettingsPage::finish() +{ + delete m_widget; +} + +} // namespace Coco::Internal diff --git a/src/plugins/coco/settings/globalsettingspage.h b/src/plugins/coco/settings/globalsettingspage.h new file mode 100644 index 00000000000..e55d6881b86 --- /dev/null +++ b/src/plugins/coco/settings/globalsettingspage.h @@ -0,0 +1,59 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "cocoinstallation.h" + +#include + +#include + +namespace Coco::Internal { + +class GlobalSettingsWidget : public QFrame +{ + Q_OBJECT + +public: + GlobalSettingsWidget(QFrame *parent = nullptr); + + void apply(); + void cancel(); + +signals: + void updateCocoDir(); + +public slots: + void setVisible(bool visible) override; + +private: + void onCocoPathChanged(); + + Utils::FilePath widgetCocoDir() const; + bool verifyCocoDirectory(const Utils::FilePath &cocoDir); + + Utils::FilePathAspect m_cocoPathAspect; + Utils::TextDisplay m_messageLabel; + + CocoInstallation m_coco; + Utils::FilePath m_previousCocoDir; +}; + +class GlobalSettingsPage : public Core::IOptionsPage +{ +public: + static GlobalSettingsPage &instance(); + + GlobalSettingsWidget *widget() override; + void apply() override; + void cancel() override; + void finish() override; + +private: + GlobalSettingsPage(); + + QPointer m_widget; +}; + +} // namespace Coco::Internal From bd345efcca0aa98b5892ca67c69ad49e6a9c57d7 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 24 Oct 2024 14:53:46 +0200 Subject: [PATCH 020/989] Debugger: Robustify tooltip widget event filter setup Amends 5354e7e557364. Change-Id: I0b02c6df8d09d04055bd17dde0754c2a5135b0a5 Reviewed-by: Marcus Tillmanns --- .../debugger/debuggertooltipmanager.cpp | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index 162994008aa..f41528d2e37 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -980,17 +980,23 @@ void DebuggerToolTipManagerPrivate::debugModeEntered() this, &DebuggerToolTipManagerPrivate::updateVisibleToolTips); connect(em, &EditorManager::editorOpened, this, &DebuggerToolTipManagerPrivate::slotEditorOpened); - connect(em, &EditorManager::editorAboutToClose, [this](IEditor *editor) { + connect(em, &EditorManager::editorAboutToClose, this, [this](IEditor *editor) { if (auto textEditor = qobject_cast(editor)) m_tooltips.erase(textEditor->editorWidget()); }); - connect(em, &EditorManager::currentEditorAboutToChange, [this](IEditor *editor) { - if (auto textEditor = qobject_cast(editor)) - textEditor->widget()->window()->removeEventFilter(this); + connect(em, &EditorManager::currentEditorAboutToChange, this, [this](IEditor *editor) { + if (auto textEditor = qobject_cast(editor)) { + QWidget *widget = textEditor->widget(); + QTC_ASSERT(widget, return); + widget->removeEventFilter(this); + } }); - connect(em, &EditorManager::currentEditorChanged, [this](IEditor *editor) { - if (auto textEditor = qobject_cast(editor)) - textEditor->widget()->window()->installEventFilter(this); + connect(em, &EditorManager::currentEditorChanged, this, [this](IEditor *editor) { + if (auto textEditor = qobject_cast(editor)) { + QWidget *widget = textEditor->widget(); + QTC_ASSERT(widget, return); + widget->window()->installEventFilter(this); + } }); setupEditors(); } From e34fca9e5cae9057c2678795699766f5ad30fdfc Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 25 Oct 2024 11:26:42 +0200 Subject: [PATCH 021/989] Coco: Fix build for qbs and older Qt Amends 090b540487c0d5e178a043f8df05d3bbc0b67bd5. Change-Id: Idea8c873da56dfabcbcc97fb0853a5ff6de0dea4 Reviewed-by: Christian Kandeler Reviewed-by: Christian Stenger --- src/plugins/coco/coco.qbs | 2 -- src/plugins/coco/cocobuild/buildsettings.cpp | 1 + src/plugins/coco/cocobuild/cmakemodificationfile.cpp | 2 +- src/plugins/coco/cocobuild/cocobuildstep.cpp | 7 +++---- src/plugins/coco/cocobuild/cococmakesettings.cpp | 6 +++--- src/plugins/coco/cocobuild/cococmakesettings.h | 4 ++-- src/plugins/coco/cocobuild/cocoprojectwidget.cpp | 8 ++++---- src/plugins/coco/cocobuild/cocoprojectwidget.h | 5 +++-- src/plugins/coco/cocobuild/cocoqmakesettings.cpp | 8 ++++---- src/plugins/coco/cocobuild/cocoqmakesettings.h | 2 +- src/plugins/coco/cocobuild/qmakefeaturefile.cpp | 8 +------- src/plugins/coco/settings/cocoinstallation.cpp | 4 ++-- src/plugins/coco/settings/cocoprojectsettingswidget.cpp | 4 ++-- src/plugins/coco/settings/globalsettings.cpp | 2 +- src/plugins/coco/settings/globalsettingspage.cpp | 4 ++-- 15 files changed, 30 insertions(+), 37 deletions(-) diff --git a/src/plugins/coco/coco.qbs b/src/plugins/coco/coco.qbs index abfe8e939f8..3e9f928f982 100644 --- a/src/plugins/coco/coco.qbs +++ b/src/plugins/coco/coco.qbs @@ -25,7 +25,6 @@ QtcPlugin { "cocobuild/cococmakesettings.h", "cocobuild/cocoprojectwidget.cpp", "cocobuild/cocoprojectwidget.h", - "cocobuild/cocoprojectwidget.ui", "cocobuild/cocoqmakesettings.cpp", "cocobuild/cocoqmakesettings.h", "cocobuild/modificationfile.cpp", @@ -55,7 +54,6 @@ QtcPlugin { "settings/globalsettings.h", "settings/globalsettingspage.cpp", "settings/globalsettingspage.h", - "settings/globalsettingspage.ui", ] } diff --git a/src/plugins/coco/cocobuild/buildsettings.cpp b/src/plugins/coco/cocobuild/buildsettings.cpp index c905b6806d1..0a16087f47f 100644 --- a/src/plugins/coco/cocobuild/buildsettings.cpp +++ b/src/plugins/coco/cocobuild/buildsettings.cpp @@ -8,6 +8,7 @@ #include "cocoqmakesettings.h" #include "modificationfile.h" +#include #include #include #include diff --git a/src/plugins/coco/cocobuild/cmakemodificationfile.cpp b/src/plugins/coco/cocobuild/cmakemodificationfile.cpp index 9813e92be0c..5becd809b88 100644 --- a/src/plugins/coco/cocobuild/cmakemodificationfile.cpp +++ b/src/plugins/coco/cocobuild/cmakemodificationfile.cpp @@ -3,7 +3,7 @@ #include "cmakemodificationfile.h" -#include "cocopluginconstants.h" +#include "../cocopluginconstants.h" #include #include diff --git a/src/plugins/coco/cocobuild/cocobuildstep.cpp b/src/plugins/coco/cocobuild/cocobuildstep.cpp index 6a71157e7b6..31d61f615da 100644 --- a/src/plugins/coco/cocobuild/cocobuildstep.cpp +++ b/src/plugins/coco/cocobuild/cocobuildstep.cpp @@ -3,13 +3,12 @@ #include "cocobuildstep.h" -#include "cocopluginconstants.h" -#include "cocotr.h" +#include "../cocopluginconstants.h" +#include "../cocotr.h" +#include "../settings/cocoinstallation.h" #include #include -#include -#include #include #include #include diff --git a/src/plugins/coco/cocobuild/cococmakesettings.cpp b/src/plugins/coco/cocobuild/cococmakesettings.cpp index ceb3ec8012a..55cb8a19015 100644 --- a/src/plugins/coco/cocobuild/cococmakesettings.cpp +++ b/src/plugins/coco/cocobuild/cococmakesettings.cpp @@ -3,9 +3,9 @@ #include "cococmakesettings.h" -#include "cocobuild/cocoprojectwidget.h" -#include "cocotr.h" -#include "common.h" +#include "../cocotr.h" +#include "../common.h" +#include "cocoprojectwidget.h" #include #include diff --git a/src/plugins/coco/cocobuild/cococmakesettings.h b/src/plugins/coco/cocobuild/cococmakesettings.h index 8535744b9f7..e641dc6098a 100644 --- a/src/plugins/coco/cocobuild/cococmakesettings.h +++ b/src/plugins/coco/cocobuild/cococmakesettings.h @@ -3,8 +3,8 @@ #pragma once -#include "cocobuild/buildsettings.h" -#include "cocobuild/cmakemodificationfile.h" +#include "buildsettings.h" +#include "cmakemodificationfile.h" #include #include diff --git a/src/plugins/coco/cocobuild/cocoprojectwidget.cpp b/src/plugins/coco/cocobuild/cocoprojectwidget.cpp index 7cf55610eba..2a4d2f65c99 100644 --- a/src/plugins/coco/cocobuild/cocoprojectwidget.cpp +++ b/src/plugins/coco/cocobuild/cocoprojectwidget.cpp @@ -3,11 +3,11 @@ #include "cocoprojectwidget.h" +#include "../cocopluginconstants.h" +#include "../cocotr.h" +#include "../common.h" +#include "../settings/globalsettingspage.h" #include "buildsettings.h" -#include "cocopluginconstants.h" -#include "cocotr.h" -#include "common.h" -#include "settings/globalsettingspage.h" #include #include diff --git a/src/plugins/coco/cocobuild/cocoprojectwidget.h b/src/plugins/coco/cocobuild/cocoprojectwidget.h index b7f2cf4e12c..454ad22432a 100644 --- a/src/plugins/coco/cocobuild/cocoprojectwidget.h +++ b/src/plugins/coco/cocobuild/cocoprojectwidget.h @@ -3,9 +3,10 @@ #pragma once +#include "../settings/cocoinstallation.h" #include "buildsettings.h" -#include "projectexplorer/buildconfiguration.h" -#include "settings/cocoinstallation.h" + +#include #include #include diff --git a/src/plugins/coco/cocobuild/cocoqmakesettings.cpp b/src/plugins/coco/cocobuild/cocoqmakesettings.cpp index c86b53ed2f7..b85763c5471 100644 --- a/src/plugins/coco/cocobuild/cocoqmakesettings.cpp +++ b/src/plugins/coco/cocobuild/cocoqmakesettings.cpp @@ -3,10 +3,10 @@ #include "cocoqmakesettings.h" -#include "cocobuild/cocoprojectwidget.h" -#include "cocopluginconstants.h" -#include "cocotr.h" -#include "common.h" +#include "../cocobuild/cocoprojectwidget.h" +#include "../cocopluginconstants.h" +#include "../cocotr.h" +#include "../common.h" #include #include diff --git a/src/plugins/coco/cocobuild/cocoqmakesettings.h b/src/plugins/coco/cocobuild/cocoqmakesettings.h index a081bb1e080..91dc8515982 100644 --- a/src/plugins/coco/cocobuild/cocoqmakesettings.h +++ b/src/plugins/coco/cocobuild/cocoqmakesettings.h @@ -3,9 +3,9 @@ #pragma once +#include "../settings/cocoinstallation.h" #include "buildsettings.h" #include "qmakefeaturefile.h" -#include "settings/cocoinstallation.h" #include #include diff --git a/src/plugins/coco/cocobuild/qmakefeaturefile.cpp b/src/plugins/coco/cocobuild/qmakefeaturefile.cpp index 897cbaefa7b..b02f545370b 100644 --- a/src/plugins/coco/cocobuild/qmakefeaturefile.cpp +++ b/src/plugins/coco/cocobuild/qmakefeaturefile.cpp @@ -3,7 +3,7 @@ #include "qmakefeaturefile.h" -#include "cocopluginconstants.h" +#include "../cocopluginconstants.h" #include #include @@ -14,12 +14,6 @@ namespace Coco::Internal { static const char assignment[] = "COVERAGE_OPTIONS = \\\n"; static const char tweaksLine[] = "# User-supplied settings follow here:\n"; -static void cutTail(QStringList &list) -{ - while (!list.isEmpty() && list.last().trimmed().isEmpty()) - list.removeLast(); -} - QMakeFeatureFile::QMakeFeatureFile() {} QString QMakeFeatureFile::fileName() const diff --git a/src/plugins/coco/settings/cocoinstallation.cpp b/src/plugins/coco/settings/cocoinstallation.cpp index 77d466eed3e..fa95eafe2fd 100644 --- a/src/plugins/coco/settings/cocoinstallation.cpp +++ b/src/plugins/coco/settings/cocoinstallation.cpp @@ -3,8 +3,8 @@ #include "cocoinstallation.h" -#include "cocotr.h" -#include "common.h" +#include "../cocotr.h" +#include "../common.h" #include "globalsettings.h" #include diff --git a/src/plugins/coco/settings/cocoprojectsettingswidget.cpp b/src/plugins/coco/settings/cocoprojectsettingswidget.cpp index 8e6f10cc5ec..880d3a823f3 100644 --- a/src/plugins/coco/settings/cocoprojectsettingswidget.cpp +++ b/src/plugins/coco/settings/cocoprojectsettingswidget.cpp @@ -3,8 +3,8 @@ #include "cocoprojectsettingswidget.h" -#include "cocobuild/cocoprojectwidget.h" -#include "cocopluginconstants.h" +#include "../cocobuild/cocoprojectwidget.h" +#include "../cocopluginconstants.h" #include #include diff --git a/src/plugins/coco/settings/globalsettings.cpp b/src/plugins/coco/settings/globalsettings.cpp index 594355964ee..89129b7c2a0 100644 --- a/src/plugins/coco/settings/globalsettings.cpp +++ b/src/plugins/coco/settings/globalsettings.cpp @@ -3,8 +3,8 @@ #include "globalsettings.h" +#include "../cocopluginconstants.h" #include "cocoinstallation.h" -#include "cocopluginconstants.h" #include #include diff --git a/src/plugins/coco/settings/globalsettingspage.cpp b/src/plugins/coco/settings/globalsettingspage.cpp index b4eda76d0ba..f8f6bb4748b 100644 --- a/src/plugins/coco/settings/globalsettingspage.cpp +++ b/src/plugins/coco/settings/globalsettingspage.cpp @@ -3,9 +3,9 @@ #include "globalsettingspage.h" +#include "../cocopluginconstants.h" +#include "../cocotr.h" #include "cocoinstallation.h" -#include "cocopluginconstants.h" -#include "cocotr.h" #include "globalsettings.h" #include From 3928f1a5062e9bd5200efa39cfd73f279a499592 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 25 Oct 2024 15:23:51 +0200 Subject: [PATCH 022/989] Coco: Remove hard dependency on Qmake and CMake Change-Id: Ieea8c873da56dfabcbcc97fb0853a5ff6de0dea1 Reviewed-by: Markus Redeker Reviewed-by: Christian Kandeler --- .../cmakeprojectmanager/builddirparameters.h | 10 +- .../cmakebuildconfiguration.cpp | 28 ++++ .../cmakebuildconfiguration.h | 16 ++- .../cmakeprojectmanager/cmakebuildsystem.cpp | 5 +- .../cmakeprojectmanager/cmakebuildsystem.h | 21 +-- src/plugins/coco/CMakeLists.txt | 54 ++++---- .../coco/{cocobuild => }/buildsettings.cpp | 25 ++-- .../coco/{cocobuild => }/buildsettings.h | 8 +- .../{cocobuild => }/cmakemodificationfile.cpp | 22 +-- .../{cocobuild => }/cmakemodificationfile.h | 10 +- src/plugins/coco/coco.qbs | 54 ++++---- .../coco/cocobuild/cococmakesettings.h | 51 ------- .../coco/cocobuild/cocoqmakesettings.h | 56 -------- .../coco/{cocobuild => }/cocobuildstep.cpp | 8 +- .../coco/{cocobuild => }/cocobuildstep.h | 0 .../{cocobuild => }/cococmakesettings.cpp | 100 +++++++++----- src/plugins/coco/cococmakesettings.h | 15 ++ .../coco/{common.cpp => cococommon.cpp} | 2 +- src/plugins/coco/{common.h => cococommon.h} | 0 .../coco/{settings => }/cocoinstallation.cpp | 4 +- .../coco/{settings => }/cocoinstallation.h | 0 src/plugins/coco/cocoplugin.cpp | 8 +- .../cocoprojectsettingswidget.cpp | 6 +- .../cocoprojectsettingswidget.h | 0 .../{cocobuild => }/cocoprojectwidget.cpp | 14 +- .../coco/{cocobuild => }/cocoprojectwidget.h | 5 +- .../{cocobuild => }/cocoqmakesettings.cpp | 130 ++++++++++-------- src/plugins/coco/cocoqmakesettings.h | 14 ++ .../coco/{settings => }/globalsettings.cpp | 2 +- .../coco/{settings => }/globalsettings.h | 0 .../{settings => }/globalsettingspage.cpp | 4 +- .../coco/{settings => }/globalsettingspage.h | 0 .../coco/{cocobuild => }/modificationfile.cpp | 24 +++- .../coco/{cocobuild => }/modificationfile.h | 35 ++--- .../coco/{cocobuild => }/qmakefeaturefile.cpp | 21 +-- .../coco/{cocobuild => }/qmakefeaturefile.h | 10 +- .../projectexplorer/buildconfiguration.cpp | 17 +++ .../projectexplorer/buildconfiguration.h | 8 ++ src/plugins/projectexplorer/buildsystem.h | 2 + .../qmakebuildconfiguration.cpp | 27 ++++ .../qmakebuildconfiguration.h | 3 + 41 files changed, 424 insertions(+), 395 deletions(-) rename src/plugins/coco/{cocobuild => }/buildsettings.cpp (75%) rename src/plugins/coco/{cocobuild => }/buildsettings.h (84%) rename src/plugins/coco/{cocobuild => }/cmakemodificationfile.cpp (77%) rename src/plugins/coco/{cocobuild => }/cmakemodificationfile.h (65%) delete mode 100644 src/plugins/coco/cocobuild/cococmakesettings.h delete mode 100644 src/plugins/coco/cocobuild/cocoqmakesettings.h rename src/plugins/coco/{cocobuild => }/cocobuildstep.cpp (95%) rename src/plugins/coco/{cocobuild => }/cocobuildstep.h (100%) rename src/plugins/coco/{cocobuild => }/cococmakesettings.cpp (58%) create mode 100644 src/plugins/coco/cococmakesettings.h rename src/plugins/coco/{common.cpp => cococommon.cpp} (96%) rename src/plugins/coco/{common.h => cococommon.h} (100%) rename src/plugins/coco/{settings => }/cocoinstallation.cpp (99%) rename src/plugins/coco/{settings => }/cocoinstallation.h (100%) rename src/plugins/coco/{settings => }/cocoprojectsettingswidget.cpp (87%) rename src/plugins/coco/{settings => }/cocoprojectsettingswidget.h (100%) rename src/plugins/coco/{cocobuild => }/cocoprojectwidget.cpp (96%) rename src/plugins/coco/{cocobuild => }/cocoprojectwidget.h (92%) rename src/plugins/coco/{cocobuild => }/cocoqmakesettings.cpp (52%) create mode 100644 src/plugins/coco/cocoqmakesettings.h rename src/plugins/coco/{settings => }/globalsettings.cpp (97%) rename src/plugins/coco/{settings => }/globalsettings.h (100%) rename src/plugins/coco/{settings => }/globalsettingspage.cpp (98%) rename src/plugins/coco/{settings => }/globalsettingspage.h (100%) rename src/plugins/coco/{cocobuild => }/modificationfile.cpp (69%) rename src/plugins/coco/{cocobuild => }/modificationfile.h (70%) rename src/plugins/coco/{cocobuild => }/qmakefeaturefile.cpp (81%) rename src/plugins/coco/{cocobuild => }/qmakefeaturefile.h (67%) diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.h b/src/plugins/cmakeprojectmanager/builddirparameters.h index fc5c812bbd8..4888ebcdee0 100644 --- a/src/plugins/cmakeprojectmanager/builddirparameters.h +++ b/src/plugins/cmakeprojectmanager/builddirparameters.h @@ -15,16 +15,12 @@ class MacroExpander; class OutputLineParser; } // namespace Utils -namespace ProjectExplorer { -class Project; -} - -namespace CMakeProjectManager { -class CMakeBuildSystem; -} +namespace ProjectExplorer { class Project; } namespace CMakeProjectManager::Internal { +class CMakeBuildSystem; + class BuildDirParameters { public: diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index c11aa6be18a..f0c43f0c60e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -1854,11 +1854,39 @@ QStringList CMakeBuildConfiguration::initialCMakeOptions() const return initialCMakeArguments.allValues(); } +void CMakeBuildConfiguration::setInitialArgs(const QStringList &args) +{ + setInitialCMakeArguments(args); +} + +QStringList CMakeBuildConfiguration::initialArgs() const +{ + return initialCMakeOptions(); +} + +QStringList CMakeBuildConfiguration::additionalArgs() const +{ + return additionalCMakeArguments(); +} + +void CMakeBuildConfiguration::reconfigure() +{ + cmakeBuildSystem()->clearCMakeCache(); + updateInitialCMakeArguments(); + cmakeBuildSystem()->runCMake(); +} + +void CMakeBuildConfiguration::stopReconfigure() +{ + cmakeBuildSystem()->stopCMakeRun(); +} + CMakeConfig CMakeBuildConfiguration::signingFlags() const { return {}; } + void CMakeBuildConfiguration::setInitialBuildAndCleanSteps(const Target *target) { const CMakeConfigItem presetItem = CMakeConfigurationKitAspect::cmakePresetConfigItem( diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index 398b42ffa50..532261aca02 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -14,10 +14,10 @@ namespace CMakeProjectManager { class CMakeProject; -class CMakeBuildSystem; namespace Internal { +class CMakeBuildSystem; class CMakeBuildSettingsWidget; class CMakeProjectImporter; @@ -75,7 +75,7 @@ public: void setRestrictedBuildTarget(const QString &buildTarget); Utils::Environment configureEnvironment() const; - CMakeBuildSystem *cmakeBuildSystem() const; + Internal::CMakeBuildSystem *cmakeBuildSystem() const; QStringList additionalCMakeArguments() const; void setAdditionalCMakeArguments(const QStringList &args); @@ -93,6 +93,12 @@ public: void updateInitialCMakeArguments(); QStringList initialCMakeOptions() const; + void setInitialArgs(const QStringList &args) override; + QStringList initialArgs() const override; + QStringList additionalArgs() const override; + void reconfigure() override; + void stopReconfigure() override; + signals: void signingFlagsChanged(); void configureEnvironmentChanged(); @@ -108,12 +114,12 @@ private: void setBuildPresetToBuildSteps(const ProjectExplorer::Target *target); void filterConfigArgumentsFromAdditionalCMakeArguments(); - CMakeBuildSystem *m_buildSystem = nullptr; - Internal::CMakeBuildSettingsWidget *m_configWidget = nullptr; + Internal::CMakeBuildSystem *m_buildSystem = nullptr; QStringList m_unrestrictedBuildTargets; + Internal::CMakeBuildSettingsWidget *m_configWidget = nullptr; friend class Internal::CMakeBuildSettingsWidget; - friend class CMakeBuildSystem; + friend class Internal::CMakeBuildSystem; }; class CMAKE_EXPORT CMakeBuildConfigurationFactory diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 3d8d75eaa78..3547e96ed10 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -62,9 +62,8 @@ using namespace ProjectExplorer; using namespace TextEditor; using namespace Utils; -using namespace CMakeProjectManager::Internal; -namespace CMakeProjectManager { +namespace CMakeProjectManager::Internal { static Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg); @@ -2524,4 +2523,4 @@ ExtraCompiler *CMakeBuildSystem::findExtraCompiler(const ExtraCompilerFilter &fi return Utils::findOrDefault(m_extraCompilers, filter); } -} // CMakeProjectManager +} // CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 2b6b3f79f2f..e25d885ecec 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -29,11 +29,13 @@ namespace CMakeProjectManager { class CMakeBuildConfiguration; class CMakeProject; +namespace Internal { + // -------------------------------------------------------------------- // CMakeBuildSystem: // -------------------------------------------------------------------- -class CMAKE_EXPORT CMakeBuildSystem final : public ProjectExplorer::BuildSystem +class CMakeBuildSystem final : public ProjectExplorer::BuildSystem { Q_OBJECT @@ -134,8 +136,6 @@ public: signals: void configurationCleared(); void configurationChanged(const CMakeConfig &config); - void errorOccurred(const QString &message); - void warningOccurred(const QString &message); private: CMakeConfig initialCMakeConfiguration() const; @@ -155,7 +155,7 @@ private: Utils::FilePaths *); bool addTsFiles(ProjectExplorer::Node *context, const Utils::FilePaths &filePaths, Utils::FilePaths *); - bool renameFile(Internal::CMakeTargetNode *context, + bool renameFile(CMakeTargetNode *context, const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath, bool &shouldRunCMake); @@ -173,10 +173,10 @@ private: }; void reparse(int reparseParameters); QString reparseParametersString(int reparseFlags); - void setParametersAndRequestParse(const Internal::BuildDirParameters ¶meters, + void setParametersAndRequestParse(const BuildDirParameters ¶meters, const int reparseParameters); - bool mustApplyConfigurationChangesArguments(const Internal::BuildDirParameters ¶meters) const; + bool mustApplyConfigurationChangesArguments(const BuildDirParameters ¶meters) const; // State handling: // Parser states: @@ -206,7 +206,7 @@ private: void wireUpConnections(); - void ensureBuildDirectory(const Internal::BuildDirParameters ¶meters); + void ensureBuildDirectory(const BuildDirParameters ¶meters); void stopParsingAndClearState(); void becameDirty(); @@ -241,7 +241,7 @@ private: ProjectExplorer::ProjectUpdater *m_cppCodeModelUpdater = nullptr; QList m_extraCompilers; QList m_buildTargets; - QSet m_cmakeFiles; + QSet m_cmakeFiles; QHash m_cmakeSymbolsHash; QHash m_dotCMakeFilesHash; QHash m_findPackagesFilesHash; @@ -252,9 +252,9 @@ private: QHash m_filesToBeRenamed; // Parsing state: - Internal::BuildDirParameters m_parameters; + BuildDirParameters m_parameters; int m_reparseParameters = REPARSE_DEFAULT; - Internal::FileApiReader m_reader; + FileApiReader m_reader; mutable bool m_isHandlingError = false; // CTest integration @@ -269,4 +269,5 @@ private: QString m_warning; }; +} // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/coco/CMakeLists.txt b/src/plugins/coco/CMakeLists.txt index 71693fac7ad..81c72afc8d9 100644 --- a/src/plugins/coco/CMakeLists.txt +++ b/src/plugins/coco/CMakeLists.txt @@ -3,49 +3,47 @@ add_qtc_plugin(Coco QtCreator::Core QtCreator::LanguageClient QtCreator::ProjectExplorer - QtCreator::QmakeProjectManager DEPENDS - QtCreator::CMakeProjectManager QtCreator::ExtensionSystem SOURCES Coco.json.in - cocobuild/buildsettings.cpp - cocobuild/buildsettings.h - cocobuild/cmakemodificationfile.cpp - cocobuild/cmakemodificationfile.h - cocobuild/cococmakesettings.cpp - cocobuild/cococmakesettings.h - cocobuild/cocobuildstep.cpp - cocobuild/cocobuildstep.h - cocobuild/cocoprojectwidget.cpp - cocobuild/cocoprojectwidget.h - cocobuild/modificationfile.cpp - cocobuild/modificationfile.h - cocobuild/qmakefeaturefile.cpp - cocobuild/qmakefeaturefile.h - cocobuild/cocoqmakesettings.cpp - cocobuild/cocoqmakesettings.h + buildsettings.cpp + buildsettings.h + cmakemodificationfile.cpp + cmakemodificationfile.h + cocobuildstep.cpp + cocobuildstep.h + cococmakesettings.cpp + cococmakesettings.h + cococommon.cpp + cococommon.h + cocoinstallation.cpp + cocoinstallation.h cocolanguageclient.cpp cocolanguageclient.h cocoplugin.cpp cocoplugin.qrc cocoplugin_global.h cocopluginconstants.h + cocoprojectsettingswidget.cpp + cocoprojectsettingswidget.h + cocoprojectwidget.cpp + cocoprojectwidget.h + cocoqmakesettings.cpp + cocoqmakesettings.h cocotr.h - common.cpp - common.h files/cocoplugin-clang.cmake files/cocoplugin-gcc.cmake files/cocoplugin-visualstudio.cmake files/cocoplugin.cmake files/cocoplugin.prf + globalsettings.cpp + globalsettings.h + globalsettingspage.cpp + globalsettingspage.h images/SquishCoco_48x48.png - settings/cocoinstallation.cpp - settings/cocoinstallation.h - settings/cocoprojectsettingswidget.cpp - settings/cocoprojectsettingswidget.h - settings/globalsettings.cpp - settings/globalsettings.h - settings/globalsettingspage.cpp - settings/globalsettingspage.h + modificationfile.cpp + modificationfile.h + qmakefeaturefile.cpp + qmakefeaturefile.h ) diff --git a/src/plugins/coco/cocobuild/buildsettings.cpp b/src/plugins/coco/buildsettings.cpp similarity index 75% rename from src/plugins/coco/cocobuild/buildsettings.cpp rename to src/plugins/coco/buildsettings.cpp index 0a16087f47f..76296628705 100644 --- a/src/plugins/coco/cocobuild/buildsettings.cpp +++ b/src/plugins/coco/buildsettings.cpp @@ -13,6 +13,8 @@ #include #include +using namespace ProjectExplorer; + namespace Coco::Internal { bool BuildSettings::supportsBuildConfig(const ProjectExplorer::BuildConfiguration &config) @@ -21,19 +23,18 @@ bool BuildSettings::supportsBuildConfig(const ProjectExplorer::BuildConfiguratio || config.id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID; } -BuildSettings *BuildSettings::createdFor(const ProjectExplorer::BuildConfiguration &config) +BuildSettings *BuildSettings::createdFor(BuildConfiguration *buildConfig) { - if (config.id() == QmakeProjectManager::Constants::QMAKE_BC_ID) - return new CocoQMakeSettings{config.project()}; - else if (config.id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID) - return new CocoCMakeSettings{config.project()}; - else - return nullptr; + if (buildConfig->id() == QmakeProjectManager::Constants::QMAKE_BC_ID) + return createCocoQMakeSettings(buildConfig); + if (buildConfig->id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID) + return createCocoCMakeSettings(buildConfig); + return nullptr; } -BuildSettings::BuildSettings(ModificationFile &featureFile, ProjectExplorer::Project *project) +BuildSettings::BuildSettings(ModificationFile &featureFile, BuildConfiguration *buildConfig) : m_featureFile{featureFile} - , m_project{*project} + , m_buildConfig{buildConfig} { // Do not use m_featureFile in the constructor; it may not yet be valid. } @@ -41,7 +42,7 @@ BuildSettings::BuildSettings(ModificationFile &featureFile, ProjectExplorer::Pro void BuildSettings::connectToBuildStep(CocoBuildStep *step) const { connect( - activeTarget(), + buildConfig()->target(), &ProjectExplorer::Target::buildSystemUpdated, step, &CocoBuildStep::buildSystemUpdated); @@ -93,9 +94,9 @@ void BuildSettings::setEnabled(bool enabled) m_enabled = enabled; } -ProjectExplorer::Target *BuildSettings::activeTarget() const +BuildConfiguration *BuildSettings::buildConfig() const { - return m_project.activeTarget(); + return m_buildConfig; } } // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/buildsettings.h b/src/plugins/coco/buildsettings.h similarity index 84% rename from src/plugins/coco/cocobuild/buildsettings.h rename to src/plugins/coco/buildsettings.h index 10cf8e96925..28e3e7c9a78 100644 --- a/src/plugins/coco/cocobuild/buildsettings.h +++ b/src/plugins/coco/buildsettings.h @@ -23,9 +23,9 @@ class BuildSettings : public QObject Q_OBJECT public: static bool supportsBuildConfig(const ProjectExplorer::BuildConfiguration &config); - static BuildSettings *createdFor(const ProjectExplorer::BuildConfiguration &config); + static BuildSettings *createdFor(ProjectExplorer::BuildConfiguration *config); - explicit BuildSettings(ModificationFile &featureFile, ProjectExplorer::Project *project); + BuildSettings(ModificationFile &featureFile, ProjectExplorer::BuildConfiguration *buildConfig); virtual ~BuildSettings() {} void connectToBuildStep(CocoBuildStep *step) const; @@ -56,11 +56,11 @@ public: protected: QString tableRow(const QString &name, const QString &value) const; void setEnabled(bool enabled); - ProjectExplorer::Target *activeTarget() const; + ProjectExplorer::BuildConfiguration *buildConfig() const; private: ModificationFile &m_featureFile; - ProjectExplorer::Project &m_project; + ProjectExplorer::BuildConfiguration *m_buildConfig; bool m_enabled = false; }; diff --git a/src/plugins/coco/cocobuild/cmakemodificationfile.cpp b/src/plugins/coco/cmakemodificationfile.cpp similarity index 77% rename from src/plugins/coco/cocobuild/cmakemodificationfile.cpp rename to src/plugins/coco/cmakemodificationfile.cpp index 5becd809b88..c212397d419 100644 --- a/src/plugins/coco/cocobuild/cmakemodificationfile.cpp +++ b/src/plugins/coco/cmakemodificationfile.cpp @@ -3,7 +3,7 @@ #include "cmakemodificationfile.h" -#include "../cocopluginconstants.h" +#include "cocopluginconstants.h" #include #include @@ -16,25 +16,11 @@ using namespace ProjectExplorer; static const char flagsSetting[] = "set(coverage_flags_list\n"; static const char tweaksLine[] = "# User-supplied settings follow here:\n"; -CMakeModificationFile::CMakeModificationFile(Project *project) - : m_project{project} +CMakeModificationFile::CMakeModificationFile(ProjectExplorer::Project *project) + : ModificationFile{QString(Constants::PROFILE_NAME) + ".cmake", ":/cocoplugin/files/cocoplugin.cmake"} + , m_project{project} {} -QString CMakeModificationFile::fileName() const -{ - return QString(Constants::PROFILE_NAME) + ".cmake"; -} - -void CMakeModificationFile::setProjectDirectory(const Utils::FilePath &projectDirectory) -{ - setFilePath(projectDirectory.pathAppended(fileName())); -} - -QStringList CMakeModificationFile::defaultModificationFile() const -{ - return contentOf(":/cocoplugin/files/cocoplugin.cmake"); -} - void CMakeModificationFile::read() { clear(); diff --git a/src/plugins/coco/cocobuild/cmakemodificationfile.h b/src/plugins/coco/cmakemodificationfile.h similarity index 65% rename from src/plugins/coco/cocobuild/cmakemodificationfile.h rename to src/plugins/coco/cmakemodificationfile.h index 485c5fa4326..eb9bda987f9 100644 --- a/src/plugins/coco/cocobuild/cmakemodificationfile.h +++ b/src/plugins/coco/cmakemodificationfile.h @@ -16,14 +16,8 @@ class CMakeModificationFile : public ModificationFile public: CMakeModificationFile(ProjectExplorer::Project *project); - void read() override; - void write() const override; - - QString fileName() const override; - void setProjectDirectory(const Utils::FilePath &projectDirectory) override; - -protected: - QStringList defaultModificationFile() const override; + void read(); + void write() const; private: ProjectExplorer::Project *m_project; diff --git a/src/plugins/coco/coco.qbs b/src/plugins/coco/coco.qbs index 3e9f928f982..711e86e4880 100644 --- a/src/plugins/coco/coco.qbs +++ b/src/plugins/coco/coco.qbs @@ -5,55 +5,53 @@ QtcPlugin { Depends { name: "Core" } Depends { name: "LanguageClient" } - Depends { name: "CMakeProjectManager" } Depends { name: "ExtensionSystem" } Depends { name: "ProjectExplorer" } - Depends { name: "QmakeProjectManager" } Depends { name: "TextEditor" } Depends { name: "Utils" } Depends { name: "Qt"; submodules: ["widgets"] } files: [ - "cocobuild/buildsettings.cpp", - "cocobuild/buildsettings.h", - "cocobuild/cmakemodificationfile.cpp", - "cocobuild/cmakemodificationfile.h", - "cocobuild/cocobuildstep.cpp", - "cocobuild/cocobuildstep.h", - "cocobuild/cococmakesettings.cpp", - "cocobuild/cococmakesettings.h", - "cocobuild/cocoprojectwidget.cpp", - "cocobuild/cocoprojectwidget.h", - "cocobuild/cocoqmakesettings.cpp", - "cocobuild/cocoqmakesettings.h", - "cocobuild/modificationfile.cpp", - "cocobuild/modificationfile.h", - "cocobuild/qmakefeaturefile.cpp", - "cocobuild/qmakefeaturefile.h", + "buildsettings.cpp", + "buildsettings.h", + "cmakemodificationfile.cpp", + "cmakemodificationfile.h", + "cocobuildstep.cpp", + "cocobuildstep.h", + "cococmakesettings.cpp", + "cococmakesettings.h", + "cococommon.cpp", + "cococommon.h", + "cocoinstallation.cpp", + "cocoinstallation.h", "cocolanguageclient.cpp", "cocolanguageclient.h", "cocoplugin.cpp", "cocoplugin.qrc", "cocoplugin_global.h", "cocopluginconstants.h", + "cocoprojectsettingswidget.cpp", + "cocoprojectsettingswidget.h", + "cocoprojectwidget.cpp", + "cocoprojectwidget.h", + "cocoqmakesettings.cpp", + "cocoqmakesettings.h", "cocotr.h", - "common.cpp", - "common.h", "files/cocoplugin-clang.cmake", "files/cocoplugin-gcc.cmake", "files/cocoplugin-visualstudio.cmake", "files/cocoplugin.cmake", "files/cocoplugin.prf", + "globalsettings.cpp", + "globalsettings.h", + "globalsettingspage.cpp", + "globalsettingspage.h", "images/SquishCoco_48x48.png", - "settings/cocoinstallation.cpp", - "settings/cocoinstallation.h", - "settings/cocoprojectsettingswidget.cpp", - "settings/cocoprojectsettingswidget.h", - "settings/globalsettings.cpp", - "settings/globalsettings.h", - "settings/globalsettingspage.cpp", - "settings/globalsettingspage.h", + "modificationfile.cpp", + "modificationfile.h", + "qmakefeaturefile.cpp", + "qmakefeaturefile.h", ] } diff --git a/src/plugins/coco/cocobuild/cococmakesettings.h b/src/plugins/coco/cocobuild/cococmakesettings.h deleted file mode 100644 index e641dc6098a..00000000000 --- a/src/plugins/coco/cocobuild/cococmakesettings.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "buildsettings.h" -#include "cmakemodificationfile.h" - -#include -#include - -namespace CMakeProjectManager { -class CMakeBuildConfiguration; -class CMakeConfig; -} - -namespace Coco::Internal { - -class CocoProjectWidget; - -class CocoCMakeSettings : public BuildSettings -{ - Q_OBJECT -public: - explicit CocoCMakeSettings(ProjectExplorer::Project *project); - ~CocoCMakeSettings() override; - - void connectToProject(CocoProjectWidget *parent) const override; - void read() override; - bool validSettings() const override; - void setCoverage(bool on) override; - - QString saveButtonText() const override; - QString configChanges() const override; - bool needsReconfigure() const override { return true; } - void reconfigure() override; - void stopReconfigure() override; - - QString projectDirectory() const override; - void write(const QString &options, const QString &tweaks) override; - -private: - bool hasInitialCacheOption(const QStringList &args) const; - QString initialCacheOption() const; - void writeToolchainFile(const QString &internalPath); - - CMakeProjectManager::CMakeBuildConfiguration *m_buildConfig; - CMakeModificationFile m_featureFile; -}; - -} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cocoqmakesettings.h b/src/plugins/coco/cocobuild/cocoqmakesettings.h deleted file mode 100644 index 91dc8515982..00000000000 --- a/src/plugins/coco/cocobuild/cocoqmakesettings.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "../settings/cocoinstallation.h" -#include "buildsettings.h" -#include "qmakefeaturefile.h" - -#include -#include - -#include -#include - -namespace QmakeProjectManager { -class QMakeStep; -class QmakeBuildConfiguration; -} - -namespace Coco::Internal { - -class CocoProjectWidget; - -class CocoQMakeSettings : public BuildSettings -{ - Q_OBJECT -public: - explicit CocoQMakeSettings(ProjectExplorer::Project *project); - ~CocoQMakeSettings() override; - - void read() override; - bool validSettings() const override; - void setCoverage(bool on) override; - - QString saveButtonText() const override; - QString configChanges() const override; - QString projectDirectory() const override; - void write(const QString &options, const QString &tweaks) override; - -private: - bool environmentSet() const; - QString pathAssignment() const; - const QStringList userArgumentList() const; - Utils::Environment buildEnvironment() const; - void setQMakeFeatures() const; - bool cocoPathValid() const; - - QmakeProjectManager::QmakeBuildConfiguration *m_buildConfig; - QmakeProjectManager::QMakeStep *m_qmakeStep; - - QMakeFeatureFile m_featureFile; - CocoInstallation m_coco; -}; - -} // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/cocobuildstep.cpp b/src/plugins/coco/cocobuildstep.cpp similarity index 95% rename from src/plugins/coco/cocobuild/cocobuildstep.cpp rename to src/plugins/coco/cocobuildstep.cpp index 31d61f615da..a28497a5618 100644 --- a/src/plugins/coco/cocobuild/cocobuildstep.cpp +++ b/src/plugins/coco/cocobuildstep.cpp @@ -3,9 +3,9 @@ #include "cocobuildstep.h" -#include "../cocopluginconstants.h" -#include "../cocotr.h" -#include "../settings/cocoinstallation.h" +#include "cocoinstallation.h" +#include "cocopluginconstants.h" +#include "cocotr.h" #include #include @@ -109,7 +109,7 @@ void CocoBuildStep::display(BuildConfiguration *buildConfig) { Q_ASSERT( m_buildSettings.isNull() ); - m_buildSettings = BuildSettings::createdFor(*buildConfig); + m_buildSettings = BuildSettings::createdFor(buildConfig); m_buildSettings->read(); m_buildSettings->connectToBuildStep(this); diff --git a/src/plugins/coco/cocobuild/cocobuildstep.h b/src/plugins/coco/cocobuildstep.h similarity index 100% rename from src/plugins/coco/cocobuild/cocobuildstep.h rename to src/plugins/coco/cocobuildstep.h diff --git a/src/plugins/coco/cocobuild/cococmakesettings.cpp b/src/plugins/coco/cococmakesettings.cpp similarity index 58% rename from src/plugins/coco/cocobuild/cococmakesettings.cpp rename to src/plugins/coco/cococmakesettings.cpp index 55cb8a19015..2b3c22f4e9e 100644 --- a/src/plugins/coco/cocobuild/cococmakesettings.cpp +++ b/src/plugins/coco/cococmakesettings.cpp @@ -3,33 +3,64 @@ #include "cococmakesettings.h" -#include "../cocotr.h" -#include "../common.h" +#include "buildsettings.h" +#include "cmakemodificationfile.h" +#include "cococommon.h" #include "cocoprojectwidget.h" +#include "cocotr.h" -#include -#include +#include #include +#include + +#include +#include using namespace ProjectExplorer; -using namespace CMakeProjectManager; +using namespace Utils; namespace Coco::Internal { -CocoCMakeSettings::CocoCMakeSettings(Project *project) - : BuildSettings{m_featureFile, project} - , m_featureFile{project} -{} +class CocoCMakeSettings : public BuildSettings +{ +public: + explicit CocoCMakeSettings(BuildConfiguration *bc) + : BuildSettings{m_featureFile, bc} + , m_featureFile{bc->project()} + {} -CocoCMakeSettings::~CocoCMakeSettings() {} + void connectToProject(CocoProjectWidget *parent) const override; + void read() override; + bool validSettings() const override; + void setCoverage(bool on) override; + + QString saveButtonText() const override; + QString configChanges() const override; + bool needsReconfigure() const override { return true; } + void reconfigure() override; + void stopReconfigure() override; + + QString projectDirectory() const override; + void write(const QString &options, const QString &tweaks) override; + +private: + bool hasInitialCacheOption(const QStringList &args) const; + QString initialCacheOption() const; + void writeToolchainFile(const QString &internalPath); + + CMakeModificationFile m_featureFile; +}; void CocoCMakeSettings::connectToProject(CocoProjectWidget *parent) const { connect( - activeTarget(), &Target::buildSystemUpdated, parent, &CocoProjectWidget::buildSystemUpdated); + buildConfig()->target(), + &Target::buildSystemUpdated, + parent, + &CocoProjectWidget::buildSystemUpdated); connect( - qobject_cast(activeTarget()->buildSystem()), - &CMakeProjectManager::CMakeBuildSystem::errorOccurred, + buildConfig()->buildSystem(), + &ProjectExplorer::BuildSystem::errorOccurred, parent, &CocoProjectWidget::configurationErrorOccurred); } @@ -37,14 +68,9 @@ void CocoCMakeSettings::connectToProject(CocoProjectWidget *parent) const void CocoCMakeSettings::read() { setEnabled(false); - if (Target *target = activeTarget()) { - if ((m_buildConfig = qobject_cast( - target->activeBuildConfiguration()))) { - m_featureFile.setProjectDirectory(m_buildConfig->project()->projectDirectory()); - m_featureFile.read(); - setEnabled(true); - } - } + m_featureFile.setFilePath(buildConfig()); + m_featureFile.read(); + setEnabled(true); } QString CocoCMakeSettings::initialCacheOption() const @@ -67,8 +93,8 @@ bool CocoCMakeSettings::hasInitialCacheOption(const QStringList &args) const bool CocoCMakeSettings::validSettings() const { - return enabled() && m_featureFile.exists() - && hasInitialCacheOption(m_buildConfig->additionalCMakeArguments()); + const QStringList args = buildConfig()->additionalArgs(); + return enabled() && m_featureFile.exists() && hasInitialCacheOption(args); } void CocoCMakeSettings::setCoverage(bool on) @@ -76,7 +102,7 @@ void CocoCMakeSettings::setCoverage(bool on) if (!enabled()) return; - auto values = m_buildConfig->initialCMakeOptions(); + QStringList values = buildConfig()->initialArgs(); QStringList args = Utils::filtered(values, [&](const QString &option) { return !(option.startsWith("-C") && option.endsWith(featureFilenName())); }); @@ -84,7 +110,7 @@ void CocoCMakeSettings::setCoverage(bool on) if (on) args << QString("-C%1").arg(m_featureFile.nativePath()); - m_buildConfig->setInitialCMakeArguments(args); + buildConfig()->setInitialArgs(args); } QString CocoCMakeSettings::saveButtonText() const @@ -95,30 +121,27 @@ QString CocoCMakeSettings::saveButtonText() const QString CocoCMakeSettings::configChanges() const { return "" - + tableRow("Additional CMake options: ", maybeQuote(initialCacheOption())) - + tableRow("Initial cache script: ", maybeQuote(featureFilePath())) + "
"; + + tableRow(Tr::tr("Additional CMake options: "), maybeQuote(initialCacheOption())) + + tableRow(Tr::tr("Initial cache script: "), maybeQuote(featureFilePath())) + + ""; } void CocoCMakeSettings::reconfigure() { - if (!enabled()) - return; - - m_buildConfig->cmakeBuildSystem()->clearCMakeCache(); - m_buildConfig->updateInitialCMakeArguments(); - m_buildConfig->cmakeBuildSystem()->runCMake(); + if (enabled()) + buildConfig()->reconfigure(); } void Coco::Internal::CocoCMakeSettings::stopReconfigure() { if (enabled()) - m_buildConfig->cmakeBuildSystem()->stopCMakeRun(); + buildConfig()->stopReconfigure(); } QString CocoCMakeSettings::projectDirectory() const { if (enabled()) - return m_buildConfig->project()->projectDirectory().path(); + return buildConfig()->project()->projectDirectory().path(); else return ""; } @@ -136,7 +159,7 @@ void CocoCMakeSettings::write(const QString &options, const QString &tweaks) void CocoCMakeSettings::writeToolchainFile(const QString &internalPath) { - const Utils::FilePath projectDirectory = m_buildConfig->project()->projectDirectory(); + const Utils::FilePath projectDirectory = buildConfig()->project()->projectDirectory(); QFile internalFile{internalPath}; internalFile.open(QIODeviceBase::ReadOnly); @@ -164,4 +187,9 @@ void CocoCMakeSettings::writeToolchainFile(const QString &internalPath) out.close(); } +BuildSettings *createCocoCMakeSettings(BuildConfiguration *bc) +{ + return new CocoCMakeSettings(bc); +} + } // namespace Coco::Internal diff --git a/src/plugins/coco/cococmakesettings.h b/src/plugins/coco/cococmakesettings.h new file mode 100644 index 00000000000..a3697758adb --- /dev/null +++ b/src/plugins/coco/cococmakesettings.h @@ -0,0 +1,15 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace ProjectExplorer { class BuildConfiguration; } + +namespace Coco::Internal { + +class BuildSettings; + +BuildSettings *createCocoCMakeSettings(ProjectExplorer::BuildConfiguration *bc); + +} // namespace Coco::Internal + diff --git a/src/plugins/coco/common.cpp b/src/plugins/coco/cococommon.cpp similarity index 96% rename from src/plugins/coco/common.cpp rename to src/plugins/coco/cococommon.cpp index e822e6eb7b7..9d0b1d32072 100644 --- a/src/plugins/coco/common.cpp +++ b/src/plugins/coco/cococommon.cpp @@ -1,7 +1,7 @@ // 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 "common.h" +#include "cococommon.h" #include "cocopluginconstants.h" diff --git a/src/plugins/coco/common.h b/src/plugins/coco/cococommon.h similarity index 100% rename from src/plugins/coco/common.h rename to src/plugins/coco/cococommon.h diff --git a/src/plugins/coco/settings/cocoinstallation.cpp b/src/plugins/coco/cocoinstallation.cpp similarity index 99% rename from src/plugins/coco/settings/cocoinstallation.cpp rename to src/plugins/coco/cocoinstallation.cpp index fa95eafe2fd..7a3c4441249 100644 --- a/src/plugins/coco/settings/cocoinstallation.cpp +++ b/src/plugins/coco/cocoinstallation.cpp @@ -3,8 +3,8 @@ #include "cocoinstallation.h" -#include "../cocotr.h" -#include "../common.h" +#include "cococommon.h" +#include "cocotr.h" #include "globalsettings.h" #include diff --git a/src/plugins/coco/settings/cocoinstallation.h b/src/plugins/coco/cocoinstallation.h similarity index 100% rename from src/plugins/coco/settings/cocoinstallation.h rename to src/plugins/coco/cocoinstallation.h diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index 13b0d690e90..a87e163ee59 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -1,13 +1,13 @@ // 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 "cocobuild/cocobuildstep.h" +#include "cocobuildstep.h" #include "cocolanguageclient.h" #include "cocopluginconstants.h" +#include "cocoprojectsettingswidget.h" #include "cocotr.h" -#include "settings/cocoprojectsettingswidget.h" -#include "settings/globalsettings.h" -#include "settings/globalsettingspage.h" +#include "globalsettings.h" +#include "globalsettingspage.h" #include #include diff --git a/src/plugins/coco/settings/cocoprojectsettingswidget.cpp b/src/plugins/coco/cocoprojectsettingswidget.cpp similarity index 87% rename from src/plugins/coco/settings/cocoprojectsettingswidget.cpp rename to src/plugins/coco/cocoprojectsettingswidget.cpp index 880d3a823f3..6b6b05426c0 100644 --- a/src/plugins/coco/settings/cocoprojectsettingswidget.cpp +++ b/src/plugins/coco/cocoprojectsettingswidget.cpp @@ -3,8 +3,8 @@ #include "cocoprojectsettingswidget.h" -#include "../cocobuild/cocoprojectwidget.h" -#include "../cocopluginconstants.h" +#include "cocopluginconstants.h" +#include "cocoprojectwidget.h" #include #include @@ -27,7 +27,7 @@ CocoProjectSettingsWidget::CocoProjectSettingsWidget(ProjectExplorer::Project *p if (abc->id() == QmakeProjectManager::Constants::QMAKE_BC_ID || abc->id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID) - m_layout->addWidget(new CocoProjectWidget(project, *abc)); + m_layout->addWidget(new CocoProjectWidget(project, abc)); } setLayout(m_layout); } diff --git a/src/plugins/coco/settings/cocoprojectsettingswidget.h b/src/plugins/coco/cocoprojectsettingswidget.h similarity index 100% rename from src/plugins/coco/settings/cocoprojectsettingswidget.h rename to src/plugins/coco/cocoprojectsettingswidget.h diff --git a/src/plugins/coco/cocobuild/cocoprojectwidget.cpp b/src/plugins/coco/cocoprojectwidget.cpp similarity index 96% rename from src/plugins/coco/cocobuild/cocoprojectwidget.cpp rename to src/plugins/coco/cocoprojectwidget.cpp index 2a4d2f65c99..b0db3e42a8e 100644 --- a/src/plugins/coco/cocobuild/cocoprojectwidget.cpp +++ b/src/plugins/coco/cocoprojectwidget.cpp @@ -3,11 +3,11 @@ #include "cocoprojectwidget.h" -#include "../cocopluginconstants.h" -#include "../cocotr.h" -#include "../common.h" -#include "../settings/globalsettingspage.h" #include "buildsettings.h" +#include "cococommon.h" +#include "cocopluginconstants.h" +#include "cocotr.h" +#include "globalsettingspage.h" #include #include @@ -20,9 +20,9 @@ using namespace Core; namespace Coco::Internal { -CocoProjectWidget::CocoProjectWidget(Project *project, const BuildConfiguration &buildConfig) +CocoProjectWidget::CocoProjectWidget(Project *project, BuildConfiguration *buildConfig) : m_project{project} - , m_buildConfigurationName{buildConfig.displayName()} + , m_buildConfigurationName{buildConfig->displayName()} { using namespace Layouting; using namespace Utils; @@ -142,7 +142,7 @@ void CocoProjectWidget::configurationErrorOccurred(const QString &error) // The variable error seems to contain no usable information. setMessageLabel( Utils::InfoLabel::Error, - Tr::tr("Error when configuring with \"%1\". " + Tr::tr("Error when configuring with %1. " "Check General Messages for more information.") .arg(m_buildSettings->featureFilenName())); setState(configDone); diff --git a/src/plugins/coco/cocobuild/cocoprojectwidget.h b/src/plugins/coco/cocoprojectwidget.h similarity index 92% rename from src/plugins/coco/cocobuild/cocoprojectwidget.h rename to src/plugins/coco/cocoprojectwidget.h index 454ad22432a..8c39b0ad363 100644 --- a/src/plugins/coco/cocobuild/cocoprojectwidget.h +++ b/src/plugins/coco/cocoprojectwidget.h @@ -3,8 +3,8 @@ #pragma once -#include "../settings/cocoinstallation.h" #include "buildsettings.h" +#include "cocoinstallation.h" #include #include @@ -26,8 +26,7 @@ class CocoProjectWidget : public QWidget public: enum ConfigurationState { configDone, configEdited, configRunning, configStopped }; - explicit CocoProjectWidget( - ProjectExplorer::Project *project, const ProjectExplorer::BuildConfiguration &buildConfig); + explicit CocoProjectWidget(ProjectExplorer::Project *project, ProjectExplorer::BuildConfiguration *buildConfig); protected: void showEvent(QShowEvent *event) override; diff --git a/src/plugins/coco/cocobuild/cocoqmakesettings.cpp b/src/plugins/coco/cocoqmakesettings.cpp similarity index 52% rename from src/plugins/coco/cocobuild/cocoqmakesettings.cpp rename to src/plugins/coco/cocoqmakesettings.cpp index b85763c5471..ea8a3fef4bd 100644 --- a/src/plugins/coco/cocobuild/cocoqmakesettings.cpp +++ b/src/plugins/coco/cocoqmakesettings.cpp @@ -3,41 +3,62 @@ #include "cocoqmakesettings.h" -#include "../cocobuild/cocoprojectwidget.h" -#include "../cocopluginconstants.h" -#include "../cocotr.h" -#include "../common.h" +#include "buildsettings.h" +#include "cococommon.h" +#include "cocoinstallation.h" +#include "cocopluginconstants.h" +#include "cocoprojectwidget.h" +#include "cocotr.h" +#include "qmakefeaturefile.h" + +#include +#include #include #include #include -#include -#include + +#include +#include using namespace ProjectExplorer; namespace Coco::Internal { -CocoQMakeSettings::CocoQMakeSettings(Project *project) - : BuildSettings{m_featureFile, project} -{} +class CocoQMakeSettings : public BuildSettings +{ +public: + explicit CocoQMakeSettings(BuildConfiguration *buildConfig) + : BuildSettings{m_featureFile, buildConfig} + {} -CocoQMakeSettings::~CocoQMakeSettings() {} + void read() override; + bool validSettings() const override; + void setCoverage(bool on) override; + + QString saveButtonText() const override; + QString configChanges() const override; + QString projectDirectory() const override; + void write(const QString &options, const QString &tweaks) override; + +private: + bool environmentSet() const; + QString pathAssignment() const; + const QStringList userArgumentList() const; + Utils::Environment buildEnvironment() const; + void setQMakeFeatures() const; + bool cocoPathValid() const; + + QMakeFeatureFile m_featureFile; + CocoInstallation m_coco; +}; void CocoQMakeSettings::read() { setEnabled(false); - if (Target *target = activeTarget()) { - if ((m_buildConfig = qobject_cast(target->activeBuildConfiguration()))) { - if (BuildStepList *buildSteps = m_buildConfig->buildSteps()) { - if ((m_qmakeStep = buildSteps->firstOfType())) { - m_featureFile.setProjectDirectory(m_buildConfig->project()->projectDirectory()); - m_featureFile.read(); - setEnabled(true); - } - } - } - } + m_featureFile.setFilePath(buildConfig()); + m_featureFile.read(); + setEnabled(true); } QString configAssignment() @@ -54,15 +75,7 @@ const QStringList CocoQMakeSettings::userArgumentList() const if (!enabled()) return {}; - Utils::ProcessArgs::ConstArgIterator it{m_qmakeStep->userArguments.unexpandedArguments()}; - QStringList result; - - while (it.next()) { - if (it.isSimple()) - result << it.value(); - } - - return result; + return buildConfig()->initialArgs(); } Utils::Environment CocoQMakeSettings::buildEnvironment() const @@ -70,8 +83,8 @@ Utils::Environment CocoQMakeSettings::buildEnvironment() const if (!enabled()) return Utils::Environment(); - Utils::Environment env = m_buildConfig->environment(); - env.modify(m_buildConfig->userEnvironmentChanges()); + Utils::Environment env = buildConfig()->environment(); + env.modify(buildConfig()->userEnvironmentChanges()); return env; } @@ -82,15 +95,15 @@ void CocoQMakeSettings::setQMakeFeatures() const Utils::Environment env = buildEnvironment(); - const QString projectDir = m_buildConfig->project()->projectDirectory().nativePath(); + const QString projectDir = buildConfig()->project()->projectDirectory().nativePath(); if (env.value(featuresVar) != projectDir) { // Bug in prependOrSet(): It does not recognize if QMAKEFEATURES contains a single path // without a colon and then appends it twice. env.prependOrSet(featuresVar, projectDir); } - Utils::EnvironmentItems diff = m_buildConfig->baseEnvironment().diff(env); - m_buildConfig->setUserEnvironmentChanges(diff); + Utils::EnvironmentItems diff = buildConfig()->baseEnvironment().diff(env); + buildConfig()->setUserEnvironmentChanges(diff); } bool CocoQMakeSettings::environmentSet() const @@ -99,7 +112,7 @@ bool CocoQMakeSettings::environmentSet() const return true; const Utils::Environment env = buildEnvironment(); - const Utils::FilePath projectDir = m_buildConfig->project()->projectDirectory(); + const Utils::FilePath projectDir = buildConfig()->project()->projectDirectory(); const QString nativeProjectDir = projectDir.nativePath(); return env.value(featuresVar) == nativeProjectDir || env.value(featuresVar).startsWith(nativeProjectDir + projectDir.pathListSeparator()); @@ -114,25 +127,22 @@ bool CocoQMakeSettings::validSettings() const void CocoQMakeSettings::setCoverage(bool on) { - QString args = m_qmakeStep->userArguments.unexpandedArguments(); - Utils::ProcessArgs::ArgIterator it{&args}; + QStringList args; - while (it.next()) { - if (it.isSimple()) { - const QString value = it.value(); - if (value.startsWith(pathAssignmentPrefix) || value == configAssignment()) - it.deleteArg(); - } + for (const QString &arg : buildConfig()->initialArgs()) { + if (!arg.startsWith(pathAssignmentPrefix) && arg != configAssignment()) + args.append(arg); } + if (on) { - it.appendArg(configAssignment()); - it.appendArg(pathAssignment()); + args.append(configAssignment()); + args.append(pathAssignment()); setQMakeFeatures(); m_featureFile.write(); } - m_qmakeStep->userArguments.setArguments(args); + buildConfig()->setInitialArgs(args); } QString CocoQMakeSettings::saveButtonText() const @@ -144,17 +154,18 @@ QString CocoQMakeSettings::configChanges() const { return "" + tableRow( - "Additional qmake arguments: ", + Tr::tr("Additional qmake arguments: "), maybeQuote(configAssignment()) + " " + maybeQuote(pathAssignment())) + tableRow( - "Build environment: ", maybeQuote(QString(featuresVar) + "=" + projectDirectory())) - + tableRow("Feature File: ", maybeQuote(featureFilePath())) + "
"; + Tr::tr("Build environment: "), + maybeQuote(QString(featuresVar) + "=" + projectDirectory())) + + tableRow(Tr::tr("Feature File: "), maybeQuote(featureFilePath())) + ""; } QString CocoQMakeSettings::projectDirectory() const { if (enabled()) - return m_buildConfig->project()->projectDirectory().nativePath(); + return buildConfig()->project()->projectDirectory().nativePath(); else return ""; } @@ -173,16 +184,17 @@ QString CocoQMakeSettings::pathAssignment() const bool CocoQMakeSettings::cocoPathValid() const { - Utils::ProcessArgs::ConstArgIterator it{m_qmakeStep->userArguments.unexpandedArguments()}; - - while (it.next()) { - if (it.isSimple()) { - const QString value = it.value(); - if (value.startsWith(pathAssignmentPrefix) && value != pathAssignment()) - return false; - } + for (const QString &arg : buildConfig()->initialArgs()) { + if (arg.startsWith(pathAssignmentPrefix) && arg != pathAssignment()) + return false; } + return true; } +BuildSettings *createCocoQMakeSettings(BuildConfiguration *bc) +{ + return new CocoQMakeSettings(bc); +} + } // namespace Coco::Internal diff --git a/src/plugins/coco/cocoqmakesettings.h b/src/plugins/coco/cocoqmakesettings.h new file mode 100644 index 00000000000..0134738fa65 --- /dev/null +++ b/src/plugins/coco/cocoqmakesettings.h @@ -0,0 +1,14 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace ProjectExplorer { class BuildConfiguration; } + +namespace Coco::Internal { + +class BuildSettings; + +BuildSettings *createCocoQMakeSettings(ProjectExplorer::BuildConfiguration *bc); + +} // namespace Coco::Internal diff --git a/src/plugins/coco/settings/globalsettings.cpp b/src/plugins/coco/globalsettings.cpp similarity index 97% rename from src/plugins/coco/settings/globalsettings.cpp rename to src/plugins/coco/globalsettings.cpp index 89129b7c2a0..594355964ee 100644 --- a/src/plugins/coco/settings/globalsettings.cpp +++ b/src/plugins/coco/globalsettings.cpp @@ -3,8 +3,8 @@ #include "globalsettings.h" -#include "../cocopluginconstants.h" #include "cocoinstallation.h" +#include "cocopluginconstants.h" #include #include diff --git a/src/plugins/coco/settings/globalsettings.h b/src/plugins/coco/globalsettings.h similarity index 100% rename from src/plugins/coco/settings/globalsettings.h rename to src/plugins/coco/globalsettings.h diff --git a/src/plugins/coco/settings/globalsettingspage.cpp b/src/plugins/coco/globalsettingspage.cpp similarity index 98% rename from src/plugins/coco/settings/globalsettingspage.cpp rename to src/plugins/coco/globalsettingspage.cpp index f8f6bb4748b..b4eda76d0ba 100644 --- a/src/plugins/coco/settings/globalsettingspage.cpp +++ b/src/plugins/coco/globalsettingspage.cpp @@ -3,9 +3,9 @@ #include "globalsettingspage.h" -#include "../cocopluginconstants.h" -#include "../cocotr.h" #include "cocoinstallation.h" +#include "cocopluginconstants.h" +#include "cocotr.h" #include "globalsettings.h" #include diff --git a/src/plugins/coco/settings/globalsettingspage.h b/src/plugins/coco/globalsettingspage.h similarity index 100% rename from src/plugins/coco/settings/globalsettingspage.h rename to src/plugins/coco/globalsettingspage.h diff --git a/src/plugins/coco/cocobuild/modificationfile.cpp b/src/plugins/coco/modificationfile.cpp similarity index 69% rename from src/plugins/coco/cocobuild/modificationfile.cpp rename to src/plugins/coco/modificationfile.cpp index a8184021847..a3abd322851 100644 --- a/src/plugins/coco/cocobuild/modificationfile.cpp +++ b/src/plugins/coco/modificationfile.cpp @@ -2,6 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "modificationfile.h" +#include "projectexplorer/project.h" + +#include namespace Coco::Internal { @@ -11,7 +14,21 @@ static void cutTail(QStringList &list) list.removeLast(); } -ModificationFile::ModificationFile() {} +ModificationFile::ModificationFile(const QString &fileName, const Utils::FilePath &defaultModificationFile) + : m_fileName{fileName} + , m_defaultModificationFile{defaultModificationFile} +{} + +void ModificationFile::setFilePath(ProjectExplorer::BuildConfiguration *buildConfig) +{ + Utils::FilePath projectDirectory = buildConfig->project()->projectDirectory(); + m_filePath = projectDirectory.pathAppended(fileName()); +} + +QString ModificationFile::fileName() const +{ + return m_fileName; +} bool ModificationFile::exists() const { @@ -24,6 +41,11 @@ void ModificationFile::clear() m_tweaks.clear(); } +QStringList ModificationFile::defaultModificationFile() const +{ + return contentOf(m_defaultModificationFile); +} + QStringList ModificationFile::contentOf(const Utils::FilePath &filePath) const { QFile resource(filePath.nativePath()); diff --git a/src/plugins/coco/cocobuild/modificationfile.h b/src/plugins/coco/modificationfile.h similarity index 70% rename from src/plugins/coco/cocobuild/modificationfile.h rename to src/plugins/coco/modificationfile.h index 0f156ab2495..6ae675d04c0 100644 --- a/src/plugins/coco/cocobuild/modificationfile.h +++ b/src/plugins/coco/modificationfile.h @@ -7,41 +7,42 @@ #include +namespace ProjectExplorer { +class BuildConfiguration; +} + namespace Coco::Internal { class ModificationFile { public: - ModificationFile(); + ModificationFile(const QString &fileName, const Utils::FilePath &defaultModificationFile); - virtual void read() = 0; - virtual void write() const = 0; + void setFilePath(ProjectExplorer::BuildConfiguration *buildConfig); - virtual void setProjectDirectory(const Utils::FilePath &projectDirectory) = 0; - - virtual QString fileName() const = 0; + QString fileName() const; QString nativePath() const { return m_filePath.nativePath(); } bool exists() const; const QStringList &options() const { return m_options; } void setOptions(const QString &options); + void setOptions(const QStringList &options); const QStringList &tweaks() const { return m_tweaks; } void setTweaks(const QString &tweaks); - -protected: - void clear(); - - virtual QStringList defaultModificationFile() const = 0; - QStringList contentOf(const Utils::FilePath &filePath) const; - QStringList currentModificationFile() const; - - void setFilePath(const Utils::FilePath &path) { m_filePath = path; } - - void setOptions(const QStringList &options); void setTweaks(const QStringList &tweaks); + void clear(); + + QStringList defaultModificationFile() const; + QStringList currentModificationFile() const; + private: + QStringList contentOf(const Utils::FilePath &filePath) const; + + const QString m_fileName; + const Utils::FilePath m_defaultModificationFile; + QStringList m_options; QStringList m_tweaks; diff --git a/src/plugins/coco/cocobuild/qmakefeaturefile.cpp b/src/plugins/coco/qmakefeaturefile.cpp similarity index 81% rename from src/plugins/coco/cocobuild/qmakefeaturefile.cpp rename to src/plugins/coco/qmakefeaturefile.cpp index b02f545370b..b62dd608758 100644 --- a/src/plugins/coco/cocobuild/qmakefeaturefile.cpp +++ b/src/plugins/coco/qmakefeaturefile.cpp @@ -3,7 +3,7 @@ #include "qmakefeaturefile.h" -#include "../cocopluginconstants.h" +#include "cocopluginconstants.h" #include #include @@ -14,17 +14,9 @@ namespace Coco::Internal { static const char assignment[] = "COVERAGE_OPTIONS = \\\n"; static const char tweaksLine[] = "# User-supplied settings follow here:\n"; -QMakeFeatureFile::QMakeFeatureFile() {} - -QString QMakeFeatureFile::fileName() const -{ - return QString(Constants::PROFILE_NAME) + ".prf"; -} - -void QMakeFeatureFile::setProjectDirectory(const Utils::FilePath &projectDirectory) -{ - setFilePath(projectDirectory.pathAppended(fileName())); -} +QMakeFeatureFile::QMakeFeatureFile() + : ModificationFile{QString(Constants::PROFILE_NAME) + ".prf", ":/cocoplugin/files/cocoplugin.prf"} +{} QString QMakeFeatureFile::fromFileLine(const QString &line) const { @@ -91,9 +83,4 @@ void QMakeFeatureFile::write() const out.close(); } -QStringList QMakeFeatureFile::defaultModificationFile() const -{ - return contentOf(":/cocoplugin/files/cocoplugin.prf"); -} - } // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuild/qmakefeaturefile.h b/src/plugins/coco/qmakefeaturefile.h similarity index 67% rename from src/plugins/coco/cocobuild/qmakefeaturefile.h rename to src/plugins/coco/qmakefeaturefile.h index 3c865a1a25d..ca3ba6f31c9 100644 --- a/src/plugins/coco/cocobuild/qmakefeaturefile.h +++ b/src/plugins/coco/qmakefeaturefile.h @@ -17,14 +17,8 @@ class QMakeFeatureFile : public ModificationFile public: QMakeFeatureFile(); - void setProjectDirectory(const Utils::FilePath &projectDirectory) override; - void read() override; - void write() const override; - - QString fileName() const override; - -protected: - QStringList defaultModificationFile() const override; + void read(); + void write() const; private: QString fromFileLine(const QString &line) const; diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 5ad0891c6b1..99bdb600475 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -294,6 +294,23 @@ bool BuildConfiguration::createBuildDirectory() return result; } +void BuildConfiguration::setInitialArgs(const QStringList &) +{ + QTC_CHECK(false); +} + +QStringList BuildConfiguration::initialArgs() const +{ + QTC_CHECK(false); + return {}; +} + +QStringList BuildConfiguration::additionalArgs() const +{ + QTC_CHECK(false); + return {}; +} + void BuildConfiguration::setInitializer(const std::function &initializer) { d->m_initializer = initializer; diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h index f8f42917018..4f9ed30fe79 100644 --- a/src/plugins/projectexplorer/buildconfiguration.h +++ b/src/plugins/projectexplorer/buildconfiguration.h @@ -113,6 +113,14 @@ public: bool createBuildDirectory(); + // For tools that need to manipulate the main build command's argument list + virtual void setInitialArgs(const QStringList &); + virtual QStringList initialArgs() const; + virtual QStringList additionalArgs() const; + + virtual void reconfigure() {} + virtual void stopReconfigure() {} + signals: void environmentChanged(); void buildDirectoryInitialized(); diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h index 1681f28e5f3..6d82031804f 100644 --- a/src/plugins/projectexplorer/buildsystem.h +++ b/src/plugins/projectexplorer/buildsystem.h @@ -151,6 +151,8 @@ signals: void parsingFinished(bool success); void testInformationUpdated(); void debuggingStarted(); + void errorOccurred(const QString &message); + void warningOccurred(const QString &message); protected: // Helper methods to manage parsing state and signalling diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index 5d5d1caa455..8d149ee2f51 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -415,6 +415,33 @@ bool QmakeBuildConfiguration::runQmakeSystemFunctions() const return settings().runSystemFunction(); } +void QmakeBuildConfiguration::setInitialArgs(const QStringList &args) +{ + if (BuildStepList *buildSteps = this->buildSteps()) { + if (auto qmakeStep = buildSteps->firstOfType()) + qmakeStep->userArguments.setArguments(ProcessArgs::joinArgs(args)); + } +} + +QStringList QmakeBuildConfiguration::initialArgs() const +{ + if (BuildStepList *buildSteps = this->buildSteps()) { + if (auto qmakeStep = buildSteps->firstOfType()) { + QString arg = qmakeStep->userArguments.unexpandedArguments(); + ProcessArgs::ConstArgIterator it{arg}; + QStringList result; + + while (it.next()) { + if (it.isSimple()) + result << it.value(); + } + + return result; + } + } + return {}; +} + QStringList QmakeBuildConfiguration::configCommandLineArguments() const { QStringList result; diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h index 0715311822d..2d768e788a7 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h @@ -95,6 +95,9 @@ public: bool runQmakeSystemFunctions() const; + void setInitialArgs(const QStringList &) override; + QStringList initialArgs() const override; + signals: /// emitted for setQMakeBuildConfig, not emitted for Qt version changes, even /// if those change the qmakebuildconfig From 9d17f12e06b7d573f177b8ee397ab61474f24b95 Mon Sep 17 00:00:00 2001 From: Artur Twardy Date: Mon, 28 Oct 2024 13:07:14 +0100 Subject: [PATCH 023/989] Lua: Remove duplicate of LineEdit Change-Id: I05175f6eaf4dc32c7500b827adda646ac914f70d Reviewed-by: Marcus Tillmanns --- src/plugins/lua/bindings/gui.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/plugins/lua/bindings/gui.cpp b/src/plugins/lua/bindings/gui.cpp index 3e5e22c2421..5479b083f5b 100644 --- a/src/plugins/lua/bindings/gui.cpp +++ b/src/plugins/lua/bindings/gui.cpp @@ -562,17 +562,6 @@ void setupGuiModule() sol::base_classes, sol::bases()); - gui.new_usertype( - "LineEdit", - sol::call_constructor, - sol::factories([guard](const sol::table &children) { - return constructWidgetType(children, guard); - }), - "text", - sol::property(&LineEdit::text), - sol::base_classes, - sol::bases()); - gui.new_usertype( "SpinBox", sol::call_constructor, From 43a3516ff45969ce8231a5b29a71ee8d5d7612ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Thu, 26 Sep 2024 12:33:51 +0200 Subject: [PATCH 024/989] SquishTests: Remove unused parameter from waitForProjectParsing() Its last usage was removed in 14.0 because it had already stopped working back then. Change-Id: I672a9769261e2acff4bf55eba0f867401c1f2d1b Reviewed-by: Christian Stenger --- tests/system/shared/project.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 86692c3410c..acf2bc1d7da 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -688,17 +688,10 @@ def addCPlusPlusFile(name, template, projectName, forceOverwrite=False, addToVCS % (buttonToClick, overwriteDialog)) # if one of the parameters is set to 0 the function will not wait in this step -# beginParsingTimeout milliseconds to wait for parsing to begin # projectParsingTimeout milliseconds to wait for project parsing # codemodelParsingTimeout milliseconds to wait for C++ parsing -def waitForProjectParsing(beginParsingTimeout=0, projectParsingTimeout=10000, - codemodelParsingTimeout=10000): +def waitForProjectParsing(projectParsingTimeout=10000, codemodelParsingTimeout=10000): runButton = findObject(':*Qt Creator.Run_Core::Internal::FancyToolButton') - if beginParsingTimeout > 0: - # currently unused - test.warning("Waiting for the runButton to become disabled is probably futile.", - "The button isn't disabled during project parsing anymore.") - waitFor("not runButton.enabled", beginParsingTimeout) # Wait for parsing to complete waitFor("runButton.enabled", projectParsingTimeout) if codemodelParsingTimeout > 0: From c8adf29a78a759a9f6fce0de7e43247781ffa4fc Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 28 Oct 2024 13:03:41 +0100 Subject: [PATCH 025/989] ProjectExplorer: Hide unsuitable kits by default ... in the target setup page. Change-Id: Ibd26bfee4453e0c0ba8e898b2ba3e7f37506b69c Reviewed-by: Christian Stenger --- .../projectexplorer/targetsetuppage.cpp | 52 +++++++++++++++---- .../projectexplorer/targetsetupwidget.cpp | 1 + .../projectexplorer/targetsetupwidget.h | 1 + 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 979fb6772bc..c0eb9b82bad 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -106,6 +106,8 @@ public: kitFilterLineEdit->setFiltering(true); kitFilterLineEdit->setPlaceholderText(Tr::tr("Type to filter kits by name...")); + hideUnsuitableKitsCheckBox = new QCheckBox(Tr::tr("Hide unsuitable kits"), setupTargetPage); + m_centralWidget = new QWidget(setupTargetPage); QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Fixed); policy.setHorizontalStretch(0); @@ -134,6 +136,7 @@ public: auto verticalLayout_2 = new QVBoxLayout(setupTargetPage); verticalLayout_2->addWidget(headerLabel); verticalLayout_2->addLayout(horizontalLayout); + verticalLayout_2->addWidget(hideUnsuitableKitsCheckBox); verticalLayout_2->addWidget(noValidKitLabel); verticalLayout_2->addWidget(m_centralWidget); verticalLayout_2->addWidget(scrollAreaWidget); @@ -155,6 +158,13 @@ public: QObject::connect(allKitsCheckBox, &QAbstractButton::clicked, q, &TargetSetupPage::changeAllKitsSelections); + const auto toggleTargetWidgetVisibility = [this] { + for (TargetSetupWidget *widget : m_widgets) + toggleVisibility(widget); + }; + QObject::connect(hideUnsuitableKitsCheckBox, &QCheckBox::toggled, + this, toggleTargetWidgetVisibility); + QObject::connect(kitFilterLineEdit, &FancyLineEdit::filterChanged, this, &TargetSetupPagePrivate::kitFilterChanged); @@ -176,6 +186,7 @@ public: connect(KitManager::instance(), &KitManager::kitsChanged, this, &TargetSetupPagePrivate::updateVisibility); + toggleTargetWidgetVisibility(); } void doInitializePage(); @@ -194,7 +205,9 @@ public: void selectAtLeastOneEnabledKit(); void removeWidget(Kit *k) { removeWidget(widget(k)); } void removeWidget(Internal::TargetSetupWidget *w); - Internal::TargetSetupWidget *addWidget(Kit *k); + TargetSetupWidget *addWidget(Kit *k); + void connectWidget(TargetSetupWidget *w); + void toggleVisibility(TargetSetupWidget *w); void addAdditionalWidgets(); void removeAdditionalWidgets(QLayout *layout); void removeAdditionalWidgets(); @@ -224,6 +237,7 @@ public: QLabel *noValidKitLabel; QCheckBox *allKitsCheckBox; FancyLineEdit *kitFilterLineEdit; + QCheckBox *hideUnsuitableKitsCheckBox; TasksGenerator m_tasksGenerator; QPointer m_importer; @@ -307,10 +321,6 @@ void TargetSetupPagePrivate::setupWidgets(const QString &filterText) if (m_importer && !m_importer->filter(k)) continue; const auto widget = new TargetSetupWidget(k, m_projectPath); - connect(widget, &TargetSetupWidget::selectedToggled, - this, &TargetSetupPagePrivate::kitSelectionChanged); - connect(widget, &TargetSetupWidget::selectedToggled, - q, &QWizardPage::completeChanged); updateWidget(widget); m_widgets.push_back(widget); m_baseLayout->addWidget(widget); @@ -322,6 +332,10 @@ void TargetSetupPagePrivate::setupWidgets(const QString &filterText) kitSelectionChanged(); updateVisibility(); + for (TargetSetupWidget * const w : m_widgets) { + connectWidget(w); + toggleVisibility(w); + } } void TargetSetupPagePrivate::reset() @@ -338,6 +352,7 @@ void TargetSetupPagePrivate::reset() } allKitsCheckBox->setChecked(false); + hideUnsuitableKitsCheckBox->setChecked(true); } TargetSetupWidget *TargetSetupPagePrivate::widget(const Id kitId, TargetSetupWidget *fallback) const @@ -633,11 +648,8 @@ TargetSetupWidget *TargetSetupPagePrivate::addWidget(Kit *k) { const auto widget = new TargetSetupWidget(k, m_projectPath); updateWidget(widget); - connect(widget, &TargetSetupWidget::selectedToggled, - this, &TargetSetupPagePrivate::kitSelectionChanged); - connect(widget, &TargetSetupWidget::selectedToggled, - q, &QWizardPage::completeChanged); - + connectWidget(widget); + toggleVisibility(widget); // Insert widget, sorted. const auto insertionPos = std::find_if(m_widgets.begin(), m_widgets.end(), @@ -657,6 +669,26 @@ TargetSetupWidget *TargetSetupPagePrivate::addWidget(Kit *k) return widget; } +void TargetSetupPagePrivate::connectWidget(TargetSetupWidget *w) +{ + connect(w, &TargetSetupWidget::selectedToggled, + this, &TargetSetupPagePrivate::kitSelectionChanged); + connect(w, &TargetSetupWidget::selectedToggled, + q, &QWizardPage::completeChanged); + connect(w, &TargetSetupWidget::validToggled, this, [w, this] { toggleVisibility(w); }); +} + +void TargetSetupPagePrivate::toggleVisibility(TargetSetupWidget *w) +{ + const bool shouldBeVisible = w->isValid() || !hideUnsuitableKitsCheckBox->isChecked(); + if (shouldBeVisible) { + if (!w->isVisible()) // Prevent flickering. + w->show(); + } else { + w->hide(); + } +} + void TargetSetupPagePrivate::addAdditionalWidgets() { m_baseLayout->addWidget(m_importWidget); diff --git a/src/plugins/projectexplorer/targetsetupwidget.cpp b/src/plugins/projectexplorer/targetsetupwidget.cpp index 6a26a6a3df3..b227c4750b3 100644 --- a/src/plugins/projectexplorer/targetsetupwidget.cpp +++ b/src/plugins/projectexplorer/targetsetupwidget.cpp @@ -251,6 +251,7 @@ void TargetSetupWidget::setValid(bool valid) m_detailsWidget->setState(DetailsWidget::Collapsed); m_detailsWidget->setChecked(false); } + emit validToggled(); } const QList TargetSetupWidget::selectedBuildInfoList() const diff --git a/src/plugins/projectexplorer/targetsetupwidget.h b/src/plugins/projectexplorer/targetsetupwidget.h index 2aca36550c5..176a97f0844 100644 --- a/src/plugins/projectexplorer/targetsetupwidget.h +++ b/src/plugins/projectexplorer/targetsetupwidget.h @@ -54,6 +54,7 @@ public: signals: void selectedToggled() const; + void validToggled() const; private: static const QList buildInfoList(const Kit *k, const Utils::FilePath &projectPath); From 43d09e3802e87fa31f560527828b069c4de1b5e1 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 29 Oct 2024 13:58:15 +0100 Subject: [PATCH 026/989] QtSupport: Prefer higher Qt Versions to lower ones ... as a tie-breaker when setting up a kit. Change-Id: I243b9562e428e90fe89dfa1ea7a5ed9544c867ed Reviewed-by: hjk --- src/plugins/qtsupport/qtkitaspect.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index dbf648e392e..882bda12211 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -148,12 +148,30 @@ void QtKitAspectFactory::setup(Kit *k) }); const QtVersions &candidates = !exactMatches.empty() ? exactMatches : matches; + // Prefer higher versions to lower ones. + const QVersionNumber maxVersion = [&]() -> QVersionNumber { + if (const auto it = std::max_element( + candidates.begin(), + candidates.end(), + [](const QtVersion *v1, const QtVersion *v2) { + return v1->qtVersion() < v2->qtVersion(); + }); + it != candidates.end()) { + return (*it)->qtVersion(); + } + return {}; + }(); + const auto [highestVersions, lowerVersions] + = Utils::partition(candidates, [&maxVersion](const QtVersion *v) { + return v->qtVersion() == maxVersion; + }); + QtVersion * const qtFromPath = QtVersionManager::version( equal(&QtVersion::detectionSource, QString("PATH"))); - if (qtFromPath && candidates.contains(qtFromPath)) + if (qtFromPath && highestVersions.contains(qtFromPath)) k->setValue(id(), qtFromPath->uniqueId()); else - k->setValue(id(), candidates.first()->uniqueId()); + k->setValue(id(), highestVersions.first()->uniqueId()); } Tasks QtKitAspectFactory::validate(const Kit *k) const From 3ff0d5c8eb4d9c1b574cade4cf5d4505001ab40f Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Tue, 29 Oct 2024 10:50:56 +0100 Subject: [PATCH 027/989] QML Profiler: Fix Stop button connection QML Profiler mistakenly expected a wrong stop signal: it was bound to `RunControl::stopped` (which apparently arrives only when the remote debugging is completely stopped), instead of `QmlProfilerRunner::stopped`, which is issued when QML profiling is stopped. Fixes: QTCREATORBUG-31372 Change-Id: I0582894f1ebe8681d8e504a626eb46e5a81f72a5 Reviewed-by: hjk --- src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 631f04cef67..68e3bb63774 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -378,7 +378,7 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunner *runWorker) d->m_profilerConnections->disconnectFromServer(); }; - connect(runControl, &RunControl::stopped, this, handleStop); + connect(runWorker, &QmlProfilerRunner::stopped, this, handleStop); connect(d->m_stopAction, &QAction::triggered, runControl, &RunControl::initiateStop); updateRunActions(); From 7b4bc51dcaf13c661f7029cc34471c735541c6f5 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Sat, 19 Oct 2024 02:38:17 +0200 Subject: [PATCH 028/989] Wizards: Use is[Any]PluginRunning This replaces all occurrences of value('Plugins').indexOf('MyPlugin') >= 0 with isPluginRunning('myplugin') And combines OR'ed sequences with AnyPluginRunning. Tests for (Boot2Qt || Boot2QtQdb) are reduced to just boot2qt, since the other one is history. Change-Id: I21206116e2263579349c77ba3914f8ebfe1f089e Reviewed-by: Eike Ziller --- .../creator-projects-custom-wizards-json.qdocinc | 2 +- .../studio_templates/files/qtuiquickform/wizard.json | 2 +- .../studio_templates/files/scxml/wizard.json | 2 +- .../templates/wizards/autotest/boosttest/wizard.json | 8 ++++---- .../templates/wizards/autotest/catch/wizard.json | 8 ++++---- .../templates/wizards/autotest/gtest/wizard.json | 8 ++++---- .../templates/wizards/autotest/qttest/wizard.json | 8 ++++---- .../templates/wizards/autotest/quicktest/wizard.json | 8 ++++---- .../templates/wizards/classes/cpp/wizard.json | 2 +- .../templates/wizards/classes/itemmodel/wizard.json | 2 +- .../templates/wizards/classes/python/wizard.json | 2 +- .../templates/wizards/codesnippet/wizard.json | 2 +- .../templates/wizards/files/cppheader/wizard.json | 2 +- .../templates/wizards/files/cppsource/wizard.json | 2 +- .../qtcreator/templates/wizards/files/form/wizard.json | 2 +- .../wizards/files/glsl/gl/fragment/wizard.json | 2 +- .../templates/wizards/files/glsl/gl/vertex/wizard.json | 2 +- .../wizards/files/glsl/gles/fragment/wizard.json | 2 +- .../wizards/files/glsl/gles/vertex/wizard.json | 2 +- .../qtcreator/templates/wizards/files/java/wizard.json | 2 +- share/qtcreator/templates/wizards/files/js/wizard.json | 2 +- .../templates/wizards/files/markdown/wizard.json | 2 +- .../templates/wizards/files/modeling/model/wizard.json | 2 +- .../wizards/files/modeling/scratch/wizard.json | 2 +- .../qtcreator/templates/wizards/files/nim/wizard.json | 2 +- .../templates/wizards/files/nimscript/wizard.json | 2 +- .../templates/wizards/files/python/wizard.json | 2 +- .../qtcreator/templates/wizards/files/qrc/wizard.json | 2 +- .../templates/wizards/files/qtquick2/wizard.json | 2 +- .../templates/wizards/files/scratch/wizard.json | 2 +- .../templates/wizards/files/scxml/wizard.json | 2 +- .../templates/wizards/files/testing/wizard.json | 2 +- .../qtcreator/templates/wizards/files/text/wizard.json | 2 +- .../templates/wizards/files/translation/wizard.json | 2 +- .../templates/wizards/projects/cpplibrary/wizard.json | 10 +++++----- .../templates/wizards/projects/nim/wizard.json | 2 +- .../templates/wizards/projects/nimble/wizard.json | 2 +- .../templates/wizards/projects/plainc/wizard.json | 10 +++++----- .../templates/wizards/projects/plaincpp/wizard.json | 10 +++++----- .../templates/wizards/projects/qmake/empty/wizard.json | 2 +- .../projects/qtforpythonapplication/empty/wizard.json | 2 +- .../qtforpythonapplication/mainwindow/wizard.json | 2 +- .../qtquickapplication/wizard.json | 2 +- .../projects/qtforpythonapplication/widget/wizard.json | 2 +- .../wizards/projects/qtquick2-extension/wizard.json | 6 +++--- .../wizards/projects/qtquickapplication/wizard.json | 4 ++-- .../qtquickapplication_compat/empty/wizard.json | 10 +++++----- .../wizards/projects/qtquickuiprototype/wizard.json | 4 ++-- .../templates/wizards/projects/vcs/bazaar/wizard.json | 2 +- .../templates/wizards/projects/vcs/cvs/wizard.json | 2 +- .../templates/wizards/projects/vcs/git/wizard.json | 2 +- .../wizards/projects/vcs/mercurial/wizard.json | 2 +- .../wizards/projects/vcs/subversion/wizard.json | 2 +- .../templates/wizards/qtcreatorplugin/wizard.json | 2 +- src/plugins/haskell/share/wizards/module/wizard.json | 2 +- src/plugins/lua/wizards/luafile/wizard.json | 2 +- src/plugins/lua/wizards/qcscript/wizard.json | 2 +- src/plugins/saferenderer/wizards/qsrapp/wizard.json | 4 ++-- src/plugins/saferenderer/wizards/qsrapp2_1/wizard.json | 6 +++--- src/plugins/squish/wizard/suite/wizard.json | 2 +- 60 files changed, 98 insertions(+), 98 deletions(-) diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-custom-wizards-json.qdocinc b/doc/qtcreator/src/projects/creator-only/creator-projects-custom-wizards-json.qdocinc index f6da8a35934..4abd6107ff8 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-custom-wizards-json.qdocinc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-custom-wizards-json.qdocinc @@ -156,7 +156,7 @@ "trDisplayName": "C++ Class", "trDisplayCategory": "C++", "iconText": "h/cpp", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", \endcode \list diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json index 26c628f4b31..4a721580d43 100644 --- a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json @@ -9,7 +9,7 @@ "icon": "file_ui.png", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('qmljseditor')}", "options" : [ { "key": "QmlFile", "value": "%{Class}.%{JS: Util.preferredSuffix('text/x-qml')}" }, { "key": "UiFile", "value": "%{FormClass}.%{JS: Util.preferredSuffix('application/x-qt.ui+qml')}" }, diff --git a/share/qtcreator/qmldesigner/studio_templates/files/scxml/wizard.json b/share/qtcreator/qmldesigner/studio_templates/files/scxml/wizard.json index 36bbda7b71e..3c0cf0cdce4 100644 --- a/share/qtcreator/qmldesigner/studio_templates/files/scxml/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/files/scxml/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Modeling", "iconText": "scxml", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('ScxmlEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('scxmleditor')}", "options": [ diff --git a/share/qtcreator/templates/wizards/autotest/boosttest/wizard.json b/share/qtcreator/templates/wizards/autotest/boosttest/wizard.json index 525752701e5..ae57a42bd4f 100644 --- a/share/qtcreator/templates/wizards/autotest/boosttest/wizard.json +++ b/share/qtcreator/templates/wizards/autotest/boosttest/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Test Project", "icon": "../autotest.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", "options": [ @@ -124,17 +124,17 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "Qbs", "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qbsprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/autotest/catch/wizard.json b/share/qtcreator/templates/wizards/autotest/catch/wizard.json index 03ee5ff68ff..588723b0839 100644 --- a/share/qtcreator/templates/wizards/autotest/catch/wizard.json +++ b/share/qtcreator/templates/wizards/autotest/catch/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Test Project", "icon": "../autotest.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", "options": [ @@ -134,17 +134,17 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "Qbs", "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qbsprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/autotest/gtest/wizard.json b/share/qtcreator/templates/wizards/autotest/gtest/wizard.json index 643dd95f0ab..17484ae2e54 100644 --- a/share/qtcreator/templates/wizards/autotest/gtest/wizard.json +++ b/share/qtcreator/templates/wizards/autotest/gtest/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Test Project", "icon": "../autotest.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", "options": [ @@ -128,17 +128,17 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "Qbs", "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qbsprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/autotest/qttest/wizard.json b/share/qtcreator/templates/wizards/autotest/qttest/wizard.json index e9b0a782c47..3237f9f099f 100644 --- a/share/qtcreator/templates/wizards/autotest/qttest/wizard.json +++ b/share/qtcreator/templates/wizards/autotest/qttest/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Test Project", "icon": "../autotest.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", "options": [ @@ -101,17 +101,17 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "Qbs", "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qbsprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/autotest/quicktest/wizard.json b/share/qtcreator/templates/wizards/autotest/quicktest/wizard.json index a5411c61b1b..19c6c8a3541 100644 --- a/share/qtcreator/templates/wizards/autotest/quicktest/wizard.json +++ b/share/qtcreator/templates/wizards/autotest/quicktest/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Test Project", "icon": "../autotest.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", "options": [ @@ -96,17 +96,17 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "Qbs", "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qbsprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/classes/cpp/wizard.json b/share/qtcreator/templates/wizards/classes/cpp/wizard.json index 1902ed87897..ad2a8f77845 100644 --- a/share/qtcreator/templates/wizards/classes/cpp/wizard.json +++ b/share/qtcreator/templates/wizards/classes/cpp/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "C++ Class", "trDisplayCategory": "C/C++", "iconText": "h/cpp", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", "options": [ diff --git a/share/qtcreator/templates/wizards/classes/itemmodel/wizard.json b/share/qtcreator/templates/wizards/classes/itemmodel/wizard.json index 7e1befd8e7e..e2a9b20903b 100644 --- a/share/qtcreator/templates/wizards/classes/itemmodel/wizard.json +++ b/share/qtcreator/templates/wizards/classes/itemmodel/wizard.json @@ -6,7 +6,7 @@ "trDescription": "Creates a Qt item model.", "trDisplayName": "Qt Item Model", "trDisplayCategory": "Qt", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", "options": [ diff --git a/share/qtcreator/templates/wizards/classes/python/wizard.json b/share/qtcreator/templates/wizards/classes/python/wizard.json index 381718c054f..1a169f18669 100644 --- a/share/qtcreator/templates/wizards/classes/python/wizard.json +++ b/share/qtcreator/templates/wizards/classes/python/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Python", "icon": "../../files/python/icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Python') >= 0}", + "enabled": "%{JS: isPluginRunning('python')}", "options": [ diff --git a/share/qtcreator/templates/wizards/codesnippet/wizard.json b/share/qtcreator/templates/wizards/codesnippet/wizard.json index e5ba8bbdc73..8bc448d5073 100644 --- a/share/qtcreator/templates/wizards/codesnippet/wizard.json +++ b/share/qtcreator/templates/wizards/codesnippet/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Code Snippet", "trDisplayCategory": "Other Project", "featuresRequired": [ "QtSupport.Wizards.FeatureQt" ], - "enabled": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}", + "enabled": "%{JS: isPluginRunning('cmakeprojectmanager')}", "options": [ diff --git a/share/qtcreator/templates/wizards/files/cppheader/wizard.json b/share/qtcreator/templates/wizards/files/cppheader/wizard.json index a4bbb5ccc66..6cee047ff8f 100644 --- a/share/qtcreator/templates/wizards/files/cppheader/wizard.json +++ b/share/qtcreator/templates/wizards/files/cppheader/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "C/C++ Header File", "trDisplayCategory": "C/C++", "iconText": "h", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", "options": [ { "key": "DefaultSuffix", "value": "%{JS: Cpp.cxxHeaderSuffix()}" }, diff --git a/share/qtcreator/templates/wizards/files/cppsource/wizard.json b/share/qtcreator/templates/wizards/files/cppsource/wizard.json index 707351da501..12f9640f4c3 100644 --- a/share/qtcreator/templates/wizards/files/cppsource/wizard.json +++ b/share/qtcreator/templates/wizards/files/cppsource/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "C/C++ Source File", "trDisplayCategory": "C/C++", "iconText": "cpp", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('cppeditor')}", "options": [ { "key": "FileName", "value": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}" }, diff --git a/share/qtcreator/templates/wizards/files/form/wizard.json b/share/qtcreator/templates/wizards/files/form/wizard.json index d0d826b6c6d..45ac46557aa 100644 --- a/share/qtcreator/templates/wizards/files/form/wizard.json +++ b/share/qtcreator/templates/wizards/files/form/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Qt Widgets Designer Form", "trDisplayCategory": "Qt", "iconText": "ui", - "enabled": "%{JS: value('Plugins').indexOf('Designer') >= 0}", + "enabled": "%{JS: isPluginRunning('designer')}", "options": [ { "key": "UiClass", "value": "%{JS: QtSupport.uiClassName(value('FormContents'))}" }, diff --git a/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json index 28a018945b2..021c04e8540 100644 --- a/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json +++ b/share/qtcreator/templates/wizards/files/glsl/gl/fragment/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "GLSL", "iconText": "frag", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('GLSLEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('glsleditor')}", "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-glsl-frag')}" }, diff --git a/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json index 48f1f68afde..2a283b2f60a 100644 --- a/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json +++ b/share/qtcreator/templates/wizards/files/glsl/gl/vertex/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "GLSL", "iconText": "vert", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('GLSLEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('glsleditor')}", "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-glsl-vert')}" }, diff --git a/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json index d636d0eb21c..bd7ec81b0e0 100644 --- a/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json +++ b/share/qtcreator/templates/wizards/files/glsl/gles/fragment/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "GLSL", "iconText": "fsh", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('GLSLEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('glsleditor')}", "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-glsl-es-frag')}" }, diff --git a/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json b/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json index 83a042d91b6..41e9e2c6716 100644 --- a/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json +++ b/share/qtcreator/templates/wizards/files/glsl/gles/vertex/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "GLSL", "iconText": "vsh", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('GLSLEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('glsleditor')}", "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-glsl-es-vert')}" }, diff --git a/share/qtcreator/templates/wizards/files/java/wizard.json b/share/qtcreator/templates/wizards/files/java/wizard.json index 83087984fcb..601376e771b 100644 --- a/share/qtcreator/templates/wizards/files/java/wizard.json +++ b/share/qtcreator/templates/wizards/files/java/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Java File", "trDisplayCategory": "Java", "iconText": "java", - "enabled": "%{JS: value('Plugins').indexOf('Android') >= 0}", + "enabled": "%{JS: isPluginRunning('android')}", "options": [ { "key": "ClassName", "value": "%{JS: value('FileName').charAt(0).toUpperCase() + value('FileName').substr(1).replace(/[.]java$/,'')}" }, diff --git a/share/qtcreator/templates/wizards/files/js/wizard.json b/share/qtcreator/templates/wizards/files/js/wizard.json index 505ca578170..93a706b4224 100644 --- a/share/qtcreator/templates/wizards/files/js/wizard.json +++ b/share/qtcreator/templates/wizards/files/js/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "JS File", "trDisplayCategory": "Qt", "iconText": "js", - "enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('qmljseditor')}", "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('application/javascript')}" }, diff --git a/share/qtcreator/templates/wizards/files/markdown/wizard.json b/share/qtcreator/templates/wizards/files/markdown/wizard.json index a5e49c755e1..1255fbe293a 100644 --- a/share/qtcreator/templates/wizards/files/markdown/wizard.json +++ b/share/qtcreator/templates/wizards/files/markdown/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "General", "iconText": "md", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('TextEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('texteditor')}", "options": [ { "key": "FileName", "value": "%{JS: Util.fileName(value('TargetPath'), 'md')}" } diff --git a/share/qtcreator/templates/wizards/files/modeling/model/wizard.json b/share/qtcreator/templates/wizards/files/modeling/model/wizard.json index c971c8bf9d7..8c6bda26490 100644 --- a/share/qtcreator/templates/wizards/files/modeling/model/wizard.json +++ b/share/qtcreator/templates/wizards/files/modeling/model/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Modeling", "iconText": "qmodel", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('ModelEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('modeleditor')}", "options": [ diff --git a/share/qtcreator/templates/wizards/files/modeling/scratch/wizard.json b/share/qtcreator/templates/wizards/files/modeling/scratch/wizard.json index 8092ba60216..16a38fa53cd 100644 --- a/share/qtcreator/templates/wizards/files/modeling/scratch/wizard.json +++ b/share/qtcreator/templates/wizards/files/modeling/scratch/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Modeling", "iconText": "qmodel", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('ModelEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('modeleditor')}", "options": [ { "key": "TargetPath", "value": "%{JS: Util.mktemp('model-XXXXXX.qmodel')}" } ], diff --git a/share/qtcreator/templates/wizards/files/nim/wizard.json b/share/qtcreator/templates/wizards/files/nim/wizard.json index e1957ed3f64..ecf832c3afa 100644 --- a/share/qtcreator/templates/wizards/files/nim/wizard.json +++ b/share/qtcreator/templates/wizards/files/nim/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Nim", "icon": "../../projects/nim/icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Nim') >= 0}", + "enabled": "%{JS: isPluginRunning('nim')}", "options": { "key": "DefaultSuffix", "value": "nim" }, diff --git a/share/qtcreator/templates/wizards/files/nimscript/wizard.json b/share/qtcreator/templates/wizards/files/nimscript/wizard.json index 09afa96325d..48230d58354 100644 --- a/share/qtcreator/templates/wizards/files/nimscript/wizard.json +++ b/share/qtcreator/templates/wizards/files/nimscript/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Nim", "icon": "../../projects/nim/icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Nim') >= 0}", + "enabled": "%{JS: isPluginRunning('nim')}", "options": { "key": "DefaultSuffix", "value": "nims" }, diff --git a/share/qtcreator/templates/wizards/files/python/wizard.json b/share/qtcreator/templates/wizards/files/python/wizard.json index a4398f802bd..65126a9be8e 100644 --- a/share/qtcreator/templates/wizards/files/python/wizard.json +++ b/share/qtcreator/templates/wizards/files/python/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Python", "icon": "icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Python') >= 0}", + "enabled": "%{JS: isPluginRunning('python')}", "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-python')}" }, diff --git a/share/qtcreator/templates/wizards/files/qrc/wizard.json b/share/qtcreator/templates/wizards/files/qrc/wizard.json index fe8ea73d172..30c2bbea4a2 100644 --- a/share/qtcreator/templates/wizards/files/qrc/wizard.json +++ b/share/qtcreator/templates/wizards/files/qrc/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Qt Resource File", "trDisplayCategory": "Qt", "iconText": "qrc", - "enabled": "%{JS: value('Plugins').indexOf('ResourceEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('resourceeditor')}", "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('application/vnd.qt.xml.resource')}" }, diff --git a/share/qtcreator/templates/wizards/files/qtquick2/wizard.json b/share/qtcreator/templates/wizards/files/qtquick2/wizard.json index bcb8ca994fe..562583d9bea 100644 --- a/share/qtcreator/templates/wizards/files/qtquick2/wizard.json +++ b/share/qtcreator/templates/wizards/files/qtquick2/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "QML File (Qt Quick 2)", "trDisplayCategory": "Qt", "iconText": "qml", - "enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('qmljseditor')}", "options": [ {"key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-qml')}"}, diff --git a/share/qtcreator/templates/wizards/files/scratch/wizard.json b/share/qtcreator/templates/wizards/files/scratch/wizard.json index 7dcaf0ec23c..026d838e322 100644 --- a/share/qtcreator/templates/wizards/files/scratch/wizard.json +++ b/share/qtcreator/templates/wizards/files/scratch/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Scratch Buffer", "trDisplayCategory": "General", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('TextEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('texteditor')}", "options": [ { "key": "TargetPath", "value": "%{JS: Util.mktemp('scratch-XXXXXX.txt')}" } ], diff --git a/share/qtcreator/templates/wizards/files/scxml/wizard.json b/share/qtcreator/templates/wizards/files/scxml/wizard.json index 36bbda7b71e..3c0cf0cdce4 100644 --- a/share/qtcreator/templates/wizards/files/scxml/wizard.json +++ b/share/qtcreator/templates/wizards/files/scxml/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Modeling", "iconText": "scxml", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('ScxmlEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('scxmleditor')}", "options": [ diff --git a/share/qtcreator/templates/wizards/files/testing/wizard.json b/share/qtcreator/templates/wizards/files/testing/wizard.json index e15997abf0a..121e921fc99 100644 --- a/share/qtcreator/templates/wizards/files/testing/wizard.json +++ b/share/qtcreator/templates/wizards/files/testing/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Test Case", "icon": "../../autotest/autotest.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('AutoTest') >= 0}", + "enabled": "%{JS: isPluginRunning('autotest')}", "options": [ { "key": "TargetPath", "value": "%{Path}" }, diff --git a/share/qtcreator/templates/wizards/files/text/wizard.json b/share/qtcreator/templates/wizards/files/text/wizard.json index b983401ef33..e0d73058924 100644 --- a/share/qtcreator/templates/wizards/files/text/wizard.json +++ b/share/qtcreator/templates/wizards/files/text/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "General", "iconText": "txt", "platformIndependent": true, - "enabled": "%{JS: value('Plugins').indexOf('TextEditor') >= 0}", + "enabled": "%{JS: isPluginRunning('texteditor')}", "pages" : [ diff --git a/share/qtcreator/templates/wizards/files/translation/wizard.json b/share/qtcreator/templates/wizards/files/translation/wizard.json index 04c2f145d1f..6422a7edf95 100644 --- a/share/qtcreator/templates/wizards/files/translation/wizard.json +++ b/share/qtcreator/templates/wizards/files/translation/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Qt Translation File", "trDisplayCategory": "Qt", "iconText": "ts", - "enabled": "%{JS: value('Plugins').indexOf('QtSupport') >= 0}", + "enabled": "%{JS: isPluginRunning('qtsupport')}", "options": [ { diff --git a/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json b/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json index 5bb6749fee6..8a6b4286a13 100644 --- a/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json +++ b/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Library", "icon": "../../global/lib.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0 && (value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('MesonProjectManager') >= 0)}", + "enabled": "%{JS: isPluginRunning('cppeditor') && isAnyPluginRunning(['qmakeprojectmanager', 'cmakeprojectmanager', 'mesonprojectmanager'])}", "options": [ @@ -65,22 +65,22 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "Qbs", "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qbsprojectmanager')}" }, { "trKey": "Meson", "value": "meson", - "condition": "%{JS: value('Plugins').indexOf('MesonProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('mesonprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/projects/nim/wizard.json b/share/qtcreator/templates/wizards/projects/nim/wizard.json index 6a84ca3d463..a428f65fbd2 100644 --- a/share/qtcreator/templates/wizards/projects/nim/wizard.json +++ b/share/qtcreator/templates/wizards/projects/nim/wizard.json @@ -9,7 +9,7 @@ "featuresRequired": [ "ToolChain.Nim.NimToolChain" ], "icon": "icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Nim') >= 0 }", + "enabled": "%{JS: isPluginRunning('nim') }", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/nimble/wizard.json b/share/qtcreator/templates/wizards/projects/nimble/wizard.json index 657aad71bb7..e5762fbfa28 100644 --- a/share/qtcreator/templates/wizards/projects/nimble/wizard.json +++ b/share/qtcreator/templates/wizards/projects/nimble/wizard.json @@ -11,7 +11,7 @@ ], "icon":"../nim/icon.png", "iconKind": "Themed", - "enabled":"%{JS: value('Plugins').indexOf('Nim') >= 0 }", + "enabled":"%{JS: isPluginRunning('nim') }", "options":[ { "key":"ProjectFile", diff --git a/share/qtcreator/templates/wizards/projects/plainc/wizard.json b/share/qtcreator/templates/wizards/projects/plainc/wizard.json index a0d3bf3ec20..ca7066a93aa 100644 --- a/share/qtcreator/templates/wizards/projects/plainc/wizard.json +++ b/share/qtcreator/templates/wizards/projects/plainc/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Non-Qt Project", "icon": "../../global/consoleapplication.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0 && (value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('MesonProjectManager') >= 0)}", + "enabled": "%{JS: isPluginRunning('cppeditor') && isAnyPluginRunning(['qmakeprojectmanager', 'qbsprojectmanager', 'cmakeprojectmanager', 'mesonprojectmanager'])}", "options": [ @@ -47,22 +47,22 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "Qbs", "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qbsprojectmanager')}" }, { "trKey": "Meson", "value": "meson", - "condition": "%{JS: value('Plugins').indexOf('MesonProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('mesonprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/projects/plaincpp/wizard.json b/share/qtcreator/templates/wizards/projects/plaincpp/wizard.json index cffdb7bb78d..7896ba7a5d4 100644 --- a/share/qtcreator/templates/wizards/projects/plaincpp/wizard.json +++ b/share/qtcreator/templates/wizards/projects/plaincpp/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Non-Qt Project", "icon": "../../global/consoleapplication.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0 && (value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('MesonProjectManager') >= 0)}", + "enabled": "%{JS: isPluginRunning('cppeditor') && isAnyPluginRunning(['qmakeprojectmanager', 'qbsprojectmanager', 'cmakeprojectmanager', 'mesonprojectmanager'])}", "options": [ @@ -47,22 +47,22 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "Qbs", "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qbsprojectmanager')}" }, { "trKey": "Meson", "value": "meson", - "condition": "%{JS: value('Plugins').indexOf('MesonProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('mesonprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/projects/qmake/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qmake/empty/wizard.json index 24256547669..4bd1c19ae2f 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/empty/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qmake/empty/wizard.json @@ -9,7 +9,7 @@ "icon": "../../../global/guiapplication.png", "iconKind": "Themed", "featuresRequired": [ "QtSupport.Wizards.FeatureQt" ], - "enabled": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}", + "enabled": "%{JS: isPluginRunning('qmakeprojectmanager')}", "options": [ { "key": "ProFileName", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'pro')}" } diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json index 72cfd75423a..6e28ffac686 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Application (Qt for Python)", "icon": "icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Python') >= 0 && (!value('Platform').length || ['Desktop', 'DockerDeviceType', 'GenericLinuxOsType'].includes(value('Platform')))}", + "enabled": "%{JS: isPluginRunning('python') && (!value('Platform').length || ['Desktop', 'DockerDeviceType', 'GenericLinuxOsType'].includes(value('Platform')))}", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json index 5197b5e598c..c2a7e072db6 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Application (Qt for Python)", "icon": "../icons/icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Python') >= 0 && (!value('Platform').length || ['Desktop', 'DockerDeviceType', 'GenericLinuxOsType'].includes(value('Platform')))}", + "enabled": "%{JS: isPluginRunning('python') && (!value('Platform').length || ['Desktop', 'DockerDeviceType', 'GenericLinuxOsType'].includes(value('Platform')))}", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json index a0f8d592001..9b172eabc23 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Application (Qt for Python)", "icon": "../icons/icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Python') >= 0 && (!value('Platform').length || ['Desktop', 'DockerDeviceType', 'GenericLinuxOsType'].includes(value('Platform')))}", + "enabled": "%{JS: isPluginRunning('python') && (!value('Platform').length || ['Desktop', 'DockerDeviceType', 'GenericLinuxOsType'].includes(value('Platform')))}", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json index 6d3f968c1bf..41efb4c448b 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Application (Qt for Python)", "icon": "../icons/icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Python') >= 0 && (!value('Platform').length || ['Desktop', 'DockerDeviceType', 'GenericLinuxOsType'].includes(value('Platform')))}", + "enabled": "%{JS: isPluginRunning('python') && (!value('Platform').length || ['Desktop', 'DockerDeviceType', 'GenericLinuxOsType'].includes(value('Platform')))}", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/qtquick2-extension/wizard.json b/share/qtcreator/templates/wizards/projects/qtquick2-extension/wizard.json index c2692ee641e..0ea0d6e9ee5 100644 --- a/share/qtcreator/templates/wizards/projects/qtquick2-extension/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquick2-extension/wizard.json @@ -9,7 +9,7 @@ "icon": "lib.png", "iconKind": "Themed", "featuresRequired": [ "QtSupport.Wizards.FeatureQtQuick", "QtSupport.Wizards.FeatureQtQuick.2" ], - "enabled": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}", + "enabled": "%{JS: isPluginRunning('qmakeprojectmanager')}", "options": [ @@ -60,12 +60,12 @@ { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index 2c8a5af02f7..18fcccf559d 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -9,13 +9,13 @@ "icon": "icon.png", "iconKind": "Themed", "featuresRequired": [ "QtSupport.Wizards.FeatureQtQmlCMakeApi" ], - "enabled": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0 }", + "enabled": "%{JS: isPluginRunning('cmakeprojectmanager') }", "options": [ { "key": "ProjectFile", "value": "%{ProjectDirectory}/CMakeLists.txt" }, { "key": "MainCppFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }" }, - { "key": "UseVirtualKeyboardByDefault", "value": "%{JS: value('Plugins').indexOf('Boot2Qt') >= 0 || value('Plugins').indexOf('Boot2QtQdb') >= 0 }" }, + { "key": "UseVirtualKeyboardByDefault", "value": "%{JS: isPluginRunning('boot2qt') }" }, { "key": "TargetName", "value": "%{JS: 'app' + value('ProjectName') }" }, { "key": "HasQSPSetup", "value": "%{JS: value('MinimumSupportedQtVersion') > '6.2' }"}, { "key": "HasFailureSignal", "value": "%{JS: value('MinimumSupportedQtVersion') > '6.3' }"}, diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication_compat/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication_compat/empty/wizard.json index d721e0e6191..f3b717bbc34 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication_compat/empty/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication_compat/empty/wizard.json @@ -9,7 +9,7 @@ "icon": "icon.png", "iconKind": "Themed", "featuresRequired": [ "QtSupport.Wizards.FeatureQt.5.6" ], - "enabled": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0}", + "enabled": "%{JS: isAnyPluginRunning(['qmakeprojectmanager', 'qbsprojectmanager', 'cmakeprojectmanager'])}", "options": [ @@ -23,7 +23,7 @@ { "key": "QtQuickWindowVersion", "value": "%{JS: value('QtVersion').QtQuickWindowVersion}" }, { "key": "QtQuickVirtualKeyboardImport", "value": "%{JS: value('QtVersion').QtQuickVirtualKeyboardImport}" }, { "key": "QtQuickFeature", "value": "%{JS: (value('QtQuickVersion')=='') ? 'QtSupport.Wizards.FeatureQt.6.2' : 'QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}'}" }, - { "key": "UseVirtualKeyboardByDefault", "value": "%{JS: value('Plugins').indexOf('Boot2Qt') >= 0 || value('Plugins').indexOf('Boot2QtQdb') >= 0}" }, + { "key": "UseVirtualKeyboardByDefault", "value": "%{JS: isPluginRunning('boot2qt')}" }, { "key": "HasTranslation", "value": "%{JS: value('TsFileName') !== ''}" }, { "key": "SetQPAPhysicalSize", "value": "%{UseVirtualKeyboardByDefault}" }, { "key": "AdditionalQmlFiles", "value": "" }, @@ -58,17 +58,17 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "CMake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" }, { "trKey": "Qbs", "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qbsprojectmanager')}" } ] } diff --git a/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json index a1534182145..06090c099ea 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json @@ -8,14 +8,14 @@ "trDisplayCategory": "Other Project", "icon": "qtquickuiprototype.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('QmlProjectManager') >= 0}", + "enabled": "%{JS: isPluginRunning('qmlprojectmanager')}", "featuresRequired": [ "QtSupport.Wizards.FeatureQtQuickProject", "QtSupport.Wizards.FeatureQtQuick.6" ], "options": [ { "key": "QmlProjectFileName", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'qmlproject')}" }, { "key": "MainQmlFileName", "value": "%{JS: Util.fileName(value('ProjectName'), 'qml')}" }, - { "key": "UseVirtualKeyboardByDefault", "value": "%{JS: value('Plugins').indexOf('Boot2Qt') >= 0 || value('Plugins').indexOf('Boot2QtQdb') >= 0}" }, + { "key": "UseVirtualKeyboardByDefault", "value": "%{JS: isPluginRunning('boot2qt')}" }, { "key": "QdsWizardPath", "value": "%{IDE:ResourcePath}/qmldesigner/studio_templates/projects" }, { "key": "NoQdsProjectStyle", "value": "%{JS: !%{QdsProjectStyle} }" }, diff --git a/share/qtcreator/templates/wizards/projects/vcs/bazaar/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/bazaar/wizard.json index 101a73dc64c..c0d5a14e6a1 100644 --- a/share/qtcreator/templates/wizards/projects/vcs/bazaar/wizard.json +++ b/share/qtcreator/templates/wizards/projects/vcs/bazaar/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Import Project", "icon": "icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Bazaar') >= 0}", + "enabled": "%{JS: isPluginRunning('bazaar')}", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/vcs/cvs/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/cvs/wizard.json index 25287a56b07..4c4f2aa70ff 100644 --- a/share/qtcreator/templates/wizards/projects/vcs/cvs/wizard.json +++ b/share/qtcreator/templates/wizards/projects/vcs/cvs/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Import Project", "icon": "icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('CVS') >= 0}", + "enabled": "%{JS: isPluginRunning('cvs')}", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json index ab193990fc1..55f50a34d6c 100644 --- a/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json +++ b/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Import Project", "icon": "icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Git') >= 0}", + "enabled": "%{JS: isPluginRunning('git')}", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/vcs/mercurial/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/mercurial/wizard.json index 84ec489c3ae..e414725bd97 100644 --- a/share/qtcreator/templates/wizards/projects/vcs/mercurial/wizard.json +++ b/share/qtcreator/templates/wizards/projects/vcs/mercurial/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Import Project", "icon": "icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Mercurial') >= 0}", + "enabled": "%{JS: isPluginRunning('mercurial')}", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/vcs/subversion/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/subversion/wizard.json index 5ef76615509..8072502649c 100644 --- a/share/qtcreator/templates/wizards/projects/vcs/subversion/wizard.json +++ b/share/qtcreator/templates/wizards/projects/vcs/subversion/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Import Project", "icon": "icon.png", "iconKind": "Themed", - "enabled": "%{JS: value('Plugins').indexOf('Subversion') >= 0}", + "enabled": "%{JS: isPluginRunning('subversion')}", "options": [ diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/wizard.json b/share/qtcreator/templates/wizards/qtcreatorplugin/wizard.json index a1e9bb00aa1..4ff17acaba9 100644 --- a/share/qtcreator/templates/wizards/qtcreatorplugin/wizard.json +++ b/share/qtcreator/templates/wizards/qtcreatorplugin/wizard.json @@ -9,7 +9,7 @@ "icon": "qtcreatorplugin.png", "iconKind": "Themed", "featuresRequired": [ "QtSupport.Wizards.FeatureQt", "QtSupport.Wizards.FeatureDesktop" ], - "enabled": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}", + "enabled": "%{JS: isPluginRunning('cmakeprojectmanager')}", "options": [ diff --git a/src/plugins/haskell/share/wizards/module/wizard.json b/src/plugins/haskell/share/wizards/module/wizard.json index 37f6ebf975b..48860a29efc 100644 --- a/src/plugins/haskell/share/wizards/module/wizard.json +++ b/src/plugins/haskell/share/wizards/module/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Module", "trDisplayCategory": "Haskell", "iconText": "hs", - "enabled": "%{JS: value('Plugins').indexOf('Haskell') >= 0}", + "enabled": "%{JS: isPluginRunning('haskell')}", "options": [ { "key": "FileName", "value": "%{JS: Util.fileName(value('TargetPath'), 'hs')}" }, diff --git a/src/plugins/lua/wizards/luafile/wizard.json b/src/plugins/lua/wizards/luafile/wizard.json index eb1a0863d00..02dc61653b3 100644 --- a/src/plugins/lua/wizards/luafile/wizard.json +++ b/src/plugins/lua/wizards/luafile/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Lua Script", "trDisplayCategory": "Lua", "iconText": "ts", - "enabled": "%{JS: value('Plugins').indexOf('Lua') >= 0}", + "enabled": "%{JS: isPluginRunning('lua')}", "options": [ { "key": "DefaultSuffix", diff --git a/src/plugins/lua/wizards/qcscript/wizard.json b/src/plugins/lua/wizards/qcscript/wizard.json index 1c6fec4b606..140868a74d6 100644 --- a/src/plugins/lua/wizards/qcscript/wizard.json +++ b/src/plugins/lua/wizards/qcscript/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Qt Creator Script", "trDisplayCategory": "Lua", "iconText": "ts", - "enabled": "%{JS: value('Plugins').indexOf('Lua') >= 0}", + "enabled": "%{JS: isPluginRunning('lua')}", "options": [ { "key": "DefaultSuffix", diff --git a/src/plugins/saferenderer/wizards/qsrapp/wizard.json b/src/plugins/saferenderer/wizards/qsrapp/wizard.json index 0f1aa508293..13353fbfeae 100644 --- a/src/plugins/saferenderer/wizards/qsrapp/wizard.json +++ b/src/plugins/saferenderer/wizards/qsrapp/wizard.json @@ -9,7 +9,7 @@ "icon": "../icon.png", "iconKind": "Themed", "featuresRequired": [ "QtSupport.Wizards.FeatureQt" ], - "enabled": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0}", + "enabled": "%{JS: isAnyPluginRunning(['qmakeprojectmanager', 'cmakeprojectmanager'])}", "options": [ @@ -47,7 +47,7 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" } ] } diff --git a/src/plugins/saferenderer/wizards/qsrapp2_1/wizard.json b/src/plugins/saferenderer/wizards/qsrapp2_1/wizard.json index e3f25810e69..ff0c0ab2240 100644 --- a/src/plugins/saferenderer/wizards/qsrapp2_1/wizard.json +++ b/src/plugins/saferenderer/wizards/qsrapp2_1/wizard.json @@ -9,7 +9,7 @@ "icon": "../icon.png", "iconKind": "Themed", "featuresRequired": [ "QtSupport.Wizards.FeatureQt" ], - "enabled": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0}", + "enabled": "%{JS: isAnyPluginRunning(['qmakeprojectmanager', 'cmakeprojectmanager'])}", "options": [ @@ -49,12 +49,12 @@ { "trKey": "qmake", "value": "qmake", - "condition": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('qmakeprojectmanager')}" }, { "trKey": "cmake", "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" + "condition": "%{JS: isPluginRunning('cmakeprojectmanager')}" } ] } diff --git a/src/plugins/squish/wizard/suite/wizard.json b/src/plugins/squish/wizard/suite/wizard.json index 44ef21bde24..3e17a50675f 100644 --- a/src/plugins/squish/wizard/suite/wizard.json +++ b/src/plugins/squish/wizard/suite/wizard.json @@ -7,7 +7,7 @@ "trDisplayName": "Squish Test Suite", "trDisplayCategory": "Squish", "iconText": "STS", - "enabled": "%{JS: value('Plugins').indexOf('Squish') >= 0}", + "enabled": "%{JS: isPluginRunning('squish')}", "options": [ From a59fdbc999aebf7f39b0688d83e0967f9f8fb595 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 28 Oct 2024 13:37:33 +0100 Subject: [PATCH 029/989] ProjectExplorer: Move qml debug command line construction here From libs/qmldebug. While conceptually related to qml debugging it used a #include projectexplorer_constants.h which prevented it from being implemented out-of-line which then is annoying when debugging. Having it here does not make PE dependent on QmlDebug includes and is less evil in my opinion. Change-Id: Iebf0f2adc51db6a8e2c5ccbc6efa4d6f82bfe23d Reviewed-by: Christian Kandeler --- src/libs/qmldebug/CMakeLists.txt | 1 - src/libs/qmldebug/qmldebug.qbs | 1 - .../android/androidqmltoolingsupport.cpp | 5 ++- src/plugins/android/androidrunner.cpp | 1 + src/plugins/android/androidrunner.h | 1 - src/plugins/android/androidrunnerworker.cpp | 19 ++++---- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 17 ++++--- src/plugins/debugger/debuggerruncontrol.cpp | 19 ++++---- src/plugins/ios/iosrunner.cpp | 20 ++++----- src/plugins/projectexplorer/CMakeLists.txt | 1 + .../projectexplorer/projectexplorer.qbs | 1 + .../qmldebugcommandlinearguments.cpp} | 44 +++++++------------ .../qmldebugcommandlinearguments.h | 44 +++++++++++++++++++ .../qmlpreview/qmlpreviewruncontrol.cpp | 4 +- .../qmlprofiler/qmlprofilerruncontrol.cpp | 5 +-- src/plugins/qnx/qnxanalyzesupport.cpp | 6 +-- src/plugins/qnx/qnxdebugsupport.cpp | 6 +-- .../appmanagerruncontrol.cpp | 15 +++---- .../remotelinux/remotelinuxdebugsupport.cpp | 9 ++-- 19 files changed, 122 insertions(+), 97 deletions(-) rename src/{libs/qmldebug/qmldebugcommandlinearguments.h => plugins/projectexplorer/qmldebugcommandlinearguments.cpp} (62%) create mode 100644 src/plugins/projectexplorer/qmldebugcommandlinearguments.h diff --git a/src/libs/qmldebug/CMakeLists.txt b/src/libs/qmldebug/CMakeLists.txt index 02cb5cfa48a..2c9ec678031 100644 --- a/src/libs/qmldebug/CMakeLists.txt +++ b/src/libs/qmldebug/CMakeLists.txt @@ -7,7 +7,6 @@ add_qtc_library(QmlDebug qmldebug_global.h qmldebugtr.h qmldebugclient.cpp qmldebugclient.h - qmldebugcommandlinearguments.h qmldebugconnection.cpp qmldebugconnection.h qmldebugconnectionmanager.cpp qmldebugconnectionmanager.h qmldebugconstants.h diff --git a/src/libs/qmldebug/qmldebug.qbs b/src/libs/qmldebug/qmldebug.qbs index 387f22b0aa0..6167d2bcd0c 100644 --- a/src/libs/qmldebug/qmldebug.qbs +++ b/src/libs/qmldebug/qmldebug.qbs @@ -17,7 +17,6 @@ QtcLibrary { "qmldebugtr.h", "qmldebugclient.cpp", "qmldebugclient.h", - "qmldebugcommandlinearguments.h", "qmldebugconnection.cpp", "qmldebugconnection.h", "qmldebugconnectionmanager.cpp", diff --git a/src/plugins/android/androidqmltoolingsupport.cpp b/src/plugins/android/androidqmltoolingsupport.cpp index 063ec837b18..e7e6837754a 100644 --- a/src/plugins/android/androidqmltoolingsupport.cpp +++ b/src/plugins/android/androidqmltoolingsupport.cpp @@ -6,6 +6,9 @@ #include "androidconstants.h" #include "androidrunner.h" +#include +#include + using namespace ProjectExplorer; namespace Android::Internal { @@ -20,7 +23,7 @@ public: auto runner = new AndroidRunner(runControl); addStartDependency(runner); - auto worker = runControl->createWorker(QmlDebug::runnerIdForRunMode(runControl->runMode())); + auto worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); worker->addStartDependency(this); connect(runner, &AndroidRunner::qmlServerReady, this, [this, worker](const QUrl &server) { diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index e0dc9446d25..183060efb75 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -12,6 +12,7 @@ #include "androidtr.h" #include +#include #include #include diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 748b3879d00..cd4bf83934c 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -7,7 +7,6 @@ #include -#include #include #include diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index c5e7ece5872..18e51317536 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -13,11 +13,10 @@ #include #include #include +#include #include #include -#include - #include #include @@ -162,7 +161,7 @@ public: qint64 m_processUser = -1; bool m_useCppDebugger = false; bool m_useLldb = false; - QmlDebug::QmlDebugServicesPreset m_qmlDebugServices; + QmlDebugServicesPreset m_qmlDebugServices; QUrl m_qmlServer; QString m_extraAppParams; Utils::Environment m_extraEnvVars; @@ -180,15 +179,15 @@ static void setupStorage(RunnerStorage *storage, RunnerInterface *glue) const bool debuggingMode = runMode == ProjectExplorer::Constants::DEBUG_RUN_MODE; storage->m_useCppDebugger = debuggingMode && aspect->useCppDebugger; if (debuggingMode && aspect->useQmlDebugger) - storage->m_qmlDebugServices = QmlDebug::QmlDebuggerServices; + storage->m_qmlDebugServices = QmlDebuggerServices; else if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) - storage->m_qmlDebugServices = QmlDebug::QmlProfilerServices; + storage->m_qmlDebugServices = QmlProfilerServices; else if (runMode == ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE) - storage->m_qmlDebugServices = QmlDebug::QmlPreviewServices; + storage->m_qmlDebugServices = QmlPreviewServices; else - storage->m_qmlDebugServices = QmlDebug::NoQmlDebugServices; + storage->m_qmlDebugServices = NoQmlDebugServices; - if (storage->m_qmlDebugServices != QmlDebug::NoQmlDebugServices) { + if (storage->m_qmlDebugServices != NoQmlDebugServices) { qCDebug(androidRunWorkerLog) << "QML debugging enabled"; QTcpServer server; const bool isListening = server.listen(QHostAddress::LocalHost); @@ -509,7 +508,7 @@ static ExecutableItem preStartRecipe(const Storage &storage) }; const auto isQmlDebug = [storage] { - return storage->m_qmlDebugServices != QmlDebug::NoQmlDebugServices; + return storage->m_qmlDebugServices != NoQmlDebugServices; }; const auto onTaskTreeSetup = [storage](TaskTree &taskTree) { const QString port = "tcp:" + QString::number(storage->m_qmlServer.port()); @@ -517,7 +516,7 @@ static ExecutableItem preStartRecipe(const Storage &storage) }; const auto onQmlDebugSync = [storage, argsStorage] { const QString qmljsdebugger = QString("port:%1,block,services:%2") - .arg(storage->m_qmlServer.port()).arg(QmlDebug::qmlDebugServices(storage->m_qmlDebugServices)); + .arg(storage->m_qmlServer.port()).arg(qmlDebugServices(storage->m_qmlDebugServices)); if (storage->m_useAppParamsForQmlDebugger) { if (!storage->m_extraAppParams.isEmpty()) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index f00f72fb424..284a83d4de5 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -9,10 +9,9 @@ #include #include +#include #include -#include - #include #include @@ -30,7 +29,7 @@ namespace Qdb::Internal { class QdbDeviceInferiorRunner : public RunWorker { public: - QdbDeviceInferiorRunner(RunControl *runControl, QmlDebug::QmlDebugServicesPreset qmlServices) + QdbDeviceInferiorRunner(RunControl *runControl, QmlDebugServicesPreset qmlServices) : RunWorker(runControl), m_qmlServices(qmlServices) { @@ -62,7 +61,7 @@ public: if (usesQmlChannel()) { cmd.addArg("--debug-qml"); cmd.addArg("--qml-debug-services"); - cmd.addArg(QmlDebug::qmlDebugServices(m_qmlServices)); + cmd.addArg(qmlDebugServices(m_qmlServices)); lowerPort = upperPort = qmlChannel().port(); } if (usesDebugChannel() && usesQmlChannel()) { @@ -98,7 +97,7 @@ private: friend class QdbDeviceQmlToolingSupport; friend class QdbDevicePerfProfilerSupport; - QmlDebug::QmlDebugServicesPreset m_qmlServices; + QmlDebugServicesPreset m_qmlServices; Process m_launcher; }; @@ -144,7 +143,7 @@ QdbDeviceDebugSupport::QdbDeviceDebugSupport(RunControl *runControl) if (isQmlDebugging()) runControl->requestQmlChannel(); - auto debuggee = new QdbDeviceInferiorRunner(runControl, QmlDebug::QmlDebuggerServices); + auto debuggee = new QdbDeviceInferiorRunner(runControl, QmlDebuggerServices); addStartDependency(debuggee); debuggee->addStopDependency(this); @@ -186,12 +185,12 @@ QdbDeviceQmlToolingSupport::QdbDeviceQmlToolingSupport(RunControl *runControl) setId("QdbDeviceQmlToolingSupport"); runControl->requestQmlChannel(); - QmlDebug::QmlDebugServicesPreset services = QmlDebug::servicesForRunMode(runControl->runMode()); + QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); auto runner = new QdbDeviceInferiorRunner(runControl, services); addStartDependency(runner); addStopDependency(runner); - auto worker = runControl->createWorker(QmlDebug::runnerIdForRunMode(runControl->runMode())); + auto worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); worker->addStartDependency(this); addStopDependency(worker); } @@ -210,7 +209,7 @@ QdbDevicePerfProfilerSupport::QdbDevicePerfProfilerSupport(RunControl *runContro setId("QdbDevicePerfProfilerSupport"); runControl->requestPerfChannel(); - auto profilee = new QdbDeviceInferiorRunner(runControl, QmlDebug::NoQmlDebugServices); + auto profilee = new QdbDeviceInferiorRunner(runControl, NoQmlDebugServices); addStartDependency(profilee); addStopDependency(profilee); } diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 04d282015d6..a1f15429201 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -49,8 +50,6 @@ #include #include -#include - #include #include @@ -459,7 +458,7 @@ void DebuggerRunTool::continueAfterTerminalStart() QString mode = QString("port:%1").arg(qmlServerPort); CommandLine cmd{m_runParameters.inferior.command.executable()}; - cmd.addArg(qmlDebugCommandLineArguments(QmlDebug::QmlDebuggerServices, mode, true)); + cmd.addArg(qmlDebugCommandLineArguments(QmlDebuggerServices, mode, true)); cmd.addArgs(m_runParameters.inferior.command.arguments(), CommandLine::Raw); m_runParameters.inferior.command = cmd; @@ -799,20 +798,20 @@ bool DebuggerRunTool::fixupParameters() } if (rp.isQmlDebugging) { - QmlDebug::QmlDebugServicesPreset service; + QmlDebugServicesPreset service; if (rp.isCppDebugging()) { if (rp.nativeMixedEnabled) { - service = QmlDebug::QmlNativeDebuggerServices; + service = QmlNativeDebuggerServices; } else { - service = QmlDebug::QmlDebuggerServices; + service = QmlDebuggerServices; } } else { - service = QmlDebug::QmlDebuggerServices; + service = QmlDebuggerServices; } if (rp.startMode != AttachToLocalProcess && rp.startMode != AttachToCrashedProcess) { QString qmlarg = rp.isCppDebugging() && rp.nativeMixedEnabled - ? QmlDebug::qmlDebugNativeArguments(service, false) - : QmlDebug::qmlDebugTcpArguments(service, rp.qmlServer); + ? qmlDebugNativeArguments(service, false) + : qmlDebugTcpArguments(service, rp.qmlServer); rp.inferior.command.addArg(qmlarg); } } @@ -1056,7 +1055,7 @@ void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup() if (usesQmlChannel() && !usesDebugChannel()) { // FIXME: Case should not happen? cmd.setExecutable(commandLine.executable()); - cmd.addArg(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices, qmlChannel())); + cmd.addArg(qmlDebugTcpArguments(QmlDebuggerServices, qmlChannel())); cmd.addArgs(commandLine.arguments(), CommandLine::Raw); } else { cmd.setExecutable(device()->debugServerPath()); diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index a3396892ac0..3b6ab2ef2e4 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -18,12 +18,12 @@ #include #include +#include #include #include #include #include -#include #include #include @@ -399,7 +399,7 @@ public: ~IosRunner() override; void setCppDebugging(bool cppDebug); - void setQmlDebugging(QmlDebug::QmlDebugServicesPreset qmlDebugServices); + void setQmlDebugging(QmlDebugServicesPreset qmlDebugServices); void start() override; void stop() final; @@ -431,7 +431,7 @@ private: IDeviceConstPtr m_device; IosDeviceType m_deviceType; bool m_cppDebug = false; - QmlDebug::QmlDebugServicesPreset m_qmlDebugServices = QmlDebug::NoQmlDebugServices; + QmlDebugServicesPreset m_qmlDebugServices = NoQmlDebugServices; bool m_cleanExit = false; Port m_qmlServerPort; @@ -461,7 +461,7 @@ void IosRunner::setCppDebugging(bool cppDebug) m_cppDebug = cppDebug; } -void IosRunner::setQmlDebugging(QmlDebug::QmlDebugServicesPreset qmlDebugServices) +void IosRunner::setQmlDebugging(QmlDebugServicesPreset qmlDebugServices) { m_qmlDebugServices = qmlDebugServices; } @@ -493,7 +493,7 @@ bool IosRunner::cppDebug() const bool IosRunner::qmlDebug() const { - return m_qmlDebugServices != QmlDebug::NoQmlDebugServices; + return m_qmlDebugServices != NoQmlDebugServices; } void IosRunner::start() @@ -515,7 +515,7 @@ void IosRunner::start() reportFailure(); return; } - if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) + if (m_qmlDebugServices != NoQmlDebugServices) m_qmlServerPort = iosDevice->nextPort(); } else { IosSimulator::ConstPtr sim = std::dynamic_pointer_cast(m_device); @@ -523,7 +523,7 @@ void IosRunner::start() reportFailure(); return; } - if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) + if (m_qmlDebugServices != NoQmlDebugServices) m_qmlServerPort = sim->nextPort(); } @@ -546,7 +546,7 @@ void IosRunner::start() if (m_qmlServerPort.isValid()) { QUrl qmlServer; qmlServer.setPort(m_qmlServerPort.number()); - args.append(QmlDebug::qmlDebugTcpArguments(m_qmlDebugServices, qmlServer)); + args.append(qmlDebugTcpArguments(m_qmlDebugServices, qmlServer)); } m_toolHandler->requestRunApp(bundlePath(), args, runType(), deviceId()); @@ -749,7 +749,7 @@ IosQmlProfilerSupport::IosQmlProfilerSupport(RunControl *runControl) setId("IosQmlProfilerSupport"); m_runner = new IosRunner(runControl); - m_runner->setQmlDebugging(QmlDebug::QmlProfilerServices); + m_runner->setQmlDebugging(QmlProfilerServices); addStartDependency(m_runner); m_profiler = runControl->createWorker(ProjectExplorer::Constants::QML_PROFILER_RUNNER); @@ -798,7 +798,7 @@ IosDebugSupport::IosDebugSupport(RunControl *runControl) m_runner = new IosRunner(runControl); m_runner->setCppDebugging(isCppDebugging()); - m_runner->setQmlDebugging(isQmlDebugging() ? QmlDebug::QmlDebuggerServices : QmlDebug::NoQmlDebugServices); + m_runner->setQmlDebugging(isQmlDebugging() ? QmlDebuggerServices : NoQmlDebugServices); addStartDependency(m_runner); } diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index 04473e85890..3998ceb2c06 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -151,6 +151,7 @@ add_qtc_plugin(ProjectExplorer projectwelcomepage.cpp projectwelcomepage.h projectwindow.cpp projectwindow.h projectwizardpage.cpp projectwizardpage.h + qmldebugcommandlinearguments.cpp qmldebugcommandlinearguments.h rawprojectpart.cpp rawprojectpart.h removetaskhandler.cpp removetaskhandler.h runconfiguration.cpp runconfiguration.h diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 8281cd8ce3f..82750105f23 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -124,6 +124,7 @@ QtcPlugin { "projectupdater.cpp", "projectupdater.h", "projectwindow.cpp", "projectwindow.h", "projectwizardpage.cpp", "projectwizardpage.h", + "qmldebugcommandlinearguments.cpp", "qmldebugcommandlinearguments.h", "rawprojectpart.cpp", "rawprojectpart.h", "removetaskhandler.cpp", "removetaskhandler.h", "runconfiguration.cpp", "runconfiguration.h", diff --git a/src/libs/qmldebug/qmldebugcommandlinearguments.h b/src/plugins/projectexplorer/qmldebugcommandlinearguments.cpp similarity index 62% rename from src/libs/qmldebug/qmldebugcommandlinearguments.h rename to src/plugins/projectexplorer/qmldebugcommandlinearguments.cpp index ea740f172c1..ae6c37615bc 100644 --- a/src/libs/qmldebug/qmldebugcommandlinearguments.h +++ b/src/plugins/projectexplorer/qmldebugcommandlinearguments.cpp @@ -1,26 +1,13 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#pragma once +#include "qmldebugcommandlinearguments.h" #include -#include +namespace ProjectExplorer { -#include -#include - -namespace QmlDebug { - -enum QmlDebugServicesPreset { - NoQmlDebugServices, - QmlDebuggerServices, - QmlProfilerServices, - QmlNativeDebuggerServices, - QmlPreviewServices -}; - -inline QString qmlDebugServices(QmlDebugServicesPreset preset) +QString qmlDebugServices(QmlDebugServicesPreset preset) { switch (preset) { case NoQmlDebugServices: @@ -39,8 +26,8 @@ inline QString qmlDebugServices(QmlDebugServicesPreset preset) } } -inline QString qmlDebugCommandLineArguments(QmlDebugServicesPreset services, - const QString &connectionMode, bool block) +QString qmlDebugCommandLineArguments(QmlDebugServicesPreset services, + const QString &connectionMode, bool block) { if (services == NoQmlDebugServices) return QString(); @@ -49,25 +36,24 @@ inline QString qmlDebugCommandLineArguments(QmlDebugServicesPreset services, .arg(QLatin1String(block ? ",block" : "")).arg(qmlDebugServices(services)); } -inline QString qmlDebugTcpArguments(QmlDebugServicesPreset services, - const QUrl &server, bool block = true) +QString qmlDebugTcpArguments(QmlDebugServicesPreset services, const QUrl &server, bool block) { // TODO: Also generate host: if applicable. return qmlDebugCommandLineArguments(services, QString("port:%1").arg(server.port()), block); } -inline QString qmlDebugNativeArguments(QmlDebugServicesPreset services, bool block = true) +QString qmlDebugNativeArguments(QmlDebugServicesPreset services, bool block) { return qmlDebugCommandLineArguments(services, QLatin1String("native"), block); } -inline QString qmlDebugLocalArguments(QmlDebugServicesPreset services, const QString &socket, - bool block = true) +QString qmlDebugLocalArguments(QmlDebugServicesPreset services, const QString &socket, + bool block) { return qmlDebugCommandLineArguments(services, QLatin1String("file:") + socket, block); } -inline Utils::Id runnerIdForRunMode(Utils::Id runMode) +Utils::Id runnerIdForRunMode(Utils::Id runMode) { if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) return ProjectExplorer::Constants::QML_PROFILER_RUNNER; @@ -76,15 +62,15 @@ inline Utils::Id runnerIdForRunMode(Utils::Id runMode) return {}; } -inline QmlDebugServicesPreset servicesForRunMode(Utils::Id runMode) +QmlDebugServicesPreset servicesForRunMode(Utils::Id runMode) { if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) - return QmlDebug::QmlProfilerServices; + return QmlProfilerServices; if (runMode == ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE) - return QmlDebug::QmlPreviewServices; + return QmlPreviewServices; if (runMode == ProjectExplorer::Constants::DEBUG_RUN_MODE) - return QmlDebug::QmlDebuggerServices; + return QmlDebuggerServices; return {}; } -} // namespace QmlDebug +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/qmldebugcommandlinearguments.h b/src/plugins/projectexplorer/qmldebugcommandlinearguments.h new file mode 100644 index 00000000000..8a793e3ce47 --- /dev/null +++ b/src/plugins/projectexplorer/qmldebugcommandlinearguments.h @@ -0,0 +1,44 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "projectexplorer_export.h" + +#include + +#include +#include + +namespace ProjectExplorer { + +enum QmlDebugServicesPreset { + NoQmlDebugServices, + QmlDebuggerServices, + QmlProfilerServices, + QmlNativeDebuggerServices, + QmlPreviewServices +}; + +PROJECTEXPLORER_EXPORT QString qmlDebugServices(QmlDebugServicesPreset preset); + +PROJECTEXPLORER_EXPORT QString qmlDebugCommandLineArguments(QmlDebugServicesPreset services, + const QString &connectionMode, + bool block); + +PROJECTEXPLORER_EXPORT QString qmlDebugTcpArguments(QmlDebugServicesPreset services, + const QUrl &server, + bool block = true); + +PROJECTEXPLORER_EXPORT QString qmlDebugNativeArguments(QmlDebugServicesPreset services, + bool block = true); + +PROJECTEXPLORER_EXPORT QString qmlDebugLocalArguments(QmlDebugServicesPreset services, + const QString &socket, + bool block = true); + +PROJECTEXPLORER_EXPORT Utils::Id runnerIdForRunMode(Utils::Id runMode); + +PROJECTEXPLORER_EXPORT QmlDebugServicesPreset servicesForRunMode(Utils::Id runMode); + +} // namespace ProjectExplorer diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp index 83598125e74..d0baa3173ee 100644 --- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp +++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp @@ -10,9 +10,9 @@ #include #include #include +#include #include -#include #include #include #include @@ -225,7 +225,7 @@ public: } } - cmd.addArg(QmlDebug::qmlDebugLocalArguments(QmlDebug::QmlPreviewServices, serverUrl.path())); + cmd.addArg(qmlDebugLocalArguments(QmlPreviewServices, serverUrl.path())); setCommandLine(cmd); forceRunOnHost(); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index 159a1f68582..b3eccb6136f 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -18,8 +19,6 @@ #include #include -#include - #include #include #include @@ -213,7 +212,7 @@ LocalQmlProfilerSupport::LocalQmlProfilerSupport(RunControl *runControl, const Q QTC_CHECK(false); QString arguments = Utils::ProcessArgs::quoteArg( - QmlDebug::qmlDebugCommandLineArguments(QmlDebug::QmlProfilerServices, code, true)); + qmlDebugCommandLineArguments(QmlProfilerServices, code, true)); Utils::CommandLine cmd = commandLine(); const QString oldArgs = cmd.arguments(); diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index 19c85d9eefa..f0aa20d88d6 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -8,11 +8,11 @@ #include "slog2inforunner.h" #include +#include +#include #include -#include - using namespace ProjectExplorer; using namespace Utils; @@ -38,7 +38,7 @@ public: setStartModifier([this] { CommandLine cmd = commandLine(); - cmd.addArg(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, qmlChannel())); + cmd.addArg(qmlDebugTcpArguments(QmlProfilerServices, qmlChannel())); setCommandLine(cmd); }); } diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index f83ab4a8327..19109e62f20 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -22,12 +22,11 @@ #include #include #include +#include #include #include #include -#include - #include #include @@ -90,8 +89,7 @@ public: arguments.append(QString::number(pdebugPort)); } if (usesQmlChannel()) { - arguments.append(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices, - qmlChannel())); + arguments.append(qmlDebugTcpArguments(QmlDebuggerServices, qmlChannel())); } cmd.setArguments(ProcessArgs::joinArgs(arguments)); setCommandLine(cmd); diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 2553f9e99f1..31c125748fb 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -24,12 +24,11 @@ #include #include #include +#include #include #include #include -#include - #include #include @@ -100,7 +99,7 @@ class AppManInferiorRunner : public SimpleTargetRunner public: AppManInferiorRunner(RunControl *runControl, bool usePerf, bool useGdbServer, bool useQmlServer, - QmlDebug::QmlDebugServicesPreset qmlServices) + QmlDebugServicesPreset qmlServices) : SimpleTargetRunner(runControl), m_qmlServices(qmlServices) { @@ -177,7 +176,7 @@ public: } private: - QmlDebug::QmlDebugServicesPreset m_qmlServices; + QmlDebugServicesPreset m_qmlServices; }; @@ -196,7 +195,7 @@ public: setId("ApplicationManagerPlugin.Debug.Support"); m_debuggee = new AppManInferiorRunner(runControl, false, isCppDebugging(), isQmlDebugging(), - QmlDebug::QmlDebuggerServices); + QmlDebuggerServices); addStartDependency(m_debuggee); addStopDependency(m_debuggee); @@ -268,12 +267,12 @@ public: { setId("AppManagerQmlToolingSupport"); - QmlDebug::QmlDebugServicesPreset services = QmlDebug::servicesForRunMode(runControl->runMode()); + QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); m_runner = new AppManInferiorRunner(runControl, false, false, true, services); addStartDependency(m_runner); addStopDependency(m_runner); - m_worker = runControl->createWorker(QmlDebug::runnerIdForRunMode(runControl->runMode())); + m_worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); m_worker->addStartDependency(this); addStopDependency(m_worker); @@ -303,7 +302,7 @@ public: setId("AppManagerPerfProfilerSupport"); m_profilee = new AppManInferiorRunner(runControl, true, false, false, - QmlDebug::NoQmlDebugServices); + NoQmlDebugServices); addStartDependency(m_profilee); addStopDependency(m_profilee); } diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp index 502d0d0165f..b9552f09953 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp @@ -7,12 +7,11 @@ #include #include +#include #include #include -#include - using namespace Debugger; using namespace ProjectExplorer; using namespace Utils; @@ -52,15 +51,15 @@ public: runControl->requestQmlChannel(); - auto runworker = runControl->createWorker(QmlDebug::runnerIdForRunMode(runControl->runMode())); + auto runworker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); runworker->addStartDependency(this); addStopDependency(runworker); setStartModifier([this, runControl] { - QmlDebug::QmlDebugServicesPreset services = QmlDebug::servicesForRunMode(runControl->runMode()); + QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); CommandLine cmd = commandLine(); - cmd.addArg(QmlDebug::qmlDebugTcpArguments(services, qmlChannel())); + cmd.addArg(qmlDebugTcpArguments(services, qmlChannel())); setCommandLine(cmd); }); } From b402edf22eac67f955d85f9915664726b3791b90 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 30 Oct 2024 15:18:45 +0100 Subject: [PATCH 030/989] ProjectExplorer: Fix kit visibility in target setup page Both kit validity and filter text have to be taken into account always. Amends c8adf29a78a759a9f6fce0de7e43247781ffa4fc. Change-Id: Idd3dc3a8c3d9279085c413d1fd908022705de41c Reviewed-by: Christian Stenger --- .../projectexplorer/targetsetuppage.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index c0eb9b82bad..42414d69a2b 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -166,7 +166,7 @@ public: this, toggleTargetWidgetVisibility); QObject::connect(kitFilterLineEdit, &FancyLineEdit::filterChanged, - this, &TargetSetupPagePrivate::kitFilterChanged); + this, toggleTargetWidgetVisibility); for (IPotentialKit *pk : std::as_const(g_potentialKits)) { if (pk->isEnabled()) @@ -227,7 +227,6 @@ public: } void setUseScrollArea(bool b); - void kitFilterChanged(const QString &filterText); TargetSetupPage *q; QWidget *m_centralWidget; @@ -572,14 +571,6 @@ void TargetSetupPagePrivate::kitSelectionChanged() allKitsCheckBox->setCheckState(Qt::Unchecked); } -void TargetSetupPagePrivate::kitFilterChanged(const QString &filterText) -{ - for (TargetSetupWidget *widget : m_widgets) { - Kit *kit = widget->kit(); - widget->setVisible(filterText.isEmpty() || kit->displayName().contains(filterText, Qt::CaseInsensitive)); - } -} - void TargetSetupPagePrivate::doInitializePage() { reset(); @@ -680,7 +671,13 @@ void TargetSetupPagePrivate::connectWidget(TargetSetupWidget *w) void TargetSetupPagePrivate::toggleVisibility(TargetSetupWidget *w) { - const bool shouldBeVisible = w->isValid() || !hideUnsuitableKitsCheckBox->isChecked(); + const bool shouldBeVisible = [w, this] { + if (!w->isValid() && hideUnsuitableKitsCheckBox->isChecked()) + return false; + const QString filterText = kitFilterLineEdit->text(); + return filterText.isEmpty() + || w->kit()->displayName().contains(filterText, Qt::CaseInsensitive); + }(); if (shouldBeVisible) { if (!w->isVisible()) // Prevent flickering. w->show(); From 7be2a112593ac7f85c90dce8af4dc07c8a208ebc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 22 Oct 2024 10:49:36 +0200 Subject: [PATCH 031/989] Various plugins: Reuse QScopedPointerDeleteLater Change-Id: I1fac311192c1cc8dd79e2a05802c132522d07483 Reviewed-by: hjk --- .../projectexplorer/jsonwizard/jsonwizard_test.cpp | 12 ++++-------- src/plugins/qmlprofiler/qmlprofilertraceclient.cpp | 12 ++++++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp index d8e9a0c290e..100be4c6cf0 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp @@ -7,16 +7,14 @@ #include -#include +#include +#include #include #include #include -#include #include -#include #include - -#include +#include using namespace Utils; @@ -80,9 +78,7 @@ QComboBox *findComboBox(Wizard *wizard, const QString &objectName) return wizard->findChild(objectName + "ComboBox"); }; -struct FactoryDeleter { void operator()(JsonWizardFactory *f) { f->deleteLater(); } }; - -using FactoryPtr = std::unique_ptr; +using FactoryPtr = std::unique_ptr; void ProjectExplorerTest::testJsonWizardsEmptyWizard() { diff --git a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp index ecd8f175c22..c73c73f079f 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp @@ -5,12 +5,14 @@ #include "qmltypedevent.h" #include "qmlprofilermodelmanager.h" -#include #include +#include #include + #include #include +#include namespace QmlProfiler { @@ -34,8 +36,6 @@ inline bool operator!=(const QmlEventType &type1, const QmlEventType &type2) return !(type1 == type2); } -struct ObjectDeleteLater { void operator()(QObject *o) { o->deleteLater(); } }; - class QmlProfilerTraceClientPrivate { public: QmlProfilerTraceClientPrivate(QmlProfilerTraceClient *q, @@ -63,13 +63,13 @@ public: QmlProfilerTraceClient *q; QmlProfilerModelManager *modelManager; - // Use deleteLater here. The connection will call stateChanged() on all clients that are + // Use QScopedPointerDeleteLater here. The connection will call stateChanged() on all clients that are // alive when it gets disconnected. One way to notice a disconnection is failing to send the // plugin advertisement when a client unregisters. If one of the other clients is // half-destructed at that point, we get invalid memory accesses. Therefore, we cannot nest the // dtor calls. - std::unique_ptr engineControl; - std::unique_ptr messageClient; + std::unique_ptr engineControl; + std::unique_ptr messageClient; qint64 maximumTime; bool recording; quint64 requestedFeatures; From 83f00a63a36b7127ec142bf2cd18200feb8608c1 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 30 Oct 2024 15:15:06 +0100 Subject: [PATCH 032/989] Utils: Add an option to BoolAspect to show tooltip as permanent label Task-number: QTCREATORBUG-31929 Change-Id: Ifbd563ed933210f0267ac1c901e39d09d47ec97c Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 14 ++++++++++++++ src/libs/utils/aspects.h | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 7dc9bfb4b02..1b3bf074d1c 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -17,6 +17,7 @@ #include "qtcassert.h" #include "qtcolorbutton.h" #include "qtcsettings.h" +#include "stylehelper.h" #include "utilsicons.h" #include "utilstr.h" #include "variablechooser.h" @@ -2094,6 +2095,19 @@ void BoolAspect::addToLayoutHelper(Layouting::Layout &parent, QAbstractButton *b case LabelPlacement::InExtraLabel: addLabeledItem(parent, button); break; + case LabelPlacement::ShowTip: { + parent.addItem(empty); + button->setText(labelText()); + auto ttLabel = new QLabel(toolTip()); + ttLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementLabelSmall)); + auto lt = new QVBoxLayout; + lt->setContentsMargins({}); + lt->setSpacing(StyleHelper::SpacingTokens::VGapXxs); + lt->addWidget(button); + lt->addWidget(ttLabel); + parent.addItem(lt); + break; + } } connect(button, &QAbstractButton::clicked, this, [button, this] { diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 3fa54a2827d..1e3fba25052 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -464,7 +464,7 @@ public: QAction *action() override; - enum class LabelPlacement { AtCheckBox, Compact, InExtraLabel }; + enum class LabelPlacement { AtCheckBox, Compact, InExtraLabel, ShowTip }; void setLabel(const QString &labelText, LabelPlacement labelPlacement = LabelPlacement::InExtraLabel); void setLabelPlacement(LabelPlacement labelPlacement); From 84cefcc7483ea79605bdfa0540b65d2a007275f2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 31 Oct 2024 10:41:23 +0100 Subject: [PATCH 033/989] Debugger: Fix a crash Ensure that editor and editor window aren't nullptr. Amends b04271108cfca914991a248d4fe84755efca6036 Fixes: QTCREATORBUG-31913 Change-Id: I3ed7e6d67cecea40a011b0ccaa6f1439375c04ab Reviewed-by: Eike Ziller --- src/plugins/debugger/debuggertooltipmanager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index f41528d2e37..946a45955f9 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -863,8 +863,10 @@ DebuggerToolTipManagerPrivate::DebuggerToolTipManagerPrivate(DebuggerEngine *eng DebuggerToolTipManagerPrivate::~DebuggerToolTipManagerPrivate() { - for (const auto &[editor, tooltips] : m_tooltips) - editor->window()->removeEventFilter(this); + for (const auto &[editor, tooltips] : m_tooltips) { + if (editor && editor->window()) + editor->window()->removeEventFilter(this); + } } void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested From a17303e0dcfced204bd3a381706d054a8873fba5 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 31 Oct 2024 14:23:36 +0100 Subject: [PATCH 034/989] CMake: Avoid magic delay to next event handling The goal is to wait for devices to be restored, so wait for that explicitly. Change-Id: I942c4ae5babd13509c0dfe8a0cc10ec0b0ca1536 Reviewed-by: Marcus Tillmanns --- src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp index f03ae6bebdc..179a9962cce 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -107,7 +108,9 @@ class CMakeProjectPlugin final : public ExtensionSystem::IPlugin void extensionsInitialized() final { // Delay the restoration to allow the devices to load first. - QTimer::singleShot(0, this, [] { CMakeToolManager::restoreCMakeTools(); }); + connect(DeviceManager::instance(), &DeviceManager::devicesLoaded, this, [] { + CMakeToolManager::restoreCMakeTools(); + }); setupOnlineHelpManager(); } From 9317282c0048e983e2a2c16969d0389f5277200f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 31 Oct 2024 13:58:11 +0100 Subject: [PATCH 035/989] ProjectExplorer: Use consistent member naming in TargetSetupPagePrivate It was very confusing that some of them had the "m_" prefix and others did not. Use the prefix-less version for all of them, as we usually do with public members of private classes. Change-Id: I3ba3dd092e7c4b40270444e02f33474f303201aa Reviewed-by: hjk --- .../projectexplorer/targetsetuppage.cpp | 198 +++++++++--------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 36560a820a3..9f4b6f4dddf 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -62,12 +62,12 @@ public: explicit TargetSetupPagePrivate(TargetSetupPage *parent) : q(parent) { - m_tasksGenerator = defaultTasksGenerator({}); + tasksGenerator = defaultTasksGenerator({}); - m_importWidget = new ImportWidget(q); - m_importWidget->setVisible(false); + importWidget = new ImportWidget(q); + importWidget->setVisible(false); - m_spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); + spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); auto setupTargetPage = new QWidget(q); @@ -95,12 +95,12 @@ public: hideUnsuitableKitsCheckBox = new QCheckBox(Tr::tr("Hide unsuitable kits"), setupTargetPage); - m_centralWidget = new QWidget(setupTargetPage); + centralWidget = new QWidget(setupTargetPage); QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Fixed); policy.setHorizontalStretch(0); policy.setVerticalStretch(0); - policy.setHeightForWidth(m_centralWidget->sizePolicy().hasHeightForWidth()); - m_centralWidget->setSizePolicy(policy); + policy.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth()); + centralWidget->setSizePolicy(policy); scrollAreaWidget = new QWidget(setupTargetPage); scrollArea = new QScrollArea(scrollAreaWidget); @@ -125,7 +125,7 @@ public: verticalLayout_2->addLayout(horizontalLayout); verticalLayout_2->addWidget(hideUnsuitableKitsCheckBox); verticalLayout_2->addWidget(noValidKitLabel); - verticalLayout_2->addWidget(m_centralWidget); + verticalLayout_2->addWidget(centralWidget); verticalLayout_2->addWidget(scrollAreaWidget); auto verticalLayout_3 = new QVBoxLayout(q); @@ -136,8 +136,8 @@ public: scrollArea->setWidget(centralWidget); centralWidget->setLayout(new QVBoxLayout); - m_centralWidget->setLayout(new QVBoxLayout); - m_centralWidget->layout()->setContentsMargins(0, 0, 0, 0); + this->centralWidget->setLayout(new QVBoxLayout); + this->centralWidget->layout()->setContentsMargins(0, 0, 0, 0); QObject::connect(noValidKitLabel, &QLabel::linkActivated, q, &TargetSetupPage::openOptions); @@ -146,7 +146,7 @@ public: q, &TargetSetupPage::changeAllKitsSelections); const auto toggleTargetWidgetVisibility = [this] { - for (TargetSetupWidget *widget : m_widgets) + for (TargetSetupWidget *widget : widgets) toggleVisibility(widget); }; QObject::connect(hideUnsuitableKitsCheckBox, &QCheckBox::toggled, @@ -163,7 +163,7 @@ public: connect(km, &KitManager::kitAdded, this, &TargetSetupPagePrivate::handleKitAddition); connect(km, &KitManager::kitRemoved, this, &TargetSetupPagePrivate::handleKitRemoval); connect(km, &KitManager::kitUpdated, this, &TargetSetupPagePrivate::handleKitUpdate); - connect(m_importWidget, &ImportWidget::importFrom, + connect(importWidget, &ImportWidget::importFrom, this, [this](const FilePath &dir) { import(dir); }); connect(KitManager::instance(), &KitManager::kitsChanged, this, &TargetSetupPagePrivate::updateVisibility); @@ -211,7 +211,7 @@ public: void setUseScrollArea(bool b); TargetSetupPage *q; - QWidget *m_centralWidget; + QWidget *centralWidget; QWidget *scrollAreaWidget; QScrollArea *scrollArea; QLabel *headerLabel; @@ -220,17 +220,17 @@ public: FancyLineEdit *kitFilterLineEdit; QCheckBox *hideUnsuitableKitsCheckBox; - TasksGenerator m_tasksGenerator; - QPointer m_importer; - QLayout *m_baseLayout = nullptr; - FilePath m_projectPath; - QString m_defaultShadowBuildLocation; - std::vector m_widgets; + TasksGenerator tasksGenerator; + QPointer importer; + QLayout *baseLayout = nullptr; + FilePath projectPath; + QString defaultShadowBuildLocation; + std::vector widgets; - Internal::ImportWidget *m_importWidget = nullptr; - QSpacerItem *m_spacer; + Internal::ImportWidget *importWidget = nullptr; + QSpacerItem *spacer; - bool m_widgetsWereSetUp = false; + bool widgetsWereSetUp = false; }; } // namespace Internal @@ -265,13 +265,13 @@ void TargetSetupPage::initializePage() void TargetSetupPage::setTasksGenerator(const TasksGenerator &tasksGenerator) { - d->m_tasksGenerator = defaultTasksGenerator(tasksGenerator); + d->tasksGenerator = defaultTasksGenerator(tasksGenerator); } QList TargetSetupPage::selectedKits() const { QList result; - for (TargetSetupWidget *w : d->m_widgets) { + for (TargetSetupWidget *w : d->widgets) { if (w->isKitSelected()) result.append(w->kit()->id()); } @@ -282,13 +282,13 @@ TargetSetupPage::~TargetSetupPage() { disconnect(); d->reset(); - delete d->m_spacer; + delete d->spacer; delete d; } bool TargetSetupPage::isComplete() const { - return anyOf(d->m_widgets, [](const TargetSetupWidget *w) { + return anyOf(d->widgets, [](const TargetSetupWidget *w) { return w->isKitSelected(); }); } @@ -298,21 +298,21 @@ void TargetSetupPagePrivate::setupWidgets(const QString &filterText) for (Kit *k : KitManager::sortedKits()) { if (!filterText.isEmpty() && !k->displayName().contains(filterText, Qt::CaseInsensitive)) continue; - if (m_importer && !m_importer->filter(k)) + if (importer && !importer->filter(k)) continue; - const auto widget = new TargetSetupWidget(k, m_projectPath); + const auto widget = new TargetSetupWidget(k, projectPath); updateWidget(widget); - m_widgets.push_back(widget); - m_baseLayout->addWidget(widget); + widgets.push_back(widget); + baseLayout->addWidget(widget); } addAdditionalWidgets(); // Setup import widget: - m_importWidget->setCurrentDirectory(Internal::importDirectory(m_projectPath)); + importWidget->setCurrentDirectory(Internal::importDirectory(projectPath)); kitSelectionChanged(); updateVisibility(); - for (TargetSetupWidget * const w : m_widgets) { + for (TargetSetupWidget * const w : widgets) { connectWidget(w); toggleVisibility(w); } @@ -321,12 +321,12 @@ void TargetSetupPagePrivate::setupWidgets(const QString &filterText) void TargetSetupPagePrivate::reset() { removeAdditionalWidgets(); - while (m_widgets.size() > 0) { - TargetSetupWidget *w = m_widgets.back(); + while (widgets.size() > 0) { + TargetSetupWidget *w = widgets.back(); Kit *k = w->kit(); - if (k && m_importer) - m_importer->removeProject(k); + if (k && importer) + importer->removeProject(k); removeWidget(w); } @@ -337,65 +337,65 @@ void TargetSetupPagePrivate::reset() TargetSetupWidget *TargetSetupPagePrivate::widget(const Id kitId, TargetSetupWidget *fallback) const { - return findOr(m_widgets, fallback, [kitId](const TargetSetupWidget *w) { + return findOr(widgets, fallback, [kitId](const TargetSetupWidget *w) { return w->kit() && w->kit()->id() == kitId; }); } void TargetSetupPage::setProjectPath(const FilePath &path) { - d->m_projectPath = path; - if (!d->m_projectPath.isEmpty()) { + d->projectPath = path; + if (!d->projectPath.isEmpty()) { QFileInfo fileInfo(QDir::cleanPath(path.toString())); QStringList subDirsList = fileInfo.absolutePath().split('/'); d->headerLabel->setText(Tr::tr("The following kits can be used for project %1:", "%1: Project name").arg(subDirsList.last())); } - d->headerLabel->setVisible(!d->m_projectPath.isEmpty()); + d->headerLabel->setVisible(!d->projectPath.isEmpty()); - if (d->m_widgetsWereSetUp) + if (d->widgetsWereSetUp) initializePage(); } void TargetSetupPage::setProjectImporter(ProjectImporter *importer) { - if (importer == d->m_importer) + if (importer == d->importer) return; - if (d->m_widgetsWereSetUp) + if (d->widgetsWereSetUp) d->reset(); // Reset before changing the importer! - if (d->m_importer) { - disconnect(d->m_importer, &ProjectImporter::cmakePresetsUpdated, + if (d->importer) { + disconnect(d->importer, &ProjectImporter::cmakePresetsUpdated, this, &TargetSetupPage::initializePage); } - d->m_importer = importer; - d->m_importWidget->setVisible(d->m_importer); + d->importer = importer; + d->importWidget->setVisible(d->importer); - if (d->m_importer) { + if (d->importer) { // FIXME: Needed for the refresh of CMake preset kits created by // CMakeProjectImporter - connect(d->m_importer, &ProjectImporter::cmakePresetsUpdated, + connect(d->importer, &ProjectImporter::cmakePresetsUpdated, this, &TargetSetupPage::initializePage); } - if (d->m_widgetsWereSetUp) + if (d->widgetsWereSetUp) initializePage(); } bool TargetSetupPage::importLineEditHasFocus() const { - return d->m_importWidget->ownsReturnKey(); + return d->importWidget->ownsReturnKey(); } void TargetSetupPagePrivate::setupImports() { - if (!m_importer || m_projectPath.isEmpty()) + if (!importer || projectPath.isEmpty()) return; - const FilePaths toImport = m_importer->importCandidates(); + const FilePaths toImport = importer->importCandidates(); for (const FilePath &path : toImport) import(path, true); } @@ -416,8 +416,8 @@ void TargetSetupPagePrivate::handleKitRemoval(Kit *k) if (isUpdating()) return; - if (m_importer) - m_importer->cleanupKit(k); + if (importer) + importer->cleanupKit(k); removeWidget(k); kitSelectionChanged(); @@ -429,12 +429,12 @@ void TargetSetupPagePrivate::handleKitUpdate(Kit *k) if (isUpdating()) return; - if (m_importer) - m_importer->makePersistent(k); + if (importer) + importer->makePersistent(k); const auto newWidgetList = sortedWidgetList(); - if (newWidgetList != m_widgets) { // Sorting has changed. - m_widgets = newWidgetList; + if (newWidgetList != widgets) { // Sorting has changed. + widgets = newWidgetList; reLayout(); } updateWidget(widget(k)); @@ -444,7 +444,7 @@ void TargetSetupPagePrivate::handleKitUpdate(Kit *k) void TargetSetupPagePrivate::selectAtLeastOneEnabledKit() { - if (anyOf(m_widgets, [](const TargetSetupWidget *w) { return w->isKitSelected(); })) { + if (anyOf(widgets, [](const TargetSetupWidget *w) { return w->isKitSelected(); })) { // Something is already selected, we are done. return; } @@ -454,30 +454,30 @@ void TargetSetupPagePrivate::selectAtLeastOneEnabledKit() const Kit *defaultKit = KitManager::defaultKit(); auto isPreferred = [this](const TargetSetupWidget *w) { - const Tasks tasks = m_tasksGenerator(w->kit()); + const Tasks tasks = tasksGenerator(w->kit()); return w->isValid() && tasks.isEmpty(); }; // Use default kit if that is preferred: - toCheckWidget = findOrDefault(m_widgets, [defaultKit, isPreferred](const TargetSetupWidget *w) { + toCheckWidget = findOrDefault(widgets, [defaultKit, isPreferred](const TargetSetupWidget *w) { return isPreferred(w) && w->kit() == defaultKit; }); if (!toCheckWidget) { // Use the first preferred widget: - toCheckWidget = findOrDefault(m_widgets, isPreferred); + toCheckWidget = findOrDefault(widgets, isPreferred); } if (!toCheckWidget) { // Use default kit if it is enabled: - toCheckWidget = findOrDefault(m_widgets, [defaultKit](const TargetSetupWidget *w) { + toCheckWidget = findOrDefault(widgets, [defaultKit](const TargetSetupWidget *w) { return w->isValid() && w->kit() == defaultKit; }); } if (!toCheckWidget) { // Use the first enabled widget: - toCheckWidget = findOrDefault(m_widgets, + toCheckWidget = findOrDefault(widgets, [](const TargetSetupWidget *w) { return w->isValid(); }); } @@ -491,8 +491,8 @@ void TargetSetupPagePrivate::selectAtLeastOneEnabledKit() void TargetSetupPagePrivate::updateVisibility() { // Always show the widgets, the import widget always makes sense to show. - scrollAreaWidget->setVisible(m_baseLayout == scrollArea->widget()->layout()); - m_centralWidget->setVisible(m_baseLayout == m_centralWidget->layout()); + scrollAreaWidget->setVisible(baseLayout == scrollArea->widget()->layout()); + centralWidget->setVisible(baseLayout == centralWidget->layout()); const bool hasUsableKits = KitManager::kit([this](const Kit *k) { return isUsable(k); }); noValidKitLabel->setVisible(!hasUsableKits); @@ -504,10 +504,10 @@ void TargetSetupPagePrivate::updateVisibility() void TargetSetupPagePrivate::reLayout() { removeAdditionalWidgets(); - for (TargetSetupWidget * const w : std::as_const(m_widgets)) - m_baseLayout->removeWidget(w); - for (TargetSetupWidget * const w : std::as_const(m_widgets)) - m_baseLayout->addWidget(w); + for (TargetSetupWidget * const w : std::as_const(widgets)) + baseLayout->removeWidget(w); + for (TargetSetupWidget * const w : std::as_const(widgets)) + baseLayout->addWidget(w); addAdditionalWidgets(); } @@ -524,7 +524,7 @@ bool TargetSetupPagePrivate::compareKits(const Kit *k1, const Kit *k2) std::vector TargetSetupPagePrivate::sortedWidgetList() const { - return sorted(m_widgets, [](const TargetSetupWidget *w1, const TargetSetupWidget *w2) { + return sorted(widgets, [](const TargetSetupWidget *w1, const TargetSetupWidget *w2) { return compareKits(w1->kit(), w2->kit()); }); } @@ -538,7 +538,7 @@ void TargetSetupPagePrivate::kitSelectionChanged() { int selected = 0; int deselected = 0; - for (const TargetSetupWidget *widget : m_widgets) { + for (const TargetSetupWidget *widget : widgets) { if (widget->isKitSelected()) ++selected; else @@ -573,7 +573,7 @@ void TargetSetupPage::changeAllKitsSelections() if (d->allKitsCheckBox->checkState() == Qt::PartiallyChecked) d->allKitsCheckBox->setCheckState(Qt::Checked); bool checked = d->allKitsCheckBox->isChecked(); - for (TargetSetupWidget *widget : d->m_widgets) { + for (TargetSetupWidget *widget : d->widgets) { if (!checked || widget->isValid()) widget->setKitSelected(checked); } @@ -582,15 +582,15 @@ void TargetSetupPage::changeAllKitsSelections() bool TargetSetupPagePrivate::isUpdating() const { - return m_importer && m_importer->isUpdating(); + return importer && importer->isUpdating(); } void TargetSetupPagePrivate::import(const FilePath &path, bool silent) { - if (!m_importer) + if (!importer) return; - for (const BuildInfo &info : m_importer->import(path, silent)) { + for (const BuildInfo &info : importer->import(path, silent)) { TargetSetupWidget *w = widget(info.kitId); if (!w) { Kit *k = KitManager::kit(info.kitId); @@ -615,26 +615,26 @@ void TargetSetupPagePrivate::removeWidget(TargetSetupWidget *w) return; w->deleteLater(); w->clearKit(); - m_widgets.erase(std::find(m_widgets.begin(), m_widgets.end(), w)); + widgets.erase(std::find(widgets.begin(), widgets.end(), w)); } TargetSetupWidget *TargetSetupPagePrivate::addWidget(Kit *k) { - const auto widget = new TargetSetupWidget(k, m_projectPath); + const auto widget = new TargetSetupWidget(k, projectPath); updateWidget(widget); connectWidget(widget); toggleVisibility(widget); // Insert widget, sorted. - const auto insertionPos = std::find_if(m_widgets.begin(), m_widgets.end(), + const auto insertionPos = std::find_if(widgets.begin(), widgets.end(), [k](const TargetSetupWidget *w) { return compareKits(k, w->kit()); }); - const bool addedToEnd = insertionPos == m_widgets.end(); - m_widgets.insert(insertionPos, widget); + const bool addedToEnd = insertionPos == widgets.end(); + widgets.insert(insertionPos, widget); if (addedToEnd) { removeAdditionalWidgets(); - m_baseLayout->addWidget(widget); + baseLayout->addWidget(widget); addAdditionalWidgets(); } else { reLayout(); @@ -671,43 +671,43 @@ void TargetSetupPagePrivate::toggleVisibility(TargetSetupWidget *w) void TargetSetupPagePrivate::addAdditionalWidgets() { - m_baseLayout->addWidget(m_importWidget); - m_baseLayout->addItem(m_spacer); + baseLayout->addWidget(importWidget); + baseLayout->addItem(spacer); } void TargetSetupPagePrivate::removeAdditionalWidgets(QLayout *layout) { - layout->removeWidget(m_importWidget); - layout->removeItem(m_spacer); + layout->removeWidget(importWidget); + layout->removeItem(spacer); } void TargetSetupPagePrivate::removeAdditionalWidgets() { - removeAdditionalWidgets(m_baseLayout); + removeAdditionalWidgets(baseLayout); } void TargetSetupPagePrivate::updateWidget(TargetSetupWidget *widget) { QTC_ASSERT(widget, return ); - widget->update(m_tasksGenerator); + widget->update(tasksGenerator); } bool TargetSetupPagePrivate::isUsable(const Kit *kit) const { - return !containsType(m_tasksGenerator(kit), Task::Error); + return !containsType(tasksGenerator(kit), Task::Error); } bool TargetSetupPage::setupProject(Project *project) { QList toSetUp; - for (TargetSetupWidget *widget : d->m_widgets) { + for (TargetSetupWidget *widget : d->widgets) { if (!widget->isKitSelected()) continue; Kit *k = widget->kit(); - if (k && d->m_importer) - d->m_importer->makePersistent(k); + if (k && d->importer) + d->importer->makePersistent(k); toSetUp << widget->selectedBuildInfoList(); widget->clearKit(); } @@ -719,8 +719,8 @@ bool TargetSetupPage::setupProject(Project *project) d->reset(); Target *activeTarget = nullptr; - if (d->m_importer) - activeTarget = d->m_importer->preferredTarget(project->targets()); + if (d->importer) + activeTarget = d->importer->preferredTarget(project->targets()); if (activeTarget) project->setActiveTarget(activeTarget, SetActive::NoCascade); @@ -734,12 +734,12 @@ void TargetSetupPage::setUseScrollArea(bool b) void TargetSetupPagePrivate::setUseScrollArea(bool b) { - QLayout *oldBaseLayout = m_baseLayout; - m_baseLayout = b ? scrollArea->widget()->layout() : m_centralWidget->layout(); - if (oldBaseLayout == m_baseLayout) + QLayout *oldBaseLayout = baseLayout; + baseLayout = b ? scrollArea->widget()->layout() : centralWidget->layout(); + if (oldBaseLayout == baseLayout) return; scrollAreaWidget->setVisible(b); - m_centralWidget->setVisible(!b); + centralWidget->setVisible(!b); if (oldBaseLayout) removeAdditionalWidgets(oldBaseLayout); From 9b4779c23ff12cc15ece24b8b95c40fe4da3370c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 31 Oct 2024 16:32:13 +0100 Subject: [PATCH 036/989] ProjectExplorer: De-inline TargetSetupPagePrivate It was strange that this non-trivial function was the only inlined member function. Change-Id: I02d4298a11362c8319d829e25a38ce265493700b Reviewed-by: hjk --- .../projectexplorer/targetsetuppage.cpp | 224 +++++++++--------- 1 file changed, 113 insertions(+), 111 deletions(-) diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 9f4b6f4dddf..3c81640f337 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -59,117 +59,7 @@ static TasksGenerator defaultTasksGenerator(const TasksGenerator &childGenerator class TargetSetupPagePrivate : public QObject { public: - explicit TargetSetupPagePrivate(TargetSetupPage *parent) - : q(parent) - { - tasksGenerator = defaultTasksGenerator({}); - - importWidget = new ImportWidget(q); - importWidget->setVisible(false); - - spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); - - auto setupTargetPage = new QWidget(q); - - headerLabel = new QLabel(setupTargetPage); - headerLabel->setWordWrap(true); - headerLabel->setVisible(false); - - noValidKitLabel = new QLabel(setupTargetPage); - noValidKitLabel->setWordWrap(true); - noValidKitLabel->setText("" - + Tr::tr("No suitable kits found.") + "
" - + Tr::tr("Add a kit in the " - "options or via the maintenance tool of" - " the SDK.")); - noValidKitLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - noValidKitLabel->setVisible(false); - - allKitsCheckBox = new QCheckBox(setupTargetPage); - allKitsCheckBox->setTristate(true); - allKitsCheckBox->setText(Tr::tr("Select all kits")); - - kitFilterLineEdit = new FancyLineEdit(setupTargetPage); - kitFilterLineEdit->setFiltering(true); - kitFilterLineEdit->setPlaceholderText(Tr::tr("Type to filter kits by name...")); - - hideUnsuitableKitsCheckBox = new QCheckBox(Tr::tr("Hide unsuitable kits"), setupTargetPage); - - centralWidget = new QWidget(setupTargetPage); - QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Fixed); - policy.setHorizontalStretch(0); - policy.setVerticalStretch(0); - policy.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth()); - centralWidget->setSizePolicy(policy); - - scrollAreaWidget = new QWidget(setupTargetPage); - scrollArea = new QScrollArea(scrollAreaWidget); - scrollArea->setWidgetResizable(true); - - auto scrollAreaWidgetContents = new QWidget(); - scrollAreaWidgetContents->setGeometry(QRect(0, 0, 230, 81)); - scrollArea->setWidget(scrollAreaWidgetContents); - - auto verticalLayout = new QVBoxLayout(scrollAreaWidget); - verticalLayout->setSpacing(0); - verticalLayout->setContentsMargins(0, 0, 0, 0); - verticalLayout->addWidget(scrollArea); - - auto horizontalLayout = new QHBoxLayout; - horizontalLayout->addWidget(allKitsCheckBox); - horizontalLayout->addSpacing(10); - horizontalLayout->addWidget(kitFilterLineEdit); - - auto verticalLayout_2 = new QVBoxLayout(setupTargetPage); - verticalLayout_2->addWidget(headerLabel); - verticalLayout_2->addLayout(horizontalLayout); - verticalLayout_2->addWidget(hideUnsuitableKitsCheckBox); - verticalLayout_2->addWidget(noValidKitLabel); - verticalLayout_2->addWidget(centralWidget); - verticalLayout_2->addWidget(scrollAreaWidget); - - auto verticalLayout_3 = new QVBoxLayout(q); - verticalLayout_3->setContentsMargins(0, 0, 0, -1); - verticalLayout_3->addWidget(setupTargetPage); - - auto centralWidget = new QWidget(q); - scrollArea->setWidget(centralWidget); - centralWidget->setLayout(new QVBoxLayout); - - this->centralWidget->setLayout(new QVBoxLayout); - this->centralWidget->layout()->setContentsMargins(0, 0, 0, 0); - - QObject::connect(noValidKitLabel, &QLabel::linkActivated, - q, &TargetSetupPage::openOptions); - - QObject::connect(allKitsCheckBox, &QAbstractButton::clicked, - q, &TargetSetupPage::changeAllKitsSelections); - - const auto toggleTargetWidgetVisibility = [this] { - for (TargetSetupWidget *widget : widgets) - toggleVisibility(widget); - }; - QObject::connect(hideUnsuitableKitsCheckBox, &QCheckBox::toggled, - this, toggleTargetWidgetVisibility); - - QObject::connect(kitFilterLineEdit, &FancyLineEdit::filterChanged, - this, toggleTargetWidgetVisibility); - - setUseScrollArea(true); - - KitManager *km = KitManager::instance(); - // do note that those slots are triggered once *per* targetsetuppage - // thus the same slot can be triggered multiple times on different instances! - connect(km, &KitManager::kitAdded, this, &TargetSetupPagePrivate::handleKitAddition); - connect(km, &KitManager::kitRemoved, this, &TargetSetupPagePrivate::handleKitRemoval); - connect(km, &KitManager::kitUpdated, this, &TargetSetupPagePrivate::handleKitUpdate); - connect(importWidget, &ImportWidget::importFrom, - this, [this](const FilePath &dir) { import(dir); }); - connect(KitManager::instance(), &KitManager::kitsChanged, - this, &TargetSetupPagePrivate::updateVisibility); - - toggleTargetWidgetVisibility(); - } + explicit TargetSetupPagePrivate(TargetSetupPage *parent); void doInitializePage(); void handleKitAddition(Kit *k); @@ -534,6 +424,118 @@ void TargetSetupPage::openOptions() Core::ICore::showOptionsDialog(Constants::KITS_SETTINGS_PAGE_ID, this); } +TargetSetupPagePrivate::TargetSetupPagePrivate(TargetSetupPage *parent) + : q(parent) +{ + tasksGenerator = defaultTasksGenerator({}); + + importWidget = new ImportWidget(q); + importWidget->setVisible(false); + + spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); + + auto setupTargetPage = new QWidget(q); + + headerLabel = new QLabel(setupTargetPage); + headerLabel->setWordWrap(true); + headerLabel->setVisible(false); + + noValidKitLabel = new QLabel(setupTargetPage); + noValidKitLabel->setWordWrap(true); + noValidKitLabel->setText("" + + Tr::tr("No suitable kits found.") + "
" + + Tr::tr("Add a kit in the " + "options or via the maintenance tool of" + " the SDK.")); + noValidKitLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + noValidKitLabel->setVisible(false); + + allKitsCheckBox = new QCheckBox(setupTargetPage); + allKitsCheckBox->setTristate(true); + allKitsCheckBox->setText(Tr::tr("Select all kits")); + + kitFilterLineEdit = new FancyLineEdit(setupTargetPage); + kitFilterLineEdit->setFiltering(true); + kitFilterLineEdit->setPlaceholderText(Tr::tr("Type to filter kits by name...")); + + hideUnsuitableKitsCheckBox = new QCheckBox(Tr::tr("Hide unsuitable kits"), setupTargetPage); + + centralWidget = new QWidget(setupTargetPage); + QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Fixed); + policy.setHorizontalStretch(0); + policy.setVerticalStretch(0); + policy.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth()); + centralWidget->setSizePolicy(policy); + + scrollAreaWidget = new QWidget(setupTargetPage); + scrollArea = new QScrollArea(scrollAreaWidget); + scrollArea->setWidgetResizable(true); + + auto scrollAreaWidgetContents = new QWidget(); + scrollAreaWidgetContents->setGeometry(QRect(0, 0, 230, 81)); + scrollArea->setWidget(scrollAreaWidgetContents); + + auto verticalLayout = new QVBoxLayout(scrollAreaWidget); + verticalLayout->setSpacing(0); + verticalLayout->setContentsMargins(0, 0, 0, 0); + verticalLayout->addWidget(scrollArea); + + auto horizontalLayout = new QHBoxLayout; + horizontalLayout->addWidget(allKitsCheckBox); + horizontalLayout->addSpacing(10); + horizontalLayout->addWidget(kitFilterLineEdit); + + auto verticalLayout_2 = new QVBoxLayout(setupTargetPage); + verticalLayout_2->addWidget(headerLabel); + verticalLayout_2->addLayout(horizontalLayout); + verticalLayout_2->addWidget(hideUnsuitableKitsCheckBox); + verticalLayout_2->addWidget(noValidKitLabel); + verticalLayout_2->addWidget(centralWidget); + verticalLayout_2->addWidget(scrollAreaWidget); + + auto verticalLayout_3 = new QVBoxLayout(q); + verticalLayout_3->setContentsMargins(0, 0, 0, -1); + verticalLayout_3->addWidget(setupTargetPage); + + auto centralWidget = new QWidget(q); + scrollArea->setWidget(centralWidget); + centralWidget->setLayout(new QVBoxLayout); + + this->centralWidget->setLayout(new QVBoxLayout); + this->centralWidget->layout()->setContentsMargins(0, 0, 0, 0); + + QObject::connect(noValidKitLabel, &QLabel::linkActivated, + q, &TargetSetupPage::openOptions); + + QObject::connect(allKitsCheckBox, &QAbstractButton::clicked, + q, &TargetSetupPage::changeAllKitsSelections); + + const auto toggleTargetWidgetVisibility = [this] { + for (TargetSetupWidget *widget : widgets) + toggleVisibility(widget); + }; + QObject::connect(hideUnsuitableKitsCheckBox, &QCheckBox::toggled, + this, toggleTargetWidgetVisibility); + + QObject::connect(kitFilterLineEdit, &FancyLineEdit::filterChanged, + this, toggleTargetWidgetVisibility); + + setUseScrollArea(true); + + KitManager *km = KitManager::instance(); + // do note that those slots are triggered once *per* targetsetuppage + // thus the same slot can be triggered multiple times on different instances! + connect(km, &KitManager::kitAdded, this, &TargetSetupPagePrivate::handleKitAddition); + connect(km, &KitManager::kitRemoved, this, &TargetSetupPagePrivate::handleKitRemoval); + connect(km, &KitManager::kitUpdated, this, &TargetSetupPagePrivate::handleKitUpdate); + connect(importWidget, &ImportWidget::importFrom, + this, [this](const FilePath &dir) { import(dir); }); + connect(KitManager::instance(), &KitManager::kitsChanged, + this, &TargetSetupPagePrivate::updateVisibility); + + toggleTargetWidgetVisibility(); +} + void TargetSetupPagePrivate::kitSelectionChanged() { int selected = 0; From a03a964b0afc4aea1621dfd9ea4c86b6de90db8e Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 30 Oct 2024 08:30:43 +0100 Subject: [PATCH 037/989] Android: Create runner command more directly Avoid manual splitting of existing command line. Change-Id: Ibc1a96eb4e30c2c9f8cb2952b08ad9a840f47b14 Reviewed-by: Jarek Kobus --- src/plugins/android/androidrunnerworker.cpp | 37 +++++++++------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 80025ca7128..9d36543fa9e 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -156,7 +156,7 @@ public: QString m_intentName; QStringList m_beforeStartAdbCommands; QStringList m_afterFinishAdbCommands; - QStringList m_amStartExtraArgs; + QString m_amStartExtraArgs; qint64 m_processPID = -1; qint64 m_processUser = -1; bool m_useCppDebugger = false; @@ -216,8 +216,7 @@ static void setupStorage(RunnerStorage *storage, RunnerInterface *glue) if (const Store sd = glue->runControl()->settingsData(Constants::ANDROID_AM_START_ARGS); !sd.isEmpty()) { QTC_CHECK(sd.first().typeId() == QMetaType::QString); - const QString startArgs = sd.first().toString(); - storage->m_amStartExtraArgs = ProcessArgs::splitArgs(startArgs, OsTypeOtherUnix); + storage->m_amStartExtraArgs = sd.first().toString(); } if (const Store sd = glue->runControl()->settingsData(Constants::ANDROID_PRESTARTSHELLCMDLIST); @@ -488,15 +487,15 @@ static ExecutableItem logcatRecipe(const Storage &storage) static ExecutableItem preStartRecipe(const Storage &storage) { - const Storage argsStorage; + const Storage cmdStorage; const LoopUntil iterator([storage](int iteration) { return iteration < storage->m_beforeStartAdbCommands.size(); }); - const auto onArgsSetup = [storage, argsStorage] { - *argsStorage = {"shell", "am", "start", "-n", storage->m_intentName}; + const auto onArgsSetup = [storage, cmdStorage] { + *cmdStorage = storage->adbCommand({"shell", "am", "start", "-n", storage->m_intentName}); if (storage->m_useCppDebugger) - *argsStorage << "-D"; + *cmdStorage << "-D"; }; const auto onPreCommandSetup = [storage, iterator](Process &process) { @@ -514,7 +513,7 @@ static ExecutableItem preStartRecipe(const Storage &storage) const QString port = "tcp:" + QString::number(storage->m_qmlServer.port()); taskTree.setRecipe({removeForwardPortRecipe(storage.activeStorage(), port, port, "QML")}); }; - const auto onQmlDebugSync = [storage, argsStorage] { + const auto onQmlDebugSync = [storage, cmdStorage] { const QString qmljsdebugger = QString("port:%1,block,services:%2") .arg(storage->m_qmlServer.port()).arg(qmlDebugServices(storage->m_qmlDebugServices)); @@ -523,29 +522,25 @@ static ExecutableItem preStartRecipe(const Storage &storage) storage->m_extraAppParams.prepend(' '); storage->m_extraAppParams.prepend("-qmljsdebugger=" + qmljsdebugger); } else { - *argsStorage << "-e" << "qml_debug" << "true" + *cmdStorage << "-e" << "qml_debug" << "true" << "-e" << "qmljsdebugger" << qmljsdebugger; } }; - const auto onActivitySetup = [storage, argsStorage](Process &process) { - QStringList args = *argsStorage; - args << storage->m_amStartExtraArgs; + const auto onActivitySetup = [storage, cmdStorage](Process &process) { + cmdStorage->addArgs(storage->m_amStartExtraArgs, CommandLine::Raw); if (!storage->m_extraAppParams.isEmpty()) { - const QStringList appArgs = - ProcessArgs::splitArgs(storage->m_extraAppParams, Utils::OsType::OsTypeLinux); + const QByteArray appArgs = storage->m_extraAppParams.toUtf8(); qCDebug(androidRunWorkerLog).noquote() << "Using application arguments: " << appArgs; - args << "-e" << "extraappparams" - << QString::fromLatin1(appArgs.join(' ').toUtf8().toBase64()); + *cmdStorage << "-e" << "extraappparams" << QString::fromLatin1(appArgs.toBase64()); } if (storage->m_extraEnvVars.hasChanges()) { - args << "-e" << "extraenvvars" - << QString::fromLatin1(storage->m_extraEnvVars.toStringList().join('\t') - .toUtf8().toBase64()); + const QByteArray extraEnv = storage->m_extraEnvVars.toStringList().join('\t').toUtf8(); + *cmdStorage << "-e" << "extraenvvars" << QString::fromLatin1(extraEnv.toBase64()); } - process.setCommand(storage->adbCommand({args})); + process.setCommand(*cmdStorage); }; const auto onActivityDone = [storage](const Process &process) { storage->m_glue->setFinished( @@ -553,7 +548,7 @@ static ExecutableItem preStartRecipe(const Storage &storage) }; return Group { - argsStorage, + cmdStorage, onGroupSetup(onArgsSetup), For (iterator) >> Do { ProcessTask(onPreCommandSetup, onPreCommandDone, CallDoneIf::Error) From 44049801832ca97829ee85a8f0c18b786a3711b4 Mon Sep 17 00:00:00 2001 From: Liu Zhangjian Date: Sun, 29 Sep 2024 10:15:21 +0800 Subject: [PATCH 038/989] Locator: Update the locator position when the window moved Change-Id: Id3fa3fe227c0b693e63459ff61dd100e07358258 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/locator/locatorwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index c5444344a69..4349bd12c11 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -374,7 +374,7 @@ bool LocatorPopup::eventFilter(QObject *watched, QEvent *event) auto fe = static_cast(event); if (fe->reason() == Qt::ActiveWindowFocusReason && !QApplication::activeWindow()) hide(); - } else if (watched == m_window && event->type() == QEvent::Resize) { + } else if (watched == m_window && (event->type() == QEvent::Resize || event->type() == QEvent::Move)) { doUpdateGeometry(); } return QWidget::eventFilter(watched, event); From dedc6556d47f73ecb9274a53ca3e84dc760876a2 Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Wed, 30 Oct 2024 16:16:47 +0100 Subject: [PATCH 039/989] Debugger: Fix dumping with _GLIBCXX_DEBUG Fixed dumping of the standard library iterator types in case the binary is compiled with _GLIBCXX_DEBUG switch. Some non-stdlib tests that also used to fail after enabling _GLIBCXX_DEBUG due to a crash in `QCborMap::fromVariantMap` were adjusted as well. Full list of affected tests: * StdMap - fix * StdSet - fix * QC41700 - indirect fix (this test uses map iterators internally) * QCbor - workaround (QCborMap::fromVariantMap is simply avoided) * QJson - workaround (same as above) All in all, enabling _GLIBCXX_DEBUG in the test should not produce more failures compared to running without it. *Note: tested locally with mingw 13.10.* Fixes: QTCREATORBUG-31876 Change-Id: Ie55a40dc9a1aadb20795ad43abd0597047c429e4 Reviewed-by: hjk --- share/qtcreator/debugger/stdtypes.py | 30 +- tests/auto/debugger/tst_dumpers.cpp | 489 +++++++++++++++------------ 2 files changed, 295 insertions(+), 224 deletions(-) diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index b825195311a..f7acc264ac2 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -448,7 +448,35 @@ def qdump__std__map__iterator(d, value): def qdump____gnu_debug___Safe_iterator(d, value): - d.putItem(value["_M_current"]) + node = value["_M_node"].dereference() + d.putExpandable() + d.putEmptyValue() + if d.isExpanded(): + with Children(d): + real_iterator_type = value.type[0] # std::_Rb_tree_iterator or std::_Rb_tree_iterator> + inner_type = real_iterator_type[0] # T or std::pair + is_map = inner_type.name.startswith('std::pair') + if is_map: + key_type = inner_type[0] + value_type = inner_type[1] + typecode = f'pppp@{{{key_type.name}}}@{{{value_type.name}}}' + (color, parent, left, right, pad1, key, pad2, value) = d.split(typecode, node) + d.putSubItem("first", key) + d.putSubItem("second", value) + else: + typecode = f'pppp@{{{inner_type.name}}}' + (color, parent, left, right, pad1, key) = d.split(typecode, node) + d.putSubItem("value", key) + with SubItem(d, "[node]"): + d.putExpandable() + d.putEmptyValue() + d.putType(" ") + if d.isExpanded(): + with Children(d): + nodeType = node.type.pointer() + d.putSubItem("left", d.createValue(left, nodeType)) + d.putSubItem("right", d.createValue(right, nodeType)) + d.putSubItem("parent", d.createValue(parent, nodeType)) def qdump__std__map__const_iterator(d, value): diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index bf110533899..45e91af5657 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -7844,243 +7844,286 @@ void tst_Dumpers::dumper_data() + Check("pol", "<5 items>", "@QPolygonF") + Check("p", "<5 items>", "@QGraphicsPolygonItem"); + // clang-format off + auto qcborData = Data{ + R"( + #include + #if QT_VERSION >= 0x050c00 + #include + #include + #include + #include + #endif + )", + R"( + #if QT_VERSION >= 0x050c00 + QCborMap ob0; + #ifndef _GLIBCXX_DEBUG // crashes in QCborMap::fromVariantMap if _GLIBCXX_DEBUG is on + QCborMap ob = QCborMap::fromVariantMap({ + {"a", 1}, + {"bb", 2}, + {"ccc", "hallo"}, + {"s", "ssss"} + }); + ob.insert(QLatin1String("d"), QCborMap::fromVariantMap({{"ddd", 1234}})); + #endif - QTest::newRow("QCbor") - << Data("#include \n" - "#if QT_VERSION >= 0x050c00\n" - "#include \n" - "#include \n" - "#include \n" - "#include \n" - "#endif\n", + QCborValue a0; + QCborValue a1(1); + QCborValue a2("asd"); + QCborValue a3(QString::fromUtf8("cöder")); + QCborValue a4(1.4); + QCborValue a5(true); + QCborValue a6(QByteArray("cder")); - "#if QT_VERSION >= 0x050c00\n" - "QCborMap ob0;\n" - "QCborMap ob = QCborMap::fromVariantMap({\n" - " {\"a\", 1},\n" - " {\"bb\", 2},\n" - " {\"ccc\", \"hallo\"},\n" - " {\"s\", \"ssss\"}\n" - "});\n" - "ob.insert(QLatin1String(\"d\"), QCborMap::fromVariantMap({{\"ddd\", 1234}}));\n" - "\n" - "QCborValue a0;\n" - "QCborValue a1(1);\n" - "QCborValue a2(\"asd\");\n" - "QCborValue a3(QString::fromUtf8(\"cöder\"));\n" - "QCborValue a4(1.4);\n" - "QCborValue a5(true);\n" - "QCborValue a6(QByteArray(\"cder\"));\n" - "\n" - "QCborArray aa;\n" - "QCborArray a;\n" - "a.append(a1);\n" - "a.append(a2);\n" - "a.append(a3);\n" - "a.append(a4);\n" - "a.append(a5);\n" - "a.append(a0);\n" - "a.append(ob);\n" - "\n" - "QCborArray b;\n" - "b.append(QCborValue(1));\n" - "b.append(a);\n" - "b.append(QCborValue(2));\n" - "\n" - "QCborArray c;\n" - "for (unsigned int i = 0; i < 32; ++i) {\n" - " c.append(QCborValue(qint64(1u << i) - 1));\n" - " c.append(QCborValue(qint64(1u << i)));\n" - " c.append(QCborValue(qint64(1u << i) + 1));\n" - "}\n" - "for (unsigned int i = 0; i < 32; ++i) {\n" - " c.append(QCborValue(-qint64(1u << i) + 1));\n" - " c.append(QCborValue(-qint64(1u << i)));\n" - " c.append(QCborValue(-qint64(1u << i) - 1));\n" - "}" - "unused(&b, &a, &aa);\n" - "#endif\n", + QCborArray aa; + QCborArray a; + a.append(a1); + a.append(a2); + a.append(a3); + a.append(a4); + a.append(a5); + a.append(a0); + #ifndef _GLIBCXX_DEBUG // see above + a.append(ob); + #endif - "") + QCborArray b; + b.append(QCborValue(1)); + b.append(a); + b.append(QCborValue(2)); - + Cxx11Profile() - + CoreProfile() - + QtVersion(0x50f00) - + MsvcVersion(1900) + QCborArray c; + for (unsigned int i = 0; i < 32; ++i) { + c.append(QCborValue(qint64(1u << i) - 1)); + c.append(QCborValue(qint64(1u << i))); + c.append(QCborValue(qint64(1u << i) + 1)); + } + for (unsigned int i = 0; i < 32; ++i) { + c.append(QCborValue(-qint64(1u << i) + 1)); + c.append(QCborValue(-qint64(1u << i))); + c.append(QCborValue(-qint64(1u << i) - 1)); + } + unused(&b, &a, &aa); + #endif + )", + "" + } - + Check("a0", "Undefined", "QCborValue (Undefined)") - + Check("a1", "1", "QCborValue (Integer)") - + Check("a2", "\"asd\"", "QCborValue (String)") - + Check("a3", "\"cöder\"", "QCborValue (String)") - + Check("a4", "1.400000", "QCborValue (Double)") - + Check("a5", "True", "QCborValue (True)") - + Check("a6", "\"cder\"", "QCborValue (ByteArray)") - + Check("aa", "<0 items>", "@QCborArray") - + Check("a", "<7 items>", "@QCborArray") - + Check("a.0", "[0]", "1", "QCborValue (Integer)") - + Check("a.1", "[1]", "\"asd\"", "QCborValue (String)") - + Check("a.2", "[2]", "\"cöder\"", "QCborValue (String)") - + Check("a.3", "[3]", "1.400000", "QCborValue (Double)") - + Check("a.4", "[4]", "True", "QCborValue (True)") - + Check("a.5", "[5]", "Undefined", "QCborValue (Undefined)") - + Check("a.6", "[6]", "<5 items>", "QCborValue (Map)") - + Check("a.6.0", "[0] \"a\"", "1", "") - + Check("a.6.1", "[1] \"bb\"", "2", "") - + Check("a.6.2", "[2] \"ccc\"", "\"hallo\"", "") - + Check("a.6.3", "[3] \"s\"", "\"ssss\"", "") - + Check("a.6.4", "[4] \"d\"", "<1 items>", "") - + Check("b", "b", "<3 items>" , "@QCborArray") - + Check("b.0", "[0]", "1", "QCborValue (Integer)") - + Check("b.1", "[1]", "<7 items>", "QCborValue (Array)") - + Check("b.1.0", "[0]", "1", "QCborValue (Integer)") - + Check("b.1.1", "[1]", "\"asd\"", "QCborValue (String)") - + Check("b.1.2", "[2]", "\"cöder\"", "QCborValue (String)") - + Check("b.1.3", "[3]", "1.400000", "QCborValue (Double)") - + Check("b.1.4", "[4]", "True", "QCborValue (True)") - + Check("b.1.5", "[5]", "Undefined", "QCborValue (Undefined)") - + Check("b.1.6", "[6]", "<5 items>", "QCborValue (Map)") - + Check("b.2", "[2]", "2", "QCborValue (Integer)") - + Check("c", "c", "<192 items>", "@QCborArray") - + Check("c.0", "[0]", "0", "QCborValue (Integer)") - + Check("c.1", "[1]", "1", "QCborValue (Integer)") - + Check("c.78", "[78]", "67108863", "QCborValue (Integer)") - + Check("c.79", "[79]", "67108864", "QCborValue (Integer)") - + Check("c.94", "[94]", "2147483648", "QCborValue (Integer)") - + Check("c.95", "[95]", "2147483649", "QCborValue (Integer)") - + Check("c.96", "[96]", "0", "QCborValue (Integer)") - + Check("c.97", "[97]", "-1", "QCborValue (Integer)") - + Check("c.174", "[174]", "-67108863", "QCborValue (Integer)") - + Check("c.175", "[175]", "-67108864", "QCborValue (Integer)") - + Check("ob0", "ob0", "<0 items>", "@QCborMap") - + Check("ob", "ob", "<5 items>", "@QCborMap") - + Check("ob.0", "[0] \"a\"", "1", "") - + Check("ob.0.key", "key", "\"a\"", "QCborValue (String)") - + Check("ob.0.value", "value", "1", "QCborValue (Integer)") - + Check("ob.1", "[1] \"bb\"", "2", "") - + Check("ob.2", "[2] \"ccc\"", "\"hallo\"", "") - + Check("ob.3", "[3] \"s\"", "\"ssss\"", "") - + Check("ob.4", "[4] \"d\"", "<1 items>", "") - ; + + Cxx11Profile() + + CoreProfile() + + QtVersion(0x50f00) + + MsvcVersion(1900) + + Check("a0", "Undefined", "QCborValue (Undefined)") + + Check("a1", "1", "QCborValue (Integer)") + + Check("a2", "\"asd\"", "QCborValue (String)") + + Check("a3", "\"cöder\"", "QCborValue (String)") + + Check("a4", "1.400000", "QCborValue (Double)") + + Check("a5", "True", "QCborValue (True)") + + Check("a6", "\"cder\"", "QCborValue (ByteArray)") + + Check("aa", "<0 items>", "@QCborArray") + + Check("a.0", "[0]", "1", "QCborValue (Integer)") + + Check("a.1", "[1]", "\"asd\"", "QCborValue (String)") + + Check("a.2", "[2]", "\"cöder\"", "QCborValue (String)") + + Check("a.3", "[3]", "1.400000", "QCborValue (Double)") + + Check("a.4", "[4]", "True", "QCborValue (True)") + + Check("a.5", "[5]", "Undefined", "QCborValue (Undefined)") + + Check("b", "b", "<3 items>" , "@QCborArray") + + Check("b.0", "[0]", "1", "QCborValue (Integer)") + + Check("b.1.0", "[0]", "1", "QCborValue (Integer)") + + Check("b.1.1", "[1]", "\"asd\"", "QCborValue (String)") + + Check("b.1.2", "[2]", "\"cöder\"", "QCborValue (String)") + + Check("b.1.3", "[3]", "1.400000", "QCborValue (Double)") + + Check("b.1.4", "[4]", "True", "QCborValue (True)") + + Check("b.1.5", "[5]", "Undefined", "QCborValue (Undefined)") + + Check("b.2", "[2]", "2", "QCborValue (Integer)") + + Check("c", "c", "<192 items>", "@QCborArray") + + Check("c.0", "[0]", "0", "QCborValue (Integer)") + + Check("c.1", "[1]", "1", "QCborValue (Integer)") + + Check("c.78", "[78]", "67108863", "QCborValue (Integer)") + + Check("c.79", "[79]", "67108864", "QCborValue (Integer)") + + Check("c.94", "[94]", "2147483648", "QCborValue (Integer)") + + Check("c.95", "[95]", "2147483649", "QCborValue (Integer)") + + Check("c.96", "[96]", "0", "QCborValue (Integer)") + + Check("c.97", "[97]", "-1", "QCborValue (Integer)") + + Check("c.174", "[174]", "-67108863", "QCborValue (Integer)") + + Check("c.175", "[175]", "-67108864", "QCborValue (Integer)") + + Check("ob0", "ob0", "<0 items>", "@QCborMap"); + + // there's a SIGSEGV in QCborMap::fromVariantMap if the test is run with _GLIBCXX_DEBUG on + if (!m_useGLibCxxDebug) + { + qcborData = qcborData + + Check("a", "<7 items>", "@QCborArray") + + Check("a.6", "[6]", "<5 items>", "QCborValue (Map)") + + Check("a.6.0", "[0] \"a\"", "1", "") + + Check("a.6.1", "[1] \"bb\"", "2", "") + + Check("a.6.2", "[2] \"ccc\"", "\"hallo\"", "") + + Check("a.6.3", "[3] \"s\"", "\"ssss\"", "") + + Check("a.6.4", "[4] \"d\"", "<1 items>", "") + + Check("b.1", "[1]", "<7 items>", "QCborValue (Array)") + + Check("b.1.6", "[6]", "<5 items>", "QCborValue (Map)") + + Check("ob", "ob", "<5 items>", "@QCborMap") + + Check("ob.0", "[0] \"a\"", "1", "") + + Check("ob.0.key", "key", "\"a\"", "QCborValue (String)") + + Check("ob.0.value", "value", "1", "QCborValue (Integer)") + + Check("ob.1", "[1] \"bb\"", "2", "") + + Check("ob.2", "[2] \"ccc\"", "\"hallo\"", "") + + Check("ob.3", "[3] \"s\"", "\"ssss\"", "") + + Check("ob.4", "[4] \"d\"", "<1 items>", ""); + } + else + { + qcborData = qcborData + + Check("a", "<6 items>", "@QCborArray") + + Check("b.1", "[1]", "<6 items>", "QCborValue (Array)"); + } + // clang-format on + QTest::newRow("QCbor") << qcborData; const QtVersion jsonv1{0, 0x50f00}; const QtVersion jsonv2{0x50f00, 0x60000}; + // clang-format off + auto qjsonData = Data{ + R"( + #include + #if QT_VERSION >= 0x050000 + #include + #include + #include + #include + #endif + )", + R"( + #if QT_VERSION >= 0x050000 + QJsonObject ob0; + #ifndef _GLIBCXX_DEBUG // crashes in QCborMap::fromVariantMap if _GLIBCXX_DEBUG is on + QJsonObject ob = QJsonObject::fromVariantMap({ + {"a", 1}, + {"bb", 2}, + {"ccc", "hallo"}, + {"s", "ssss"} + }); + ob.insert(QLatin1String("d"), QJsonObject::fromVariantMap({{"ddd", 1234}})); + #endif - QTest::newRow("QJson") - << Data("#include \n" - "#if QT_VERSION >= 0x050000\n" - "#include \n" - "#include \n" - "#include \n" - "#include \n" - "#endif\n", + QJsonArray aa; + QJsonArray a; + a.append(QJsonValue(1)); + a.append(QJsonValue("asd")); + a.append(QJsonValue(QString::fromLatin1("cdfer"))); + a.append(QJsonValue(1.4)); + a.append(QJsonValue(true)); + #ifndef _GLIBCXX_DEBUG // see above + a.append(ob); + #endif - "#if QT_VERSION >= 0x050000\n" - "QJsonObject ob0;\n" - "QJsonObject ob = QJsonObject::fromVariantMap({\n" - " {\"a\", 1},\n" - " {\"bb\", 2},\n" - " {\"ccc\", \"hallo\"},\n" - " {\"s\", \"ssss\"}\n" - "});\n" - "ob.insert(QLatin1String(\"d\"), QJsonObject::fromVariantMap({{\"ddd\", 1234}}));\n" - "\n" - "QJsonArray aa;\n" - "QJsonArray a;\n" - "a.append(QJsonValue(1));\n" - "a.append(QJsonValue(\"asd\"));\n" - "a.append(QJsonValue(QString::fromLatin1(\"cdfer\")));\n" - "a.append(QJsonValue(1.4));\n" - "a.append(QJsonValue(true));\n" - "a.append(ob);\n" - "\n" - "QJsonArray b;\n" - "b.append(QJsonValue(1));\n" - "b.append(a);\n" - "b.append(QJsonValue(2));\n" - "\n" - "QJsonArray c;\n" - "for (unsigned int i = 0; i < 32; ++i) {\n" - " c.append(QJsonValue(qint64(1u << i) - 1));\n" - " c.append(QJsonValue(qint64(1u << i)));\n" - " c.append(QJsonValue(qint64(1u << i) + 1));\n" - "}\n" - "for (unsigned int i = 0; i < 32; ++i) {\n" - " c.append(QJsonValue(-qint64(1u << i) + 1));\n" - " c.append(QJsonValue(-qint64(1u << i)));\n" - " c.append(QJsonValue(-qint64(1u << i) - 1));\n" - "}" - "unused(&ob, &b, &a, &aa);\n" - "#endif\n", + QJsonArray b; + b.append(QJsonValue(1)); + b.append(a); + b.append(QJsonValue(2)); - "") + QJsonArray c; + for (unsigned int i = 0; i < 32; ++i) { + c.append(QJsonValue(qint64(1u << i) - 1)); + c.append(QJsonValue(qint64(1u << i))); + c.append(QJsonValue(qint64(1u << i) + 1)); + } + for (unsigned int i = 0; i < 32; ++i) { + c.append(QJsonValue(-qint64(1u << i) + 1)); + c.append(QJsonValue(-qint64(1u << i))); + c.append(QJsonValue(-qint64(1u << i) - 1)); + } + unused( + #ifndef _GLIBCXX_DEBUG // see above + &ob, + #endif + &b, &a, &aa); + #endif + )", + "" + } - + Cxx11Profile() - + CoreProfile() - + QtVersion(0x50000) - + MsvcVersion(1900) + + Cxx11Profile() + + CoreProfile() + + QtVersion(0x50000) + + MsvcVersion(1900) - + Check("aa", "<0 items>", "@QJsonArray") - + Check("a", "<6 items>", "@QJsonArray") - + Check("a.0", "[0]", "1", "QJsonValue (Number)") - + Check("a.1", "[1]", "\"asd\"", "QJsonValue (String)") - + Check("a.2", "[2]", "\"cdfer\"", "QJsonValue (String)") - + Check("a.3", "[3]", "1.4", "QJsonValue (Number)") % jsonv1 - + Check("a.3", "[3]", "1.400000", "QJsonValue (Number)") % jsonv2 - + Check("a.4", "[4]", "true", "QJsonValue (Bool)") % jsonv1 - + Check("a.4", "[4]", "True", "QJsonValue (Bool)") % jsonv2 - + Check("a.5", "[5]", "<5 items>", "QJsonValue (Object)") - + Check("a.5.0", "\"a\"", "1", "QJsonValue (Number)") % jsonv1 - + Check("a.5.0", "[0] \"a\"", "1", "" ) % jsonv2 - + Check("a.5.1", "\"bb\"", "2", "QJsonValue (Number)") % jsonv1 - + Check("a.5.1", "[1] \"bb\"", "2", "" ) % jsonv2 - + Check("a.5.2", "\"ccc\"", "\"hallo\"", "QJsonValue (String)") % jsonv1 - + Check("a.5.2", "[2] \"ccc\"","\"hallo\"", "" ) % jsonv2 - + Check("a.5.3", "\"d\"", "<1 items>", "QJsonValue (Object)") % jsonv1 - + Check("a.5.3", "[3] \"d\"", "<1 items>", "" ) % jsonv2 - + Check("a.5.4", "\"s\"", "\"ssss\"", "QJsonValue (String)") % jsonv1 - + Check("a.5.4", "[4] \"s\"", "\"ssss\"", "" ) % jsonv2 - + Check("b", "b", "<3 items>" , "@QJsonArray") - + Check("b.0", "[0]", "1", "QJsonValue (Number)") - + Check("b.1", "[1]", "<6 items>", "QJsonValue (Array)") - + Check("b.1.0", "[0]", "1", "QJsonValue (Number)") % jsonv2 - + Check("b.1.1", "[1]", "\"asd\"", "QJsonValue (String)") % jsonv2 - + Check("b.1.2", "[2]", "\"cdfer\"", "QJsonValue (String)") % jsonv2 - + Check("b.1.3", "[3]", "1.4", "QJsonValue (Number)") % jsonv1 - + Check("b.1.3", "[3]", "1.400000", "QJsonValue (Number)") % jsonv2 - + Check("b.1.4", "[4]", "true", "QJsonValue (Bool)") % jsonv1 - + Check("b.1.5", "[5]", "<5 items>", "QJsonValue (Object)") % jsonv2 - + Check("b.2", "[2]", "2", "QJsonValue (Number)") % jsonv2 - + Check("c", "c", "<192 items>", "@QJsonArray") - + Check("c.0", "[0]", "0.0", "QJsonValue (Number)") % jsonv1 - + Check("c.0", "[0]", "0", "QJsonValue (Number)") % jsonv2 - + Check("c.1", "[1]", "1", "QJsonValue (Number)") - + Check("c.78", "[78]", "67108863", "QJsonValue (Number)") - + Check("c.79", "[79]", "67108864.0", "QJsonValue (Number)") % jsonv1 - + Check("c.79", "[79]", "67108864", " QJsonValue (Number)") % jsonv2 - + Check("c.94", "[94]", "2147483648.0", "QJsonValue (Number)") % jsonv1 - + Check("c.94", "[94]", "2147483648", "QJsonValue (Number)") % jsonv2 - + Check("c.95", "[95]", "2147483649.0", "QJsonValue (Number)") % jsonv1 - + Check("c.95", "[95]", "2147483649", "QJsonValue (Number)") % jsonv2 - + Check("c.96", "[96]", "0.0", "QJsonValue (Number)") % jsonv1 - + Check("c.96", "[96]", "0", "QJsonValue (Number)") % jsonv2 - + Check("c.97", "[97]", "-1", "QJsonValue (Number)") - + Check("c.174", "[174]", "-67108863", "QJsonValue (Number)") - + Check("c.175", "[175]", "-67108864.0", "QJsonValue (Number)") % jsonv1 - + Check("c.175", "[175]", "-67108864", "QJsonValue (Number)") % jsonv2 - + Check("ob0", "ob0", "<0 items>", "@QJsonObject") - + Check("ob", "ob", "<5 items>", "@QJsonObject") - + Check("ob.0", "\"a\"", "1", "QJsonValue (Number)") % jsonv1 - + Check("ob.0", "[0] \"a\"", "1", "" ) % jsonv2 - + Check("ob.1", "\"bb\"", "2", "QJsonValue (Number)") % jsonv1 - + Check("ob.1", "[1] \"bb\"", "2", "" ) % jsonv2 - + Check("ob.2", "\"ccc\"", "\"hallo\"", "QJsonValue (String)") % jsonv1 - + Check("ob.2", "[2] \"ccc\"", "\"hallo\"", "" ) % jsonv2 - + Check("ob.3", "\"d\"", "<1 items>", "QJsonValue (Object)") % jsonv1 - + Check("ob.3", "[3] \"d\"", "<1 items>", "" ) % jsonv2 - + Check("ob.4", "\"s\"", "\"ssss\"", "QJsonValue (String)") % jsonv1 - + Check("ob.4", "[4] \"s\"", "\"ssss\"", "" ) % jsonv2; + + Check("aa", "<0 items>", "@QJsonArray") + + Check("a.0", "[0]", "1", "QJsonValue (Number)") + + Check("a.1", "[1]", "\"asd\"", "QJsonValue (String)") + + Check("a.2", "[2]", "\"cdfer\"", "QJsonValue (String)") + + Check("a.3", "[3]", "1.4", "QJsonValue (Number)") % jsonv1 + + Check("a.3", "[3]", "1.400000", "QJsonValue (Number)") % jsonv2 + + Check("a.4", "[4]", "true", "QJsonValue (Bool)") % jsonv1 + + Check("a.4", "[4]", "True", "QJsonValue (Bool)") % jsonv2 + + Check("b", "b", "<3 items>" , "@QJsonArray") + + Check("b.0", "[0]", "1", "QJsonValue (Number)") + + Check("b.2", "[2]", "2", "QJsonValue (Number)") % jsonv2 + + Check("c", "c", "<192 items>", "@QJsonArray") + + Check("c.0", "[0]", "0.0", "QJsonValue (Number)") % jsonv1 + + Check("c.0", "[0]", "0", "QJsonValue (Number)") % jsonv2 + + Check("c.1", "[1]", "1", "QJsonValue (Number)") + + Check("c.78", "[78]", "67108863", "QJsonValue (Number)") + + Check("c.79", "[79]", "67108864.0", "QJsonValue (Number)") % jsonv1 + + Check("c.79", "[79]", "67108864", "QJsonValue (Number)") % jsonv2 + + Check("c.94", "[94]", "2147483648.0", "QJsonValue (Number)") % jsonv1 + + Check("c.94", "[94]", "2147483648", "QJsonValue (Number)") % jsonv2 + + Check("c.95", "[95]", "2147483649.0", "QJsonValue (Number)") % jsonv1 + + Check("c.95", "[95]", "2147483649", "QJsonValue (Number)") % jsonv2 + + Check("c.96", "[96]", "0.0", "QJsonValue (Number)") % jsonv1 + + Check("c.96", "[96]", "0", "QJsonValue (Number)") % jsonv2 + + Check("c.97", "[97]", "-1", "QJsonValue (Number)") + + Check("c.174", "[174]", "-67108863", "QJsonValue (Number)") + + Check("c.175", "[175]", "-67108864.0", "QJsonValue (Number)") % jsonv1 + + Check("c.175", "[175]", "-67108864", "QJsonValue (Number)") % jsonv2 + + Check("ob0", "ob0", "<0 items>", "@QJsonObject"); + // there's a SIGSEGV in QCborMap::fromVariantMap if the test is run with _GLIBCXX_DEBUG on + if (!m_useGLibCxxDebug) + { + qjsonData = qjsonData + + Check("ob", "ob", "<5 items>", "@QJsonObject") + + Check("ob.0", "\"a\"", "1", "QJsonValue (Number)") % jsonv1 + + Check("ob.0", "[0] \"a\"", "1", "" ) % jsonv2 + + Check("ob.1", "\"bb\"", "2", "QJsonValue (Number)") % jsonv1 + + Check("ob.1", "[1] \"bb\"", "2", "" ) % jsonv2 + + Check("ob.2", "\"ccc\"", "\"hallo\"", "QJsonValue (String)") % jsonv1 + + Check("ob.2", "[2] \"ccc\"", "\"hallo\"", "" ) % jsonv2 + + Check("ob.3", "\"d\"", "<1 items>", "QJsonValue (Object)") % jsonv1 + + Check("ob.3", "[3] \"d\"", "<1 items>", "" ) % jsonv2 + + Check("ob.4", "\"s\"", "\"ssss\"", "QJsonValue (String)") % jsonv1 + + Check("ob.4", "[4] \"s\"", "\"ssss\"", "" ) % jsonv2 + + Check("a", "<6 items>", "@QJsonArray") + + Check("a.5", "[5]", "<5 items>", "QJsonValue (Object)") + + Check("a.5.0", "\"a\"", "1", "QJsonValue (Number)") % jsonv1 + + Check("a.5.0", "[0] \"a\"", "1", "" ) % jsonv2 + + Check("a.5.1", "\"bb\"", "2", "QJsonValue (Number)") % jsonv1 + + Check("a.5.1", "[1] \"bb\"", "2", "" ) % jsonv2 + + Check("a.5.2", "\"ccc\"", "\"hallo\"", "QJsonValue (String)") % jsonv1 + + Check("a.5.2", "[2] \"ccc\"", "\"hallo\"", "" ) % jsonv2 + + Check("a.5.3", "\"d\"", "<1 items>", "QJsonValue (Object)") % jsonv1 + + Check("a.5.3", "[3] \"d\"", "<1 items>", "" ) % jsonv2 + + Check("a.5.4", "\"s\"", "\"ssss\"", "QJsonValue (String)") % jsonv1 + + Check("a.5.4", "[4] \"s\"", "\"ssss\"", "" ) % jsonv2 + + Check("b.1", "[1]", "<6 items>", "QJsonValue (Array)") + + Check("b.1.0", "[0]", "1", "QJsonValue (Number)") % jsonv2 + + Check("b.1.1", "[1]", "\"asd\"", "QJsonValue (String)") % jsonv2 + + Check("b.1.2", "[2]", "\"cdfer\"", "QJsonValue (String)") % jsonv2 + + Check("b.1.3", "[3]", "1.4", "QJsonValue (Number)") % jsonv1 + + Check("b.1.3", "[3]", "1.400000", "QJsonValue (Number)") % jsonv2 + + Check("b.1.4", "[4]", "true", "QJsonValue (Bool)") % jsonv1 + + Check("b.1.5", "[5]", "<5 items>", "QJsonValue (Object)") % jsonv2; + } + else + { + qjsonData = qjsonData + + Check("a", "<5 items>", "@QJsonArray") + + Check("b.1", "[1]", "<5 items>", "QJsonValue (Array)"); + } + // clang-format on + QTest::newRow("QJson") << qjsonData; QTest::newRow("QV4") << Data("#include \n" @@ -8640,7 +8683,7 @@ void tst_Dumpers::dumper_data() + Check{"err_enum.inner", "Bad (1)", "ErrCode"} % NoGdbEngine + Check{"err_class", "Unexpected", "tl::expected"} + Check{"err_class.inner.m_x", "10", "int"}; - //clang-format on + // clang-format on } int main(int argc, char *argv[]) From f4109e8e53022802543d3599590b34dc8da57a92 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 29 Oct 2024 18:14:07 +0100 Subject: [PATCH 040/989] Utils: Provide a full set of {min,max}Element() ... and use the respective variant in place of std::{min,max}Element(). Change-Id: Ie4a74d735253c16506edf728ffb9a114711d63c4 Reviewed-by: Eike Ziller --- src/libs/extensionsystem/pluginmanager.cpp | 10 +- src/libs/qmljs/parser/qmljsast.cpp | 15 ++- src/libs/qmljs/parser/qmljsast_p.h | 2 +- src/libs/utils/algorithm.h | 92 ++++++++++++++++--- .../cmakeprojectmanager/cmaketoolmanager.cpp | 2 +- .../dialogs/filepropertiesdialog.cpp | 13 ++- .../projectexplorer/toolchainkitaspect.cpp | 6 +- src/plugins/qtsupport/qtkitaspect.cpp | 16 +--- 8 files changed, 106 insertions(+), 50 deletions(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 7560c86a85d..3825477ad3a 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -441,11 +441,11 @@ QString PluginManager::systemInformation() if (qtDiagProc.result() == ProcessResult::FinishedWithSuccess) result += qtDiagProc.allOutput() + "\n"; result += "Plugin information:\n\n"; - auto longestSpec = std::max_element(d->pluginSpecs.cbegin(), d->pluginSpecs.cend(), - [](const PluginSpec *left, const PluginSpec *right) { - return left->name().size() < right->name().size(); - }); - int size = (*longestSpec)->name().size(); + PluginSpec * const longestSpec = Utils::maxElementOrDefault( + d->pluginSpecs, [](const PluginSpec *left, const PluginSpec *right) { + return left->name().size() < right->name().size(); + }); + int size = longestSpec->name().size(); for (const PluginSpec *spec : plugins()) { result += QLatin1String(spec->isEffectivelyEnabled() ? "+ " : " ") + filled(spec->name(), size) + " " + spec->version() + "\n"; diff --git a/src/libs/qmljs/parser/qmljsast.cpp b/src/libs/qmljs/parser/qmljsast.cpp index 9a4503dff42..e0e2536e243 100644 --- a/src/libs/qmljs/parser/qmljsast.cpp +++ b/src/libs/qmljs/parser/qmljsast.cpp @@ -2,13 +2,14 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qmljsast_p.h" + +#include "qmljsastvisitor_p.h" + +#include + #include #include -#include "qmljsastvisitor_p.h" -#include - -#include #include QT_QML_BEGIN_NAMESPACE @@ -1606,8 +1607,7 @@ SourceLocation UiPropertyAttributes::firstSourceLocation() const &m_defaultToken, &m_readonlyToken, &m_requiredToken}; - const auto it = std::min_element(tokens.begin(), tokens.end(), compareLocationsByBegin); - return **it; + return *Utils::minElementOrDefault(tokens, compareLocationsByBegin); } SourceLocation UiPropertyAttributes::lastSourceLocation() const @@ -1616,8 +1616,7 @@ SourceLocation UiPropertyAttributes::lastSourceLocation() const &m_defaultToken, &m_readonlyToken, &m_requiredToken}; - const auto it = std::max_element(tokens.begin(), tokens.end(), compareLocationsByBegin); - return **it; + return *Utils::maxElementOrDefault(tokens, compareLocationsByBegin); } } } // namespace QmlJS::AST diff --git a/src/libs/qmljs/parser/qmljsast_p.h b/src/libs/qmljs/parser/qmljsast_p.h index aaf1d7be4c4..26ef47992b9 100644 --- a/src/libs/qmljs/parser/qmljsast_p.h +++ b/src/libs/qmljs/parser/qmljsast_p.h @@ -3335,7 +3335,7 @@ public: SourceLocation propertyToken() const { return m_propertyToken; } template - static bool compareLocationsByBegin(const SourceLocation *&lhs, const SourceLocation *&rhs) + static bool compareLocationsByBegin(const SourceLocation *lhs, const SourceLocation *rhs) { if (lhs->isValid() && rhs->isValid()) return lhs->begin() < rhs->begin(); diff --git a/src/libs/utils/algorithm.h b/src/libs/utils/algorithm.h index f173f9844a5..f0b296e8733 100644 --- a/src/libs/utils/algorithm.h +++ b/src/libs/utils/algorithm.h @@ -112,10 +112,25 @@ template Q_REQUIRED_RESULT int indexOf(const C &container, F function); ///////////////////////// -// maxElementOr +// {min,max}ElementOr ///////////////////////// -template -typename T::value_type maxElementOr(const T &container, typename T::value_type other); +template +typename C::value_type maxElementOr(const C &container, typename C::value_type other); +template +typename C::value_type maxElementOrDefault(const C &container); +template +typename C::value_type maxElementOr(const C &container, const Cmp &cmp, typename C::value_type other); +template +typename C::value_type maxElementOrDefault(const C &container, const Cmp &cmp); + +template +typename C::value_type minElementOr(const C &container, typename C::value_type other); +template +typename C::value_type minElementOrDefault(const C &container); +template +typename C::value_type minElementOr(const C &container, const Cmp &cmp, typename C::value_type other); +template +typename C::value_type minElementOrDefault(const C &container, const Cmp &cmp); ///////////////////////// // filtered @@ -569,21 +584,72 @@ int indexOf(const C& container, F function) ////////////////// -// max element +// min/max element ////////////////// -template -typename T::value_type maxElementOr(const T &container, typename T::value_type other) +template +typename C::value_type maxElementOr(const C &container, typename C::value_type other) { - typename T::const_iterator begin = std::begin(container); - typename T::const_iterator end = std::end(container); - - typename T::const_iterator it = std::max_element(begin, end); - if (it == end) - return other; - return *it; + const auto begin = std::begin(container); + const auto end = std::end(container); + if (const auto it = std::max_element(begin, end); it != end) + return *it; + return other; } +template +typename C::value_type maxElementOrDefault(const C &container) +{ + return maxElementOr(container, typename C::value_type()); +} + +template +typename C::value_type maxElementOr(const C &container, const Cmp &cmp, typename C::value_type other) +{ + const auto begin = std::begin(container); + const auto end = std::end(container); + if (const auto it = std::max_element(begin, end, cmp); it != end) + return *it; + return other; +} + +template +typename C::value_type maxElementOrDefault(const C &container, const Cmp &cmp) +{ + return maxElementOr(container, cmp, typename C::value_type()); +} + +template +typename C::value_type minElementOr(const C &container, typename C::value_type other) +{ + const auto begin = std::begin(container); + const auto end = std::end(container); + if (const auto it = std::min_element(begin, end); it != end) + return *it; + return other; +} + +template +typename C::value_type minElementOrDefault(const C &container) +{ + return minElementOr(container, typename C::value_type()); +} + +template +typename C::value_type minElementOr(const C &container, const Cmp &cmp, typename C::value_type other) +{ + const auto begin = std::begin(container); + const auto end = std::end(container); + if (const auto it = std::min_element(begin, end, cmp); it != end) + return *it; + return other; +} + +template +typename C::value_type minElementOrDefault(const C &container, const Cmp &cmp) +{ + return minElementOr(container, cmp, typename C::value_type()); +} ////////////////// // transform diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp index 85008e497ab..113021b3d7f 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp @@ -582,7 +582,7 @@ CMakeToolManagerPrivate::CMakeToolManagerPrivate() if (HostOsInfo::isWindowsHost()) { const QStringList locations = QStandardPaths::standardLocations( QStandardPaths::GenericConfigLocation); - m_junctionsDir = FilePath::fromString(*std::min_element(locations.begin(), locations.end())) + m_junctionsDir = FilePath::fromString(Utils::minElementOrDefault(locations)) .pathAppended("QtCreator/Links"); auto project = ProjectManager::startupProject(); diff --git a/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp index 2a480ff17b5..c0ef31cc00d 100644 --- a/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp +++ b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp @@ -4,9 +4,9 @@ #include "filepropertiesdialog.h" #include "../coreplugintr.h" -#include "../editormanager/editormanager.h" #include "../editormanager/ieditorfactory.h" +#include #include #include #include @@ -161,17 +161,16 @@ void FilePropertiesDialog::detectTextFileSettings() break; } - const std::map::iterator max = std::max_element( - indents.begin(), indents.end(), - [](const std::pair &a, const std::pair &b) { - return a.second < b.second; - }); + const auto max = Utils::maxElementOrDefault( + indents, [](const std::pair &a, const std::pair &b) { + return a.second < b.second; + }); if (!indents.empty()) { if (tabIndented) { m_indentation->setText(Tr::tr("Mixed")); } else { - m_indentation->setText(Tr::tr("%1 Spaces").arg(max->first)); + m_indentation->setText(Tr::tr("%1 Spaces").arg(max.first)); } } else if (tabIndented) { m_indentation->setText(Tr::tr("Tabs")); diff --git a/src/plugins/projectexplorer/toolchainkitaspect.cpp b/src/plugins/projectexplorer/toolchainkitaspect.cpp index 77668bf558d..36e9249b715 100644 --- a/src/plugins/projectexplorer/toolchainkitaspect.cpp +++ b/src/plugins/projectexplorer/toolchainkitaspect.cpp @@ -336,9 +336,9 @@ static void setToolchainsFromAbis(Kit *k, const LanguagesAndAbis &abisByLanguage continue; } - const auto bestBundle = std::min_element( - matchingBundles.begin(), matchingBundles.end(), &ToolchainManager::isBetterToolchain); - ToolchainKitAspect::setBundle(k, *bestBundle); + const ToolchainBundle bestBundle = Utils::minElementOr( + matchingBundles, &ToolchainManager::isBetterToolchain, matchingBundles.first()); + ToolchainKitAspect::setBundle(k, bestBundle); } } diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index 882bda12211..f59dba58d8a 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -149,18 +149,10 @@ void QtKitAspectFactory::setup(Kit *k) const QtVersions &candidates = !exactMatches.empty() ? exactMatches : matches; // Prefer higher versions to lower ones. - const QVersionNumber maxVersion = [&]() -> QVersionNumber { - if (const auto it = std::max_element( - candidates.begin(), - candidates.end(), - [](const QtVersion *v1, const QtVersion *v2) { - return v1->qtVersion() < v2->qtVersion(); - }); - it != candidates.end()) { - return (*it)->qtVersion(); - } - return {}; - }(); + const QVersionNumber maxVersion + = Utils::maxElementOrDefault(candidates, [](const QtVersion *v1, const QtVersion *v2) { + return v1->qtVersion() < v2->qtVersion(); + })->qtVersion(); const auto [highestVersions, lowerVersions] = Utils::partition(candidates, [&maxVersion](const QtVersion *v) { return v->qtVersion() == maxVersion; From d0fb80a3b2e801862ec878e27964d0a4a62f4188 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 27 Sep 2024 15:45:28 +0200 Subject: [PATCH 041/989] Ios: Dismantle IosRunSupport Use IosRunner directly instead. Change-Id: I697b79300faa9c47030a2d9df3be83a22408fb79 Reviewed-by: hjk Reviewed-by: Eike Ziller --- src/plugins/ios/iosrunner.cpp | 40 +++++------------------------------ 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index 3b6ab2ef2e4..cc78fac2ed9 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -549,6 +549,7 @@ void IosRunner::start() args.append(qmlDebugTcpArguments(m_qmlDebugServices, qmlServer)); } + appendMessage(Tr::tr("Starting remote process."), NormalMessageFormat); m_toolHandler->requestRunApp(bundlePath(), args, runType(), deviceId()); } @@ -693,40 +694,6 @@ Port IosRunner::qmlServerPort() const return m_qmlServerPort; } -// -// IosRunner -// - -class IosRunSupport : public IosRunner -{ -public: - explicit IosRunSupport(RunControl *runControl); - ~IosRunSupport() override; - -private: - void start() override; -}; - -IosRunSupport::IosRunSupport(RunControl *runControl) - : IosRunner(runControl) -{ - setId("IosRunSupport"); - runControl->setIcon(Icons::RUN_SMALL_TOOLBAR); - runControl->setDisplayName(QString("Run on %1") - .arg(device() ? device()->displayName() : QString())); -} - -IosRunSupport::~IosRunSupport() -{ - stop(); -} - -void IosRunSupport::start() -{ - appendMessage(Tr::tr("Starting remote process."), NormalMessageFormat); - IosRunner::start(); -} - // // IosQmlProfilerSupport // @@ -897,7 +864,10 @@ IosRunWorkerFactory::IosRunWorkerFactory() if (iosdevice && iosdevice->handler() == IosDevice::Handler::DeviceCtl) { return new DeviceCtlRunner(control); } - return new IosRunSupport(control); + control->setIcon(Icons::RUN_SMALL_TOOLBAR); + control->setDisplayName(QString("Run on %1") + .arg(iosdevice ? iosdevice->displayName() : QString())); + return new IosRunner(control); }); addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); addSupportedRunConfig(Constants::IOS_RUNCONFIG_ID); From 62c15f62cfc7cea97c5f72a4c4d8ebbf5c3da1c9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 1 Nov 2024 09:25:35 +0100 Subject: [PATCH 042/989] CppEditor: Get rid of unused FriendlyThread class Change-Id: Id701ef0f3c86c218c2d3af28b77560a051fa1acc Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppchecksymbols.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/plugins/cppeditor/cppchecksymbols.cpp b/src/plugins/cppeditor/cppchecksymbols.cpp index 7fa1ed3f5bd..d62f5bce75b 100644 --- a/src/plugins/cppeditor/cppchecksymbols.cpp +++ b/src/plugins/cppeditor/cppchecksymbols.cpp @@ -24,12 +24,6 @@ namespace CppEditor { namespace { -class FriendlyThread: public QThread -{ -public: - using QThread::msleep; -}; - class CollectSymbols: protected SymbolVisitor { Document::Ptr _doc; From 5651cd5d71635976220261c4fa1bfad418ed4217 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 31 Oct 2024 15:24:02 +0100 Subject: [PATCH 043/989] Core: Replace an include with a declaration Change-Id: I812abba2c32642d21e3e9df248b2ebde6b35378a Reviewed-by: Christian Stenger --- src/plugins/coreplugin/ioutputpane.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/ioutputpane.h b/src/plugins/coreplugin/ioutputpane.h index 35abe881d59..e51f74a6fff 100644 --- a/src/plugins/coreplugin/ioutputpane.h +++ b/src/plugins/coreplugin/ioutputpane.h @@ -4,13 +4,13 @@ #pragma once #include "core_global.h" -#include "icontext.h" #include #include namespace Core { -class IContext; + +class Context; class OutputWindow; class CORE_EXPORT IOutputPane : public QObject From b6907f15d5c2e18c54ac5286ac65d7e585afdfe1 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 31 Oct 2024 09:50:36 +0100 Subject: [PATCH 044/989] Core: Remove direct access to QmlJSEngine in JsExpander Was only used to run evaluate() for which there is a function already. Change-Id: I2738786e37d837955cd8e074efc7ef47ab4267f7 Reviewed-by: Eike Ziller Reviewed-by: Christian Stenger --- src/plugins/coreplugin/jsexpander.cpp | 5 ----- src/plugins/coreplugin/jsexpander.h | 2 -- src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp | 7 +++---- .../projectexplorer/jsonwizard/jsonwizardfactory.cpp | 7 +++---- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/plugins/coreplugin/jsexpander.cpp b/src/plugins/coreplugin/jsexpander.cpp index 2378cbadb49..6ae8eb2bdc4 100644 --- a/src/plugins/coreplugin/jsexpander.cpp +++ b/src/plugins/coreplugin/jsexpander.cpp @@ -64,11 +64,6 @@ QString JsExpander::evaluate(const QString &expression, QString *errorMessage) return QString(); } -QJSEngine &JsExpander::engine() -{ - return d->m_engine; -} - void JsExpander::registerForExpander(Utils::MacroExpander *macroExpander) { macroExpander->registerPrefix( diff --git a/src/plugins/coreplugin/jsexpander.h b/src/plugins/coreplugin/jsexpander.h index f5737588b74..bf984a5fd8e 100644 --- a/src/plugins/coreplugin/jsexpander.h +++ b/src/plugins/coreplugin/jsexpander.h @@ -8,7 +8,6 @@ #include QT_BEGIN_NAMESPACE -class QJSEngine; class QObject; class QString; QT_END_NAMESPACE @@ -41,7 +40,6 @@ public: void registerObject(const QString &name, QObject *obj); QString evaluate(const QString &expression, QString *errorMessage = nullptr); - QJSEngine &engine(); void registerForExpander(Utils::MacroExpander *macroExpander); private: diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp index 95e6b15e4aa..5ee0965e9ec 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -145,9 +144,9 @@ JsonWizard::JsonWizard(QWidget *parent) }); // override default JS macro by custom one that adds Wizard specific features m_jsExpander.registerObject("Wizard", new Internal::JsonWizardJsExtension(this)); - m_jsExpander.engine().evaluate("var value = Wizard.value"); - m_jsExpander.engine().evaluate("var isPluginRunning = Wizard.isPluginRunning"); - m_jsExpander.engine().evaluate("var isAnyPluginRunning = Wizard.isAnyPluginRunning"); + m_jsExpander.evaluate("var value = Wizard.value"); + m_jsExpander.evaluate("var isPluginRunning = Wizard.isPluginRunning"); + m_jsExpander.evaluate("var isAnyPluginRunning = Wizard.isAnyPluginRunning"); m_jsExpander.registerForExpander(&m_expander); } diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index 146b89abcad..0d74f2fbf27 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -809,9 +808,9 @@ bool JsonWizardFactory::isAvailable(Id platformId) const availableFeatures( platformId), pluginFeatures())); - jsExpander.engine().evaluate("var value = Wizard.value"); - jsExpander.engine().evaluate("var isPluginRunning = Wizard.isPluginRunning"); - jsExpander.engine().evaluate("var isAnyPluginRunning = Wizard.isAnyPluginRunning"); + jsExpander.evaluate("var value = Wizard.value"); + jsExpander.evaluate("var isPluginRunning = Wizard.isPluginRunning"); + jsExpander.evaluate("var isAnyPluginRunning = Wizard.isAnyPluginRunning"); jsExpander.registerForExpander(e); return JsonWizard::boolFromVariant(m_enabledExpression, &expander); From a27a4fc4736626be2c2526cc9712da6b36531fea Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 1 Nov 2024 11:56:56 +0100 Subject: [PATCH 045/989] Process: Get rid of process launcher implementation Change-Id: Ief42af62f07fa19667a84b92a263c0330acc2262 Reviewed-by: Marcus Tillmanns Reviewed-by: hjk --- CMakePresets.json | 2 +- src/libs/utils/CMakeLists.txt | 3 - src/libs/utils/launcherinterface.cpp | 207 ------ src/libs/utils/launcherinterface.h | 45 -- src/libs/utils/launcherpackets.cpp | 195 ----- src/libs/utils/launcherpackets.h | 210 ------ src/libs/utils/launchersocket.cpp | 669 ------------------ src/libs/utils/launchersocket.h | 214 ------ src/libs/utils/processenums.h | 7 - src/libs/utils/processinterface.h | 3 - src/libs/utils/qtcprocess.cpp | 162 +---- src/libs/utils/qtcprocess.h | 2 - src/libs/utils/utils.qbs | 6 - src/plugins/docker/dockerdevice.cpp | 1 - .../tests/testmesoninfoparser.cpp | 3 - .../tests/testmesonwrapper.cpp | 3 - src/plugins/remotelinux/linuxdevice.cpp | 2 - src/tools/CMakeLists.txt | 1 - src/tools/processlauncher/CMakeLists.txt | 35 - src/tools/processlauncher/launcherlogging.cpp | 10 - src/tools/processlauncher/launcherlogging.h | 16 - .../processlauncher/launchersockethandler.cpp | 284 -------- .../processlauncher/launchersockethandler.h | 57 -- .../processlauncher/processlauncher-main.cpp | 40 -- src/tools/processlauncher/processlauncher.qbs | 46 -- src/tools/tools.qbs | 1 - .../utils/commandline/tst_commandline.cpp | 7 +- .../utils/deviceshell/tst_deviceshell.cpp | 6 +- .../utils/process/processtestapp/main.cpp | 5 +- tests/auto/utils/process/tst_process.cpp | 21 +- tests/auto/valgrind/memcheck/modeldemo.cpp | 4 - tests/manual/cmdbridge/tst_cmdbridge.cpp | 5 +- tests/manual/deviceshell/tst_deviceshell.cpp | 6 +- .../tst_subdirfilecontainer.cpp | 6 +- tests/unit/tests/unittests/unittests-main.cpp | 3 - 35 files changed, 13 insertions(+), 2274 deletions(-) delete mode 100644 src/libs/utils/launcherinterface.cpp delete mode 100644 src/libs/utils/launcherinterface.h delete mode 100644 src/libs/utils/launcherpackets.cpp delete mode 100644 src/libs/utils/launcherpackets.h delete mode 100644 src/libs/utils/launchersocket.cpp delete mode 100644 src/libs/utils/launchersocket.h delete mode 100644 src/tools/processlauncher/CMakeLists.txt delete mode 100644 src/tools/processlauncher/launcherlogging.cpp delete mode 100644 src/tools/processlauncher/launcherlogging.h delete mode 100644 src/tools/processlauncher/launchersockethandler.cpp delete mode 100644 src/tools/processlauncher/launchersockethandler.h delete mode 100644 src/tools/processlauncher/processlauncher-main.cpp delete mode 100644 src/tools/processlauncher/processlauncher.qbs diff --git a/CMakePresets.json b/CMakePresets.json index 0e4b60e22b7..b859e1ac4ef 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -8,7 +8,7 @@ "hidden" : true, "cacheVariables": { "BUILD_PLUGINS": "Core;Designer;DiffEditor;TextEditor;ProjectExplorer;CppEditor;CodePaster;Docker;Git;Help;QmakeProjectManager;CMakeProjectManager;ClangCodeModel;ClangTools;ClangFormat;Debugger;QtSupport;ResourceEditor;VcsBase;Welcome;LanguageClient;RemoteLinux", - "BUILD_EXECUTABLES": "QtCreator;qtcreator_ctrlc_stub;qtcreator_process_stub;win64interrupt;qtcreator_processlauncher", + "BUILD_EXECUTABLES": "QtCreator;qtcreator_ctrlc_stub;qtcreator_process_stub;win64interrupt", "WITH_QMLDESIGNER": "OFF" } } diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index f1f730dd389..c8a5f84196c 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -90,9 +90,6 @@ add_qtc_library(Utils infolabel.cpp infolabel.h itemviews.cpp itemviews.h jsontreeitem.cpp jsontreeitem.h - launcherinterface.cpp launcherinterface.h - launcherpackets.cpp launcherpackets.h - launchersocket.cpp launchersocket.h layoutbuilder.cpp layoutbuilder.h link.cpp link.h listmodel.h diff --git a/src/libs/utils/launcherinterface.cpp b/src/libs/utils/launcherinterface.cpp deleted file mode 100644 index d188e224fc1..00000000000 --- a/src/libs/utils/launcherinterface.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "launcherinterface.h" - -#include "filepath.h" -#include "launchersocket.h" -#include "qtcassert.h" -#include "temporarydirectory.h" -#include "utilstr.h" - -#include -#include -#include -#include - -#ifdef Q_OS_UNIX -#include -#endif - -namespace Utils { -namespace Internal { - -static QString launcherSocketName() -{ - return TemporaryDirectory::masterDirectoryPath() - + QStringLiteral("/launcher-%1").arg(QString::number(qApp->applicationPid())); -} - -class LauncherInterfacePrivate : public QObject -{ - Q_OBJECT -public: - LauncherInterfacePrivate(); - ~LauncherInterfacePrivate() override; - - void doStart(); - void doStop(); - void handleNewConnection(); - void handleProcessError(); - void handleProcessFinished(); - void handleProcessStderr(); - Internal::LauncherSocket *socket() const { return m_socket; } - - void setPathToLauncher(const QString &path) { if (!path.isEmpty()) m_pathToLauncher = path; } - QString launcherFilePath() const { return m_pathToLauncher + QLatin1String("/qtcreator_processlauncher"); } -signals: - void errorOccurred(const QString &error); - -private: - QLocalServer * const m_server; - Internal::LauncherSocket *const m_socket; - QProcess *m_process = nullptr; - QString m_pathToLauncher; -}; - -LauncherInterfacePrivate::LauncherInterfacePrivate() - : m_server(new QLocalServer(this)), m_socket(new LauncherSocket(this)) -{ - m_pathToLauncher = qApp->applicationDirPath() + '/' + QLatin1String(RELATIVE_LIBEXEC_PATH); - QObject::connect(m_server, &QLocalServer::newConnection, - this, &LauncherInterfacePrivate::handleNewConnection); -} - -LauncherInterfacePrivate::~LauncherInterfacePrivate() -{ - m_server->disconnect(); -} - -void LauncherInterfacePrivate::doStart() -{ - const QString &socketName = launcherSocketName(); - QLocalServer::removeServer(socketName); - if (!m_server->listen(socketName)) { - emit errorOccurred(m_server->errorString()); - return; - } - m_process = new QProcess(this); - connect(m_process, &QProcess::errorOccurred, this, &LauncherInterfacePrivate::handleProcessError); - connect(m_process, &QProcess::finished, - this, &LauncherInterfacePrivate::handleProcessFinished); - connect(m_process, &QProcess::readyReadStandardError, - this, &LauncherInterfacePrivate::handleProcessStderr); -#ifdef Q_OS_UNIX -# if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) - m_process->setUnixProcessParameters(QProcess::UnixProcessFlag::CreateNewSession); -# else - m_process->setChildProcessModifier([] { - setpgid(0, 0); - }); -# endif -#endif - - m_process->start(launcherFilePath(), QStringList(m_server->fullServerName())); -} - -void LauncherInterfacePrivate::doStop() -{ - m_server->close(); - QTC_ASSERT(m_process, return); - m_socket->shutdown(); - m_process->waitForFinished(-1); // Let the process interface finish so that it finishes - // reaping any possible processes it has started. - delete m_process; - m_process = nullptr; -} - -void LauncherInterfacePrivate::handleNewConnection() -{ - QLocalSocket * const socket = m_server->nextPendingConnection(); - if (!socket) - return; - m_server->close(); - m_socket->setSocket(socket); -} - -void LauncherInterfacePrivate::handleProcessError() -{ - if (m_process->error() == QProcess::FailedToStart) { - const QString launcherPathForUser - = QDir::toNativeSeparators(QDir::cleanPath(m_process->program())); - emit errorOccurred(Tr::tr("Failed to start process launcher at \"%1\": %2") - .arg(launcherPathForUser, m_process->errorString())); - } -} - -void LauncherInterfacePrivate::handleProcessFinished() -{ - emit errorOccurred(Tr::tr("Process launcher closed unexpectedly: %1") - .arg(m_process->errorString())); -} - -void LauncherInterfacePrivate::handleProcessStderr() -{ - qDebug() << "[launcher]" << m_process->readAllStandardError(); -} - -} // namespace Internal - -using namespace Utils::Internal; - -static QMutex s_instanceMutex; -static QString s_pathToLauncher; -static std::atomic_bool s_started = false; - -LauncherInterface::LauncherInterface() - : m_private(new LauncherInterfacePrivate()) -{ - m_private->moveToThread(&m_thread); - QObject::connect(&m_thread, &QThread::finished, m_private, &QObject::deleteLater); - m_thread.start(); - m_thread.moveToThread(qApp->thread()); - - m_private->setPathToLauncher(s_pathToLauncher); - const FilePath launcherFilePath = FilePath::fromString(m_private->launcherFilePath()) - .cleanPath().withExecutableSuffix(); - auto launcherIsNotExecutable = [&launcherFilePath] { - qWarning() << "The Creator's process launcher" - << launcherFilePath << "is not executable."; - }; - QTC_ASSERT(launcherFilePath.isExecutableFile(), launcherIsNotExecutable(); return); - s_started = true; - // Call in launcher's thread. - QMetaObject::invokeMethod(m_private, &LauncherInterfacePrivate::doStart); -} - -LauncherInterface::~LauncherInterface() -{ - QMutexLocker locker(&s_instanceMutex); - LauncherInterfacePrivate *p = instance()->m_private; - // Call in launcher's thread. - QMetaObject::invokeMethod(p, &LauncherInterfacePrivate::doStop, Qt::BlockingQueuedConnection); - m_thread.quit(); - m_thread.wait(); -} - -void LauncherInterface::setPathToLauncher(const QString &pathToLauncher) -{ - s_pathToLauncher = pathToLauncher; -} - -bool LauncherInterface::isStarted() -{ - return s_started; -} - -void LauncherInterface::sendData(const QByteArray &data) -{ - QMutexLocker locker(&s_instanceMutex); - instance()->m_private->socket()->sendData(data); -} - -Internal::CallerHandle *LauncherInterface::registerHandle(QObject *parent, quintptr token) -{ - QMutexLocker locker(&s_instanceMutex); - return instance()->m_private->socket()->registerHandle(parent, token); -} - -void LauncherInterface::unregisterHandle(quintptr token) -{ - QMutexLocker locker(&s_instanceMutex); - instance()->m_private->socket()->unregisterHandle(token); -} - -} // namespace Utils - -#include "launcherinterface.moc" diff --git a/src/libs/utils/launcherinterface.h b/src/libs/utils/launcherinterface.h deleted file mode 100644 index 71d6c7977ac..00000000000 --- a/src/libs/utils/launcherinterface.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "utils_global.h" - -#include "processreaper.h" -#include "singleton.h" - -#include - -namespace Utils { -namespace Internal { -class CallerHandle; -class LauncherHandle; -class LauncherInterfacePrivate; -class ProcessLauncherImpl; -} - -class QTCREATOR_UTILS_EXPORT LauncherInterface final - : public SingletonWithOptionalDependencies -{ -public: - static void setPathToLauncher(const QString &pathToLauncher); - -private: - friend class Internal::CallerHandle; - friend class Internal::LauncherHandle; - friend class Internal::ProcessLauncherImpl; - - static bool isStarted(); - static void sendData(const QByteArray &data); - static Internal::CallerHandle *registerHandle(QObject *parent, quintptr token); - static void unregisterHandle(quintptr token); - - LauncherInterface(); - ~LauncherInterface(); - - QThread m_thread; - Internal::LauncherInterfacePrivate *m_private; - friend class SingletonWithOptionalDependencies; -}; - -} // namespace Utils diff --git a/src/libs/utils/launcherpackets.cpp b/src/libs/utils/launcherpackets.cpp deleted file mode 100644 index a770e8865da..00000000000 --- a/src/libs/utils/launcherpackets.cpp +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "launcherpackets.h" - -#include - -namespace Utils { -namespace Internal { - -LauncherPacket::~LauncherPacket() = default; - -QByteArray LauncherPacket::serialize() const -{ - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << static_cast(0) << static_cast(type) << token; - doSerialize(stream); - stream.device()->reset(); - stream << static_cast(data.size() - sizeof(int)); - return data; -} - -void LauncherPacket::deserialize(const QByteArray &data) -{ - QDataStream stream(data); - doDeserialize(stream); -} - - -StartProcessPacket::StartProcessPacket(quintptr token) - : LauncherPacket(LauncherPacketType::StartProcess, token) -{ -} - -void StartProcessPacket::doSerialize(QDataStream &stream) const -{ - stream << command - << arguments - << workingDir - << env - << int(processMode) - << writeData - << int(processChannelMode) - << standardInputFile - << belowNormalPriority - << nativeArguments - << lowPriority - << unixTerminalDisabled - << useCtrlCStub - << reaperTimeout - << createConsoleOnWindows - << forceDefaultErrorMode; -} - -void StartProcessPacket::doDeserialize(QDataStream &stream) -{ - int processModeInt; - int processChannelModeInt; - stream >> command - >> arguments - >> workingDir - >> env - >> processModeInt - >> writeData - >> processChannelModeInt - >> standardInputFile - >> belowNormalPriority - >> nativeArguments - >> lowPriority - >> unixTerminalDisabled - >> useCtrlCStub - >> reaperTimeout - >> createConsoleOnWindows - >> forceDefaultErrorMode; - processMode = Utils::ProcessMode(processModeInt); - processChannelMode = QProcess::ProcessChannelMode(processChannelModeInt); -} - - -ProcessStartedPacket::ProcessStartedPacket(quintptr token) - : LauncherPacket(LauncherPacketType::ProcessStarted, token) -{ -} - -void ProcessStartedPacket::doSerialize(QDataStream &stream) const -{ - stream << processId; -} - -void ProcessStartedPacket::doDeserialize(QDataStream &stream) -{ - stream >> processId; -} - - -ControlProcessPacket::ControlProcessPacket(quintptr token) - : LauncherPacket(LauncherPacketType::ControlProcess, token) -{ -} - -void ControlProcessPacket::doSerialize(QDataStream &stream) const -{ - stream << int(signalType); -} - -void ControlProcessPacket::doDeserialize(QDataStream &stream) -{ - int signalTypeInt; - stream >> signalTypeInt; - signalType = SignalType(signalTypeInt); -} - -void WritePacket::doSerialize(QDataStream &stream) const -{ - stream << inputData; -} - -void WritePacket::doDeserialize(QDataStream &stream) -{ - stream >> inputData; -} - -void ReadyReadPacket::doSerialize(QDataStream &stream) const -{ - stream << standardChannel; -} - -void ReadyReadPacket::doDeserialize(QDataStream &stream) -{ - stream >> standardChannel; -} - - -ProcessDonePacket::ProcessDonePacket(quintptr token) - : LauncherPacket(LauncherPacketType::ProcessDone, token) -{ -} - -void ProcessDonePacket::doSerialize(QDataStream &stream) const -{ - stream << exitCode - << int(exitStatus) - << int(error) - << errorString - << stdOut - << stdErr; -} - -void ProcessDonePacket::doDeserialize(QDataStream &stream) -{ - int exitStatusInt, errorInt; - stream >> exitCode - >> exitStatusInt - >> errorInt - >> errorString - >> stdOut - >> stdErr; - exitStatus = QProcess::ExitStatus(exitStatusInt); - error = QProcess::ProcessError(errorInt); -} - -ShutdownPacket::ShutdownPacket() : LauncherPacket(LauncherPacketType::Shutdown, 0) { } -void ShutdownPacket::doSerialize(QDataStream &stream) const { Q_UNUSED(stream); } -void ShutdownPacket::doDeserialize(QDataStream &stream) { Q_UNUSED(stream); } - -void PacketParser::setDevice(QIODevice *device) -{ - m_stream.setDevice(device); - m_sizeOfNextPacket = -1; -} - -bool PacketParser::parse() -{ - static const int commonPayloadSize = static_cast(1 + sizeof(quintptr)); - if (m_sizeOfNextPacket == -1) { - if (m_stream.device()->bytesAvailable() < static_cast(sizeof m_sizeOfNextPacket)) - return false; - m_stream >> m_sizeOfNextPacket; - if (m_sizeOfNextPacket < commonPayloadSize) - throw InvalidPacketSizeException(m_sizeOfNextPacket); - } - if (m_stream.device()->bytesAvailable() < m_sizeOfNextPacket) - return false; - quint8 type; - m_stream >> type; - m_type = static_cast(type); - m_stream >> m_token; - m_packetData = m_stream.device()->read(m_sizeOfNextPacket - commonPayloadSize); - m_sizeOfNextPacket = -1; - return true; -} - -} // namespace Internal -} // namespace Utils diff --git a/src/libs/utils/launcherpackets.h b/src/libs/utils/launcherpackets.h deleted file mode 100644 index d00169c1f6f..00000000000 --- a/src/libs/utils/launcherpackets.h +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "processenums.h" - -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QByteArray; -QT_END_NAMESPACE - -namespace Utils { -namespace Internal { - -enum class LauncherPacketType { - // client -> launcher packets: - Shutdown, - StartProcess, - WriteIntoProcess, - ControlProcess, - // launcher -> client packets: - ProcessStarted, - ReadyReadStandardOutput, - ReadyReadStandardError, - ProcessDone -}; - -class PacketParser -{ -public: - class InvalidPacketSizeException - { - public: - InvalidPacketSizeException(int size) : size(size) { } - const int size; - }; - - void setDevice(QIODevice *device); - bool parse(); - LauncherPacketType type() const { return m_type; } - quintptr token() const { return m_token; } - const QByteArray &packetData() const { return m_packetData; } - -private: - QDataStream m_stream; - LauncherPacketType m_type = LauncherPacketType::Shutdown; - quintptr m_token = 0; - QByteArray m_packetData; - int m_sizeOfNextPacket = -1; -}; - -class LauncherPacket -{ -public: - virtual ~LauncherPacket(); - - template static Packet extractPacket(quintptr token, const QByteArray &data) - { - Packet p(token); - p.deserialize(data); - return p; - } - - QByteArray serialize() const; - void deserialize(const QByteArray &data); - - const LauncherPacketType type; - const quintptr token = 0; - -protected: - LauncherPacket(LauncherPacketType type, quintptr token) : type(type), token(token) { } - -private: - virtual void doSerialize(QDataStream &stream) const = 0; - virtual void doDeserialize(QDataStream &stream) = 0; -}; - -class StartProcessPacket : public LauncherPacket -{ -public: - StartProcessPacket(quintptr token); - - QString command; - QStringList arguments; - QString workingDir; - QStringList env; - ProcessMode processMode = ProcessMode::Reader; - QByteArray writeData; - QProcess::ProcessChannelMode processChannelMode = QProcess::SeparateChannels; - QString standardInputFile; - bool belowNormalPriority = false; - QString nativeArguments; - bool lowPriority = false; - bool unixTerminalDisabled = false; - bool useCtrlCStub = false; - int reaperTimeout = 500; - bool createConsoleOnWindows = false; - bool forceDefaultErrorMode = false; - -private: - void doSerialize(QDataStream &stream) const override; - void doDeserialize(QDataStream &stream) override; -}; - -class ProcessStartedPacket : public LauncherPacket -{ -public: - ProcessStartedPacket(quintptr token); - - int processId = 0; - -private: - void doSerialize(QDataStream &stream) const override; - void doDeserialize(QDataStream &stream) override; -}; - -class ControlProcessPacket : public LauncherPacket -{ -public: - ControlProcessPacket(quintptr token); - - enum class SignalType { - Kill, // Calls QProcess::kill - Terminate, // Calls QProcess::terminate - Close, // Puts the process into the reaper, no confirmation signal is being sent. - CloseWriteChannel - }; - - SignalType signalType = SignalType::Kill; - -private: - void doSerialize(QDataStream &stream) const override; - void doDeserialize(QDataStream &stream) override; -}; - -class WritePacket : public LauncherPacket -{ -public: - WritePacket(quintptr token) : LauncherPacket(LauncherPacketType::WriteIntoProcess, token) { } - - QByteArray inputData; - -private: - void doSerialize(QDataStream &stream) const override; - void doDeserialize(QDataStream &stream) override; -}; - -class ShutdownPacket : public LauncherPacket -{ -public: - ShutdownPacket(); - -private: - void doSerialize(QDataStream &stream) const override; - void doDeserialize(QDataStream &stream) override; -}; - -class ReadyReadPacket : public LauncherPacket -{ -public: - QByteArray standardChannel; - -protected: - ReadyReadPacket(LauncherPacketType type, quintptr token) : LauncherPacket(type, token) { } - -private: - void doSerialize(QDataStream &stream) const override; - void doDeserialize(QDataStream &stream) override; -}; - -class ReadyReadStandardOutputPacket : public ReadyReadPacket -{ -public: - ReadyReadStandardOutputPacket(quintptr token) - : ReadyReadPacket(LauncherPacketType::ReadyReadStandardOutput, token) { } -}; - -class ReadyReadStandardErrorPacket : public ReadyReadPacket -{ -public: - ReadyReadStandardErrorPacket(quintptr token) - : ReadyReadPacket(LauncherPacketType::ReadyReadStandardError, token) { } -}; - -class ProcessDonePacket : public LauncherPacket -{ -public: - ProcessDonePacket(quintptr token); - - QByteArray stdOut; - QByteArray stdErr; - - int exitCode = 0; - QProcess::ExitStatus exitStatus = QProcess::NormalExit; - QProcess::ProcessError error = QProcess::UnknownError; - QString errorString; - -private: - void doSerialize(QDataStream &stream) const override; - void doDeserialize(QDataStream &stream) override; -}; - -} // namespace Internal -} // namespace Utils - -Q_DECLARE_METATYPE(Utils::Internal::LauncherPacketType); diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp deleted file mode 100644 index 61796a2bb3d..00000000000 --- a/src/libs/utils/launchersocket.cpp +++ /dev/null @@ -1,669 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "launchersocket.h" - -#include "algorithm.h" -#include "launcherinterface.h" -#include "qtcassert.h" -#include "utilstr.h" - -#include -#include - -namespace Utils { -namespace Internal { - -class LauncherSignal -{ -public: - CallerHandle::SignalType signalType() const { return m_signalType; } - virtual ~LauncherSignal() = default; -protected: - LauncherSignal(CallerHandle::SignalType signalType) : m_signalType(signalType) {} -private: - const CallerHandle::SignalType m_signalType; -}; - -class LauncherStartedSignal : public LauncherSignal -{ -public: - LauncherStartedSignal(int processId) - : LauncherSignal(CallerHandle::SignalType::Started) - , m_processId(processId) {} - int processId() const { return m_processId; } -private: - const int m_processId; -}; - -class LauncherReadyReadSignal : public LauncherSignal -{ -public: - LauncherReadyReadSignal(const QByteArray &stdOut, const QByteArray &stdErr) - : LauncherSignal(CallerHandle::SignalType::ReadyRead) - , m_stdOut(stdOut) - , m_stdErr(stdErr) {} - QByteArray stdOut() const { return m_stdOut; } - QByteArray stdErr() const { return m_stdErr; } - -private: - QByteArray m_stdOut; - QByteArray m_stdErr; -}; - -class LauncherDoneSignal : public LauncherSignal -{ -public: - LauncherDoneSignal(const ProcessResultData &resultData) - : LauncherSignal(CallerHandle::SignalType::Done) - , m_resultData(resultData) {} - ProcessResultData resultData() const { return m_resultData; } -private: - const ProcessResultData m_resultData; -}; - -CallerHandle::~CallerHandle() -{ - qDeleteAll(m_signals); -} - -void CallerHandle::flush() -{ - flushFor(SignalType::NoSignal); -} - -bool CallerHandle::flushFor(SignalType signalType) -{ - QTC_ASSERT(isCalledFromCallersThread(), return {}); - QList oldSignals; - { - QMutexLocker locker(&m_mutex); - const QList storedSignals = - Utils::transform(std::as_const(m_signals), [](const LauncherSignal *launcherSignal) { - return launcherSignal->signalType(); - }); - - // If we are flushing for ReadyRead or Done - flush all. - // If we are flushing for Started: - // - if Started was buffered - flush Started only. - // - otherwise if Done signal was buffered - flush all. - const bool flushAll = (signalType != SignalType::Started) - || (!storedSignals.contains(SignalType::Started) - && storedSignals.contains(SignalType::Done)); - if (flushAll) { - oldSignals = m_signals; - m_signals = {}; - } else { - auto matchingIndex = storedSignals.lastIndexOf(signalType); - if (matchingIndex >= 0) { - oldSignals = m_signals.mid(0, matchingIndex + 1); - m_signals = m_signals.mid(matchingIndex + 1); - } - } - } - bool signalMatched = false; - for (const LauncherSignal *storedSignal : std::as_const(oldSignals)) { - const SignalType storedSignalType = storedSignal->signalType(); - if (storedSignalType == signalType) - signalMatched = true; - switch (storedSignalType) { - case SignalType::NoSignal: - break; - case SignalType::Started: - handleStarted(static_cast(storedSignal)); - break; - case SignalType::ReadyRead: - handleReadyRead(static_cast(storedSignal)); - break; - case SignalType::Done: - signalMatched = true; - handleDone(static_cast(storedSignal)); - break; - } - delete storedSignal; - } - return signalMatched; -} - -// Called from caller's thread exclusively. -bool CallerHandle::shouldFlush() const -{ - QTC_ASSERT(isCalledFromCallersThread(), return false); - QMutexLocker locker(&m_mutex); - return !m_signals.isEmpty(); -} - -void CallerHandle::handleStarted(const LauncherStartedSignal *launcherSignal) -{ - QTC_ASSERT(isCalledFromCallersThread(), return); - m_processState = QProcess::Running; - m_processId = launcherSignal->processId(); - emit started(m_processId); -} - -void CallerHandle::handleReadyRead(const LauncherReadyReadSignal *launcherSignal) -{ - QTC_ASSERT(isCalledFromCallersThread(), return); - emit readyRead(launcherSignal->stdOut(), launcherSignal->stdErr()); -} - -void CallerHandle::handleDone(const LauncherDoneSignal *launcherSignal) -{ - QTC_ASSERT(isCalledFromCallersThread(), return); - m_processState = QProcess::NotRunning; - emit done(launcherSignal->resultData()); - m_processId = 0; -} - -// Called from launcher's thread exclusively. -void CallerHandle::appendSignal(LauncherSignal *newSignal) -{ - QTC_ASSERT(!isCalledFromCallersThread(), return); - QTC_ASSERT(newSignal->signalType() != SignalType::NoSignal, delete newSignal; return); - - QMutexLocker locker(&m_mutex); - QTC_ASSERT(isCalledFromLaunchersThread(), return); - m_signals.append(newSignal); -} - -QProcess::ProcessState CallerHandle::state() const -{ - return m_processState; -} - -void CallerHandle::sendControlPacket(ControlProcessPacket::SignalType signalType) -{ - if (m_processState == QProcess::NotRunning) - return; - - // TODO: In case m_processState == QProcess::Starting and the launcher socket isn't ready yet - // we might want to remove posted start packet and finish the process immediately. - // In addition, we may always try to check if correspodning start packet for the m_token - // is still awaiting and do the same (remove the packet from the stack and finish immediately). - ControlProcessPacket packet(m_token); - packet.signalType = signalType; - sendPacket(packet); -} - -void CallerHandle::terminate() -{ - QTC_ASSERT(isCalledFromCallersThread(), return); - sendControlPacket(ControlProcessPacket::SignalType::Terminate); -} - -void CallerHandle::kill() -{ - QTC_ASSERT(isCalledFromCallersThread(), return); - sendControlPacket(ControlProcessPacket::SignalType::Kill); -} - -void CallerHandle::close() -{ - QTC_ASSERT(isCalledFromCallersThread(), return); - sendControlPacket(ControlProcessPacket::SignalType::Close); -} - -void CallerHandle::closeWriteChannel() -{ - QTC_ASSERT(isCalledFromCallersThread(), return); - sendControlPacket(ControlProcessPacket::SignalType::CloseWriteChannel); -} - -qint64 CallerHandle::processId() const -{ - QTC_ASSERT(isCalledFromCallersThread(), return 0); - return m_processId; -} - -void CallerHandle::start(const QString &program, const QStringList &arguments) -{ - QTC_ASSERT(isCalledFromCallersThread(), return); - if (!m_launcherHandle || m_launcherHandle->isSocketError()) { - const QString errorString = Tr::tr("Process launcher socket error."); - const ProcessResultData result = { 0, QProcess::NormalExit, QProcess::FailedToStart, - errorString }; - emit done(result); - return; - } - - auto startWhenRunning = [&program, &oldProgram = m_command] { - qWarning() << "Trying to start" << program << "while" << oldProgram - << "is still running for the same Process instance." - << "The current call will be ignored."; - }; - QTC_ASSERT(m_processState == QProcess::NotRunning, startWhenRunning(); return); - - auto processLauncherNotStarted = [&program] { - qWarning() << "Trying to start" << program << "while process launcher wasn't started yet."; - }; - QTC_ASSERT(LauncherInterface::isStarted(), processLauncherNotStarted()); - - QMutexLocker locker(&m_mutex); - m_command = program; - m_arguments = arguments; - m_processState = QProcess::Starting; - StartProcessPacket p(m_token); - p.command = m_command; - p.arguments = m_arguments; - p.env = m_setup->m_environment.toStringList(); - if (p.env.isEmpty()) - p.env = Environment::systemEnvironment().toStringList(); - p.workingDir = m_setup->m_workingDirectory.path(); - p.processMode = m_setup->m_processMode; - p.writeData = m_setup->m_writeData; - p.processChannelMode = m_setup->m_processChannelMode; - p.standardInputFile = m_setup->m_standardInputFile; - p.belowNormalPriority = m_setup->m_belowNormalPriority; - p.nativeArguments = m_setup->m_nativeArguments; - p.lowPriority = m_setup->m_lowPriority; - p.unixTerminalDisabled = m_setup->m_unixTerminalDisabled; - p.useCtrlCStub = m_setup->m_useCtrlCStub; - p.reaperTimeout = m_setup->m_reaperTimeout.count(); - p.createConsoleOnWindows = m_setup->m_createConsoleOnWindows; - p.forceDefaultErrorMode = m_setup->m_forceDefaultErrorMode; - sendPacket(p); -} - -// Called from caller's thread exclusively. -void CallerHandle::sendPacket(const Internal::LauncherPacket &packet) -{ - LauncherInterface::sendData(packet.serialize()); -} - -qint64 CallerHandle::write(const QByteArray &data) -{ - QTC_ASSERT(isCalledFromCallersThread(), return -1); - - if (m_processState != QProcess::Running) - return -1; - - WritePacket p(m_token); - p.inputData = data; - sendPacket(p); - return data.size(); -} - -QString CallerHandle::program() const -{ - QMutexLocker locker(&m_mutex); - return m_command; -} - -QStringList CallerHandle::arguments() const -{ - QMutexLocker locker(&m_mutex); - return m_arguments; -} - -void CallerHandle::setProcessSetupData(ProcessSetupData *setup) -{ - QTC_ASSERT(isCalledFromCallersThread(), return); - m_setup = setup; -} - -bool CallerHandle::waitForSignal(SignalType signalType, QDeadlineTimer timeout) -{ - QTC_ASSERT(isCalledFromCallersThread(), return false); - QTC_ASSERT(m_launcherHandle, return false); - return m_launcherHandle->waitForSignal(signalType, timeout); -} - -// Called from caller's or launcher's thread. -bool CallerHandle::isCalledFromCallersThread() const -{ - return QThread::currentThread() == thread(); -} - -// Called from caller's or launcher's thread. Call me with mutex locked. -bool CallerHandle::isCalledFromLaunchersThread() const -{ - if (!m_launcherHandle) - return false; - return QThread::currentThread() == m_launcherHandle->thread(); -} - -// Called from caller's thread exclusively. -bool LauncherHandle::waitForSignal(CallerHandle::SignalType newSignal, QDeadlineTimer timeout) -{ - QTC_ASSERT(!isCalledFromLaunchersThread(), return false); - while (true) { - if (timeout.hasExpired()) - break; - if (!doWaitForSignal(timeout)) - break; - // Matching (or Done) signal was flushed - if (m_callerHandle->flushFor(newSignal)) - return true; - // Otherwise continue awaiting (e.g. when ReadyRead came while waitForFinished()) - } - return false; -} - -// Called from caller's thread exclusively. -bool LauncherHandle::doWaitForSignal(QDeadlineTimer deadline) -{ - QMutexLocker locker(&m_mutex); - QTC_ASSERT(isCalledFromCallersThread(), return false); - - // Flush, if we have any stored signals. - // This must be called when holding laucher's mutex locked prior to the call to wait, - // so that it's done atomically. - if (m_callerHandle->shouldFlush()) - return true; - - return m_waitCondition.wait(&m_mutex, deadline); -} - -// Called from launcher's thread exclusively. Call me with mutex locked. -void LauncherHandle::flushCaller() -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - if (!m_callerHandle) - return; - - m_waitCondition.wakeOne(); - - // call in callers thread - QMetaObject::invokeMethod(m_callerHandle, &CallerHandle::flush); -} - -void LauncherHandle::handlePacket(LauncherPacketType type, const QByteArray &payload) -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - switch (type) { - case LauncherPacketType::ProcessStarted: - handleStartedPacket(payload); - break; - case LauncherPacketType::ReadyReadStandardOutput: - handleReadyReadStandardOutput(payload); - break; - case LauncherPacketType::ReadyReadStandardError: - handleReadyReadStandardError(payload); - break; - case LauncherPacketType::ProcessDone: - handleDonePacket(payload); - break; - default: - QTC_ASSERT(false, break); - } -} - -void LauncherHandle::handleStartedPacket(const QByteArray &packetData) -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - QMutexLocker locker(&m_mutex); - if (!m_callerHandle) - return; - - const auto packet = LauncherPacket::extractPacket(m_token, packetData); - m_callerHandle->appendSignal(new LauncherStartedSignal(packet.processId)); - flushCaller(); -} - -void LauncherHandle::handleReadyReadStandardOutput(const QByteArray &packetData) -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - QMutexLocker locker(&m_mutex); - if (!m_callerHandle) - return; - - const auto packet = LauncherPacket::extractPacket(m_token, packetData); - if (packet.standardChannel.isEmpty()) - return; - - m_callerHandle->appendSignal(new LauncherReadyReadSignal(packet.standardChannel, {})); - flushCaller(); -} - -void LauncherHandle::handleReadyReadStandardError(const QByteArray &packetData) -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - QMutexLocker locker(&m_mutex); - if (!m_callerHandle) - return; - - const auto packet = LauncherPacket::extractPacket(m_token, packetData); - if (packet.standardChannel.isEmpty()) - return; - - m_callerHandle->appendSignal(new LauncherReadyReadSignal({}, packet.standardChannel)); - flushCaller(); -} - -void LauncherHandle::handleDonePacket(const QByteArray &packetData) -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - QMutexLocker locker(&m_mutex); - if (!m_callerHandle) - return; - - const auto packet = LauncherPacket::extractPacket(m_token, packetData); - const QByteArray stdOut = packet.stdOut; - const QByteArray stdErr = packet.stdErr; - const ProcessResultData result = { packet.exitCode, packet.exitStatus, - packet.error, packet.errorString }; - - if (!stdOut.isEmpty() || !stdErr.isEmpty()) - m_callerHandle->appendSignal(new LauncherReadyReadSignal(stdOut, stdErr)); - m_callerHandle->appendSignal(new LauncherDoneSignal(result)); - flushCaller(); -} - -void LauncherHandle::handleSocketError(const QString &message) -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - m_socketError = true; // TODO: ??? - QMutexLocker locker(&m_mutex); - if (!m_callerHandle) - return; - - // TODO: FailedToStart may be wrong in case process has already started - const QString errorString = Tr::tr("Internal socket error: %1").arg(message); - const ProcessResultData result = { 0, QProcess::NormalExit, QProcess::FailedToStart, - errorString }; - m_callerHandle->appendSignal(new LauncherDoneSignal(result)); - flushCaller(); -} - -bool LauncherHandle::isCalledFromLaunchersThread() const -{ - return QThread::currentThread() == thread(); -} - -// call me with mutex locked -bool LauncherHandle::isCalledFromCallersThread() const -{ - if (!m_callerHandle) - return false; - return QThread::currentThread() == m_callerHandle->thread(); -} - -LauncherSocket::LauncherSocket(QObject *parent) : QObject(parent) -{ - qRegisterMetaType(); - qRegisterMetaType("quintptr"); -} - -LauncherSocket::~LauncherSocket() -{ - QMutexLocker locker(&m_mutex); - auto displayHandles = [&handles = m_handles] { - qWarning() << "Destroying process launcher while" << handles.count() - << "processes are still alive. The following processes are still alive:"; - for (LauncherHandle *handle : handles) { - CallerHandle *callerHandle = handle->callerHandle(); - if (callerHandle->state() != QProcess::NotRunning) { - qWarning() << " " << callerHandle->program() << callerHandle->arguments() - << "in thread" << (void *)callerHandle->thread(); - } else { - qWarning() << " Not running process in thread" << (void *)callerHandle->thread(); - } - } - }; - QTC_ASSERT(m_handles.isEmpty(), displayHandles()); -} - -void LauncherSocket::sendData(const QByteArray &data) -{ - auto storeRequest = [this](const QByteArray &data) - { - QMutexLocker locker(&m_mutex); - m_requests.push_back(data); - return m_requests.size() == 1; // Returns true if requests handling should be triggered. - }; - - if (storeRequest(data)) // Call handleRequests() in launcher's thread. - QMetaObject::invokeMethod(this, &LauncherSocket::handleRequests); -} - -CallerHandle *LauncherSocket::registerHandle(QObject *parent, quintptr token) -{ - QTC_ASSERT(!isCalledFromLaunchersThread(), return nullptr); - QMutexLocker locker(&m_mutex); - if (m_handles.contains(token)) - return nullptr; // TODO: issue a warning - - CallerHandle *callerHandle = new CallerHandle(parent, token); - LauncherHandle *launcherHandle = new LauncherHandle(token); - callerHandle->setLauncherHandle(launcherHandle); - launcherHandle->setCallerHandle(callerHandle); - launcherHandle->moveToThread(thread()); - // Call it after moving LauncherHandle to the launcher's thread. - // Since this method is invoked from caller's thread, CallerHandle will live in caller's thread. - m_handles.insert(token, launcherHandle); - connect(this, &LauncherSocket::errorOccurred, - launcherHandle, &LauncherHandle::handleSocketError); - - return callerHandle; -} - -void LauncherSocket::unregisterHandle(quintptr token) -{ - QTC_ASSERT(!isCalledFromLaunchersThread(), return); - QMutexLocker locker(&m_mutex); - auto it = m_handles.constFind(token); - if (it == m_handles.constEnd()) - return; // TODO: issue a warning - - LauncherHandle *launcherHandle = it.value(); - CallerHandle *callerHandle = launcherHandle->callerHandle(); - launcherHandle->setCallerHandle(nullptr); - callerHandle->setLauncherHandle(nullptr); - launcherHandle->deleteLater(); - callerHandle->deleteLater(); - m_handles.erase(it); -} - -LauncherHandle *LauncherSocket::handleForToken(quintptr token) const -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return nullptr); - QMutexLocker locker(&m_mutex); - return m_handles.value(token); -} - -void LauncherSocket::setSocket(QLocalSocket *socket) -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - QTC_ASSERT(!m_socket, return); - m_socket.store(socket); - m_packetParser.setDevice(m_socket); - connect(m_socket, &QLocalSocket::errorOccurred, - this, &LauncherSocket::handleSocketError); - connect(m_socket, &QLocalSocket::readyRead, - this, &LauncherSocket::handleSocketDataAvailable); - connect(m_socket, &QLocalSocket::disconnected, - this, &LauncherSocket::handleSocketDisconnected); - handleRequests(); -} - -void LauncherSocket::shutdown() -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - const auto socket = m_socket.exchange(nullptr); - if (!socket) - return; - socket->disconnect(); - socket->write(ShutdownPacket().serialize()); - socket->waitForBytesWritten(1000); - socket->deleteLater(); // or schedule a queued call to delete later? -} - -void LauncherSocket::handleSocketError() -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - auto socket = m_socket.load(); - if (socket->error() != QLocalSocket::PeerClosedError) - handleError(Tr::tr("Socket error: %1").arg(socket->errorString())); -} - -void LauncherSocket::handleSocketDataAvailable() -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - try { - if (!m_packetParser.parse()) - return; - } catch (const PacketParser::InvalidPacketSizeException &e) { - handleError(Tr::tr("Internal protocol error: invalid packet size %1.").arg(e.size)); - return; - } - LauncherHandle *handle = handleForToken(m_packetParser.token()); - if (handle) { - switch (m_packetParser.type()) { - case LauncherPacketType::ProcessStarted: - case LauncherPacketType::ReadyReadStandardOutput: - case LauncherPacketType::ReadyReadStandardError: - case LauncherPacketType::ProcessDone: - handle->handlePacket(m_packetParser.type(), m_packetParser.packetData()); - break; - default: - handleError(Tr::tr("Internal protocol error: invalid packet type %1.") - .arg(static_cast(m_packetParser.type()))); - return; - } - } else { -// qDebug() << "No handler for token" << m_packetParser.token() << m_handles; - // in this case the Process was canceled and deleted - } - handleSocketDataAvailable(); -} - -void LauncherSocket::handleSocketDisconnected() -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - handleError(Tr::tr("Launcher socket closed unexpectedly.")); -} - -void LauncherSocket::handleError(const QString &error) -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - const auto socket = m_socket.exchange(nullptr); - socket->disconnect(); - socket->deleteLater(); - emit errorOccurred(error); -} - -void LauncherSocket::handleRequests() -{ - QTC_ASSERT(isCalledFromLaunchersThread(), return); - const auto socket = m_socket.load(); - if (!socket) - return; - - std::vector requests; - { - QMutexLocker locker(&m_mutex); - requests = m_requests; - m_requests.clear(); - } - - for (const QByteArray &request : std::as_const(requests)) - socket->write(request); -} - -bool LauncherSocket::isCalledFromLaunchersThread() const -{ - return QThread::currentThread() == thread(); -} - -} // namespace Internal -} // namespace Utils diff --git a/src/libs/utils/launchersocket.h b/src/libs/utils/launchersocket.h deleted file mode 100644 index 9f906d1dcc4..00000000000 --- a/src/libs/utils/launchersocket.h +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "launcherpackets.h" -#include "processinterface.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QLocalSocket; -QT_END_NAMESPACE - -namespace Utils { -namespace Internal { - -class LauncherInterfacePrivate; -class LauncherHandle; -class LauncherSignal; -class LauncherStartedSignal; -class LauncherReadyReadSignal; -class LauncherDoneSignal; - -// All the methods and data fields in this class are called / accessed from the caller's thread. -// Exceptions are explicitly marked. -class CallerHandle : public QObject -{ - Q_OBJECT -public: - enum class SignalType { - NoSignal, - Started, - ReadyRead, - Done - }; - Q_ENUM(SignalType) - CallerHandle(QObject *parent, quintptr token) - : QObject(parent), m_token(token) {} - ~CallerHandle() override; - - LauncherHandle *launcherHandle() const { return m_launcherHandle; } - void setLauncherHandle(LauncherHandle *handle) { QMutexLocker locker(&m_mutex); m_launcherHandle = handle; } - - bool waitForSignal(CallerHandle::SignalType signalType, QDeadlineTimer timeout); - - // Returns the list of flushed signals. - void flush(); - bool flushFor(SignalType signalType); - bool shouldFlush() const; - // Called from launcher's thread exclusively. - void appendSignal(LauncherSignal *launcherSignal); - - // Called from caller's or launcher's thread. - QProcess::ProcessState state() const; - void sendControlPacket(ControlProcessPacket::SignalType signalType); - void terminate(); - void kill(); - void close(); - void closeWriteChannel(); - - qint64 processId() const; - - void start(const QString &program, const QStringList &arguments); - - qint64 write(const QByteArray &data); - - // Called from caller's or launcher's thread. - QString program() const; - // Called from caller's or launcher's thread. - QStringList arguments() const; - void setProcessSetupData(ProcessSetupData *setup); - -signals: - void started(qint64 processId, qint64 applicationMainThreadId = 0); - void readyRead(const QByteArray &outputData, const QByteArray &errorData); - void done(const Utils::ProcessResultData &resultData); - -private: - // Called from caller's thread exclusively. - void sendPacket(const Internal::LauncherPacket &packet); - // Called from caller's or launcher's thread. - bool isCalledFromCallersThread() const; - // Called from caller's or launcher's thread. Call me with mutex locked. - bool isCalledFromLaunchersThread() const; - - QByteArray readAndClear(QByteArray &data) const - { - const QByteArray tmp = data; - data.clear(); - return tmp; - } - - void handleStarted(const LauncherStartedSignal *launcherSignal); - void handleReadyRead(const LauncherReadyReadSignal *launcherSignal); - void handleDone(const LauncherDoneSignal *launcherSignal); - - // Lives in launcher's thread. Modified from caller's thread. - LauncherHandle *m_launcherHandle = nullptr; - - mutable QMutex m_mutex; - // Accessed from caller's and launcher's thread - QList m_signals; - - const quintptr m_token; - - // Modified from caller's thread, read from launcher's thread - std::atomic m_processState = QProcess::NotRunning; - int m_processId = 0; - - QString m_command; - QStringList m_arguments; - ProcessSetupData *m_setup = nullptr; -}; - -// Moved to the launcher thread, returned to caller's thread. -// It's assumed that this object will be alive at least -// as long as the corresponding Process is alive. - -class LauncherHandle : public QObject -{ -public: - // Called from caller's thread, moved to launcher's thread afterwards. - LauncherHandle(quintptr token) : m_token(token) {} - // Called from caller's thread exclusively. - bool waitForSignal(CallerHandle::SignalType newSignal, QDeadlineTimer timeout); - CallerHandle *callerHandle() const { return m_callerHandle; } - void setCallerHandle(CallerHandle *handle) { QMutexLocker locker(&m_mutex); m_callerHandle = handle; } - - // Called from launcher's thread exclusively. - void handleSocketError(const QString &message); - void handlePacket(LauncherPacketType type, const QByteArray &payload); - - // Called from caller's thread exclusively. - bool isSocketError() const { return m_socketError; } - -private: - // Called from caller's thread exclusively. - bool doWaitForSignal(QDeadlineTimer deadline); - // Called from launcher's thread exclusively. Call me with mutex locked. - void flushCaller(); - // Called from launcher's thread exclusively. - void handleStartedPacket(const QByteArray &packetData); - void handleReadyReadStandardOutput(const QByteArray &packetData); - void handleReadyReadStandardError(const QByteArray &packetData); - void handleDonePacket(const QByteArray &packetData); - - // Called from caller's or launcher's thread. - bool isCalledFromLaunchersThread() const; - bool isCalledFromCallersThread() const; - - // Lives in caller's thread. Modified only in caller's thread. TODO: check usages - all should be with mutex - CallerHandle *m_callerHandle = nullptr; - - mutable QMutex m_mutex; - QWaitCondition m_waitCondition; - const quintptr m_token; - std::atomic_bool m_socketError = false; -}; - -class LauncherSocket : public QObject -{ - Q_OBJECT - friend class LauncherInterfacePrivate; -public: - // Called from caller's thread exclusively. - void sendData(const QByteArray &data); - CallerHandle *registerHandle(QObject *parent, quintptr token); - void unregisterHandle(quintptr token); - -signals: - void errorOccurred(const QString &error); - -private: - // Called from caller's thread, moved to launcher's thread. - LauncherSocket(QObject *parent = nullptr); - // Called from launcher's thread exclusively. - ~LauncherSocket() override; - - // Called from launcher's thread exclusively. - LauncherHandle *handleForToken(quintptr token) const; - - // Called from launcher's thread exclusively. - void setSocket(QLocalSocket *socket); - void shutdown(); - - // Called from launcher's thread exclusively. - void handleSocketError(); - void handleSocketDataAvailable(); - void handleSocketDisconnected(); - void handleError(const QString &error); - void handleRequests(); - - // Called from caller's or launcher's thread. - bool isCalledFromLaunchersThread() const; - - std::atomic m_socket{nullptr}; - PacketParser m_packetParser; - std::vector m_requests; - mutable QMutex m_mutex; - QHash m_handles; -}; - -} // namespace Internal -} // namespace Utils diff --git a/src/libs/utils/processenums.h b/src/libs/utils/processenums.h index e19321fcd04..7990ca2a123 100644 --- a/src/libs/utils/processenums.h +++ b/src/libs/utils/processenums.h @@ -15,13 +15,6 @@ enum class ProcessMode { Writer // This opens in ReadWrite mode and doesn't close the write channel }; -enum class ProcessImpl { - QProcess, - ProcessLauncher, - Default // Defaults to ProcessLauncherImpl, if QTC_USE_QPROCESS env var is set - // it equals to QProcessImpl. -}; - enum class TerminalMode { Off, Run, // Start with process stub enabled diff --git a/src/libs/utils/processinterface.h b/src/libs/utils/processinterface.h index 7cea1420182..217ade70a8e 100644 --- a/src/libs/utils/processinterface.h +++ b/src/libs/utils/processinterface.h @@ -71,7 +71,6 @@ public: class QTCREATOR_UTILS_EXPORT ProcessSetupData { public: - ProcessImpl m_processImpl = ProcessImpl::Default; ProcessMode m_processMode = ProcessMode::Reader; TerminalMode m_terminalMode = TerminalMode::Off; @@ -165,8 +164,6 @@ private: // It's being called in Starting or Running state. virtual void sendControlSignal(ControlSignal controlSignal) = 0; - virtual ProcessBlockingInterface *processBlockingInterface() const { return nullptr; } - friend class Process; friend class Internal::ProcessPrivate; }; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index fcd5a465bdb..239bad5fa63 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -7,9 +7,8 @@ #include "environment.h" #include "guard.h" #include "hostosinfo.h" -#include "launcherinterface.h" -#include "launchersocket.h" #include "processhelper.h" +#include "processinterface.h" #include "processreaper.h" #include "stringutils.h" #include "terminalhooks.h" @@ -28,6 +27,7 @@ #include #include #include +#include #ifdef QT_GUI_LIB // qmlpuppet does not use that. @@ -40,7 +40,6 @@ #include #include #include -#include #include using namespace Utils::Internal; @@ -300,38 +299,6 @@ bool DefaultImpl::ensureProgramExists(const QString &program) return false; } -// TODO: Remove QProcessBlockingImpl later, after Creator 13.0 is released at least. - -// Rationale: QProcess::waitForReadyRead() waits only for one channel, either stdOut or stdErr. -// Since we can't predict where the data will come first, -// setting the QProcess::setReadChannel() in advance is a mis-design of the QProcess API. -// This issue does not affect GeneralProcessBlockingImpl, but it might be not as optimal -// as QProcessBlockingImpl. However, since we are blocking the caller thread anyway, -// the small overhead in speed doesn't play the most significant role, thus the proper -// behavior of Process::waitForReadyRead(), which listens to both channels, wins. - -// class QProcessBlockingImpl : public ProcessBlockingInterface -// { -// public: -// QProcessBlockingImpl(QProcess *process) : m_process(process) {} - -// private: -// bool waitForSignal(ProcessSignalType signalType, int msecs) final -// { -// switch (signalType) { -// case ProcessSignalType::Started: -// return m_process->waitForStarted(msecs); -// case ProcessSignalType::ReadyRead: -// return m_process->waitForReadyRead(msecs); -// case ProcessSignalType::Done: -// return m_process->waitForFinished(msecs); -// } -// return false; -// } - -// QProcess *m_process = nullptr; -// }; - class PtyProcessImpl final : public DefaultImpl { public: @@ -555,113 +522,6 @@ private: // QProcessBlockingImpl *m_blockingImpl = nullptr; }; -static uint uniqueToken() -{ - static std::atomic_uint globalUniqueToken = 0; - return ++globalUniqueToken; -} - -class ProcessLauncherBlockingImpl : public ProcessBlockingInterface -{ -public: - ProcessLauncherBlockingImpl(CallerHandle *caller) : m_caller(caller) {} - -private: - bool waitForSignal(ProcessSignalType signalType, QDeadlineTimer timeout) final - { - // TODO: Remove CallerHandle::SignalType - const CallerHandle::SignalType type = [signalType] { - switch (signalType) { - case ProcessSignalType::Started: - return CallerHandle::SignalType::Started; - case ProcessSignalType::ReadyRead: - return CallerHandle::SignalType::ReadyRead; - case ProcessSignalType::Done: - return CallerHandle::SignalType::Done; - } - QTC_CHECK(false); - return CallerHandle::SignalType::NoSignal; - }(); - return m_caller->waitForSignal(type, timeout); - } - - CallerHandle *m_caller = nullptr; -}; - -class ProcessLauncherImpl final : public DefaultImpl -{ - Q_OBJECT -public: - ProcessLauncherImpl() : m_token(uniqueToken()) - { - m_handle = LauncherInterface::registerHandle(this, token()); - m_handle->setProcessSetupData(&m_setup); - connect(m_handle, &CallerHandle::started, - this, &ProcessInterface::started); - connect(m_handle, &CallerHandle::readyRead, - this, &ProcessInterface::readyRead); - connect(m_handle, &CallerHandle::done, - this, &ProcessInterface::done); - m_blockingImpl = new ProcessLauncherBlockingImpl(m_handle); - } - ~ProcessLauncherImpl() final - { - m_handle->close(); - LauncherInterface::unregisterHandle(token()); - m_handle = nullptr; - } - -private: - qint64 write(const QByteArray &data) final { return m_handle->write(data); } - void sendControlSignal(ControlSignal controlSignal) final { - switch (controlSignal) { - case ControlSignal::Terminate: - m_handle->terminate(); - break; - case ControlSignal::Kill: - m_handle->kill(); - break; - case ControlSignal::Interrupt: - ProcessHelper::interruptPid(m_handle->processId()); - break; - case ControlSignal::KickOff: - QTC_CHECK(false); - break; - case ControlSignal::CloseWriteChannel: - m_handle->closeWriteChannel(); - break; - } - } - - ProcessBlockingInterface *processBlockingInterface() const override { return m_blockingImpl; } - - void doDefaultStart(const QString &program, const QStringList &arguments) final - { - m_handle->start(program, arguments); - } - - quintptr token() const { return m_token; } - - const uint m_token = 0; - // Lives in caller's thread. - CallerHandle *m_handle = nullptr; - ProcessLauncherBlockingImpl *m_blockingImpl = nullptr; -}; - -static ProcessImpl defaultProcessImplHelper() -{ - const QString value = qtcEnvironmentVariable("QTC_USE_QPROCESS", "TRUE").toUpper(); - if (value != "FALSE" && value != "0") - return ProcessImpl::QProcess; - return ProcessImpl::ProcessLauncher; -} - -static ProcessImpl defaultProcessImpl() -{ - static const ProcessImpl impl = defaultProcessImplHelper(); - return impl; -} - class ProcessInterfaceSignal { public: @@ -799,12 +659,7 @@ public: return new PtyProcessImpl; if (m_setup.m_terminalMode != TerminalMode::Off) return Terminal::Hooks::instance().createTerminalProcessInterface(); - - const ProcessImpl impl = m_setup.m_processImpl == ProcessImpl::Default - ? defaultProcessImpl() : m_setup.m_processImpl; - if (impl == ProcessImpl::QProcess) - return new QProcessImpl; - return new ProcessLauncherImpl; + return new QProcessImpl; } void setProcessInterface(ProcessInterface *process) @@ -820,9 +675,7 @@ public: connect(m_process.get(), &ProcessInterface::done, this, &ProcessPrivate::handleDone); - m_blockingInterface.reset(process->processBlockingInterface()); - if (!m_blockingInterface) - m_blockingInterface.reset(new GeneralProcessBlockingImpl(this)); + m_blockingInterface.reset(new GeneralProcessBlockingImpl(this)); m_blockingInterface->setParent(this); } @@ -1157,11 +1010,6 @@ Process::~Process() delete d; } -void Process::setProcessImpl(ProcessImpl processImpl) -{ - d->m_setup.m_processImpl = processImpl; -} - void Process::setPtyData(const std::optional &data) { d->m_setup.m_ptyData = data; @@ -2200,5 +2048,3 @@ void ProcessTaskAdapter::start() } } // namespace Utils - -#include "qtcprocess.moc" diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 65ca569d559..1de06a359b4 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -91,8 +91,6 @@ public: void setControlEnvironment(const Environment &env); // Possible helper process (ssh on host etc) const Environment &controlEnvironment() const; - void setProcessImpl(ProcessImpl processImpl); - void setPtyData(const std::optional &data); std::optional ptyData() const; diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 0bba92bf04d..8f49a8486c3 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -177,12 +177,6 @@ QtcLibrary { "itemviews.h", "jsontreeitem.cpp", "jsontreeitem.h", - "launcherinterface.cpp", - "launcherinterface.h", - "launcherpackets.cpp", - "launcherpackets.h", - "launchersocket.cpp", - "launchersocket.h", "layoutbuilder.cpp", "layoutbuilder.h", "link.cpp", diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index f5ae6600b9a..dcb55c868a3 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -400,7 +400,6 @@ DockerProcessImpl::~DockerProcessImpl() void DockerProcessImpl::start() { - m_process.setProcessImpl(m_setup.m_processImpl); m_process.setProcessMode(m_setup.m_processMode); m_process.setTerminalMode(m_setup.m_terminalMode); m_process.setPtyData(m_setup.m_ptyData); diff --git a/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp index 88325392116..d9e29e33164 100644 --- a/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp +++ b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp @@ -4,7 +4,6 @@ #include "../mesoninfoparser.h" #include "../mesontools.h" -#include #include #include #include @@ -40,8 +39,6 @@ private slots: { Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/mesontest-XXXXXX"); - Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); const auto path = findTool(ToolType::Meson); if (!path) diff --git a/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp index 7fc13e1d49e..1e049be7f16 100644 --- a/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp +++ b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp @@ -3,7 +3,6 @@ #include "../mesontools.h" -#include #include #include #include @@ -28,8 +27,6 @@ private slots: { Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/mesontest-XXXXXX"); - Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); const auto path = findTool(ToolType::Meson); if (!path) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index b52b3cb36d3..e8d9a1b80f8 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -674,7 +674,6 @@ void SshProcessInterfacePrivate::start() cmd.addArg(QString("%1:localhost:%1").arg(forwardPort)); } - m_process.setProcessImpl(q->m_setup.m_processImpl); m_process.setProcessMode(q->m_setup.m_processMode); m_process.setTerminalMode(q->m_setup.m_terminalMode); m_process.setPtyData(q->m_setup.m_ptyData); @@ -743,7 +742,6 @@ void SshProcessInterfacePrivate::clearForStart() void SshProcessInterfacePrivate::doStart() { - m_process.setProcessImpl(q->m_setup.m_processImpl); m_process.setProcessMode(q->m_setup.m_processMode); m_process.setTerminalMode(q->m_setup.m_terminalMode); m_process.setPtyData(q->m_setup.m_ptyData); diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 576c626aaea..2d92b0d0974 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -26,7 +26,6 @@ if (APPLE) add_subdirectory(iostool) endif() -add_subdirectory(processlauncher) if (WITH_QMLDESIGNER) add_subdirectory(qml2puppet) add_subdirectory(sqlitetester) diff --git a/src/tools/processlauncher/CMakeLists.txt b/src/tools/processlauncher/CMakeLists.txt deleted file mode 100644 index d866bc9a8d4..00000000000 --- a/src/tools/processlauncher/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -set(LIBSDIR "${PROJECT_SOURCE_DIR}/src/libs") -set(UTILSDIR "${PROJECT_SOURCE_DIR}/src/libs/utils") - -add_qtc_executable(qtcreator_processlauncher - INCLUDES "${LIBSDIR}" - DEPENDS Qt::Core Qt::Network - DEFINES UTILS_STATIC_LIBRARY - SOURCES - launcherlogging.cpp - launcherlogging.h - launchersockethandler.cpp - launchersockethandler.h - processlauncher-main.cpp - ${UTILSDIR}/launcherpackets.cpp - ${UTILSDIR}/launcherpackets.h - ${UTILSDIR}/processenums.h - ${UTILSDIR}/processhelper.cpp - ${UTILSDIR}/processhelper.h - ${UTILSDIR}/processreaper.cpp - ${UTILSDIR}/processreaper.h - ${UTILSDIR}/qtcassert.cpp - ${UTILSDIR}/qtcassert.h - ${UTILSDIR}/singleton.cpp - ${UTILSDIR}/singleton.h - ${UTILSDIR}/threadutils.cpp - ${UTILSDIR}/threadutils.h - ) - -if (MSVC) - find_library(DbgHelpLib dbghelp) -endif() - -extend_qtc_executable(qtcreator_processlauncher CONDITION MSVC - DEPENDS ${DbgHelpLib} -) diff --git a/src/tools/processlauncher/launcherlogging.cpp b/src/tools/processlauncher/launcherlogging.cpp deleted file mode 100644 index 1a7dd50e323..00000000000 --- a/src/tools/processlauncher/launcherlogging.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "launcherlogging.h" - -namespace Utils { -namespace Internal { -Q_LOGGING_CATEGORY(launcherLog, "qtc.utils.launcher", QtWarningMsg) -} -} diff --git a/src/tools/processlauncher/launcherlogging.h b/src/tools/processlauncher/launcherlogging.h deleted file mode 100644 index 25d14978855..00000000000 --- a/src/tools/processlauncher/launcherlogging.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include - -namespace Utils { -namespace Internal { -Q_DECLARE_LOGGING_CATEGORY(launcherLog) -template void logDebug(const T &msg) { qCDebug(launcherLog) << msg; } -template void logWarn(const T &msg) { qCWarning(launcherLog) << msg; } -template void logError(const T &msg) { qCCritical(launcherLog) << msg; } -} -} diff --git a/src/tools/processlauncher/launchersockethandler.cpp b/src/tools/processlauncher/launchersockethandler.cpp deleted file mode 100644 index 53ef9171295..00000000000 --- a/src/tools/processlauncher/launchersockethandler.cpp +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "launchersockethandler.h" -#include "launcherlogging.h" - -#include -#include - -#include -#include -#include - -namespace Utils { -namespace Internal { - -class ProcessWithToken : public ProcessHelper -{ - Q_OBJECT -public: - ProcessWithToken(quintptr token, QObject *parent = nullptr) : - ProcessHelper(parent), m_token(token) { } - - quintptr token() const { return m_token; } - void setReaperTimeout(int msecs) { m_reaperTimeout = msecs; }; - int reaperTimeout() const { return m_reaperTimeout; } - -private: - const quintptr m_token; - int m_reaperTimeout = 500; -}; - -LauncherSocketHandler::LauncherSocketHandler(QString serverPath, QObject *parent) - : QObject(parent), - m_serverPath(std::move(serverPath)), - m_socket(new QLocalSocket(this)) -{ - m_packetParser.setDevice(m_socket); -} - -LauncherSocketHandler::~LauncherSocketHandler() -{ - for (auto it = m_processes.cbegin(); it != m_processes.cend(); ++it) { - ProcessWithToken *p = it.value(); - if (p->state() != QProcess::NotRunning) - logWarn(QStringLiteral("Shutting down while process %1 is running").arg(p->program())); - ProcessReaper::reap(p); - } - - m_socket->disconnect(); - m_socket->disconnectFromServer(); - if (m_socket->state() != QLocalSocket::UnconnectedState - && !m_socket->waitForDisconnected()) { - logWarn("Could not disconnect from server"); - m_socket->close(); - } -} - -void LauncherSocketHandler::start() -{ - connect(m_socket, &QLocalSocket::disconnected, - this, &LauncherSocketHandler::handleSocketClosed); - connect(m_socket, &QLocalSocket::readyRead, this, &LauncherSocketHandler::handleSocketData); - connect(m_socket, - &QLocalSocket::errorOccurred, - this, &LauncherSocketHandler::handleSocketError); - m_socket->connectToServer(m_serverPath); -} - -void LauncherSocketHandler::handleSocketData() -{ - try { - if (!m_packetParser.parse()) - return; - } catch (const PacketParser::InvalidPacketSizeException &e) { - logWarn(QStringLiteral("Internal protocol error: Invalid packet size %1") - .arg(e.size)); - return; - } - switch (m_packetParser.type()) { - case LauncherPacketType::StartProcess: - handleStartPacket(); - break; - case LauncherPacketType::WriteIntoProcess: - handleWritePacket(); - break; - case LauncherPacketType::ControlProcess: - handleControlPacket(); - break; - case LauncherPacketType::Shutdown: - handleShutdownPacket(); - return; - default: - logWarn(QStringLiteral("Internal protocol error: Invalid packet type %1") - .arg(static_cast(m_packetParser.type()))); - return; - } - handleSocketData(); -} - -void LauncherSocketHandler::handleSocketError() -{ - if (m_socket->error() != QLocalSocket::PeerClosedError) { - logError(QStringLiteral("Socket error: %1").arg(m_socket->errorString())); - m_socket->disconnect(); - qApp->quit(); - } -} - -void LauncherSocketHandler::handleSocketClosed() -{ - logWarn("The connection has closed unexpectedly, shutting down"); - m_socket->disconnect(); - qApp->quit(); -} - -void LauncherSocketHandler::handleProcessError(ProcessWithToken *process) -{ - // In case of FailedToStart we won't receive finished signal, so we send the error - // packet and remove the process here and now. For all other errors we should expect - // corresponding finished signal to appear, so we will send the error data together with - // the finished packet later on. - if (process->error() == QProcess::FailedToStart) - handleProcessFinished(process); -} - -void LauncherSocketHandler::handleProcessStarted(ProcessWithToken *process) -{ - ProcessStartedPacket packet(process->token()); - packet.processId = process->processId(); - process->processStartHandler()->handleProcessStarted(); - sendPacket(packet); -} - -void LauncherSocketHandler::handleReadyReadStandardOutput(ProcessWithToken *process) -{ - ReadyReadStandardOutputPacket packet(process->token()); - packet.standardChannel = process->readAllStandardOutput(); - sendPacket(packet); -} - -void LauncherSocketHandler::handleReadyReadStandardError(ProcessWithToken *process) -{ - ReadyReadStandardErrorPacket packet(process->token()); - packet.standardChannel = process->readAllStandardError(); - sendPacket(packet); -} - -void LauncherSocketHandler::handleProcessFinished(ProcessWithToken *process) -{ - ProcessDonePacket packet(process->token()); - packet.exitCode = process->exitCode(); - packet.exitStatus = process->exitStatus(); - packet.error = process->error(); - packet.errorString = process->errorString(); - if (process->processChannelMode() != QProcess::MergedChannels) - packet.stdErr = process->readAllStandardError(); - packet.stdOut = process->readAllStandardOutput(); - sendPacket(packet); - removeProcess(process->token()); -} - -void LauncherSocketHandler::handleStartPacket() -{ - ProcessWithToken *& process = m_processes[m_packetParser.token()]; - if (!process) - process = setupProcess(m_packetParser.token()); - if (process->state() != QProcess::NotRunning) { - logWarn("Got start request while process was running"); - return; - } - const auto packet = LauncherPacket::extractPacket( - m_packetParser.token(), - m_packetParser.packetData()); - - process->setEnvironment(packet.env); - process->setWorkingDirectory(packet.workingDir); - // Forwarding is handled by the LauncherInterface - process->setProcessChannelMode(packet.processChannelMode == QProcess::MergedChannels - ? QProcess::MergedChannels : QProcess::SeparateChannels); - process->setStandardInputFile(packet.standardInputFile); - ProcessStartHandler *handler = process->processStartHandler(); - handler->setWindowsSpecificStartupFlags(packet.belowNormalPriority, - packet.createConsoleOnWindows, - packet.forceDefaultErrorMode); - handler->setProcessMode(packet.processMode); - handler->setWriteData(packet.writeData); - handler->setNativeArguments(packet.nativeArguments); - if (packet.lowPriority) - process->setLowPriority(); - if (packet.unixTerminalDisabled) - process->setUnixTerminalDisabled(); - process->setUseCtrlCStub(packet.useCtrlCStub); - process->setReaperTimeout(packet.reaperTimeout); - process->start(packet.command, packet.arguments, handler->openMode()); - handler->handleProcessStart(); -} - -void LauncherSocketHandler::handleWritePacket() -{ - ProcessWithToken * const process = m_processes.value(m_packetParser.token()); - if (!process) { - logWarn("Got write request for unknown process"); - return; - } - if (process->state() != QProcess::Running) { - logDebug("Can't write into not running process"); - return; - } - const auto packet = LauncherPacket::extractPacket( - m_packetParser.token(), - m_packetParser.packetData()); - process->write(packet.inputData); -} - -void LauncherSocketHandler::handleControlPacket() -{ - ProcessWithToken * const process = m_processes.value(m_packetParser.token()); - if (!process) { - // This can happen when the process finishes on its own at about the same time the client - // sends the request. In this case the process was already deleted. - logDebug("Got stop request for unknown process"); - return; - } - const auto packet = LauncherPacket::extractPacket( - m_packetParser.token(), - m_packetParser.packetData()); - - switch (packet.signalType) { - case ControlProcessPacket::SignalType::Terminate: - process->terminate(); - break; - case ControlProcessPacket::SignalType::Kill: - process->kill(); - break; - case ControlProcessPacket::SignalType::Close: - removeProcess(process->token()); - break; - case ControlProcessPacket::SignalType::CloseWriteChannel: - process->closeWriteChannel(); - break; - } -} - -void LauncherSocketHandler::handleShutdownPacket() -{ - logDebug("Got shutdown request, closing down"); - m_socket->disconnect(); - qApp->quit(); -} - -void LauncherSocketHandler::sendPacket(const LauncherPacket &packet) -{ - m_socket->write(packet.serialize()); -} - -ProcessWithToken *LauncherSocketHandler::setupProcess(quintptr token) -{ - const auto p = new ProcessWithToken(token, this); - connect(p, &QProcess::started, this, [this, p] { handleProcessStarted(p); }); - connect(p, &QProcess::errorOccurred, this, [this, p] { handleProcessError(p); }); - connect(p, &QProcess::finished, this, [this, p] { handleProcessFinished(p); }); - connect(p, &QProcess::readyReadStandardOutput, - this, [this, p] { handleReadyReadStandardOutput(p); }); - connect(p, &QProcess::readyReadStandardError, - this, [this, p] { handleReadyReadStandardError(p); }); - return p; -} - -void LauncherSocketHandler::removeProcess(quintptr token) -{ - const auto it = m_processes.constFind(token); - if (it == m_processes.constEnd()) - return; - - ProcessWithToken *process = it.value(); - m_processes.erase(it); - ProcessReaper::reap(process, std::chrono::milliseconds(process->reaperTimeout())); -} - -} // namespace Internal -} // namespace Utils - -#include "launchersockethandler.moc" diff --git a/src/tools/processlauncher/launchersockethandler.h b/src/tools/processlauncher/launchersockethandler.h deleted file mode 100644 index 05eefb09b82..00000000000 --- a/src/tools/processlauncher/launchersockethandler.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QLocalSocket; -QT_END_NAMESPACE - -namespace Utils { -namespace Internal { -class ProcessWithToken; - -class LauncherSocketHandler : public QObject -{ - Q_OBJECT -public: - explicit LauncherSocketHandler(QString socketPath, QObject *parent = nullptr); - ~LauncherSocketHandler() override; - - void start(); - -private: - void handleSocketData(); - void handleSocketError(); - void handleSocketClosed(); - - void handleProcessStarted(ProcessWithToken *process); - void handleProcessError(ProcessWithToken *process); - void handleProcessFinished(ProcessWithToken *process); - void handleReadyReadStandardOutput(ProcessWithToken *process); - void handleReadyReadStandardError(ProcessWithToken *process); - - void handleStartPacket(); - void handleWritePacket(); - void handleControlPacket(); - void handleShutdownPacket(); - - void sendPacket(const LauncherPacket &packet); - - ProcessWithToken *setupProcess(quintptr token); - void removeProcess(quintptr token); - - const QString m_serverPath; - QLocalSocket * const m_socket; - PacketParser m_packetParser; - QHash m_processes; -}; - -} // namespace Internal -} // namespace Utils diff --git a/src/tools/processlauncher/processlauncher-main.cpp b/src/tools/processlauncher/processlauncher-main.cpp deleted file mode 100644 index 980839cd8a8..00000000000 --- a/src/tools/processlauncher/processlauncher-main.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "launcherlogging.h" -#include "launchersockethandler.h" - -#include - -#include -#include -#include - -#ifdef Q_OS_WIN -#include - -BOOL WINAPI consoleCtrlHandler(DWORD) -{ - // Ignore Ctrl-C / Ctrl-Break. QtCreator will tell us to exit gracefully. - return TRUE; -} -#endif - -int main(int argc, char *argv[]) -{ -#ifdef Q_OS_WIN - SetConsoleCtrlHandler(consoleCtrlHandler, TRUE); -#endif - - QCoreApplication app(argc, argv); - if (app.arguments().size() != 2) { - Utils::Internal::logError("Need exactly one argument (path to socket)"); - return 1; - } - - const QScopeGuard cleanup([] { Utils::Singleton::deleteAll(); }); - - Utils::Internal::LauncherSocketHandler launcher(app.arguments().constLast()); - QTimer::singleShot(0, &launcher, &Utils::Internal::LauncherSocketHandler::start); - return app.exec(); -} diff --git a/src/tools/processlauncher/processlauncher.qbs b/src/tools/processlauncher/processlauncher.qbs deleted file mode 100644 index ca2973cd952..00000000000 --- a/src/tools/processlauncher/processlauncher.qbs +++ /dev/null @@ -1,46 +0,0 @@ -import qbs -import qbs.FileInfo - -QtcTool { - name: "qtcreator_processlauncher" - - Depends { name: "Qt.network" } - - cpp.defines: base.concat("UTILS_STATIC_LIBRARY") - cpp.includePaths: base.concat(pathToLibs) - - Properties { - condition: qbs.targetOS.contains("windows") - cpp.dynamicLibraries: qbs.toolchain.contains("msvc") ? ["user32", "dbghelp"] : ["user32"] - } - - files: [ - "launcherlogging.cpp", - "launcherlogging.h", - "launchersockethandler.cpp", - "launchersockethandler.h", - "processlauncher-main.cpp", - ] - - property string pathToLibs: sourceDirectory + "/../../libs" - property string pathToUtils: sourceDirectory + "/../../libs/utils" - Group { - name: "protocol sources" - prefix: pathToUtils + '/' - files: [ - "launcherpackets.cpp", - "launcherpackets.h", - "processenums.h", - "processhelper.cpp", - "processhelper.h", - "processreaper.cpp", - "processreaper.h", - "qtcassert.cpp", - "qtcassert.h", - "singleton.cpp", - "singleton.h", - "threadutils.cpp", - "threadutils.h", - ] - } -} diff --git a/src/tools/tools.qbs b/src/tools/tools.qbs index 48a35448d7e..39012049493 100644 --- a/src/tools/tools.qbs +++ b/src/tools/tools.qbs @@ -8,7 +8,6 @@ Project { "cplusplustools.qbs", "disclaim/disclaim.qbs", "process_stub/process_stub.qbs", - "processlauncher/processlauncher.qbs", "qml2puppet/qml2puppet.qbs", "qtcdebugger/qtcdebugger.qbs", "qtcreatorcrashhandler/qtcreatorcrashhandler.qbs", diff --git a/tests/auto/utils/commandline/tst_commandline.cpp b/tests/auto/utils/commandline/tst_commandline.cpp index aca984adf54..7bc54db50d4 100644 --- a/tests/auto/utils/commandline/tst_commandline.cpp +++ b/tests/auto/utils/commandline/tst_commandline.cpp @@ -6,10 +6,9 @@ #include #include #include -#include #include #include -#include +#include #include #include @@ -43,10 +42,6 @@ private slots: TemporaryDirectory::setMasterTemporaryDirectory( QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); - const QString libExecPath(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - LauncherInterface::setPathToLauncher(libExecPath); - testEnv.set("TEST_ECHO", "1"); if (HostOsInfo::isWindowsHost()) diff --git a/tests/auto/utils/deviceshell/tst_deviceshell.cpp b/tests/auto/utils/deviceshell/tst_deviceshell.cpp index 75150add83b..5ec8acab803 100644 --- a/tests/auto/utils/deviceshell/tst_deviceshell.cpp +++ b/tests/auto/utils/deviceshell/tst_deviceshell.cpp @@ -7,8 +7,8 @@ #include #include #include -#include #include +#include #include #include @@ -71,10 +71,6 @@ private slots: TemporaryDirectory::setMasterTemporaryDirectory( QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); - const QString libExecPath(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - LauncherInterface::setPathToLauncher(libExecPath); - std::iota(m_asciiTestData.begin(), m_asciiTestData.end(), 0); const FilePath dockerExecutable = Environment::systemEnvironment() diff --git a/tests/auto/utils/process/processtestapp/main.cpp b/tests/auto/utils/process/processtestapp/main.cpp index 5b0dda04b32..51d2e37ccfc 100644 --- a/tests/auto/utils/process/processtestapp/main.cpp +++ b/tests/auto/utils/process/processtestapp/main.cpp @@ -5,8 +5,8 @@ #include -#include #include +#include #include #include @@ -32,9 +32,6 @@ int main(int argc, char **argv) TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); - const QString libExecPath(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - LauncherInterface::setPathToLauncher(libExecPath); SubProcessConfig::setPathToProcessTestApp(QLatin1String(PROCESS_TESTAPP)); QMetaObject::invokeMethod(&app, [] { ProcessTestApp::invokeSubProcess(); }, Qt::QueuedConnection); diff --git a/tests/auto/utils/process/tst_process.cpp b/tests/auto/utils/process/tst_process.cpp index 01704d3d2ac..ef9553ea5bf 100644 --- a/tests/auto/utils/process/tst_process.cpp +++ b/tests/auto/utils/process/tst_process.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -21,9 +20,6 @@ #include #include -#include -#include - using namespace Utils; using namespace std::chrono; @@ -167,9 +163,6 @@ void tst_Process::initTestCase() msgHandler = new MessageHandler; TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); - const QString libExecPath(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - LauncherInterface::setPathToLauncher(libExecPath); SubProcessConfig::setPathToProcessTestApp(QLatin1String(PROCESS_TESTAPP)); homeStr = QLatin1String("@HOME@"); @@ -1286,29 +1279,20 @@ void tst_Process::stdinToShell() void tst_Process::eventLoopMode_data() { - QTest::addColumn("processImpl"); QTest::addColumn("eventLoopMode"); - QTest::newRow("QProcess, blocking with event loop") - << ProcessImpl::QProcess << EventLoopMode::On; - QTest::newRow("QProcess, blocking without event loop") - << ProcessImpl::QProcess << EventLoopMode::Off; - QTest::newRow("ProcessLauncher, blocking with event loop") - << ProcessImpl::ProcessLauncher << EventLoopMode::On; - QTest::newRow("ProcessLauncher, blocking without event loop") - << ProcessImpl::ProcessLauncher << EventLoopMode::Off; + QTest::newRow("EventLoopMode::On") << EventLoopMode::On; + QTest::newRow("EventLoopMode::Off") << EventLoopMode::Off; } void tst_Process::eventLoopMode() { - QFETCH(ProcessImpl, processImpl); QFETCH(EventLoopMode, eventLoopMode); { SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {}); Process process; subConfig.setupSubProcess(&process); - process.setProcessImpl(processImpl); process.runBlocking(10s, eventLoopMode); QCOMPARE(process.result(), ProcessResult::FinishedWithSuccess); } @@ -1317,7 +1301,6 @@ void tst_Process::eventLoopMode() Process process; process.setCommand( CommandLine{"there_is_a_big_chance_that_executable_with_that_name_does_not_exists"}); - process.setProcessImpl(processImpl); process.runBlocking(10s, eventLoopMode); QCOMPARE(process.result(), ProcessResult::StartFailed); } diff --git a/tests/auto/valgrind/memcheck/modeldemo.cpp b/tests/auto/valgrind/memcheck/modeldemo.cpp index 04735fc5f40..83e2c55aca1 100644 --- a/tests/auto/valgrind/memcheck/modeldemo.cpp +++ b/tests/auto/valgrind/memcheck/modeldemo.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include -#include #include #include @@ -24,9 +23,6 @@ int main(int argc, char *argv[]) QApplication app(argc, argv); Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/QtCreator-XXXXXX"); - const QString libExecPath(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - Utils::LauncherInterface::setPathToLauncher(libExecPath); qRegisterMetaType(); diff --git a/tests/manual/cmdbridge/tst_cmdbridge.cpp b/tests/manual/cmdbridge/tst_cmdbridge.cpp index d4c96b1d14e..f52a14378a1 100644 --- a/tests/manual/cmdbridge/tst_cmdbridge.cpp +++ b/tests/manual/cmdbridge/tst_cmdbridge.cpp @@ -8,8 +8,8 @@ #include #include -#include #include +#include #include #include @@ -60,9 +60,6 @@ private slots: { TemporaryDirectory::setMasterTemporaryDirectory( QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); - - libExecPath = qApp->applicationDirPath() + '/' + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH); - LauncherInterface::setPathToLauncher(libExecPath); } void cleanupTestCase() { Singleton::deleteAll(); } diff --git a/tests/manual/deviceshell/tst_deviceshell.cpp b/tests/manual/deviceshell/tst_deviceshell.cpp index 88f95fd7115..c93f05dff1c 100644 --- a/tests/manual/deviceshell/tst_deviceshell.cpp +++ b/tests/manual/deviceshell/tst_deviceshell.cpp @@ -5,8 +5,8 @@ #include #include -#include #include +#include #include #include @@ -131,10 +131,6 @@ private slots: TemporaryDirectory::setMasterTemporaryDirectory( QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); - const QString libExecPath(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - LauncherInterface::setPathToLauncher(libExecPath); - if (TestShell::cmdLine().isEmpty()) { QSKIP("Skipping deviceshell tests, as no compatible shell could be found"); } diff --git a/tests/manual/subdirfilecontainer/tst_subdirfilecontainer.cpp b/tests/manual/subdirfilecontainer/tst_subdirfilecontainer.cpp index 6493bd9121c..a1bffbcda5c 100644 --- a/tests/manual/subdirfilecontainer/tst_subdirfilecontainer.cpp +++ b/tests/manual/subdirfilecontainer/tst_subdirfilecontainer.cpp @@ -5,8 +5,8 @@ #include #include -#include #include +#include #include #include @@ -114,10 +114,6 @@ private slots: TemporaryDirectory::setMasterTemporaryDirectory( QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); - const QString libExecPath(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - LauncherInterface::setPathToLauncher(libExecPath); - qDebug() << "This manual test compares the performance of the SubDirFileContainer with a " "manually written iterator using QDir::entryInfoList() and with QDirIterator."; QTC_SCOPED_TIMER("GENERATING TEMPORARY FILES TREE"); diff --git a/tests/unit/tests/unittests/unittests-main.cpp b/tests/unit/tests/unittests/unittests-main.cpp index 06c8268f07e..4b16f32a273 100644 --- a/tests/unit/tests/unittests/unittests-main.cpp +++ b/tests/unit/tests/unittests/unittests-main.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -38,8 +37,6 @@ int main(int argc, char *argv[]) Sqlite::Database::activateLogging(); QGuiApplication application(argc, argv); - Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); testing::InitGoogleTest(&argc, argv); #ifdef WITH_BENCHMARKS benchmark::Initialize(&argc, argv); From a03f63c32dace3390cfb794b59d1b4630cfdab08 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 1 Nov 2024 12:09:43 +0100 Subject: [PATCH 046/989] Process: Hide ProcessBlockingInterface And merge it with the only one subclass. Change-Id: I725b00052a8fcd1a31162d399c7948776fde30cc Reviewed-by: hjk --- src/libs/utils/processinterface.h | 12 ------- src/libs/utils/qtcprocess.cpp | 52 ++++++++++++++++--------------- 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/src/libs/utils/processinterface.h b/src/libs/utils/processinterface.h index 217ade70a8e..f437d4083b9 100644 --- a/src/libs/utils/processinterface.h +++ b/src/libs/utils/processinterface.h @@ -119,18 +119,6 @@ enum class ProcessSignalType { Done }; -class QTCREATOR_UTILS_EXPORT ProcessBlockingInterface : public QObject -{ -private: - // Wait for: - // - Started is being called only in Starting state. - // - ReadyRead is being called in Starting or Running state. - // - Done is being called in Starting or Running state. - virtual bool waitForSignal(ProcessSignalType signalType, QDeadlineTimer timeout) = 0; - - friend class Internal::ProcessPrivate; -}; - class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject { Q_OBJECT diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 239bad5fa63..8b462f559cc 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -466,8 +466,6 @@ private: } } - // ProcessBlockingInterface *processBlockingInterface() const override { return m_blockingImpl; } - void doDefaultStart(const QString &program, const QStringList &arguments) final { QTC_ASSERT(QThread::currentThread()->eventDispatcher(), @@ -572,12 +570,12 @@ private: const ProcessResultData m_resultData; }; -class GeneralProcessBlockingImpl; +class ProcessBlockingInterface; class ProcessInterfaceHandler : public QObject { public: - ProcessInterfaceHandler(GeneralProcessBlockingImpl *caller, ProcessInterface *process); + ProcessInterfaceHandler(ProcessBlockingInterface *caller, ProcessInterface *process); // Called from caller's thread exclusively. bool waitForSignal(ProcessSignalType newSignal, QDeadlineTimer timeout); @@ -594,16 +592,23 @@ private: void handleDone(const ProcessResultData &data); void appendSignal(ProcessInterfaceSignal *newSignal); - GeneralProcessBlockingImpl *m_caller = nullptr; + ProcessBlockingInterface *m_caller = nullptr; QMutex m_mutex; QWaitCondition m_waitCondition; }; -class GeneralProcessBlockingImpl : public ProcessBlockingInterface +class ProcessBlockingInterface : public QObject { public: - GeneralProcessBlockingImpl(ProcessPrivate *parent); + ProcessBlockingInterface(ProcessPrivate *parent); + // Wait for: + // - Started is being called only in Starting state. + // - ReadyRead is being called in Starting or Running state. + // - Done is being called in Starting or Running state. + bool waitForSignal(ProcessSignalType signalType, QDeadlineTimer timeout); + +private: void flush() { flushSignals(takeAllSignals()); } bool flushFor(ProcessSignalType signalType) { return flushSignals(takeSignalsFor(signalType), &signalType); @@ -613,10 +618,6 @@ public: // Called from ProcessInterfaceHandler thread exclusively. void appendSignal(ProcessInterfaceSignal *launcherSignal); -private: - // Called from caller's thread exclusively - bool waitForSignal(ProcessSignalType newSignal, QDeadlineTimer timeout) final; - QList takeAllSignals(); QList takeSignalsFor(ProcessSignalType signalType); bool flushSignals(const QList &signalList, @@ -626,6 +627,7 @@ private: void handleReadyReadSignal(const ReadyReadSignal *launcherSignal); void handleDoneSignal(const DoneSignal *launcherSignal); + friend class ProcessInterfaceHandler; ProcessPrivate *m_caller = nullptr; std::unique_ptr m_processHandler; mutable QMutex m_mutex; @@ -675,7 +677,7 @@ public: connect(m_process.get(), &ProcessInterface::done, this, &ProcessPrivate::handleDone); - m_blockingInterface.reset(new GeneralProcessBlockingImpl(this)); + m_blockingInterface.reset(new ProcessBlockingInterface(this)); m_blockingInterface->setParent(this); } @@ -718,7 +720,7 @@ public: Guard m_guard; }; -ProcessInterfaceHandler::ProcessInterfaceHandler(GeneralProcessBlockingImpl *caller, +ProcessInterfaceHandler::ProcessInterfaceHandler(ProcessBlockingInterface *caller, ProcessInterface *process) : m_caller(caller) { @@ -795,10 +797,10 @@ void ProcessInterfaceHandler::appendSignal(ProcessInterfaceSignal *newSignal) } m_waitCondition.wakeOne(); // call in callers thread - QMetaObject::invokeMethod(m_caller, &GeneralProcessBlockingImpl::flush); + QMetaObject::invokeMethod(m_caller, &ProcessBlockingInterface::flush); } -GeneralProcessBlockingImpl::GeneralProcessBlockingImpl(ProcessPrivate *parent) +ProcessBlockingInterface::ProcessBlockingInterface(ProcessPrivate *parent) : m_caller(parent) , m_processHandler(new ProcessInterfaceHandler(this, parent->m_process.get())) { @@ -808,14 +810,14 @@ GeneralProcessBlockingImpl::GeneralProcessBlockingImpl(ProcessPrivate *parent) // So the hierarchy looks like: // ProcessPrivate // | - // +- GeneralProcessBlockingImpl + // +- ProcessBlockingInterface // | // +- ProcessInterfaceHandler // | // +- ProcessInterface } -bool GeneralProcessBlockingImpl::waitForSignal(ProcessSignalType newSignal, QDeadlineTimer timeout) +bool ProcessBlockingInterface::waitForSignal(ProcessSignalType newSignal, QDeadlineTimer timeout) { QTC_ASSERT(!m_guard.isLocked(), qWarning("Process::waitForSignal() called recursively. " "The call is being ignored."); return false); @@ -839,14 +841,14 @@ bool GeneralProcessBlockingImpl::waitForSignal(ProcessSignalType newSignal, QDea } // Called from caller's thread exclusively -QList GeneralProcessBlockingImpl::takeAllSignals() +QList ProcessBlockingInterface::takeAllSignals() { QMutexLocker locker(&m_mutex); return std::exchange(m_signals, {}); } // Called from caller's thread exclusively -QList GeneralProcessBlockingImpl::takeSignalsFor(ProcessSignalType signalType) +QList ProcessBlockingInterface::takeSignalsFor(ProcessSignalType signalType) { // If we are flushing for ReadyRead or Done - flush all. if (signalType != ProcessSignalType::Started) @@ -876,8 +878,8 @@ QList GeneralProcessBlockingImpl::takeSignalsFor(Proce } // Called from caller's thread exclusively -bool GeneralProcessBlockingImpl::flushSignals(const QList &signalList, - ProcessSignalType *signalType) +bool ProcessBlockingInterface::flushSignals(const QList &signalList, + ProcessSignalType *signalType) { bool signalMatched = false; for (const ProcessInterfaceSignal *storedSignal : std::as_const(signalList)) { @@ -902,23 +904,23 @@ bool GeneralProcessBlockingImpl::flushSignals(const QListhandleStarted(aSignal->processId(), aSignal->applicationMainThreadId()); } -void GeneralProcessBlockingImpl::handleReadyReadSignal(const ReadyReadSignal *aSignal) +void ProcessBlockingInterface::handleReadyReadSignal(const ReadyReadSignal *aSignal) { m_caller->handleReadyRead(aSignal->stdOut(), aSignal->stdErr()); } -void GeneralProcessBlockingImpl::handleDoneSignal(const DoneSignal *aSignal) +void ProcessBlockingInterface::handleDoneSignal(const DoneSignal *aSignal) { m_caller->handleDone(aSignal->resultData()); } // Called from ProcessInterfaceHandler thread exclusively. -void GeneralProcessBlockingImpl::appendSignal(ProcessInterfaceSignal *newSignal) +void ProcessBlockingInterface::appendSignal(ProcessInterfaceSignal *newSignal) { QMutexLocker locker(&m_mutex); m_signals.append(newSignal); From 10fcef63bc72749178b1858a52001558986e85f8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 1 Nov 2024 12:46:18 +0100 Subject: [PATCH 047/989] ProcessReaper: Transform it into namespace Sync with what we have in QProcessTask implementation. Don't derive from Singleton anymore. Add ProcessReaper::deleteAll(). Add some assert printouts. Change-Id: I11eeb418651230cf8644e73ee468f61716422384 Reviewed-by: hjk --- src/app/main.cpp | 4 +- src/libs/utils/processreaper.cpp | 80 ++++++++++++++----- src/libs/utils/processreaper.h | 29 ++----- src/libs/utils/qtcprocess.cpp | 1 + .../tests/testmesoninfoparser.cpp | 4 +- .../tests/testmesonwrapper.cpp | 4 +- .../utils/commandline/tst_commandline.cpp | 4 +- .../utils/deviceshell/tst_deviceshell.cpp | 4 +- .../utils/process/processtestapp/main.cpp | 4 +- tests/auto/utils/process/tst_process.cpp | 12 +-- tests/manual/cmdbridge/tst_cmdbridge.cpp | 4 +- tests/manual/deviceshell/tst_deviceshell.cpp | 4 +- .../tst_subdirfilecontainer.cpp | 4 +- tests/unit/tests/unittests/unittests-main.cpp | 6 +- 14 files changed, 95 insertions(+), 69 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index c3531afd5a8..f090c3e2d35 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -685,7 +685,7 @@ int main(int argc, char **argv) QCoreApplication::setOrganizationName(QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR)); QGuiApplication::setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME); - const QScopeGuard cleanup([] { Singleton::deleteAll(); }); + const QScopeGuard cleanup([] { ProcessReaper::deleteAll(); }); const QStringList pluginArguments = app.arguments(); diff --git a/src/libs/utils/processreaper.cpp b/src/libs/utils/processreaper.cpp index 138c9ad1278..7b5860f87ff 100644 --- a/src/libs/utils/processreaper.cpp +++ b/src/libs/utils/processreaper.cpp @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include @@ -18,8 +20,7 @@ using namespace Utils; using namespace std::chrono; -namespace Utils { -namespace Internal { +namespace Utils::ProcessReaper { /* @@ -55,6 +56,22 @@ never ending running process: */ +class ProcessReaperPrivate; + +class ProcessReaperImpl final +{ +public: + static void reap(QProcess *process, milliseconds timeout); + ProcessReaperImpl(); + ~ProcessReaperImpl(); + +private: + static ProcessReaperImpl *instance(); + + QThread m_thread; + ProcessReaperPrivate *m_private; +}; + static const int s_timeoutThreshold = 10000; // 10 seconds static QString execWithArguments(QProcess *process) @@ -87,7 +104,7 @@ public: terminate(); } -signals: +Q_SIGNALS: void finished(); private: @@ -146,7 +163,9 @@ public: // Called from non-reaper's thread void scheduleReap(const ReaperSetup &reaperSetup) { - QTC_CHECK(QThread::currentThread() != thread()); + QTC_ASSERT(QThread::currentThread() != thread(), + qWarning() << "Can't schedule reap from the reaper internal thread."); + QMutexLocker locker(&m_mutex); m_reaperSetupList.append(reaperSetup); QMetaObject::invokeMethod(this, &ProcessReaperPrivate::flush); @@ -155,7 +174,9 @@ public: // Called from non-reaper's thread void waitForFinished() { - QTC_CHECK(QThread::currentThread() != thread()); + QTC_ASSERT(QThread::currentThread() != thread(), + qWarning() << "Can't wait for finished from the reaper internal thread."); + QMetaObject::invokeMethod(this, &ProcessReaperPrivate::flush, Qt::BlockingQueuedConnection); QMutexLocker locker(&m_mutex); @@ -190,7 +211,9 @@ private: connect(reaper, &Reaper::finished, this, [this, reaper, process = reaperSetup.m_process] { QMutexLocker locker(&m_mutex); const bool isRemoved = m_reaperList.removeOne(reaper); - QTC_CHECK(isRemoved); + QTC_ASSERT(isRemoved, + qWarning() << "Reaper list doesn't contain the finished process."); + delete reaper; delete process; if (m_reaperList.isEmpty()) @@ -211,14 +234,19 @@ private: QList m_reaperList; }; -} // namespace Internal - -using namespace Utils::Internal; - +static ProcessReaperImpl *s_instance = nullptr; static QMutex s_instanceMutex; -ProcessReaper::ProcessReaper() - : m_private(new ProcessReaperPrivate()) +// Call me with s_instanceMutex locked. +ProcessReaperImpl *ProcessReaperImpl::instance() +{ + if (!s_instance) + s_instance = new ProcessReaperImpl; + return s_instance; +} + +ProcessReaperImpl::ProcessReaperImpl() + : m_private(new ProcessReaperPrivate) { m_private->moveToThread(&m_thread); QObject::connect(&m_thread, &QThread::finished, m_private, &QObject::deleteLater); @@ -226,25 +254,27 @@ ProcessReaper::ProcessReaper() m_thread.moveToThread(qApp->thread()); } -ProcessReaper::~ProcessReaper() +ProcessReaperImpl::~ProcessReaperImpl() { - QTC_CHECK(isMainThread()); - QMutexLocker locker(&s_instanceMutex); + QTC_ASSERT(Utils::isMainThread(), + qWarning() << "Destructing process reaper from non-main thread."); + instance()->m_private->waitForFinished(); m_thread.quit(); m_thread.wait(); } -void ProcessReaper::reap(QProcess *process, milliseconds timeout) +void ProcessReaperImpl::reap(QProcess *process, milliseconds timeout) { if (!process) return; - QTC_ASSERT(QThread::currentThread() == process->thread(), return); + QTC_ASSERT(QThread::currentThread() == process->thread(), + qWarning() << "Can't reap process from non-process's thread."; return); process->disconnect(); if (process->state() == QProcess::NotRunning) { - process->deleteLater(); + delete process; return; } @@ -260,6 +290,18 @@ void ProcessReaper::reap(QProcess *process, milliseconds timeout) priv->scheduleReap(reaperSetup); } -} // namespace Utils +void deleteAll() +{ + QMutexLocker locker(&s_instanceMutex); + delete s_instance; + s_instance = nullptr; +} + +void reap(QProcess *process, milliseconds timeout) +{ + ProcessReaperImpl::reap(process, timeout); +} + +} // namespace Utils::ProcessReaper #include "processreaper.moc" diff --git a/src/libs/utils/processreaper.h b/src/libs/utils/processreaper.h index 6bea7789d1c..16397d0eff5 100644 --- a/src/libs/utils/processreaper.h +++ b/src/libs/utils/processreaper.h @@ -5,31 +5,14 @@ #include "utils_global.h" -#include "singleton.h" - -#include +#include QT_BEGIN_NAMESPACE class QProcess; QT_END_NAMESPACE -namespace Utils { -namespace Internal { class ProcessReaperPrivate; } - -class QTCREATOR_UTILS_EXPORT ProcessReaper final - : public SingletonWithOptionalDependencies -{ -public: - static void reap(QProcess *process, - std::chrono::milliseconds timeout = std::chrono::milliseconds(500)); - -private: - ProcessReaper(); - ~ProcessReaper(); - - QThread m_thread; - Internal::ProcessReaperPrivate *m_private; - friend class SingletonWithOptionalDependencies; -}; - -} // namespace Utils +namespace Utils::ProcessReaper { +QTCREATOR_UTILS_EXPORT void deleteAll(); +QTCREATOR_UTILS_EXPORT void reap(QProcess *process, + std::chrono::milliseconds timeout = std::chrono::milliseconds(500)); +} // namespace Utils::ProcessReaper diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 8b462f559cc..af4833c3ff2 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp index d9e29e33164..e54b5f4aeb7 100644 --- a/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp +++ b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp @@ -5,7 +5,7 @@ #include "../mesontools.h" #include -#include +#include #include #include @@ -101,7 +101,7 @@ private slots: void cleanupTestCase() { - Utils::Singleton::deleteAll(); + ProcessReaper::deleteAll(); } }; diff --git a/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp index 1e049be7f16..210d77978c1 100644 --- a/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp +++ b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp @@ -4,7 +4,7 @@ #include "../mesontools.h" #include -#include +#include #include #include @@ -93,7 +93,7 @@ private slots: void cleanupTestCase() { - Utils::Singleton::deleteAll(); + Utils::ProcessReaper::deleteAll(); } }; diff --git a/tests/auto/utils/commandline/tst_commandline.cpp b/tests/auto/utils/commandline/tst_commandline.cpp index 7bc54db50d4..c6c9a95d1d8 100644 --- a/tests/auto/utils/commandline/tst_commandline.cpp +++ b/tests/auto/utils/commandline/tst_commandline.cpp @@ -7,8 +7,8 @@ #include #include #include +#include #include -#include #include #include @@ -50,7 +50,7 @@ private slots: newLine = "\n"; } - void cleanupTestCase() { Singleton::deleteAll(); } + void cleanupTestCase() { ProcessReaper::deleteAll(); } void testSpace() { diff --git a/tests/auto/utils/deviceshell/tst_deviceshell.cpp b/tests/auto/utils/deviceshell/tst_deviceshell.cpp index 5ec8acab803..f3408b46ac4 100644 --- a/tests/auto/utils/deviceshell/tst_deviceshell.cpp +++ b/tests/auto/utils/deviceshell/tst_deviceshell.cpp @@ -7,8 +7,8 @@ #include #include #include +#include #include -#include #include #include @@ -116,7 +116,7 @@ private slots: } } - void cleanupTestCase() { Singleton::deleteAll(); } + void cleanupTestCase() { ProcessReaper::deleteAll(); } void testArguments_data() { diff --git a/tests/auto/utils/process/processtestapp/main.cpp b/tests/auto/utils/process/processtestapp/main.cpp index 51d2e37ccfc..d5b83fb3823 100644 --- a/tests/auto/utils/process/processtestapp/main.cpp +++ b/tests/auto/utils/process/processtestapp/main.cpp @@ -5,8 +5,8 @@ #include +#include #include -#include #include #include @@ -28,7 +28,7 @@ int main(int argc, char **argv) #endif QCoreApplication app(argc, argv); - const QScopeGuard cleanup([] { Singleton::deleteAll(); }); + const QScopeGuard cleanup([] { ProcessReaper::deleteAll(); }); TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); diff --git a/tests/auto/utils/process/tst_process.cpp b/tests/auto/utils/process/tst_process.cpp index ef9553ea5bf..4e860897440 100644 --- a/tests/auto/utils/process/tst_process.cpp +++ b/tests/auto/utils/process/tst_process.cpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include @@ -176,7 +176,7 @@ void tst_Process::initTestCase() void tst_Process::cleanupTestCase() { - Singleton::deleteAll(); + ProcessReaper::deleteAll(); const int destroyCount = msgHandler->destroyCount(); delete msgHandler; if (destroyCount) @@ -200,13 +200,13 @@ static bool deleteRunningProcess() void tst_Process::processReaperCreatedInNonMainThread() { - Singleton::deleteAll(); + ProcessReaper::deleteAll(); auto future = Utils::asyncRun(deleteRunningProcess); future.waitForFinished(); QVERIFY(future.result()); - Singleton::deleteAll(); + ProcessReaper::deleteAll(); } void tst_Process::multiRead_data() @@ -1101,7 +1101,7 @@ void tst_Process::recursiveBlockingProcess() if (HostOsInfo::isWindowsHost()) QSKIP(s_skipTerminateOnWindows); - Singleton::deleteAll(); + ProcessReaper::deleteAll(); QCOMPARE(runningTestProcessCount(), 0); const int recursionDepth = 5; // must be at least 2 SubProcessConfig subConfig(ProcessTestApp::RecursiveBlockingProcess::envVar(), @@ -1123,7 +1123,7 @@ void tst_Process::recursiveBlockingProcess() QCOMPARE(process.exitStatus(), QProcess::NormalExit); QCOMPARE(process.exitCode(), s_crashCode); } - Singleton::deleteAll(); + ProcessReaper::deleteAll(); QCOMPARE(runningTestProcessCount(), 0); } diff --git a/tests/manual/cmdbridge/tst_cmdbridge.cpp b/tests/manual/cmdbridge/tst_cmdbridge.cpp index f52a14378a1..45f79f53797 100644 --- a/tests/manual/cmdbridge/tst_cmdbridge.cpp +++ b/tests/manual/cmdbridge/tst_cmdbridge.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -62,7 +62,7 @@ private slots: QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); } - void cleanupTestCase() { Singleton::deleteAll(); } + void cleanupTestCase() { ProcessReaper::deleteAll(); } void testDeviceEnvironment() { diff --git a/tests/manual/deviceshell/tst_deviceshell.cpp b/tests/manual/deviceshell/tst_deviceshell.cpp index c93f05dff1c..db8189621ce 100644 --- a/tests/manual/deviceshell/tst_deviceshell.cpp +++ b/tests/manual/deviceshell/tst_deviceshell.cpp @@ -5,8 +5,8 @@ #include #include +#include #include -#include #include #include @@ -136,7 +136,7 @@ private slots: } } - void cleanupTestCase() { Singleton::deleteAll(); } + void cleanupTestCase() { ProcessReaper::deleteAll(); } void testEncoding_data() { diff --git a/tests/manual/subdirfilecontainer/tst_subdirfilecontainer.cpp b/tests/manual/subdirfilecontainer/tst_subdirfilecontainer.cpp index a1bffbcda5c..c5f1ade9cc0 100644 --- a/tests/manual/subdirfilecontainer/tst_subdirfilecontainer.cpp +++ b/tests/manual/subdirfilecontainer/tst_subdirfilecontainer.cpp @@ -5,8 +5,8 @@ #include #include +#include #include -#include #include #include @@ -172,7 +172,7 @@ private slots: QCOMPARE(TaskTree::runBlocking(recipe), DoneWith::Success); m_tempDir.reset(); - Singleton::deleteAll(); + ProcessReaper::deleteAll(); } void testSubDirFileContainer() diff --git a/tests/unit/tests/unittests/unittests-main.cpp b/tests/unit/tests/unittests/unittests-main.cpp index 4b16f32a273..bfb7e674d65 100644 --- a/tests/unit/tests/unittests/unittests-main.cpp +++ b/tests/unit/tests/unittests/unittests-main.cpp @@ -4,10 +4,10 @@ #include "../utils/googletest.h" #include +#include #include -#include -#include +#include #include #include @@ -47,7 +47,7 @@ int main(int argc, char *argv[]) int testsHaveErrors = RUN_ALL_TESTS(); - Utils::Singleton::deleteAll(); + Utils::ProcessReaper::deleteAll(); #ifdef WITH_BENCHMARKS if (testsHaveErrors == 0 && application.arguments().contains(QStringLiteral("--with-benchmarks"))) benchmark::RunSpecifiedBenchmarks(); From 1c2f8c8a2aa8cbd5a649e8b268a9df2870052191 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 1 Nov 2024 13:07:34 +0100 Subject: [PATCH 048/989] Utils: Get rid of Singleton It's not used anymore. Change-Id: I1ed9953f4d23093f7e419d3f585102449b947722 Reviewed-by: hjk --- src/libs/utils/CMakeLists.txt | 1 - src/libs/utils/singleton.cpp | 59 ------------------------ src/libs/utils/singleton.h | 84 ----------------------------------- src/libs/utils/utils.qbs | 2 - 4 files changed, 146 deletions(-) delete mode 100644 src/libs/utils/singleton.cpp delete mode 100644 src/libs/utils/singleton.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index c8a5f84196c..891a0f66ff9 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -150,7 +150,6 @@ add_qtc_library(Utils set_algorithm.h settingsaccessor.cpp settingsaccessor.h settingsselector.cpp settingsselector.h - singleton.cpp singleton.h sizedarray.h smallstring.h smallstringfwd.h diff --git a/src/libs/utils/singleton.cpp b/src/libs/utils/singleton.cpp deleted file mode 100644 index 35ac799638e..00000000000 --- a/src/libs/utils/singleton.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qtcassert.h" -#include "singleton.h" -#include "threadutils.h" - -#include - -#include - -using namespace Utils; - -namespace Utils { - -// The order of elements reflects dependencies, i.e. -// if B requires A then B will follow A on this list -static QList s_singletonList; -static QMutex s_mutex; -static std::unordered_map s_staticDataList; - -Singleton::~Singleton() -{ - QMutexLocker locker(&s_mutex); - s_singletonList.removeAll(this); -} - -void Singleton::addSingleton(Singleton *singleton) -{ - QMutexLocker locker(&s_mutex); - s_singletonList.append(singleton); -} - -SingletonStaticData &Singleton::staticData(std::type_index index) -{ - QMutexLocker locker(&s_mutex); - return s_staticDataList[index]; -} - -// Note: it's caller responsibility to ensure that this function is being called when all other -// threads don't use any singleton. As a good practice: finish all other threads that were using -// singletons before this function is called. -// Some singletons may work only in main thread, so this method should be called from main thread -// only. -void Singleton::deleteAll() -{ - QTC_ASSERT(isMainThread(), return); - QList oldList; - { - QMutexLocker locker(&s_mutex); - oldList = s_singletonList; - s_singletonList = {}; - } - // Keep the reverse order when deleting - while (!oldList.isEmpty()) - delete oldList.takeLast(); -} - -} // namespace Utils diff --git a/src/libs/utils/singleton.h b/src/libs/utils/singleton.h deleted file mode 100644 index db114e4d483..00000000000 --- a/src/libs/utils/singleton.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "utils_global.h" - -#include -#include - -#include -#include - -namespace Utils { - -class Singleton; - -struct SingletonStaticData -{ - Singleton *m_instance = nullptr; - QMutex m_mutex; -}; - -class QTCREATOR_UTILS_EXPORT Singleton -{ - Q_DISABLE_COPY_MOVE(Singleton) -public: - static void deleteAll(); - -private: - template - friend class SingletonWithOptionalDependencies; - - Singleton() = default; - virtual ~Singleton(); - static void addSingleton(Singleton *singleton); - static SingletonStaticData &staticData(std::type_index index); -}; - -template -class SingletonWithOptionalDependencies : public Singleton -{ -public: - Q_DISABLE_COPY_MOVE(SingletonWithOptionalDependencies) - static SingletonSubClass *instance() - { - SingletonStaticData &data = staticData(); - QMutexLocker locker(&data.m_mutex); - if (data.m_instance == nullptr) { - // instantiate all dependencies first - if constexpr (sizeof...(Dependencies)) - instantiateDependencies(); - data.m_instance = new SingletonSubClass; - // put instance into static list of registered instances - addSingleton(data.m_instance); - } - return static_cast(data.m_instance); - } - -protected: - SingletonWithOptionalDependencies() = default; - ~SingletonWithOptionalDependencies() override - { - SingletonStaticData &data = staticData(); - QMutexLocker locker(&data.m_mutex); - if (data.m_instance == this) - data.m_instance = nullptr; - } - -private: - template static void instantiateDependencies() - { - static_assert ((... && std::is_base_of_v), - "All Dependencies must derive from SingletonWithOptionalDependencies class."); - (..., Dependency::instance()); - } - static SingletonStaticData &staticData() - { - static SingletonStaticData &data = Singleton::staticData(std::type_index(typeid(SingletonSubClass))); - return data; - } -}; - -} // namespace Utils diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 8f49a8486c3..aede804c6c1 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -279,8 +279,6 @@ QtcLibrary { "settingsaccessor.h", "settingsselector.cpp", "settingsselector.h", - "singleton.cpp", - "singleton.h", "sizedarray.h", "smallstring.h", "smallstringiterator.h", From dde64a0212435c4cd69a732843c9f6910729a393 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 30 Oct 2024 17:03:32 +0100 Subject: [PATCH 049/989] ProjectExplorer: Improve target setup page - Remove several unnecessary nesting layers and unused widgets. - Consolidate the two modes: We always have a scroll area now. This also prevent the "configure project" button from scrolling out of sight. Fixes: QTCREATORBUG-31314 Change-Id: I33df6ee283835b731ebb0b3c959cd671df0d3d73 Reviewed-by: hjk --- src/plugins/projectexplorer/panelswidget.cpp | 4 +- src/plugins/projectexplorer/panelswidget.h | 2 +- .../projectexplorer/targetsettingspanel.cpp | 7 +- .../projectexplorer/targetsetuppage.cpp | 122 +++++------------- src/plugins/projectexplorer/targetsetuppage.h | 5 - 5 files changed, 37 insertions(+), 103 deletions(-) diff --git a/src/plugins/projectexplorer/panelswidget.cpp b/src/plugins/projectexplorer/panelswidget.cpp index d0259f60e94..35198c422b2 100644 --- a/src/plugins/projectexplorer/panelswidget.cpp +++ b/src/plugins/projectexplorer/panelswidget.cpp @@ -65,8 +65,8 @@ PanelsWidget::PanelsWidget(QWidget *parent, bool addStretch) : QWidget(parent) //layout->addWidget(new FindToolBarPlaceHolder(this)); } -PanelsWidget::PanelsWidget(const QString &displayName, QWidget *widget) - : PanelsWidget(nullptr) +PanelsWidget::PanelsWidget(const QString &displayName, QWidget *widget, bool addStretch) + : PanelsWidget(nullptr, addStretch) { addPropertiesPanel(displayName); addWidget(widget); diff --git a/src/plugins/projectexplorer/panelswidget.h b/src/plugins/projectexplorer/panelswidget.h index 3d5603d5400..64ef56265df 100644 --- a/src/plugins/projectexplorer/panelswidget.h +++ b/src/plugins/projectexplorer/panelswidget.h @@ -20,7 +20,7 @@ class PROJECTEXPLORER_EXPORT PanelsWidget : public QWidget public: explicit PanelsWidget(QWidget *parent = nullptr, bool addStretch = true); - PanelsWidget(const QString &displayName, QWidget *widget); + PanelsWidget(const QString &displayName, QWidget *widget, bool addStretch = true); PanelsWidget(const QString &displayName, ProjectSettingsWidget *widget); ~PanelsWidget() override; diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp index bc5be1f1872..d6ad9e34cea 100644 --- a/src/plugins/projectexplorer/targetsettingspanel.cpp +++ b/src/plugins/projectexplorer/targetsettingspanel.cpp @@ -125,7 +125,6 @@ TargetSetupPageWrapper::TargetSetupPageWrapper(Project *project) m_setupPageContainer = new QVBoxLayout; layout->addLayout(m_setupPageContainer); layout->addLayout(hbox); - layout->addStretch(10); completeChanged(); connect(m_configureButton, &QAbstractButton::clicked, this, &TargetSetupPageWrapper::done); @@ -134,13 +133,12 @@ TargetSetupPageWrapper::TargetSetupPageWrapper(Project *project) void TargetSetupPageWrapper::addTargetSetupPage() { m_targetSetupPage = new TargetSetupPage(this); - m_targetSetupPage->setUseScrollArea(false); m_targetSetupPage->setProjectPath(m_project->projectFilePath()); m_targetSetupPage->setTasksGenerator( [this](const Kit *k) { return m_project->projectIssues(k); }); m_targetSetupPage->setProjectImporter(m_project->projectImporter()); m_targetSetupPage->initializePage(); - m_targetSetupPage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + m_targetSetupPage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); m_setupPageContainer->addWidget(m_targetSetupPage); completeChanged(); @@ -288,7 +286,8 @@ void TargetGroupItemPrivate::ensureWidget() if (!m_configurePage) { m_targetSetupPageWrapper = new TargetSetupPageWrapper(m_project); - m_configurePage = new PanelsWidget(Tr::tr("Configure Project"), m_targetSetupPageWrapper); + m_configurePage + = new PanelsWidget(Tr::tr("Configure Project"), m_targetSetupPageWrapper, false); m_configurePage->setFocusProxy(m_targetSetupPageWrapper); } m_targetSetupPageWrapper->ensureSetupPage(); diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 3c81640f337..5690d324764 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -81,7 +81,6 @@ public: void connectWidget(TargetSetupWidget *w); void toggleVisibility(TargetSetupWidget *w); void addAdditionalWidgets(); - void removeAdditionalWidgets(QLayout *layout); void removeAdditionalWidgets(); void updateWidget(Internal::TargetSetupWidget *widget); bool isUsable(const Kit *kit) const; @@ -98,11 +97,8 @@ public: return k ? widget(k->id(), fallback) : fallback; } - void setUseScrollArea(bool b); - TargetSetupPage *q; QWidget *centralWidget; - QWidget *scrollAreaWidget; QScrollArea *scrollArea; QLabel *headerLabel; QLabel *noValidKitLabel; @@ -112,7 +108,6 @@ public: TasksGenerator tasksGenerator; QPointer importer; - QLayout *baseLayout = nullptr; FilePath projectPath; QString defaultShadowBuildLocation; std::vector widgets; @@ -193,7 +188,7 @@ void TargetSetupPagePrivate::setupWidgets(const QString &filterText) const auto widget = new TargetSetupWidget(k, projectPath); updateWidget(widget); widgets.push_back(widget); - baseLayout->addWidget(widget); + centralWidget->layout()->addWidget(widget); } addAdditionalWidgets(); @@ -380,10 +375,6 @@ void TargetSetupPagePrivate::selectAtLeastOneEnabledKit() void TargetSetupPagePrivate::updateVisibility() { - // Always show the widgets, the import widget always makes sense to show. - scrollAreaWidget->setVisible(baseLayout == scrollArea->widget()->layout()); - centralWidget->setVisible(baseLayout == centralWidget->layout()); - const bool hasUsableKits = KitManager::kit([this](const Kit *k) { return isUsable(k); }); noValidKitLabel->setVisible(!hasUsableKits); allKitsCheckBox->setVisible(hasUsableKits); @@ -395,9 +386,9 @@ void TargetSetupPagePrivate::reLayout() { removeAdditionalWidgets(); for (TargetSetupWidget * const w : std::as_const(widgets)) - baseLayout->removeWidget(w); + centralWidget->layout()->removeWidget(w); for (TargetSetupWidget * const w : std::as_const(widgets)) - baseLayout->addWidget(w); + centralWidget->layout()->addWidget(w); addAdditionalWidgets(); } @@ -434,13 +425,11 @@ TargetSetupPagePrivate::TargetSetupPagePrivate(TargetSetupPage *parent) spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); - auto setupTargetPage = new QWidget(q); - - headerLabel = new QLabel(setupTargetPage); + headerLabel = new QLabel(q); headerLabel->setWordWrap(true); headerLabel->setVisible(false); - noValidKitLabel = new QLabel(setupTargetPage); + noValidKitLabel = new QLabel(q); noValidKitLabel->setWordWrap(true); noValidKitLabel->setText("" + Tr::tr("No suitable kits found.") + "
" @@ -450,59 +439,36 @@ TargetSetupPagePrivate::TargetSetupPagePrivate(TargetSetupPage *parent) noValidKitLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); noValidKitLabel->setVisible(false); - allKitsCheckBox = new QCheckBox(setupTargetPage); + allKitsCheckBox = new QCheckBox(q); allKitsCheckBox->setTristate(true); allKitsCheckBox->setText(Tr::tr("Select all kits")); - kitFilterLineEdit = new FancyLineEdit(setupTargetPage); + kitFilterLineEdit = new FancyLineEdit(q); kitFilterLineEdit->setFiltering(true); kitFilterLineEdit->setPlaceholderText(Tr::tr("Type to filter kits by name...")); - hideUnsuitableKitsCheckBox = new QCheckBox(Tr::tr("Hide unsuitable kits"), setupTargetPage); + hideUnsuitableKitsCheckBox = new QCheckBox(Tr::tr("Hide unsuitable kits"), q); - centralWidget = new QWidget(setupTargetPage); - QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Fixed); - policy.setHorizontalStretch(0); - policy.setVerticalStretch(0); - policy.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth()); - centralWidget->setSizePolicy(policy); - - scrollAreaWidget = new QWidget(setupTargetPage); - scrollArea = new QScrollArea(scrollAreaWidget); - scrollArea->setWidgetResizable(true); - - auto scrollAreaWidgetContents = new QWidget(); - scrollAreaWidgetContents->setGeometry(QRect(0, 0, 230, 81)); - scrollArea->setWidget(scrollAreaWidgetContents); - - auto verticalLayout = new QVBoxLayout(scrollAreaWidget); - verticalLayout->setSpacing(0); - verticalLayout->setContentsMargins(0, 0, 0, 0); - verticalLayout->addWidget(scrollArea); - - auto horizontalLayout = new QHBoxLayout; - horizontalLayout->addWidget(allKitsCheckBox); - horizontalLayout->addSpacing(10); - horizontalLayout->addWidget(kitFilterLineEdit); - - auto verticalLayout_2 = new QVBoxLayout(setupTargetPage); - verticalLayout_2->addWidget(headerLabel); - verticalLayout_2->addLayout(horizontalLayout); - verticalLayout_2->addWidget(hideUnsuitableKitsCheckBox); - verticalLayout_2->addWidget(noValidKitLabel); - verticalLayout_2->addWidget(centralWidget); - verticalLayout_2->addWidget(scrollAreaWidget); - - auto verticalLayout_3 = new QVBoxLayout(q); - verticalLayout_3->setContentsMargins(0, 0, 0, -1); - verticalLayout_3->addWidget(setupTargetPage); - - auto centralWidget = new QWidget(q); - scrollArea->setWidget(centralWidget); + centralWidget = new QWidget(q); centralWidget->setLayout(new QVBoxLayout); + centralWidget->layout()->setContentsMargins(0, 0, 0, 0); - this->centralWidget->setLayout(new QVBoxLayout); - this->centralWidget->layout()->setContentsMargins(0, 0, 0, 0); + scrollArea = new QScrollArea(q); + scrollArea->setFrameStyle(QFrame::NoFrame); + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(centralWidget); + + const auto optionsLayout = new QHBoxLayout; + optionsLayout->addWidget(hideUnsuitableKitsCheckBox); + optionsLayout->addWidget(allKitsCheckBox); + optionsLayout->addSpacing(10); + optionsLayout->addWidget(kitFilterLineEdit); + + const auto mainLayout = new QVBoxLayout(q); + mainLayout->addWidget(headerLabel); + mainLayout->addLayout(optionsLayout); + mainLayout->addWidget(noValidKitLabel); + mainLayout->addWidget(scrollArea, 255); QObject::connect(noValidKitLabel, &QLabel::linkActivated, q, &TargetSetupPage::openOptions); @@ -520,8 +486,6 @@ TargetSetupPagePrivate::TargetSetupPagePrivate(TargetSetupPage *parent) QObject::connect(kitFilterLineEdit, &FancyLineEdit::filterChanged, this, toggleTargetWidgetVisibility); - setUseScrollArea(true); - KitManager *km = KitManager::instance(); // do note that those slots are triggered once *per* targetsetuppage // thus the same slot can be triggered multiple times on different instances! @@ -636,7 +600,7 @@ TargetSetupWidget *TargetSetupPagePrivate::addWidget(Kit *k) widgets.insert(insertionPos, widget); if (addedToEnd) { removeAdditionalWidgets(); - baseLayout->addWidget(widget); + centralWidget->layout()->addWidget(widget); addAdditionalWidgets(); } else { reLayout(); @@ -673,19 +637,14 @@ void TargetSetupPagePrivate::toggleVisibility(TargetSetupWidget *w) void TargetSetupPagePrivate::addAdditionalWidgets() { - baseLayout->addWidget(importWidget); - baseLayout->addItem(spacer); -} - -void TargetSetupPagePrivate::removeAdditionalWidgets(QLayout *layout) -{ - layout->removeWidget(importWidget); - layout->removeItem(spacer); + centralWidget->layout()->addWidget(importWidget); + centralWidget->layout()->addItem(spacer); } void TargetSetupPagePrivate::removeAdditionalWidgets() { - removeAdditionalWidgets(baseLayout); + centralWidget->layout()->removeWidget(importWidget); + centralWidget->layout()->removeItem(spacer); } void TargetSetupPagePrivate::updateWidget(TargetSetupWidget *widget) @@ -729,23 +688,4 @@ bool TargetSetupPage::setupProject(Project *project) return true; } -void TargetSetupPage::setUseScrollArea(bool b) -{ - d->setUseScrollArea(b); -} - -void TargetSetupPagePrivate::setUseScrollArea(bool b) -{ - QLayout *oldBaseLayout = baseLayout; - baseLayout = b ? scrollArea->widget()->layout() : centralWidget->layout(); - if (oldBaseLayout == baseLayout) - return; - scrollAreaWidget->setVisible(b); - centralWidget->setVisible(!b); - - if (oldBaseLayout) - removeAdditionalWidgets(oldBaseLayout); - addAdditionalWidgets(); -} - } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/targetsetuppage.h b/src/plugins/projectexplorer/targetsetuppage.h index ecff0fa6391..32b1a3e2263 100644 --- a/src/plugins/projectexplorer/targetsetuppage.h +++ b/src/plugins/projectexplorer/targetsetuppage.h @@ -37,11 +37,6 @@ public: void setProjectImporter(ProjectImporter *importer); bool importLineEditHasFocus() const; - /// Sets whether the targetsetupage uses a scrollarea - /// to host the widgets from the factories - /// call this before \sa initializePage() - void setUseScrollArea(bool b); - bool isComplete() const override; bool setupProject(Project *project); QList selectedKits() const; From d7d9f4667831549a8253e32aa78aed95f6345a46 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 1 Nov 2024 11:36:54 +0100 Subject: [PATCH 050/989] Avoid std::optional::value It - checks existence of the value again, which we already do before - it throws, which static analyzers don't like because we don't catch or declare - opt.value().something is doubly wrong because operator-> does it better Use operator* and operator-> instead. Change-Id: Icfddebcadb4bba35a59876cee705393d03509129 Reviewed-by: hjk --- src/libs/solutions/tasking/barrier.h | 4 +- src/libs/utils/icon.cpp | 3 +- src/libs/utils/outputformatter.cpp | 2 +- src/libs/utils/settingsaccessor.cpp | 5 ++- src/libs/utils/settingsaccessor.h | 4 +- src/plugins/axivion/axivionperspective.cpp | 6 +-- src/plugins/clangcodemodel/clangdclient.cpp | 2 +- .../cmakebuildconfiguration.cpp | 12 +++--- .../cmakeprojectmanager/cmakebuildstep.cpp | 4 +- .../cmakeprojectimporter.cpp | 23 +++++----- src/plugins/cmakeprojectmanager/cmaketool.cpp | 3 +- .../cmakeprojectmanager/configmodel.cpp | 2 +- .../fileapidataextractor.cpp | 14 +++---- .../cmakeprojectmanager/fileapiparser.cpp | 2 +- .../cmakeprojectmanager/presetsmacros.cpp | 2 +- .../cmakeprojectmanager/presetsparser.cpp | 42 +++++++++---------- .../editormanager/documentmodel.cpp | 6 +-- .../editormanager/openeditorsview.cpp | 2 +- src/plugins/debugger/debuggerruncontrol.cpp | 7 ++-- src/plugins/fakevim/fakevimplugin.cpp | 2 +- .../lualanguageclient/lualanguageclient.cpp | 2 +- src/plugins/lua/bindings/project.cpp | 2 +- src/plugins/projectexplorer/gcctoolchain.cpp | 4 +- src/plugins/projectexplorer/msvctoolchain.cpp | 2 +- .../projectexplorer/userfileaccessor.cpp | 5 +-- 25 files changed, 79 insertions(+), 83 deletions(-) diff --git a/src/libs/solutions/tasking/barrier.h b/src/libs/solutions/tasking/barrier.h index 06316d78337..6d75c859ce4 100644 --- a/src/libs/solutions/tasking/barrier.h +++ b/src/libs/solutions/tasking/barrier.h @@ -86,8 +86,8 @@ ExecutableItem waitForBarrierTask(const MultiBarrier &sharedBarrier) Barrier *activeSharedBarrier = activeBarrier->barrier(); const std::optional result = activeSharedBarrier->result(); if (result.has_value()) { - return result.value() == DoneResult::Success ? SetupResult::StopWithSuccess - : SetupResult::StopWithError; + return *result == DoneResult::Success ? SetupResult::StopWithSuccess + : SetupResult::StopWithError; } QObject::connect(activeSharedBarrier, &Barrier::done, &barrier, &Barrier::stopWithResult); return SetupResult::Continue; diff --git a/src/libs/utils/icon.cpp b/src/libs/utils/icon.cpp index f63a5e094a4..4846a9753b3 100644 --- a/src/libs/utils/icon.cpp +++ b/src/libs/utils/icon.cpp @@ -188,8 +188,7 @@ QIcon Icon::icon() const if (const OptMasksAndColors activeMasks = highlightMasksAndColors(masks, m_iconSourceList); activeMasks.has_value()) { - const QPixmap activePixmap = masksToIcon(activeMasks.value(), - combinedMask, m_style); + const QPixmap activePixmap = masksToIcon(*activeMasks, combinedMask, m_style); m_lastIcon.addPixmap(activePixmap, QIcon::Active, QIcon::On); m_lastIcon.addPixmap(disabledIcon, QIcon::Disabled, QIcon::On); m_lastIcon.addPixmap(disabledIcon, QIcon::Disabled, QIcon::Off); diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp index d36662f4d34..d5dd40106e5 100644 --- a/src/libs/utils/outputformatter.cpp +++ b/src/libs/utils/outputformatter.cpp @@ -320,7 +320,7 @@ void OutputFormatter::doAppendMessage(const QString &text, OutputFormat format) } if (res.newContent) { - append(res.newContent.value(), charFmt); + append(*res.newContent, charFmt); return; } diff --git a/src/libs/utils/settingsaccessor.cpp b/src/libs/utils/settingsaccessor.cpp index 1c9f30ecba5..1ca9f08de76 100644 --- a/src/libs/utils/settingsaccessor.cpp +++ b/src/libs/utils/settingsaccessor.cpp @@ -63,7 +63,8 @@ bool SettingsAccessor::saveSettings(const Store &data, QWidget *parent) const const std::optional result = writeData(m_baseFilePath, data, parent); - const ProceedInfo pi = result ? reportIssues(result.value(), m_baseFilePath, parent) : ProceedInfo::Continue; + const ProceedInfo pi = result ? reportIssues(*result, m_baseFilePath, parent) + : ProceedInfo::Continue; return pi == ProceedInfo::Continue; } @@ -97,7 +98,7 @@ Store SettingsAccessor::restoreSettings(const FilePath &settingsPath, QWidget *p const RestoreData result = readData(settingsPath, parent); - const ProceedInfo pi = result.hasIssue() ? reportIssues(result.issue.value(), result.path, parent) + const ProceedInfo pi = result.hasIssue() ? reportIssues(*result.issue, result.path, parent) : ProceedInfo::Continue; return pi == ProceedInfo::DiscardAndContinue ? Store() : result.data; } diff --git a/src/libs/utils/settingsaccessor.h b/src/libs/utils/settingsaccessor.h index b882fbaeb78..c8ac8fd883b 100644 --- a/src/libs/utils/settingsaccessor.h +++ b/src/libs/utils/settingsaccessor.h @@ -83,8 +83,8 @@ public: RestoreData(const Issue &issue) : issue{issue} { } bool hasIssue() const { return bool(issue); } - bool hasError() const { return hasIssue() && issue.value().type == Issue::Type::ERROR; } - bool hasWarning() const { return hasIssue() && issue.value().type == Issue::Type::WARNING; } + bool hasError() const { return hasIssue() && issue->type == Issue::Type::ERROR; } + bool hasWarning() const { return hasIssue() && issue->type == Issue::Type::WARNING; } FilePath path; Store data; diff --git a/src/plugins/axivion/axivionperspective.cpp b/src/plugins/axivion/axivionperspective.cpp index ff5f3e11e9c..a17fa4e1671 100644 --- a/src/plugins/axivion/axivionperspective.cpp +++ b/src/plugins/axivion/axivionperspective.cpp @@ -593,14 +593,14 @@ void IssuesWidget::addIssues(const Dto::IssueTableDto &dto, int startRow) { QTC_ASSERT(m_currentTableInfo.has_value(), return); if (dto.totalRowCount.has_value()) { - m_totalRowCount = dto.totalRowCount.value(); + m_totalRowCount = *dto.totalRowCount; m_issuesModel->setExpectedRowCount(m_totalRowCount); m_totalRows->setText(Tr::tr("Total rows:") + ' ' + QString::number(m_totalRowCount)); } if (dto.totalAddedCount.has_value()) - m_addedFilter->setText(QString::number(dto.totalAddedCount.value())); + m_addedFilter->setText(QString::number(*dto.totalAddedCount)); if (dto.totalRemovedCount.has_value()) - m_removedFilter->setText(QString::number(dto.totalRemovedCount.value())); + m_removedFilter->setText(QString::number(*dto.totalRemovedCount)); const std::vector &tableColumns = m_currentTableInfo->columns; const std::vector> &rows = dto.rows; diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 8238ebf762e..ada183d4d74 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -980,7 +980,7 @@ MessageId ClangdClient::requestSymbolInfo(const Utils::FilePath &filePath, const // According to the documentation, we should receive a single // object here, but it's a list. No idea what it means if there's // more than one entry. We choose the first one. - const auto list = std::get_if>(&result.value()); + const auto list = std::get_if>(&(*result)); if (!list || list->isEmpty()) { handler({}, {}, reqId); return; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index f0c43f0c60e..00587a215d5 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -1957,7 +1957,7 @@ void CMakeBuildConfiguration::setBuildPresetToBuildSteps(const ProjectExplorer:: getEnvironmentItemsFromCMakeBuildPreset(project, target->kit(), buildPresets[i].name)); if (buildPresets[i].targets) { - QString targets = buildPresets[i].targets.value().join(" "); + QString targets = buildPresets[i].targets->join(" "); CMakePresets::Macros::expand(buildPresets[i], cbs->environment(), @@ -1969,16 +1969,16 @@ void CMakeBuildConfiguration::setBuildPresetToBuildSteps(const ProjectExplorer:: QStringList cmakeArguments; if (buildPresets[i].jobs) - cmakeArguments.append(QString("-j %1").arg(buildPresets[i].jobs.value())); - if (buildPresets[i].verbose && buildPresets[i].verbose.value()) + cmakeArguments.append(QString("-j %1").arg(*buildPresets[i].jobs)); + if (buildPresets[i].verbose && *buildPresets[i].verbose) cmakeArguments.append("--verbose"); - if (buildPresets[i].cleanFirst && buildPresets[i].cleanFirst.value()) + if (buildPresets[i].cleanFirst && *buildPresets[i].cleanFirst) cmakeArguments.append("--clean-first"); if (!cmakeArguments.isEmpty()) cbs->setCMakeArguments(cmakeArguments); if (buildPresets[i].nativeToolOptions) { - QString nativeToolOptions = buildPresets[i].nativeToolOptions.value().join(" "); + QString nativeToolOptions = buildPresets[i].nativeToolOptions->join(" "); CMakePresets::Macros::expand(buildPresets[i], cbs->environment(), @@ -1989,7 +1989,7 @@ void CMakeBuildConfiguration::setBuildPresetToBuildSteps(const ProjectExplorer:: } if (buildPresets[i].configuration) - cbs->setConfiguration(buildPresets[i].configuration.value()); + cbs->setConfiguration(*buildPresets[i].configuration); // Leave only the first build step enabled if (i > 0) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 670fa49531d..759fa6b8799 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -491,7 +491,7 @@ CommandLine CMakeBuildStep::cmakeCommand() const if (bs && bs->isMultiConfigReader()) { cmd.addArg("--config"); if (m_configuration) - cmd.addArg(m_configuration.value()); + cmd.addArg(*m_configuration); else cmd.addArg(bs->cmakeBuildType()); } @@ -586,7 +586,7 @@ QWidget *CMakeBuildStep::createConfigWidget() return bp.name == m_buildPreset; }); - const QString presetDisplayName = preset.displayName ? preset.displayName.value() + const QString presetDisplayName = preset.displayName ? *preset.displayName : preset.name; if (!presetDisplayName.isEmpty()) summaryText.append(QString("
Preset: %1").arg(presetDisplayName)); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 035692367af..4613b68ed7a 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -216,7 +216,7 @@ FilePaths CMakeProjectImporter::presetCandidates() Environment env = projectDirectory().deviceEnvironment(); CMakePresets::Macros::expand(configPreset, env, projectDirectory()); - QString binaryDir = configPreset.binaryDir.value(); + QString binaryDir = *configPreset.binaryDir; CMakePresets::Macros::expand(configPreset, env, projectDirectory(), binaryDir); const FilePath binaryFilePath = FilePath::fromString(binaryDir); @@ -263,10 +263,10 @@ static QVariant findOrRegisterDebugger( Environment &env, const PresetsDetails::ConfigurePreset &preset, const DebuggerCMakeExpander& expander) { const QString debuggerKey("debugger"); - if (!preset.vendor || !preset.vendor.value().contains(debuggerKey)) + if (!preset.vendor || !preset.vendor->contains(debuggerKey)) return {}; - const QVariant debuggerVariant = preset.vendor.value().value(debuggerKey); + const QVariant debuggerVariant = preset.vendor->value(debuggerKey); FilePath debuggerPath = FilePath::fromUserInput(expander.expand(debuggerVariant.toString())); if (!debuggerPath.isEmpty()) { if (debuggerPath.isRelativePath()) @@ -373,7 +373,7 @@ static CMakeConfig configurationFromPresetProbe( Process cmake; cmake.setDisableUnixTerminal(); - const FilePath cmakeExecutable = configurePreset.cmakeExecutable.value(); + const FilePath cmakeExecutable = configurePreset.cmakeExecutable.value_or(FilePath()); Environment env = cmakeExecutable.deviceEnvironment(); CMakePresets::Macros::expand(configurePreset, env, sourceDirectory); @@ -389,29 +389,28 @@ static CMakeConfig configurationFromPresetProbe( if (configurePreset.generator) { args.emplace_back("-G"); - args.emplace_back(configurePreset.generator.value()); + args.emplace_back(*configurePreset.generator); } - if (configurePreset.architecture && configurePreset.architecture.value().value) { + if (configurePreset.architecture && configurePreset.architecture->value) { if (!configurePreset.architecture->strategy || configurePreset.architecture->strategy != PresetsDetails::ValueStrategyPair::Strategy::external) { args.emplace_back("-A"); - args.emplace_back(configurePreset.architecture.value().value.value()); + args.emplace_back(*configurePreset.architecture->value); } } - if (configurePreset.toolset && configurePreset.toolset.value().value) { + if (configurePreset.toolset && configurePreset.toolset->value) { if (!configurePreset.toolset->strategy || configurePreset.toolset->strategy != PresetsDetails::ValueStrategyPair::Strategy::external) { args.emplace_back("-T"); - args.emplace_back(configurePreset.toolset.value().value.value()); + args.emplace_back(*configurePreset.toolset->value); } } if (configurePreset.cacheVariables) { - const CMakeConfig cache = configurePreset.cacheVariables - ? configurePreset.cacheVariables.value() - : CMakeConfig(); + const CMakeConfig cache = configurePreset.cacheVariables ? *configurePreset.cacheVariables + : CMakeConfig(); const QString cmakeMakeProgram = cache.stringValueOf("CMAKE_MAKE_PROGRAM"); const QString toolchainFile = cache.stringValueOf("CMAKE_TOOLCHAIN_FILE"); diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index 22948083109..22712536c4f 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -183,8 +183,7 @@ Store CMakeTool::toMap() const data.insert(CMAKE_INFORMATION_QCH_FILE_PATH, m_qchFilePath.toSettings()); data.insert(CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY, m_autoCreateBuildDirectory); if (m_readerType) - data.insert(CMAKE_INFORMATION_READERTYPE, - Internal::readerTypeToString(m_readerType.value())); + data.insert(CMAKE_INFORMATION_READERTYPE, Internal::readerTypeToString(*m_readerType)); data.insert(CMAKE_INFORMATION_AUTODETECTED, m_isAutoDetected); data.insert(CMAKE_INFORMATION_DETECTIONSOURCE, m_detectionSource); return data; diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index a274c5a89ea..31fc4aa54f2 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -577,7 +577,7 @@ QVariant ConfigModelTreeItem::data(int column, int role) const const QString value = currentValue(); const auto boolValue = CMakeConfigItem::toBool(value); - const bool isTrue = boolValue.has_value() && boolValue.value(); + const bool isTrue = boolValue.has_value() && *boolValue; switch (role) { case Qt::CheckStateRole: diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index ab583af3264..fd6cedc2e5b 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -271,19 +271,17 @@ static CMakeBuildTarget toBuildTarget(const TargetDetails &t, if (ct.targetType == ExecutableType) { FilePaths librarySeachPaths; // Is this a GUI application? - ct.linksToQtGui = Utils::contains(t.link.value().fragments, - [](const FragmentInfo &f) { - return f.role == "libraries" - && (f.fragment.contains("QtGui") - || f.fragment.contains("Qt5Gui") - || f.fragment.contains("Qt6Gui")); - }); + ct.linksToQtGui = Utils::contains(t.link->fragments, [](const FragmentInfo &f) { + return f.role == "libraries" + && (f.fragment.contains("QtGui") || f.fragment.contains("Qt5Gui") + || f.fragment.contains("Qt6Gui")); + }); // FIXME: remove the usage of "qtc_runnable" by parsing the CMake code instead ct.qtcRunnable = t.folderTargetProperty == QTC_RUNNABLE; // Extract library directories for executables: - for (const FragmentInfo &f : t.link.value().fragments) { + for (const FragmentInfo &f : t.link->fragments) { if (f.role == "flags") // ignore all flags fragments continue; diff --git a/src/plugins/cmakeprojectmanager/fileapiparser.cpp b/src/plugins/cmakeprojectmanager/fileapiparser.cpp index d9ea457600f..45bfb7945bd 100644 --- a/src/plugins/cmakeprojectmanager/fileapiparser.cpp +++ b/src/plugins/cmakeprojectmanager/fileapiparser.cpp @@ -197,7 +197,7 @@ static CMakeConfig readCacheFile(const FilePath &cacheFile, QString &errorMessag auto nv = nameValue(prop); if (nv.first == "ADVANCED") { const auto boolValue = CMakeConfigItem::toBool(nv.second); - item.isAdvanced = boolValue.has_value() && boolValue.value(); + item.isAdvanced = boolValue.has_value() && *boolValue; } else if (nv.first == "HELPSTRING") { item.documentation = nv.second.toUtf8(); } else if (nv.first == "STRINGS") { diff --git a/src/plugins/cmakeprojectmanager/presetsmacros.cpp b/src/plugins/cmakeprojectmanager/presetsmacros.cpp index 21342b4ab53..2dc061decad 100644 --- a/src/plugins/cmakeprojectmanager/presetsmacros.cpp +++ b/src/plugins/cmakeprojectmanager/presetsmacros.cpp @@ -44,7 +44,7 @@ static void expandAllButEnv(const PresetsDetails::ConfigurePreset &preset, value.replace("${presetName}", preset.name); value.replace("${fileDir}", preset.fileDir.path()); if (preset.generator) - value.replace("${generator}", preset.generator.value()); + value.replace("${generator}", *preset.generator); value.replace("${hostSystemName}", getHostSystemName(sourceDirectory.osType())); value.replace("${pathListSep}", diff --git a/src/plugins/cmakeprojectmanager/presetsparser.cpp b/src/plugins/cmakeprojectmanager/presetsparser.cpp index 9633808b75f..983ffb70f9b 100644 --- a/src/plugins/cmakeprojectmanager/presetsparser.cpp +++ b/src/plugins/cmakeprojectmanager/presetsparser.cpp @@ -573,14 +573,14 @@ static QStringList merge(const QStringList &first, const QStringList &second) void PresetsDetails::ConfigurePreset::inheritFrom(const ConfigurePreset &other) { - if (!condition && other.condition && !other.condition.value().isNull()) + if (!condition && other.condition && !other.condition->isNull()) condition = other.condition; if (!vendor && other.vendor) vendor = other.vendor; if (vendor && other.vendor) - vendor = merge(other.vendor.value(), vendor.value()); + vendor = merge(*other.vendor, *vendor); if (!generator && other.generator) generator = other.generator; @@ -606,12 +606,12 @@ void PresetsDetails::ConfigurePreset::inheritFrom(const ConfigurePreset &other) if (!cacheVariables && other.cacheVariables) cacheVariables = other.cacheVariables; else if (cacheVariables && other.cacheVariables) - cacheVariables = merge(other.cacheVariables.value(), cacheVariables.value()); + cacheVariables = merge(*other.cacheVariables, *cacheVariables); if (!environment && other.environment) environment = other.environment; else if (environment && other.environment) - environment = environment.value().appliedToEnvironment(other.environment.value()); + environment = environment->appliedToEnvironment(*other.environment); if (!warnings && other.warnings) warnings = other.warnings; @@ -625,19 +625,19 @@ void PresetsDetails::ConfigurePreset::inheritFrom(const ConfigurePreset &other) void PresetsDetails::BuildPreset::inheritFrom(const BuildPreset &other) { - if (!condition && other.condition && !other.condition.value().isNull()) + if (!condition && other.condition && !other.condition->isNull()) condition = other.condition; if (!vendor && other.vendor) vendor = other.vendor; if (vendor && other.vendor) - vendor = merge(other.vendor.value(), vendor.value()); + vendor = merge(*other.vendor, *vendor); if (!environment && other.environment) environment = other.environment; else if (environment && other.environment) - environment = environment.value().appliedToEnvironment(other.environment.value()); + environment = environment->appliedToEnvironment(*other.environment); if (!configurePreset && other.configurePreset) configurePreset = other.configurePreset; @@ -651,7 +651,7 @@ void PresetsDetails::BuildPreset::inheritFrom(const BuildPreset &other) if (!targets && other.targets) targets = other.targets; else if (targets && other.targets) - targets = merge(other.targets.value(), targets.value()); + targets = merge(*other.targets, *targets); if (!configuration && other.configuration) configuration = other.configuration; @@ -665,7 +665,7 @@ void PresetsDetails::BuildPreset::inheritFrom(const BuildPreset &other) if (!nativeToolOptions && other.nativeToolOptions) nativeToolOptions = other.nativeToolOptions; else if (nativeToolOptions && other.nativeToolOptions) - nativeToolOptions = merge(other.nativeToolOptions.value(), nativeToolOptions.value()); + nativeToolOptions = merge(*other.nativeToolOptions, *nativeToolOptions); } bool PresetsDetails::Condition::evaluate() const @@ -674,38 +674,38 @@ bool PresetsDetails::Condition::evaluate() const return true; if (isConst() && constValue) - return constValue.value(); + return *constValue; if (isEquals() && lhs && rhs) - return lhs.value() == rhs.value(); + return *lhs == *rhs; if (isNotEquals() && lhs && rhs) - return lhs.value() != rhs.value(); + return *lhs != *rhs; if (isInList() && string && list) - return list.value().contains(string.value()); + return list->contains(*string); if (isNotInList() && string && list) - return !list.value().contains(string.value()); + return !list->contains(*string); if (isMatches() && string && regex) { - QRegularExpression qRegex(regex.value()); - return qRegex.match(string.value()).hasMatch(); + QRegularExpression qRegex(*regex); + return qRegex.match(*string).hasMatch(); } if (isNotMatches() && string && regex) { - QRegularExpression qRegex(regex.value()); - return !qRegex.match(string.value()).hasMatch(); + QRegularExpression qRegex(*regex); + return !qRegex.match(*string).hasMatch(); } if (isAnyOf() && conditions) - return Utils::anyOf(conditions.value(), [](const ConditionPtr &c) { return c->evaluate(); }); + return Utils::anyOf(*conditions, [](const ConditionPtr &c) { return c->evaluate(); }); if (isAllOf() && conditions) - return Utils::allOf(conditions.value(), [](const ConditionPtr &c) { return c->evaluate(); }); + return Utils::allOf(*conditions, [](const ConditionPtr &c) { return c->evaluate(); }); if (isNot() && condition) - return !condition.value()->evaluate(); + return !(*condition)->evaluate(); return false; } diff --git a/src/plugins/coreplugin/editormanager/documentmodel.cpp b/src/plugins/coreplugin/editormanager/documentmodel.cpp index 7bc86fda482..dc8067f05e6 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.cpp +++ b/src/plugins/coreplugin/editormanager/documentmodel.cpp @@ -322,7 +322,7 @@ void DocumentModelPrivate::itemChanged(IDocument *document) return; const FilePath fixedPath = DocumentManager::filePathKey(document->filePath(), DocumentManager::ResolveLinks); - DocumentModel::Entry *entry = m_entries.at(idx.value()); + DocumentModel::Entry *entry = m_entries.at(*idx); bool found = false; // The entry's fileName might have changed, so find the previous fileName that was associated // with it and remove it, then add the new fileName. @@ -340,8 +340,8 @@ void DocumentModelPrivate::itemChanged(IDocument *document) if (!found && !fixedPath.isEmpty()) m_entryByFixedPath[fixedPath] = entry; - if (!disambiguateDisplayNames(m_entries.at(idx.value()))) { - QModelIndex mindex = index(idx.value() + 1/**/, 0); + if (!disambiguateDisplayNames(m_entries.at(*idx))) { + QModelIndex mindex = index(*idx + 1 /**/, 0); emit dataChanged(mindex, mindex); } diff --git a/src/plugins/coreplugin/editormanager/openeditorsview.cpp b/src/plugins/coreplugin/editormanager/openeditorsview.cpp index e72aff96bbd..6c14869d7ad 100644 --- a/src/plugins/coreplugin/editormanager/openeditorsview.cpp +++ b/src/plugins/coreplugin/editormanager/openeditorsview.cpp @@ -105,7 +105,7 @@ void OpenEditorsWidget::updateCurrentItem(IEditor *editor) } const std::optional index = DocumentModel::indexOfDocument(editor->document()); if (QTC_GUARD(index)) - setCurrentIndex(m_model->index(index.value(), 0)); + setCurrentIndex(m_model->index(*index, 0)); selectionModel()->select(currentIndex(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); scrollTo(currentIndex()); diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index a1f15429201..1549a5e94b8 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -715,9 +715,10 @@ void DebuggerRunTool::handleEngineFinished(DebuggerEngine *engine) if (--d->engineStopsNeeded == 0) { QString cmd = m_runParameters.inferior.command.toUserOutput(); QString msg = engine->runParameters().exitCode // Main engine. - ? Tr::tr("Debugging of %1 has finished with exit code %2.") - .arg(cmd).arg(engine->runParameters().exitCode.value()) - : Tr::tr("Debugging of %1 has finished.").arg(cmd); + ? Tr::tr("Debugging of %1 has finished with exit code %2.") + .arg(cmd) + .arg(*engine->runParameters().exitCode) + : Tr::tr("Debugging of %1 has finished.").arg(cmd); appendMessage(msg, NormalMessageFormat); reportStopped(); } diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index a6d812bf765..40de3337706 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -2044,7 +2044,7 @@ int FakeVimPlugin::currentFile() const if (editor) { const std::optional index = DocumentModel::indexOfDocument(editor->document()); if (QTC_GUARD(index)) - return index.value(); + return *index; } return -1; } diff --git a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp index ebc1e522fad..b2fe215363c 100644 --- a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp +++ b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp @@ -689,7 +689,7 @@ static void registerLuaApi() [](const LuaClientWrapper *c) -> sol::function { if (!c->m_onInstanceStart) return sol::lua_nil; - return c->m_onInstanceStart.value(); + return *c->m_onInstanceStart; }, [](LuaClientWrapper *c, const sol::function &f) { c->m_onInstanceStart = f; }), "registerMessage", diff --git a/src/plugins/lua/bindings/project.cpp b/src/plugins/lua/bindings/project.cpp index e140ca92790..42a71c010f1 100644 --- a/src/plugins/lua/bindings/project.cpp +++ b/src/plugins/lua/bindings/project.cpp @@ -122,7 +122,7 @@ void setupProjectModule() if (rc && rc->displayName() == displayName) { stoppedCount++; - if (force.has_value() && force.value()) { + if (force.has_value() && *force) { rc->forceStop(); } else { rc->initiateStop(); diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 7dbae83b62f..e1382e6f22e 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -616,7 +616,7 @@ Toolchain::MacroInspectionRunner GccToolchain::createMacroInspectionRunner() con arguments = reinterpretOptions(arguments); const std::optional cachedMacros = macroCache->check(arguments); if (cachedMacros) - return cachedMacros.value(); + return *cachedMacros; const expected_str macroResult = gccPredefinedMacros(findLocalCompiler(compilerCommand, env), arguments, env); @@ -795,7 +795,7 @@ static HeaderPaths builtInHeaderPaths(const Environment &env, const std::optional cachedPaths = headerCache->check({env, arguments}); if (cachedPaths) - return cachedPaths.value(); + return *cachedPaths; HeaderPaths paths = gccHeaderPaths(findLocalCompiler(compilerCommand, env), arguments, diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 7239f408398..132c9afe8a4 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1055,7 +1055,7 @@ Toolchain::MacroInspectionRunner MsvcToolchain::createMacroInspectionRunner() co const std::optional cachedMacros = macroCache->check(filteredFlags); if (cachedMacros) - return cachedMacros.value(); + return *cachedMacros; const Macros macros = msvcPredefinedMacros(filteredFlags, env); diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp index d5929353774..173594c19f8 100644 --- a/src/plugins/projectexplorer/userfileaccessor.cpp +++ b/src/plugins/projectexplorer/userfileaccessor.cpp @@ -240,9 +240,8 @@ static FilePath externalUserFilePath(const Utils::FilePath &projectFilePath, con if (externalUserFileDir) { // Recreate the relative project file hierarchy under the shared directory. // PersistentSettingsWriter::write() takes care of creating the path. - return FilePath::fromString(externalUserFileDir.value() - + '/' + makeRelative(projectFilePath.toString()) - + suffix); + return FilePath::fromString( + *externalUserFileDir + '/' + makeRelative(projectFilePath.toString()) + suffix); } return {}; } From 3e71d051c0a4b4d47ee591b1258cb948c8730e34 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 1 Nov 2024 16:27:07 +0100 Subject: [PATCH 051/989] Core: Simplify coreplugin.h a bit Change-Id: I263eaa0217de6b83e18f59f5f9fb60dd54b12a48 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/coreplugin.cpp | 70 +++++++++++++-------------- src/plugins/coreplugin/coreplugin.h | 10 ---- 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 7fc4631a690..8130a963aaf 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -204,6 +204,40 @@ static void initTAndCAcceptDialog() }); } +static void addToPathChooserContextMenu(PathChooser *pathChooser, QMenu *menu) +{ + QList actions = menu->actions(); + QAction *firstAction = actions.isEmpty() ? nullptr : actions.first(); + + if (pathChooser->filePath().exists()) { + auto showInGraphicalShell = new QAction(FileUtils::msgGraphicalShellAction(), menu); + QObject::connect(showInGraphicalShell, &QAction::triggered, pathChooser, [pathChooser] { + Core::FileUtils::showInGraphicalShell(pathChooser, pathChooser->filePath()); + }); + menu->insertAction(firstAction, showInGraphicalShell); + + auto showInTerminal = new QAction(FileUtils::msgTerminalHereAction(), menu); + QObject::connect(showInTerminal, &QAction::triggered, pathChooser, [pathChooser] { + if (pathChooser->openTerminalHandler()) + pathChooser->openTerminalHandler()(); + else + FileUtils::openTerminal(pathChooser->filePath(), {}); + }); + menu->insertAction(firstAction, showInTerminal); + + } else { + auto mkPathAct = new QAction(Tr::tr("Create Folder"), menu); + QObject::connect(mkPathAct, &QAction::triggered, pathChooser, [pathChooser] { + QDir().mkpath(pathChooser->filePath().toString()); + pathChooser->triggerChanged(); + }); + menu->insertAction(firstAction, mkPathAct); + } + + if (firstAction) + menu->insertSeparator(firstAction); +} + bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) { // register all mime types from all plugins @@ -315,7 +349,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) Tr::tr("Convert string to pure ASCII."), [expander](const QString &s) { return asciify(expander->expand(s)); }); - Utils::PathChooser::setAboutToShowContextMenuHandler(&CorePlugin::addToPathChooserContextMenu); + Utils::PathChooser::setAboutToShowContextMenuHandler(&addToPathChooserContextMenu); #ifdef ENABLE_CRASHPAD connect(ICore::instance(), &ICore::coreOpened, this, &CorePlugin::warnAboutCrashReporing, @@ -436,40 +470,6 @@ void CorePlugin::fileOpenRequest(const QString &f) remoteCommand(QStringList(), QString(), QStringList(f)); } -void CorePlugin::addToPathChooserContextMenu(Utils::PathChooser *pathChooser, QMenu *menu) -{ - QList actions = menu->actions(); - QAction *firstAction = actions.isEmpty() ? nullptr : actions.first(); - - if (pathChooser->filePath().exists()) { - auto showInGraphicalShell = new QAction(FileUtils::msgGraphicalShellAction(), menu); - connect(showInGraphicalShell, &QAction::triggered, pathChooser, [pathChooser] { - Core::FileUtils::showInGraphicalShell(pathChooser, pathChooser->filePath()); - }); - menu->insertAction(firstAction, showInGraphicalShell); - - auto showInTerminal = new QAction(FileUtils::msgTerminalHereAction(), menu); - connect(showInTerminal, &QAction::triggered, pathChooser, [pathChooser] { - if (pathChooser->openTerminalHandler()) - pathChooser->openTerminalHandler()(); - else - FileUtils::openTerminal(pathChooser->filePath(), {}); - }); - menu->insertAction(firstAction, showInTerminal); - - } else { - auto *mkPathAct = new QAction(Tr::tr("Create Folder"), menu); - connect(mkPathAct, &QAction::triggered, pathChooser, [pathChooser] { - QDir().mkpath(pathChooser->filePath().toString()); - pathChooser->triggerChanged(); - }); - menu->insertAction(firstAction, mkPathAct); - } - - if (firstAction) - menu->insertSeparator(firstAction); -} - void CorePlugin::checkSettings() { const auto showMsgBox = [this](const QString &msg, QMessageBox::Icon icon) { diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index e5c253e4dbd..682c7449e19 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -12,14 +12,6 @@ #include -QT_BEGIN_NAMESPACE -class QMenu; -QT_END_NAMESPACE - -namespace Utils { -class PathChooser; -} - namespace Core { class FolderNavigationWidgetFactory; @@ -29,7 +21,6 @@ class ICore; namespace Internal { class EditMode; -class MainWindow; class Locator; class CorePlugin : public ExtensionSystem::IPlugin @@ -70,7 +61,6 @@ private slots: #endif private: - static void addToPathChooserContextMenu(Utils::PathChooser *pathChooser, QMenu *menu); void checkSettings(); void warnAboutCrashReporing(); From 947c5f12de2eb4f3d3ed121aee9dc02ba128db75 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 1 Nov 2024 17:32:00 +0100 Subject: [PATCH 052/989] ExtensionSystem: Add a GuardedObject convenience class To simplify the creation of objects with life time bounded by shutdownGuard(). Using the guard also as connection guard is safe, as an QObject's destroyed() signal is sent before its connections are destroyed. Change-Id: Ibb25760c8e0d6c9e0aa41f2e54c6ae64e33ddc44 Reviewed-by: Eike Ziller --- src/libs/extensionsystem/shutdownguard.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/libs/extensionsystem/shutdownguard.h b/src/libs/extensionsystem/shutdownguard.h index b0a5ad4e08e..63f32f88eca 100644 --- a/src/libs/extensionsystem/shutdownguard.h +++ b/src/libs/extensionsystem/shutdownguard.h @@ -11,4 +11,24 @@ namespace ExtensionSystem { EXTENSIONSYSTEM_EXPORT QObject *shutdownGuard(); +template +class GuardedObject +{ +public: + GuardedObject() + : m_object(new T) + { + QObject::connect(shutdownGuard(), &QObject::destroyed, shutdownGuard(), [this] { + delete m_object; + m_object = nullptr; + }); + } + ~GuardedObject() = default; + + T *get() const { return m_object; } + +private: + T *m_object; +}; + } // namespace ExtensionSystem From cb534fbd2d8242cf347417694c7463437b8c5ffb Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 1 Nov 2024 17:43:05 +0100 Subject: [PATCH 053/989] Core: Create SessionManager on first access Change-Id: If242113ac1fe96c88be82fd4458b6caed0fb76f8 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/coreplugin.cpp | 1 - src/plugins/coreplugin/coreplugin.h | 4 ---- src/plugins/coreplugin/session.cpp | 19 +++++++++++++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 8130a963aaf..263b6e89fde 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -271,7 +271,6 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) m_editMode = new EditMode; ModeManager::activateMode(m_editMode->id()); m_folderNavigationWidgetFactory = new FolderNavigationWidgetFactory; - m_sessionManager.reset(new SessionManager); IWizardFactory::initialize(); diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index 682c7449e19..45cc8195025 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -10,12 +10,9 @@ #include #include -#include - namespace Core { class FolderNavigationWidgetFactory; -class SessionManager; class ICore; namespace Internal { @@ -67,7 +64,6 @@ private: ICore *m_core = nullptr; EditMode *m_editMode = nullptr; Locator *m_locator = nullptr; - std::unique_ptr m_sessionManager; FolderNavigationWidgetFactory *m_folderNavigationWidgetFactory = nullptr; const Utils::Environment m_startupSystemEnvironment; Utils::EnvironmentItems m_environmentChanges; diff --git a/src/plugins/coreplugin/session.cpp b/src/plugins/coreplugin/session.cpp index 88e4749b51f..fba84d402b3 100644 --- a/src/plugins/coreplugin/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include @@ -108,12 +110,17 @@ public: QAction *m_sessionManagerAction; }; -static SessionManager *m_instance = nullptr; static SessionManagerPrivate *d = nullptr; +SessionManager *sessionManager() +{ + static ExtensionSystem::GuardedObject theSessionManager; + return theSessionManager.get(); +} + SessionManager::SessionManager() { - m_instance = this; + QTC_ASSERT(isMainThread(), return); d = new SessionManagerPrivate; connect(PluginManager::instance(), &PluginManager::initializationDone, this, [] { @@ -158,7 +165,7 @@ SessionManager::SessionManager() cmd->setDefaultKeySequence(QKeySequence()); connect(d->m_sessionManagerAction, &QAction::triggered, - SessionManager::instance(), + this, &SessionManager::showSessionManager); MacroExpander *expander = Utils::globalMacroExpander(); @@ -177,7 +184,7 @@ SessionManager::SessionManager() SessionManager::~SessionManager() { - emit m_instance->aboutToUnloadSession(d->m_sessionName); + emit aboutToUnloadSession(d->m_sessionName); delete d->m_writer; delete d; d = nullptr; @@ -185,7 +192,7 @@ SessionManager::~SessionManager() SessionManager *SessionManager::instance() { - return m_instance; + return sessionManager(); } bool SessionManager::isDefaultVirgin() @@ -455,7 +462,7 @@ void SessionManagerPrivate::restoreStartupSession() ICore::openFiles(Utils::transform(arguments, &FilePath::fromUserInput), ICore::OpenFilesFlags(ICore::CanContainLineAndColumnNumbers | ICore::SwitchMode)); - emit m_instance->startupSessionRestored(); + emit sessionManager()->startupSessionRestored(); } void SessionManagerPrivate::saveSettings() From de692191d1914f2829b1e5f44289a369de3544e6 Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Mon, 28 Oct 2024 13:04:26 +0100 Subject: [PATCH 054/989] Boot2Qt: Fix Performance Analyzer arguments Pass performance arguments analyzer in the format that is understandable by Boo2Qt's appcontroller. Change-Id: I542dde23126f41db6f610829157b4149dd69b9e5 Reviewed-by: hjk --- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index 284a83d4de5..af046c9b679 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -74,7 +74,16 @@ public: } if (usesPerfChannel()) { const Store perfArgs = runControl()->settingsData(PerfProfiler::Constants::PerfSettingsId); - const QString recordArgs = perfArgs[PerfProfiler::Constants::PerfRecordArgsId].toString(); + // appcontroller is not very clear about this, but it expects a comma-separated list of arguments. + // Any literal commas that apper in the args should be escaped by additional commas. + // See the source at + // https://code.qt.io/cgit/qt-apps/boot2qt-appcontroller.git/tree/main.cpp?id=658dc91cf561e41704619a55fbb1f708decf134e#n434 + // and adjust if necessary. + const QString recordArgs = perfArgs[PerfProfiler::Constants::PerfRecordArgsId] + .toString() + .replace(',', ",,") + .split(' ', Qt::SkipEmptyParts) + .join(','); cmd.addArg("--profile-perf"); cmd.addArgs(recordArgs, CommandLine::Raw); lowerPort = upperPort = perfChannel().port(); From d00b5806fc27ae089e65822f8d7f258306e2df28 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 4 Nov 2024 08:51:20 +0100 Subject: [PATCH 055/989] Core: Use a unique_ptr for the persistent settings writer ... in SessionManager. Change-Id: I4cbaad60abe5545feffc0fa1603835f500cb9cbb Reviewed-by: Eike Ziller --- src/plugins/coreplugin/session.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/plugins/coreplugin/session.cpp b/src/plugins/coreplugin/session.cpp index fba84d402b3..ba15cfb1684 100644 --- a/src/plugins/coreplugin/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -104,7 +104,7 @@ public: QMap m_values; QMap m_sessionValues; QFutureInterface m_future; - PersistentSettingsWriter *m_writer = nullptr; + std::unique_ptr m_writer; QMenu *m_sessionMenu; QAction *m_sessionManagerAction; @@ -185,7 +185,6 @@ SessionManager::SessionManager() SessionManager::~SessionManager() { emit aboutToUnloadSession(d->m_sessionName); - delete d->m_writer; delete d; d = nullptr; } @@ -696,8 +695,7 @@ bool SessionManager::loadSession(const QString &session, bool initial) d->m_sessionValues.clear(); d->m_sessionName = session; - delete d->m_writer; - d->m_writer = nullptr; + d->m_writer.reset(); EditorManager::updateWindowTitles(); d->m_virginSession = false; @@ -781,10 +779,9 @@ bool SessionManager::saveSession() } data.insert("valueKeys", stringsFromKeys(keys)); - if (!d->m_writer || d->m_writer->fileName() != filePath) { - delete d->m_writer; - d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession"); - } + if (!d->m_writer || d->m_writer->fileName() != filePath) + d->m_writer.reset(new PersistentSettingsWriter(filePath, "QtCreatorSession")); + const bool result = d->m_writer->save(data, ICore::dialogParent()); if (result) { if (!SessionManager::isDefaultVirgin()) From 1455f7ecf6a55325b1af65e9be7cd8318474e442 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 4 Nov 2024 08:53:27 +0100 Subject: [PATCH 056/989] Core: Don't emit aboutToUnloadSession on SessionManager destruction There are two consumers of the signal currently: 1. AppOutputPane, using it to close tabs, possibly after getting necessary confirmation from promptToStop(), 2. DebuggerTooltipManager, using it to hide tooltips. However, at quitting time, 1 is triggered already before from Core::MainWindow::closeEvent(), and the confirmation from promptToStop() destroys the RunControls, including any associated DebuggerTooltipManager. So the call here is not necessary. Change-Id: Ie31c408826115aef3a0dbc5f78d944d568b2e34b Reviewed-by: Eike Ziller --- src/plugins/coreplugin/session.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/coreplugin/session.cpp b/src/plugins/coreplugin/session.cpp index ba15cfb1684..e1e0aea47fe 100644 --- a/src/plugins/coreplugin/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -184,7 +184,6 @@ SessionManager::SessionManager() SessionManager::~SessionManager() { - emit aboutToUnloadSession(d->m_sessionName); delete d; d = nullptr; } From 006619e765375a182e5759f6f82a6dee1bd23c96 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 30 Oct 2024 16:28:26 +0100 Subject: [PATCH 057/989] ProjectExplorer: Ensure initially selected kit is visible ... in the target setup page. Change-Id: I908319f01e10f6a50e24373ef909d44bc54e2e1d Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/targetsetuppage.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 5690d324764..7504fad8483 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -75,6 +75,7 @@ public: bool isUpdating() const; void selectAtLeastOneEnabledKit(); + void ensureSelectedKitIsVisible(); void removeWidget(Kit *k) { removeWidget(widget(k)); } void removeWidget(Internal::TargetSetupWidget *w); TargetSetupWidget *addWidget(Kit *k); @@ -373,6 +374,14 @@ void TargetSetupPagePrivate::selectAtLeastOneEnabledKit() } } +void TargetSetupPagePrivate::ensureSelectedKitIsVisible() +{ + if (TargetSetupWidget * const w + = Utils::findOrDefault(widgets, &TargetSetupWidget::isKitSelected)) { + scrollArea->ensureWidgetVisible(w); + } +} + void TargetSetupPagePrivate::updateVisibility() { const bool hasUsableKits = KitManager::kit([this](const Kit *k) { return isUsable(k); }); @@ -532,6 +541,7 @@ void TargetSetupPage::showEvent(QShowEvent *event) { WizardPage::showEvent(event); d->kitFilterLineEdit->setFocus(); // Ensure "Configure Project" gets triggered on + d->ensureSelectedKitIsVisible(); } void TargetSetupPage::changeAllKitsSelections() From 07da2227029eacb99011f334d442875ca8b05df7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 1 Nov 2024 14:53:43 +0100 Subject: [PATCH 058/989] CppEditor: Add special implementation for "apply signature changes" ... for when the change is only a switch of parameters. Fixes: QTCREATORBUG-31931 Change-Id: I44e269aace0c93cc7a250d53e614272abec9c59c Reviewed-by: Christian Stenger --- .../cppeditor/cppfunctiondecldeflink.cpp | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index 4fad2e652e2..6cd2c954b29 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -729,6 +729,7 @@ ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targetOffse QString newTargetParameters; bool hadChanges = newParamCount < existingParamCount; // below, additions and changes set this to true as well QHash renamedTargetParameters; + bool switchedOnly = true; for (int newParamIndex = 0; newParamIndex < newParamCount; ++newParamIndex) { const int existingParamIndex = newParamToSourceParam[newParamIndex]; Symbol *newParam = newFunction->argumentAt(newParamIndex); @@ -744,6 +745,7 @@ ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targetOffse FullySpecifiedType type = rewriteType(newParam->type(), &env, control); newTargetParam = overview.prettyType(type, newParam->name()); hadChanges = true; + switchedOnly = false; // otherwise preserve as much as possible from the existing parameter } else { Symbol *targetParam = targetFunction->argumentAt(existingParamIndex); @@ -785,6 +787,7 @@ ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targetOffse FullySpecifiedType replacementType = rewriteType(newParam->type(), &env, control); if (!newParam->type().match(sourceParam->type()) && !replacementType.match(targetParam->type())) { + switchedOnly = false; const int parameterTypeStart = targetFile->startOf(targetParamAst); int parameterTypeEnd = 0; if (targetParamAst->declarator) @@ -800,6 +803,7 @@ ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targetOffse hadChanges = true; // change the name only? } else if (!namesEqual(targetParam->name(), replacementName)) { + switchedOnly = false; DeclaratorIdAST *id = getDeclaratorId(targetParamAst->declarator); const QString &replacementNameStr = overview.prettyName(replacementName); if (id) { @@ -854,9 +858,27 @@ ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targetOffse newTargetParameters += ensureCorrectParameterSpacing(newTargetParam, isFirstNewParam); } if (hadChanges) { - changes.replace(targetFile->endOf(targetFunctionDeclarator->lparen_token), - targetFile->startOf(targetFunctionDeclarator->rparen_token), - newTargetParameters); + // Special case for when there was purely a parameter switch: + // This operation can simply be mapped to the "flip" change operation, with + // no heuristics as to the formatting. + if (switchedOnly) { + QList srcIndices; + for (int tgtIndex = 0; tgtIndex < newParamToSourceParam.size(); ++tgtIndex) { + if (srcIndices.contains(tgtIndex)) + continue; + const int srcIndex = newParamToSourceParam[tgtIndex]; + srcIndices << srcIndex; + const ParameterDeclarationAST * const srcDecl = targetParameterDecls.at(srcIndex); + const ParameterDeclarationAST * const tgtDecl = targetParameterDecls.at(tgtIndex); + const ChangeSet::Range srcRange = targetFile->range(srcDecl); + const ChangeSet::Range tgtRange = targetFile->range(tgtDecl); + changes.flip(srcRange, tgtRange); + } + } else { + changes.replace(targetFile->endOf(targetFunctionDeclarator->lparen_token), + targetFile->startOf(targetFunctionDeclarator->rparen_token), + newTargetParameters); + } } // Change parameter names in function documentation. From cea452e6b2527811922db2dab0efa4b52a79b9b9 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 4 Nov 2024 15:16:42 +0100 Subject: [PATCH 059/989] Utils: Fix DeviceFileAccess::fileSize() fallback return value Change-Id: If3700027431c3783ebb4a75ab91dd5a5e1bd27b4 Reviewed-by: Christian Kandeler --- src/libs/utils/devicefileaccess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 5e03996eeca..27c62d05a65 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -355,7 +355,7 @@ qint64 DeviceFileAccess::fileSize(const FilePath &filePath) const { Q_UNUSED(filePath) QTC_CHECK(false); - return false; + return -1; } qint64 DeviceFileAccess::bytesAvailable(const FilePath &filePath) const From 373f8f937832b5ed77d0bb45724a7cff7e37b51e Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 4 Nov 2024 14:20:55 +0100 Subject: [PATCH 060/989] Utils: Add an UnavailableFileAccess class This is meant to be used in cases some device is temporarily not accessible or otherwise "dead". Change-Id: Iba1c1d78138a5509f3b01c1214ebeb04d052c67c Reviewed-by: Christian Kandeler --- src/libs/utils/devicefileaccess.cpp | 231 ++++++++++++++++++++++++++++ src/libs/utils/devicefileaccess.h | 60 ++++++++ 2 files changed, 291 insertions(+) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 27c62d05a65..445aae81e7d 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -44,6 +44,8 @@ namespace Utils { // DeviceFileAccess +DeviceFileAccess::DeviceFileAccess() = default; + DeviceFileAccess::~DeviceFileAccess() = default; // This takes a \a hostPath, typically the same as used with QFileInfo @@ -396,6 +398,235 @@ Utils::expected_str> DeviceFileAccess::watch( return make_unexpected(Tr::tr("watch is not implemented.")); } +// UnavailableDeviceFileAccess + +UnavailableDeviceFileAccess::UnavailableDeviceFileAccess() = default; + +UnavailableDeviceFileAccess::~UnavailableDeviceFileAccess() = default; + +static QString unavailableMessage() +{ + return Tr::tr("Device is unavailable."); +} + +QString UnavailableDeviceFileAccess::mapToDevicePath(const QString &hostPath) const +{ + return hostPath; +} + +bool UnavailableDeviceFileAccess::isExecutableFile(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::isReadableFile(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::isWritableFile(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::isReadableDirectory(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::isWritableDirectory(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::isFile(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::isDirectory(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::isSymLink(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::hasHardLinks(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +Result UnavailableDeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const +{ + Q_UNUSED(filePath); + return Result::Error(unavailableMessage()); +} + +bool UnavailableDeviceFileAccess::ensureExistingFile(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::createDirectory(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +bool UnavailableDeviceFileAccess::exists(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +Result UnavailableDeviceFileAccess::removeFile(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return Result::Error(unavailableMessage()); +} + +bool UnavailableDeviceFileAccess::removeRecursively(const FilePath &filePath, QString *error) const +{ + Q_UNUSED(filePath) + Q_UNUSED(error) + return false; +} + +Result UnavailableDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const +{ + Q_UNUSED(filePath) + Q_UNUSED(target) + return Result::Error(unavailableMessage()); +} + +Result UnavailableDeviceFileAccess::copyRecursively(const FilePath &src, const FilePath &target) const +{ + Q_UNUSED(src) + Q_UNUSED(target) + return Result::Error(unavailableMessage()); +} + +Result UnavailableDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const +{ + Q_UNUSED(filePath) + Q_UNUSED(target) + return Result::Error(unavailableMessage()); +} + +FilePath UnavailableDeviceFileAccess::symLinkTarget(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return {}; +} + +void UnavailableDeviceFileAccess::iterateDirectory(const FilePath &filePath, + const FilePath::IterateDirCallback &callBack, + const FileFilter &filter) const +{ + Q_UNUSED(filePath) + Q_UNUSED(callBack) + Q_UNUSED(filter) +} + +Environment UnavailableDeviceFileAccess::deviceEnvironment() const +{ + return {}; +} + +expected_str UnavailableDeviceFileAccess::fileContents(const FilePath &filePath, + qint64 limit, + qint64 offset) const +{ + Q_UNUSED(filePath) + Q_UNUSED(limit) + Q_UNUSED(offset) + return make_unexpected(unavailableMessage()); +} + +expected_str UnavailableDeviceFileAccess::writeFileContents(const FilePath &filePath, + const QByteArray &data) const +{ + Q_UNUSED(filePath) + Q_UNUSED(data) + return make_unexpected(unavailableMessage()); +} + +FilePathInfo UnavailableDeviceFileAccess::filePathInfo(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return {}; +} + +QDateTime UnavailableDeviceFileAccess::lastModified(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return {}; +} + +QFile::Permissions UnavailableDeviceFileAccess::permissions(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return {}; +} + +bool UnavailableDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permissions) const +{ + Q_UNUSED(filePath) + return false; +} + +qint64 UnavailableDeviceFileAccess::fileSize(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return false; +} + +qint64 UnavailableDeviceFileAccess::bytesAvailable(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return -1; +} + +QByteArray UnavailableDeviceFileAccess::fileId(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + return {}; +} + +std::optional UnavailableDeviceFileAccess::refersToExecutableFile( + const FilePath &filePath, FilePath::MatchScope matchScope) const +{ + Q_UNUSED(filePath) + Q_UNUSED(matchScope) + return {}; +} + +expected_str UnavailableDeviceFileAccess::createTempFile(const FilePath &filePath) +{ + Q_UNUSED(filePath) + return make_unexpected(unavailableMessage()); +} + +expected_str> + UnavailableDeviceFileAccess::watch(const FilePath &path) const +{ + Q_UNUSED(path); + return make_unexpected(unavailableMessage()); +} + // DesktopDeviceFileAccess class DesktopFilePathWatcher final : public FilePathWatcher diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index 0b56a679dec..b1836f3bff3 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -19,6 +19,7 @@ class RunResult; class QTCREATOR_UTILS_EXPORT DeviceFileAccess { public: + DeviceFileAccess(); virtual ~DeviceFileAccess(); virtual Environment deviceEnvironment() const; @@ -78,6 +79,65 @@ protected: virtual Utils::expected_str> watch(const FilePath &path) const; }; +class QTCREATOR_UTILS_EXPORT UnavailableDeviceFileAccess : public DeviceFileAccess +{ +public: + UnavailableDeviceFileAccess(); + ~UnavailableDeviceFileAccess() override; + +protected: + QString mapToDevicePath(const QString &hostPath) const override; + + Environment deviceEnvironment() const override; + bool isExecutableFile(const FilePath &filePath) const override; + bool isReadableFile(const FilePath &filePath) const override; + bool isWritableFile(const FilePath &filePath) const override; + bool isReadableDirectory(const FilePath &filePath) const override; + bool isWritableDirectory(const FilePath &filePath) const override; + bool isFile(const FilePath &filePath) const override; + bool isDirectory(const FilePath &filePath) const override; + bool isSymLink(const FilePath &filePath) const override; + bool hasHardLinks(const FilePath &filePath) const override; + 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; + Result removeFile(const FilePath &filePath) const override; + bool removeRecursively(const FilePath &filePath, QString *error) const override; + Result copyFile(const FilePath &filePath, const FilePath &target) const override; + Result copyRecursively(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; + QDateTime lastModified(const FilePath &filePath) const override; + QFile::Permissions permissions(const FilePath &filePath) const override; + bool setPermissions(const FilePath &filePath, QFile::Permissions) const override; + qint64 fileSize(const FilePath &filePath) const override; + qint64 bytesAvailable(const FilePath &filePath) const override; + QByteArray fileId(const FilePath &filePath) const override; + + std::optional refersToExecutableFile( + const FilePath &filePath, + FilePath::MatchScope matchScope) const override; + + void iterateDirectory( + const FilePath &filePath, + const FilePath::IterateDirCallback &callBack, + const FileFilter &filter) const override; + + expected_str fileContents(const FilePath &filePath, + qint64 limit, + qint64 offset) const override; + + expected_str writeFileContents(const FilePath &filePath, + const QByteArray &data) const override; + + expected_str createTempFile(const FilePath &filePath) override; + + Utils::expected_str> watch(const FilePath &path) const override; +}; + class QTCREATOR_UTILS_EXPORT DesktopDeviceFileAccess : public DeviceFileAccess { public: From 646caaca1ab4e004bb66b17e157bd2cef628ef4e Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 31 Oct 2024 10:39:48 +0100 Subject: [PATCH 061/989] MessageManager: Reduce manual setup Create on first access, destroy via shutdownGuard() Change-Id: Ic4d38f86e36411874c7114e8d179c6e36823bae1 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/icore.cpp | 2 - src/plugins/coreplugin/messagemanager.cpp | 58 ++++++++----------- src/plugins/coreplugin/messagemanager.h | 3 - .../coreplugin/messageoutputwindow.cpp | 3 +- src/plugins/coreplugin/messageoutputwindow.h | 2 +- 5 files changed, 27 insertions(+), 41 deletions(-) diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 59e5957e1a5..e511b2f4a52 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -389,7 +389,6 @@ ICore::ICore() Utils::setDialogParentGetter(&ICore::dialogParent); d->m_progressManager->init(); // needs the status bar manager - MessageManager::init(); OutputPaneManager::create(); } @@ -1431,7 +1430,6 @@ ICorePrivate::~ICorePrivate() delete m_externalToolManager; m_externalToolManager = nullptr; - MessageManager::destroy(); delete m_vcsManager; m_vcsManager = nullptr; //we need to delete editormanager and statusbarmanager explicitly before the end of the destructor, diff --git a/src/plugins/coreplugin/messagemanager.cpp b/src/plugins/coreplugin/messagemanager.cpp index 730d4bfd710..68efe3020c6 100644 --- a/src/plugins/coreplugin/messagemanager.cpp +++ b/src/plugins/coreplugin/messagemanager.cpp @@ -5,9 +5,12 @@ #include "messageoutputwindow.h" +#include + #include #include +#include /*! \namespace Core::MessageManager @@ -19,55 +22,42 @@ \uicontrol{General Messages} pane. */ +using namespace Core::Internal; + namespace Core::MessageManager { -static Internal::MessageOutputWindow *s_messageOutputWindow = nullptr; +static MessageOutputWindow *messageOutputWindow() +{ + static QPointer theMessageOutputWindow + = new MessageOutputWindow(ExtensionSystem::shutdownGuard()); + return theMessageOutputWindow.get(); +} enum class Flag { Silent, Flash, Disrupt }; static void showOutputPane(Flag flags) { - QTC_ASSERT(s_messageOutputWindow, return); + QTC_ASSERT(messageOutputWindow(), return); switch (flags) { case Flag::Silent: break; case Flag::Flash: - s_messageOutputWindow->flash(); + messageOutputWindow()->flash(); break; case Flag::Disrupt: - s_messageOutputWindow->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus); + messageOutputWindow()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus); break; } } -static void doWrite(const QString &text, Flag flags) -{ - QTC_ASSERT(s_messageOutputWindow, return); - showOutputPane(flags); - s_messageOutputWindow->append(text + '\n'); -} - static void writeImpl(const QString &text, Flag flags) { - QTC_ASSERT(s_messageOutputWindow, return); - QMetaObject::invokeMethod(s_messageOutputWindow, [text, flags] { doWrite(text, flags); }); -} - -/*! - \internal -*/ -void init() -{ - s_messageOutputWindow = new Internal::MessageOutputWindow; -} - -/*! - \internal -*/ -void destroy() -{ - delete s_messageOutputWindow; - s_messageOutputWindow = nullptr; + // Make sure this end up in the GUI thread. + QMetaObject::invokeMethod(ExtensionSystem::shutdownGuard(), [text, flags] { + QTC_ASSERT(messageOutputWindow(), return); + showOutputPane(flags); + messageOutputWindow()->append(text + '\n'); + }); } /*! @@ -75,8 +65,8 @@ void destroy() */ void setFont(const QFont &font) { - QTC_ASSERT(s_messageOutputWindow, return); - s_messageOutputWindow->setFont(font); + QTC_ASSERT(messageOutputWindow(), return); + messageOutputWindow()->setFont(font); } /*! @@ -84,8 +74,8 @@ void setFont(const QFont &font) */ void setWheelZoomEnabled(bool enabled) { - QTC_ASSERT(s_messageOutputWindow, return); - s_messageOutputWindow->setWheelZoomEnabled(enabled); + QTC_ASSERT(messageOutputWindow(), return); + messageOutputWindow()->setWheelZoomEnabled(enabled); } /*! diff --git a/src/plugins/coreplugin/messagemanager.h b/src/plugins/coreplugin/messagemanager.h index 87a4b6f6499..1aa7485ec70 100644 --- a/src/plugins/coreplugin/messagemanager.h +++ b/src/plugins/coreplugin/messagemanager.h @@ -24,7 +24,4 @@ CORE_EXPORT void writeSilently(const QStringList &messages); CORE_EXPORT void writeFlashing(const QStringList &messages); CORE_EXPORT void writeDisrupting(const QStringList &messages); -void init(); -void destroy(); - } // namespace Core::MessageManager diff --git a/src/plugins/coreplugin/messageoutputwindow.cpp b/src/plugins/coreplugin/messageoutputwindow.cpp index b13a301efed..75dca7e66ad 100644 --- a/src/plugins/coreplugin/messageoutputwindow.cpp +++ b/src/plugins/coreplugin/messageoutputwindow.cpp @@ -18,7 +18,8 @@ namespace Internal { const char zoomSettingsKey[] = "Core/MessageOutput/Zoom"; -MessageOutputWindow::MessageOutputWindow() +MessageOutputWindow::MessageOutputWindow(QObject *parent) + : IOutputPane(parent) { setId("GeneralMessages"); setDisplayName(Tr::tr("General Messages")); diff --git a/src/plugins/coreplugin/messageoutputwindow.h b/src/plugins/coreplugin/messageoutputwindow.h index eabc2adcff3..f8bf96bff53 100644 --- a/src/plugins/coreplugin/messageoutputwindow.h +++ b/src/plugins/coreplugin/messageoutputwindow.h @@ -15,7 +15,7 @@ class MessageOutputWindow : public IOutputPane Q_OBJECT public: - MessageOutputWindow(); + explicit MessageOutputWindow(QObject *parent); ~MessageOutputWindow() override; QWidget *outputWidget(QWidget *parent) override; From 8c5ac9580067d9769911c9de891703b703985f69 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 4 Nov 2024 13:45:57 +0100 Subject: [PATCH 062/989] QtSupport: Read target ABI from JSON file This should be less expensive than traversing directories and poking into binaries. Fixes: QTCREATORBUG-31943 Change-Id: I8aea1bb9ce9d49daca615a90f7f1092783dbf4fa Reviewed-by: David Schulz --- src/plugins/qtsupport/baseqtversion.cpp | 176 +++++++++++++++++++++++- src/plugins/qtsupport/baseqtversion.h | 7 +- 2 files changed, 175 insertions(+), 8 deletions(-) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 4b94d9d4d30..28f580d9fa7 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -46,9 +47,14 @@ #include #include #include +#include #include #include +#include +#include +#include #include +#include #include #include @@ -71,6 +77,8 @@ const char QTVERSION_ABIS[] = "Abis"; const char MKSPEC_VALUE_LIBINFIX[] = "QT_LIBINFIX"; const char MKSPEC_VALUE_NAMESPACE[] = "QT_NAMESPACE"; +Q_LOGGING_CATEGORY(abiDetect, "qtc.qtsupport.detectAbis", QtWarningMsg) + // -------------------------------------------------------------------- // QtVersionData: // -------------------------------------------------------------------- @@ -95,6 +103,7 @@ public: Utils::FilePath libExecPath; Utils::FilePath configurationPath; Utils::FilePath dataPath; + FilePath archDataPath; Utils::FilePath demosPath; Utils::FilePath docsPath; Utils::FilePath examplesPath; @@ -184,6 +193,8 @@ public: // and by the qtoptionspage to replace Qt versions FilePaths qtCorePaths(); + ProjectExplorer::Abis qtAbisFromLibrary(); + ProjectExplorer::Abis qtAbisFromJson(); public: QtVersion *q; @@ -757,7 +768,11 @@ void QtVersion::setQtAbis(const Abis &abis) Abis QtVersion::detectQtAbis() const { - return qtAbisFromLibrary(d->qtCorePaths()); + qCDebug(abiDetect) << "Detecting ABIs for" << qmakeFilePath(); + if (const Abis abis = d->qtAbisFromJson(); !abis.isEmpty()) + return abis; + qCDebug(abiDetect) << "Got no ABI from JSON file, falling back to inspecting binaries"; + return d->qtAbisFromLibrary(); } bool QtVersion::hasAbi(ProjectExplorer::Abi::OS os, ProjectExplorer::Abi::OSFlavor flavor) const @@ -1252,6 +1267,7 @@ void QtVersionPrivate::updateVersionInfo() m_data.libExecPath = fileProperty("QT_INSTALL_LIBEXECS"); m_data.configurationPath = fileProperty("QT_INSTALL_CONFIGURATION"); m_data.dataPath = fileProperty("QT_INSTALL_DATA"); + m_data.archDataPath = fileProperty("QT_INSTALL_ARCHDATA"); m_data.demosPath = fileProperty("QT_INSTALL_DEMOS"); m_data.docsPath = fileProperty("QT_INSTALL_DOCS"); m_data.examplesPath = fileProperty("QT_INSTALL_EXAMPLES"); @@ -2213,7 +2229,7 @@ static Abi scanQtBinaryForBuildStringAndRefineAbi(const FilePath &library, return results.value(library); } -Abis QtVersion::qtAbisFromLibrary(const FilePaths &coreLibraries) +Abis QtVersionPrivate::qtAbisFromLibrary() { auto filePathToAbiList = [](const FilePath &library) { // Fetch all abis from all libraries ... Abis abis = Abi::abisOfBinary(library); @@ -2231,7 +2247,161 @@ Abis QtVersion::qtAbisFromLibrary(const FilePaths &coreLibraries) } }; - return QtConcurrent::blockingMappedReduced(coreLibraries, filePathToAbiList, uniqueAbis); + return QtConcurrent::blockingMappedReduced(qtCorePaths(), filePathToAbiList, uniqueAbis); +} + +Abis QtVersionPrivate::qtAbisFromJson() +{ + updateVersionInfo(); + + if (q->qtVersion().majorVersion() < 6) { + qCDebug(abiDetect) << "Not attempting to read JSON file for Qt < 6"; + return {}; + } + + FilePath jsonFile; + for (const FilePath &baseDir : FilePaths{m_data.archDataPath, m_data.dataPath}) { + const FilePath candidate = baseDir.pathAppended("modules/Core.json"); + qCDebug(abiDetect) << "Checking JSON file location" << candidate; + if (candidate.exists()) { + jsonFile = candidate; + break; + } + } + if (jsonFile.isEmpty()) { + Core::MessageManager::writeSilently( + Tr::tr("Core.json not found for Qt at \"%1\"").arg(m_qmakeCommand.toUserOutput())); + return {}; + } + + const auto printErrorAndReturn = [&jsonFile](const QString &detail) { + Core::MessageManager::writeSilently( + Tr::tr("Error reading \"%1\": %2").arg(jsonFile.toUserOutput(), detail)); + return Abis(); + }; + const auto content = jsonFile.fileContents(); + if (!content) + return printErrorAndReturn(content.error()); + + QJsonParseError parseError; + const QJsonDocument jsonDoc = QJsonDocument::fromJson(content.value(), &parseError); + if (parseError.error != QJsonParseError::NoError) + return printErrorAndReturn(parseError.errorString()); + + const QJsonObject obj = jsonDoc.object().value("built_with").toObject(); + const QString osString = obj.value("target_system").toString(); + const Abi::OS os = [&osString] { + if (osString == "Linux" || osString == "Android") + return Abi::LinuxOS; + if (osString == "Darwin" || osString == "iOS") + return Abi::DarwinOS; + if (osString == "Windows") + return Abi::WindowsOS; + if (osString.endsWith("BSD")) + return Abi::BsdOS; + return Abi::UnknownOS; + }(); + + if (os == Abi::DarwinOS) + return {}; // QTBUG-129996 + + const auto [arch, width] = [](const QString &arch) { + if (arch == "x86") + return std::make_pair(Abi::X86Architecture, 32); + if (arch == "x86_64") + return std::make_pair(Abi::X86Architecture, 64); + if (arch == "arm") + return std::make_pair(Abi::ArmArchitecture, 32); + if (arch == "arm64") + return std::make_pair(Abi::ArmArchitecture, 64); + if (arch == "riscv64") + return std::make_pair(Abi::RiscVArchitecture, 64); + if (arch == "wasm") + return std::make_pair(Abi::AsmJsArchitecture, 32); + return std::make_pair(Abi::UnknownArchitecture, 0); + }(obj.value("architecture").toString()); + if (os == Abi::UnknownOS && arch != Abi::AsmJsArchitecture) + return printErrorAndReturn(Tr::tr("Could not determine target OS")); + if (arch == Abi::UnknownArchitecture) + return printErrorAndReturn(Tr::tr("Could not determine target architecture")); + + const Abi::OSFlavor flavor = [&](const QString &compilerId, const QString &compilerVersion) { + if (osString == "Android") + return Abi::AndroidLinuxFlavor; + switch (os) { + case Abi::LinuxOS: + case Abi::DarwinOS: + case Abi::BareMetalOS: + case Abi::QnxOS: + return Abi::GenericFlavor; + case Abi::BsdOS: + if (osString == "FreeBSD") + return Abi::FreeBsdFlavor; + if (osString == "NetBSD") + return Abi::NetBsdFlavor; + if (osString == "OpenBSD") + return Abi::OpenBsdFlavor; + break; + case Abi::WindowsOS: { + if (compilerId == "GNU" || compilerId == "Clang") + return Abi::WindowsMSysFlavor; + + // https://learn.microsoft.com/en-us/cpp/overview/compiler-versions + const QVersionNumber rawVersion = QVersionNumber::fromString(compilerVersion); + switch (rawVersion.majorVersion()) { + case 19: + if (rawVersion.minorVersion() >= 30) + return Abi::WindowsMsvc2022Flavor; + if (rawVersion.minorVersion() >= 20) + return Abi::WindowsMsvc2019Flavor; + if (rawVersion.minorVersion() >= 10) + return Abi::WindowsMsvc2017Flavor; + return Abi::WindowsMsvc2015Flavor; + case 18: + return Abi::WindowsMsvc2013Flavor; + case 17: + return Abi::WindowsMsvc2012Flavor; + case 16: + return Abi::WindowsMsvc2010Flavor; + case 15: + return Abi::WindowsMsvc2008Flavor; + case 14: + return Abi::WindowsMsvc2005Flavor; + } + break; + } + case Abi::UnixOS: + case Abi::VxWorks: + case Abi::UnknownOS: + break; + } + return Abi::UnknownFlavor; + }(obj.value("compiler_id").toString(), obj.value("compiler_version").toString()); + if (flavor == Abi::UnknownFlavor && arch != Abi::AsmJsArchitecture) + return printErrorAndReturn(Tr::tr("Could not determine OS sub-type")); + + const Abi::BinaryFormat format = [&] { + if (arch == Abi::AsmJsArchitecture) + return Abi::EmscriptenFormat; + switch (os) { + case Abi::BareMetalOS: + case Abi::BsdOS: + case Abi::LinuxOS: + case Abi::QnxOS: + case Abi::UnixOS: + case Abi::VxWorks: + return Abi::ElfFormat; + case Abi::DarwinOS: + return Abi::MachOFormat; + case Abi::WindowsOS: + return Abi::PEFormat; + case Abi::UnknownOS: + break; + } + return Abi::UnknownFormat; + }(); + + return {Abi(arch, os, flavor, format, width)}; } void QtVersion::resetCache() const diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h index a31ef9f5de8..f810f8073b5 100644 --- a/src/plugins/qtsupport/baseqtversion.h +++ b/src/plugins/qtsupport/baseqtversion.h @@ -203,9 +203,6 @@ protected: virtual ProjectExplorer::Abis detectQtAbis() const; - // helper function for desktop and simulator to figure out the supported abis based on the libraries - static ProjectExplorer::Abis qtAbisFromLibrary(const Utils::FilePaths &coreLibraries); - void resetCache() const; void ensureMkSpecParsed() const; @@ -213,13 +210,13 @@ protected: virtual void setupQmakeRunEnvironment(Utils::Environment &env) const; private: - void updateDefaultDisplayName(); - friend class QtVersionFactory; friend class QtVersionManager; friend class Internal::QtVersionPrivate; friend class Internal::QtSettingsPageWidget; + void updateDefaultDisplayName(); + void setId(int id); QtVersion *clone() const; From e4176a457f4c03f18fcfa8d5dc8d7d2668a3192e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 5 Nov 2024 16:24:14 +0100 Subject: [PATCH 063/989] NetworkQuery: Add some QNetworkReply signals Propagate some QNetworkReply signals directly via NetwortQuery API. Change-Id: I9754d7741179e344a30ac6d29351a35526c5ea42 Reviewed-by: hjk --- src/libs/solutions/tasking/networkquery.cpp | 3 +++ src/libs/solutions/tasking/networkquery.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/libs/solutions/tasking/networkquery.cpp b/src/libs/solutions/tasking/networkquery.cpp index 30789ec925b..81c13c5db7b 100644 --- a/src/libs/solutions/tasking/networkquery.cpp +++ b/src/libs/solutions/tasking/networkquery.cpp @@ -36,6 +36,9 @@ void NetworkQuery::start() m_reply.reset(m_manager->deleteResource(m_request)); break; } + + connect(m_reply.get(), &QNetworkReply::downloadProgress, this, &NetworkQuery::downloadProgress); + connect(m_reply.get(), &QNetworkReply::sslErrors, this, &NetworkQuery::sslErrors); connect(m_reply.get(), &QNetworkReply::finished, this, [this] { disconnect(m_reply.get(), &QNetworkReply::finished, this, nullptr); emit done(toDoneResult(m_reply->error() == QNetworkReply::NoError)); diff --git a/src/libs/solutions/tasking/networkquery.h b/src/libs/solutions/tasking/networkquery.h index 6d288486712..9836a7535f6 100644 --- a/src/libs/solutions/tasking/networkquery.h +++ b/src/libs/solutions/tasking/networkquery.h @@ -40,6 +40,8 @@ public: Q_SIGNALS: void started(); + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void sslErrors(const QList &errors); void done(DoneResult result); private: From 1f3128383697265ef2e51dc75800820188a4a4a5 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 5 Nov 2024 15:05:57 +0100 Subject: [PATCH 064/989] CPlusPlus: Add support for init statements in range-based for loops Fixes: QTCREATORBUG-31961 Change-Id: I2002c0248e8f853ba5dae555b6a4cf9f6e91af9c Reviewed-by: Christian Stenger --- src/libs/3rdparty/cplusplus/AST.h | 5 +++++ src/libs/3rdparty/cplusplus/ASTClone.cpp | 4 ++++ src/libs/3rdparty/cplusplus/ASTMatcher.cpp | 9 ++++++++ src/libs/3rdparty/cplusplus/ASTVisit.cpp | 2 ++ src/libs/3rdparty/cplusplus/Bind.cpp | 5 +++++ src/libs/3rdparty/cplusplus/Parser.cpp | 12 +++++++++++ tests/auto/cplusplus/cxx11/tst_cxx11.cpp | 24 ++++++++++++++++++++++ 7 files changed, 61 insertions(+) diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 085fff92bdb..cc39fc39888 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -1720,6 +1720,11 @@ class CPLUSPLUS_EXPORT RangeBasedForStatementAST : public StatementAST public: int for_token = 0; int lparen_token = 0; + + // init-statement (C++20) + DeclarationAST *initDecl = nullptr; + StatementAST *initStmt = nullptr; + // declaration SpecifierListAST *type_specifier_list = nullptr; DeclaratorAST *declarator = nullptr; diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index c9c2fc8294a..688a7708534 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -747,6 +747,10 @@ RangeBasedForStatementAST *RangeBasedForStatementAST::clone(MemoryPool *pool) co RangeBasedForStatementAST *ast = new (pool) RangeBasedForStatementAST; ast->for_token = for_token; ast->lparen_token = lparen_token; + if (initDecl) + ast->initDecl = initDecl->clone(pool); + if (initStmt) + ast->initStmt = initStmt->clone(pool); for (SpecifierListAST *iter = type_specifier_list, **ast_iter = &ast->type_specifier_list; iter; iter = iter->next, ast_iter = &(*ast_iter)->next) *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr); diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index b264098a969..e417ecc3072 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -1244,6 +1244,15 @@ bool ASTMatcher::match(RangeBasedForStatementAST *node, RangeBasedForStatementAS pattern->lparen_token = node->lparen_token; + if (!pattern->initDecl) + pattern->initDecl = node->initDecl; + else if (!AST::match(node->initDecl, pattern->initDecl, this)) + return false; + if (!pattern->initStmt) + pattern->initStmt = node->initStmt; + else if (!AST::match(node->initStmt, pattern->initStmt, this)) + return false; + if (! pattern->type_specifier_list) pattern->type_specifier_list = node->type_specifier_list; else if (! AST::match(node->type_specifier_list, pattern->type_specifier_list, this)) diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index 5b0ef3ce330..937a9a0ab15 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -541,6 +541,8 @@ void ForeachStatementAST::accept0(ASTVisitor *visitor) void RangeBasedForStatementAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { + accept(initDecl, visitor); + accept(initStmt, visitor); accept(type_specifier_list, visitor); accept(declarator, visitor); accept(expression, visitor); diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index c85d401c49b..84418a96383 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -1462,6 +1462,11 @@ bool Bind::visit(RangeBasedForStatementAST *ast) Scope *previousScope = switchScope(block); + if (ast->initDecl) + declaration(ast->initDecl); + else if (ast->initStmt) + statement(ast->initStmt); + FullySpecifiedType type; for (SpecifierListAST *it = ast->type_specifier_list; it; it = it->next) { type = this->specifier(it->value, type); diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 5b3768a14a8..fb57afe3205 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -3984,6 +3984,18 @@ bool Parser::parseForStatement(StatementAST *&node) ast->for_token = for_token; ast->lparen_token = lparen_token; + // C++20: init-statement + if (_languageFeatures.cxx20Enabled) { + const int savedCursor = cursor(); + const bool savedBlockErrors = _translationUnit->blockErrors(true); + if (!parseSimpleDeclaration(ast->initDecl)) { + rewind(savedCursor); + if (!parseExpressionStatement(ast->initStmt)) + rewind(savedCursor); + } + _translationUnit->blockErrors(savedBlockErrors); + } + if (parseTypeSpecifier(ast->type_specifier_list)) parseDeclarator(ast->declarator, ast->type_specifier_list); diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index bfeb5c7b0fb..e2ab845e818 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -151,6 +151,7 @@ private Q_SLOTS: void coroutines(); void genericLambdas(); void ifStatementWithInitialization(); + void rangeBasedForWithInitialization(); }; @@ -574,5 +575,28 @@ int main() QVERIFY(!hasErrors); } +void tst_cxx11::rangeBasedForWithInitialization() +{ + LanguageFeatures features; + features.cxxEnabled = true; + features.cxx11Enabled = features.cxx14Enabled = features.cxx17Enabled = features.cxx20Enabled + = true; + + const QString source = R"( +int main() +{ + for (std::string s = "test"; char c : s) + return 0; +} +)"; + QByteArray errors; + Document::Ptr doc = Document::create(FilePath::fromPathPart(u"testFile")); + processDocument(doc, source.toUtf8(), features, &errors); + const bool hasErrors = !errors.isEmpty(); + if (hasErrors) + qDebug().noquote() << errors; + QVERIFY(!hasErrors); +} + QTEST_APPLESS_MAIN(tst_cxx11) #include "tst_cxx11.moc" From 3c9cda08eb687df98c5f26f6e5022259cac5ad61 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 6 Nov 2024 11:32:57 +0100 Subject: [PATCH 065/989] ProjectExplorer: Suppress a warning about misleading indentation Indentation and resulting behavior after the macro expansion are not wrong but still make gcc unhappy: /data/dev/creator/src/plugins/projectexplorer/toolchain.cpp:939:307: warning: misleading indentation; statement is not part of the previous 'for' [-Wmisleading-indentation] 939 | if (__builtin_expect(!!(m_toolchains.at(i)->typeId() == m_toolchains.first()->typeId()), true)) {} else { ::Utils::writeAssertLocation( "\"" "m_toolchains.at(i)->typeId() == m_toolchains.first()->typeId()""\" in " "/data/dev/creator/src/plugins/projectexplorer/toolchain.cpp" ":" "939"); return; } do {} while (0); /data/dev/creator/src/plugins/projectexplorer/toolchain.cpp:938:5: note: previous statement is here 938 | for (auto i = toolchains.size(); i < m_toolchains.size(); ++i) | ^ Change-Id: Ifc4de5dc41cf45454be74b57d72af5d28dc4a9a6 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/toolchain.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index 50d81a8ff07..be41444a3dd 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -935,8 +935,9 @@ ToolchainBundle::ToolchainBundle(const Toolchains &toolchains, HandleMissing han // Check post-conditions. QTC_ASSERT(m_toolchains.size() == m_toolchains.first()->factory()->supportedLanguages().size(), return); - for (auto i = toolchains.size(); i < m_toolchains.size(); ++i) + for (auto i = toolchains.size(); i < m_toolchains.size(); ++i) { QTC_ASSERT(m_toolchains.at(i)->typeId() == m_toolchains.first()->typeId(), return); + } Utils::sort(m_toolchains, [](const Toolchain *tc1, const Toolchain *tc2) { return tc1 != tc2 && tc1->language() == Constants::C_LANGUAGE_ID; From e685795331210945570387150350f02d9bfb7816 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 31 Oct 2024 16:56:38 +0100 Subject: [PATCH 066/989] ProjectExplorer: Remove unused parameters from functions ... in TargetSetupPagePrivate. Change-Id: Ie6208cc0f049fd8e2b099e789b2b0cf4620ba522 Reviewed-by: hjk --- src/plugins/projectexplorer/targetsetuppage.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 7504fad8483..d3700eb6808 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -92,11 +92,8 @@ public: void setupWidgets(const QString &filterText = QString()); void reset(); - TargetSetupWidget *widget(const Id kitId, TargetSetupWidget *fallback = nullptr) const; - TargetSetupWidget *widget(const Kit *k, TargetSetupWidget *fallback = nullptr) const - { - return k ? widget(k->id(), fallback) : fallback; - } + TargetSetupWidget *widget(const Id kitId) const; + TargetSetupWidget *widget(const Kit *k) const { return k ? widget(k->id()) : nullptr; } TargetSetupPage *q; QWidget *centralWidget; @@ -221,9 +218,9 @@ void TargetSetupPagePrivate::reset() hideUnsuitableKitsCheckBox->setChecked(true); } -TargetSetupWidget *TargetSetupPagePrivate::widget(const Id kitId, TargetSetupWidget *fallback) const +TargetSetupWidget *TargetSetupPagePrivate::widget(const Id kitId) const { - return findOr(widgets, fallback, [kitId](const TargetSetupWidget *w) { + return findOrDefault(widgets, [kitId](const TargetSetupWidget *w) { return w->kit() && w->kit()->id() == kitId; }); } From b1dee78c7c769445150b734e9630374d77fba2c3 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 23 Oct 2024 16:19:40 +0200 Subject: [PATCH 067/989] QtSupport: collect Qt version info async Change-Id: I4c041ec8250f883fda5a64feda4fbc30d3edfc03 Reviewed-by: Christian Kandeler --- src/plugins/qtsupport/baseqtversion.cpp | 250 ++++++++++++------------ 1 file changed, 126 insertions(+), 124 deletions(-) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 28f580d9fa7..41cfd80ca78 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -170,7 +171,8 @@ public: : q(parent) {} - void updateVersionInfo(); + QtVersionData &data(); + void updateVersionInfoNow(); FilePath findHostBinary(HostBinaries binary) const; void updateMkspec(); @@ -203,9 +205,9 @@ public: QString m_type; DisplayName m_unexpandedDisplayName; - QtVersionData m_data; + std::optional m_data; + QFuture> m_dataFuture; - bool m_isUpdating = false; bool m_mkspecUpToDate = false; bool m_mkspecReadUpToDate = false; bool m_defaultConfigIsDebug = true; @@ -480,97 +482,81 @@ Tasks QtVersion::validateKit(const Kit *k) FilePath QtVersion::prefix() const // QT_INSTALL_PREFIX { - d->updateVersionInfo(); - return d->m_data.prefix; + return d->data().prefix; } FilePath QtVersion::binPath() const // QT_INSTALL_BINS { - d->updateVersionInfo(); - return d->m_data.binPath; + return d->data().binPath; } FilePath QtVersion::libExecPath() const // QT_INSTALL_LIBEXECS { - d->updateVersionInfo(); - return d->m_data.libExecPath; + return d->data().libExecPath; } FilePath QtVersion::configurationPath() const // QT_INSTALL_CONFIGURATION { - d->updateVersionInfo(); - return d->m_data.configurationPath; + return d->data().configurationPath; } FilePath QtVersion::headerPath() const // QT_INSTALL_HEADERS { - d->updateVersionInfo(); - return d->m_data.headerPath; + return d->data().headerPath; } FilePath QtVersion::dataPath() const // QT_INSTALL_DATA { - d->updateVersionInfo(); - return d->m_data.dataPath; + return d->data().dataPath; } FilePath QtVersion::docsPath() const // QT_INSTALL_DOCS { - d->updateVersionInfo(); - return d->m_data.docsPath; + return d->data().docsPath; } FilePath QtVersion::importsPath() const // QT_INSTALL_IMPORTS { - d->updateVersionInfo(); - return d->m_data.importsPath; + return d->data().importsPath; } FilePath QtVersion::libraryPath() const // QT_INSTALL_LIBS { - d->updateVersionInfo(); - return d->m_data.libraryPath; + return d->data().libraryPath; } FilePath QtVersion::pluginPath() const // QT_INSTALL_PLUGINS { - d->updateVersionInfo(); - return d->m_data.pluginPath; + return d->data().pluginPath; } FilePath QtVersion::qmlPath() const // QT_INSTALL_QML { - d->updateVersionInfo(); - return d->m_data.qmlPath; + return d->data().qmlPath; } FilePath QtVersion::translationsPath() const // QT_INSTALL_TRANSLATIONS { - d->updateVersionInfo(); - return d->m_data.translationsPath; + return d->data().translationsPath; } FilePath QtVersion::hostBinPath() const // QT_HOST_BINS { - d->updateVersionInfo(); - return d->m_data.hostBinPath; + return d->data().hostBinPath; } FilePath QtVersion::hostLibexecPath() const // QT_HOST_LIBEXECS { - d->updateVersionInfo(); - return d->m_data.hostLibexecPath; + return d->data().hostLibexecPath; } FilePath QtVersion::hostDataPath() const // QT_HOST_DATA { - d->updateVersionInfo(); - return d->m_data.hostDataPath; + return d->data().hostDataPath; } FilePath QtVersion::hostPrefixPath() const // QT_HOST_PREFIX { - d->updateVersionInfo(); - return d->m_data.hostPrefixPath; + return d->data().hostPrefixPath; } FilePath QtVersion::mkspecsPath() const @@ -578,7 +564,7 @@ FilePath QtVersion::mkspecsPath() const const FilePath result = hostDataPath(); if (result.isEmpty()) return FilePath::fromUserInput( - QtVersionPrivate::qmakeProperty(d->m_data.versionInfo, "QMAKE_MKSPECS")); + QtVersionPrivate::qmakeProperty(d->data().versionInfo, "QMAKE_MKSPECS")); return result.pathAppended("mkspecs"); } @@ -658,6 +644,7 @@ void QtVersion::fromMap(const Store &map, const FilePath &filePath) } } d->m_qmakeCommand = filePath.resolvePath(d->m_qmakeCommand); + d->updateVersionInfoNow(); Store::const_iterator itQtAbis = map.find(QTVERSION_ABIS); if (itQtAbis != map.end()) { @@ -666,7 +653,7 @@ void QtVersion::fromMap(const Store &map, const FilePath &filePath) const QStringList abiList = itQtAbis.value().toStringList(); if (!abiList.isEmpty()) { const Abis abis = Utils::transform(abiList, &Abi::fromString); - d->m_data.qtAbis = Utils::filtered(abis, &Abi::isValid); + d->data().qtAbis = Utils::filtered(abis, &Abi::isValid); } } @@ -696,10 +683,9 @@ bool QtVersion::isValid() const { if (uniqueId() == -1 || displayName().isEmpty()) return false; - d->updateVersionInfo(); d->updateMkspec(); - return !qmakeFilePath().isEmpty() && d->m_data.installed && !binPath().isEmpty() + return !qmakeFilePath().isEmpty() && d->data().installed && !binPath().isEmpty() && !d->m_mkspecFullPath.isEmpty() && d->m_qmakeIsExecutable; } @@ -718,7 +704,7 @@ QString QtVersion::invalidReason() const return Tr::tr("No qmake path set"); if (!d->m_qmakeIsExecutable) return Tr::tr("qmake does not exist or is not executable"); - if (!d->m_data.installed) + if (!d->data().installed) return Tr::tr("Qt version is not properly installed, please run make install"); if (binPath().isEmpty()) return Tr::tr("Could not determine the path to the binaries of the Qt installation, " @@ -733,8 +719,8 @@ QStringList QtVersion::warningReason() const QStringList ret; if (qtAbis().isEmpty()) ret << Tr::tr("ABI detection failed: Make sure to use a matching compiler when building."); - if (d->m_data.versionInfo.value(ProKey("QT_INSTALL_PREFIX/get")) - != d->m_data.versionInfo.value(ProKey("QT_INSTALL_PREFIX"))) { + if (d->data().versionInfo.value(ProKey("QT_INSTALL_PREFIX/get")) + != d->data().versionInfo.value(ProKey("QT_INSTALL_PREFIX"))) { ret << Tr::tr("Non-installed -prefix build - for internal development only."); } return ret; @@ -747,23 +733,23 @@ FilePath QtVersion::qmakeFilePath() const bool QtVersion::hasQtAbisSet() const { - return d->m_data.qtAbis.has_value(); + return d->data().qtAbis.has_value(); } Abis QtVersion::qtAbis() const { - if (!d->m_data.qtAbis + if (!d->data().qtAbis // QTCREATORBUG-30568 give AndroidQtVersion a "second chance" to detect Qt Abis - || (d->m_type == Android::Constants::ANDROID_QT_TYPE && d->m_data.qtAbis->isEmpty())) { - d->m_data.qtAbis = detectQtAbis(); + || (d->m_type == Android::Constants::ANDROID_QT_TYPE && d->data().qtAbis->isEmpty())) { + d->data().qtAbis = detectQtAbis(); } - return *d->m_data.qtAbis; + return *d->data().qtAbis; } void QtVersion::setQtAbis(const Abis &abis) { - d->m_data.qtAbis = abis; + d->data().qtAbis = abis; } Abis QtVersion::detectQtAbis() const @@ -928,11 +914,9 @@ QString QtVersion::toHtml(bool verbose) const FilePath QtVersion::sourcePath() const { - if (d->m_data.sourcePath.isEmpty()) { - d->updateVersionInfo(); - d->m_data.sourcePath = QtVersionPrivate::sourcePath(d->m_data.versionInfo); - } - return d->m_data.sourcePath; + if (d->data().sourcePath.isEmpty()) + d->data().sourcePath = QtVersionPrivate::sourcePath(d->data().versionInfo); + return d->data().sourcePath; } FilePath QtVersion::designerFilePath() const @@ -1227,8 +1211,7 @@ QtVersion::QmakeBuildConfigs QtVersion::defaultBuildConfig() const QString QtVersion::qtVersionString() const { - d->updateVersionInfo(); - return d->m_data.qtVersionString; + return d->data().qtVersionString; } QVersionNumber QtVersion::qtVersion() const @@ -1236,51 +1219,43 @@ QVersionNumber QtVersion::qtVersion() const return QVersionNumber::fromString(qtVersionString()); } -void QtVersionPrivate::updateVersionInfo() +expected_str dataForQMake(const FilePath m_qmakeCommand, const Environment env) { - if (m_data.versionInfoUpToDate || !m_qmakeIsExecutable || m_isUpdating) - return; - - m_isUpdating = true; - - // extract data from qmake executable - m_data.versionInfo.clear(); - m_data.installed = true; - m_data.hasExamples = false; - m_data.hasDocumentation = false; + QtVersionData data; QString error; - if (!queryQMakeVariables(m_qmakeCommand, q->qmakeRunEnvironment(), &m_data.versionInfo, &error)) { - m_qmakeIsExecutable = false; - qWarning("Cannot update Qt version information from %s: %s.", - qPrintable(m_qmakeCommand.displayName()), qPrintable(error)); - return; + if (!QtVersionPrivate::queryQMakeVariables(m_qmakeCommand, env, &data.versionInfo, &error)) { + return Utils::make_unexpected(Tr::tr("Cannot update Qt version information from %1: %2.") + .arg(m_qmakeCommand.displayName(), error)); } - m_qmakeIsExecutable = true; - auto fileProperty = [this](const QByteArray &name) { - return m_qmakeCommand.withNewPath(qmakeProperty(name)).cleanPath(); + auto fileProperty = [&](const QByteArray &name) { + return m_qmakeCommand.withNewPath(QtVersionPrivate::qmakeProperty(data.versionInfo, name)) + .cleanPath(); }; - m_data.prefix = fileProperty("QT_INSTALL_PREFIX"); - m_data.binPath = fileProperty("QT_INSTALL_BINS"); - m_data.libExecPath = fileProperty("QT_INSTALL_LIBEXECS"); - m_data.configurationPath = fileProperty("QT_INSTALL_CONFIGURATION"); - m_data.dataPath = fileProperty("QT_INSTALL_DATA"); - m_data.archDataPath = fileProperty("QT_INSTALL_ARCHDATA"); - m_data.demosPath = fileProperty("QT_INSTALL_DEMOS"); - m_data.docsPath = fileProperty("QT_INSTALL_DOCS"); - m_data.examplesPath = fileProperty("QT_INSTALL_EXAMPLES"); - m_data.headerPath = fileProperty("QT_INSTALL_HEADERS"); - m_data.importsPath = fileProperty("QT_INSTALL_IMPORTS"); - m_data.libraryPath = fileProperty("QT_INSTALL_LIBS"); - m_data.pluginPath = fileProperty("QT_INSTALL_PLUGINS"); - m_data.qmlPath = fileProperty("QT_INSTALL_QML"); - m_data.translationsPath = fileProperty("QT_INSTALL_TRANSLATIONS"); - m_data.hostBinPath = fileProperty("QT_HOST_BINS"); - m_data.hostLibexecPath = fileProperty("QT_HOST_LIBEXECS"); - m_data.hostDataPath = fileProperty("QT_HOST_DATA"); - m_data.hostPrefixPath = fileProperty("QT_HOST_PREFIX"); + data.installed = true; + data.hasExamples = false; + data.hasDocumentation = false; + data.prefix = fileProperty("QT_INSTALL_PREFIX"); + data.binPath = fileProperty("QT_INSTALL_BINS"); + data.libExecPath = fileProperty("QT_INSTALL_LIBEXECS"); + data.configurationPath = fileProperty("QT_INSTALL_CONFIGURATION"); + data.dataPath = fileProperty("QT_INSTALL_DATA"); + data.archDataPath = fileProperty("QT_INSTALL_ARCHDATA"); + data.demosPath = fileProperty("QT_INSTALL_DEMOS"); + data.docsPath = fileProperty("QT_INSTALL_DOCS"); + data.examplesPath = fileProperty("QT_INSTALL_EXAMPLES"); + data.headerPath = fileProperty("QT_INSTALL_HEADERS"); + data.importsPath = fileProperty("QT_INSTALL_IMPORTS"); + data.libraryPath = fileProperty("QT_INSTALL_LIBS"); + data.pluginPath = fileProperty("QT_INSTALL_PLUGINS"); + data.qmlPath = fileProperty("QT_INSTALL_QML"); + data.translationsPath = fileProperty("QT_INSTALL_TRANSLATIONS"); + data.hostBinPath = fileProperty("QT_HOST_BINS"); + data.hostLibexecPath = fileProperty("QT_HOST_LIBEXECS"); + data.hostDataPath = fileProperty("QT_HOST_DATA"); + data.hostPrefixPath = fileProperty("QT_HOST_PREFIX"); struct CheckDir { @@ -1289,28 +1264,64 @@ void QtVersionPrivate::updateVersionInfo() }; QList checkDirs = { - {&m_data.hostBinPath, &m_data.installed}, - {&m_data.docsPath, &m_data.hasDocumentation}, - {&m_data.examplesPath, &m_data.hasExamples}, - {&m_data.demosPath, &m_data.hasDemos}, + {&data.hostBinPath, &data.installed}, + {&data.docsPath, &data.hasDocumentation}, + {&data.examplesPath, &data.hasExamples}, + {&data.demosPath, &data.hasDemos}, }; - if (m_data.binPath.osType() != OsTypeMac) - checkDirs.push_back({&m_data.headerPath, &m_data.installed}); + if (data.binPath.osType() != OsTypeMac) + checkDirs.push_back({&data.headerPath, &data.installed}); QtConcurrent::map(checkDirs, [](CheckDir &checkDir) { *checkDir.isReadable = checkDir.path->isReadableDir(); }).waitForFinished(); - m_data.qtVersionString = qmakeProperty("QT_VERSION"); + data.qtVersionString = QtVersionPrivate::qmakeProperty(data.versionInfo, "QT_VERSION"); - m_isUpdating = false; - m_data.versionInfoUpToDate = true; + data.versionInfoUpToDate = true; + + return data; +} + +QtVersionData &QtVersionPrivate::data() +{ + if (!m_data) { + if (!m_dataFuture.isRunning() && !m_dataFuture.isFinished()) + updateVersionInfoNow(); + + if (m_dataFuture.isRunning()) + m_dataFuture.waitForFinished(); + + const expected_str data = m_dataFuture.result(); + m_qmakeIsExecutable = data.has_value(); + if (!data.has_value()) { + Core::MessageManager::writeFlashing(data.error()); + + m_data = QtVersionData(); + m_data->installed = true; + m_data->hasExamples = false; + m_data->hasDocumentation = false; + } else { + m_data = data.value(); + } + } + + return *m_data; +} + +void QtVersionPrivate::updateVersionInfoNow() +{ + if (m_data || m_dataFuture.isRunning()) + return; + + // extract data from qmake executable + m_dataFuture = Utils::asyncRun( + [qmake = m_qmakeCommand] { return dataForQMake(qmake, qmake.deviceEnvironment()); }); } QHash QtVersionPrivate::versionInfo() { - updateVersionInfo(); - return m_data.versionInfo; + return data().versionInfo; } QString QtVersionPrivate::qmakeProperty(const QHash &versionInfo, @@ -1336,19 +1347,17 @@ void QtVersion::applyProperties(QMakeGlobals *qmakeGlobals) const bool QtVersion::hasDocs() const { - d->updateVersionInfo(); - return d->m_data.hasDocumentation; + return d->data().hasDocumentation; } bool QtVersion::hasDemos() const { - d->updateVersionInfo(); - return d->m_data.hasDemos; + return d->data().hasDemos; } FilePath QtVersion::demosPath() const { - return d->m_data.demosPath; + return d->data().demosPath; } FilePath QtVersion::frameworkPath() const @@ -1360,13 +1369,12 @@ FilePath QtVersion::frameworkPath() const bool QtVersion::hasExamples() const { - d->updateVersionInfo(); - return d->m_data.hasExamples; + return d->data().hasExamples; } FilePath QtVersion::examplesPath() const // QT_INSTALL_EXAMPLES { - return d->m_data.examplesPath; + return d->data().examplesPath; } FilePaths QtVersion::qtSoPaths() const @@ -1690,9 +1698,6 @@ static QByteArray runQmakeQuery(const FilePath &binary, const Environment &env, { QTC_ASSERT(error, return QByteArray()); - // Prevent e.g. qmake 4.x on MinGW to show annoying errors about missing dll's. - WindowsCrashDialogBlocker crashDialogBlocker; - Process process; process.setEnvironment(env); process.setCommand({binary, {"-query"}}); @@ -1773,8 +1778,7 @@ bool QtVersionPrivate::queryQMakeVariables(const FilePath &binary, const Environ QString QtVersionPrivate::qmakeProperty(const QByteArray &name, QtVersionPrivate::PropertyVariant variant) { - updateVersionInfo(); - return qmakeProperty(m_data.versionInfo, name, variant); + return qmakeProperty(data().versionInfo, name, variant); } FilePath QtVersionPrivate::mkspecDirectoryFromVersionInfo(const QHash &versionInfo, @@ -2005,8 +2009,7 @@ bool QtVersion::isQtQuickCompilerSupported(QString *reason) const FilePaths QtVersionPrivate::qtCorePaths() { - updateVersionInfo(); - const QString versionString = m_data.qtVersionString; + const QString versionString = data().qtVersionString; const QDir::Filters filters = QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot; static const QStringList nameFilters{"QtCore*.framework", @@ -2017,8 +2020,8 @@ FilePaths QtVersionPrivate::qtCorePaths() "Qt5Core*", "Qt6Core*"}; - const FilePaths entries = m_data.libraryPath.dirEntries({nameFilters, filters}) - + m_data.binPath.dirEntries(filters); + const FilePaths entries = data().libraryPath.dirEntries({nameFilters, filters}) + + data().binPath.dirEntries(filters); FilePaths staticLibs; FilePaths dynamicLibs; @@ -2252,15 +2255,13 @@ Abis QtVersionPrivate::qtAbisFromLibrary() Abis QtVersionPrivate::qtAbisFromJson() { - updateVersionInfo(); - if (q->qtVersion().majorVersion() < 6) { qCDebug(abiDetect) << "Not attempting to read JSON file for Qt < 6"; return {}; } FilePath jsonFile; - for (const FilePath &baseDir : FilePaths{m_data.archDataPath, m_data.dataPath}) { + for (const FilePath &baseDir : FilePaths{data().archDataPath, data().dataPath}) { const FilePath candidate = baseDir.pathAppended("modules/Core.json"); qCDebug(abiDetect) << "Checking JSON file location" << candidate; if (candidate.exists()) { @@ -2452,6 +2453,7 @@ QtVersion *QtVersionFactory::createQtVersionFromQMakePath ver->d->m_id = QtVersionManager::getUniqueId(); QTC_CHECK(ver->d->m_qmakeCommand.isEmpty()); // Should only be used once. ver->d->m_qmakeCommand = qmakePath; + ver->d->updateVersionInfoNow(); ver->d->m_detectionSource = detectionSource; ver->d->m_isAutodetected = isAutoDetected; ver->updateDefaultDisplayName(); From 34cb13fc0af4a206d7e1da26ec860a9360729a21 Mon Sep 17 00:00:00 2001 From: Xu Jin Date: Wed, 30 Oct 2024 16:07:04 +0800 Subject: [PATCH 068/989] Add loongarch support LoongArch, or LA for short, is an instruction set architecture developed by Loongson Technology Corporation Limited.[0] LoongArch is a new RISC ISA, which is a bit like MIPS or RISC-V.[1] [0]https://zh.wikipedia.org/wiki/LoongArch [1]https://www.kernel.org/doc/html/latest/arch/loongarch/introduction.html Change-Id: I6066f25bc3202f11a74112ecb7589e7449fd686d Reviewed-by: hjk Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/abi.cpp | 16 ++++++++++++++++ src/plugins/projectexplorer/abi.h | 1 + .../defaultpropertyprovider.cpp | 5 +++++ src/plugins/qmakeprojectmanager/qmakestep.cpp | 2 ++ 4 files changed, 24 insertions(+) diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 34289f9d8ba..3f6b392f1e4 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -145,6 +145,8 @@ static Abi::Architecture architectureFromQt() return Abi::AvrArchitecture; if (arch.startsWith("asmjs")) return Abi::AsmJsArchitecture; + if (arch.startsWith("loongarch")) + return Abi::LoongArchArchitecture; return Abi::UnknownArchitecture; } @@ -377,6 +379,9 @@ static Abis abiOf(const QByteArray &data) case 50: // EM_IA_64 result.append(Abi(Abi::ItaniumArchitecture, os, flavor, Abi::ElfFormat, 64)); break; + case 258: // EM_LOONGARCH + result.append(Abi(Abi::LoongArchArchitecture, os, flavor, Abi::ElfFormat, 64)); + break; default: ; } @@ -639,6 +644,9 @@ Abi Abi::abiFromTargetTriplet(const QString &triple) os = BareMetalOS; flavor = GenericFlavor; format = ElfFormat; + } else if (p == "loongarch64") { + arch = LoongArchArchitecture; + width = 64; } } @@ -812,6 +820,8 @@ QString Abi::toString(const Architecture &a) return QLatin1String("cr16"); case RiscVArchitecture: return QLatin1String("riscv"); + case LoongArchArchitecture: + return QLatin1String("loongarch"); case UnknownArchitecture: Q_FALLTHROUGH(); default: @@ -990,6 +1000,8 @@ Abi::Architecture Abi::architectureFromString(const QString &a) return XtensaArchitecture; if (a == "asmjs") return AsmJsArchitecture; + if (a == "loongarch") + return LoongArchArchitecture; return UnknownArchitecture; } @@ -1550,6 +1562,10 @@ void ProjectExplorerTest::testAbiFromTargetTriplet_data() QTest::newRow("asmjs-unknown-emscripten") << int(Abi::AsmJsArchitecture) << int(Abi::UnknownOS) << int(Abi::UnknownFlavor) << int(Abi::EmscriptenFormat) << 32; + + QTest::newRow("loongarch64-linux-gnuabi") << int(Abi::LoongArchArchitecture) + << int(Abi::LinuxOS) << int(Abi::GenericFlavor) + << int(Abi::ElfFormat) << 64; } void ProjectExplorerTest::testAbiFromTargetTriplet() diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h index 7bf808071cc..71f62ad7338 100644 --- a/src/plugins/projectexplorer/abi.h +++ b/src/plugins/projectexplorer/abi.h @@ -54,6 +54,7 @@ public: R32CArchitecture, CR16Architecture, RiscVArchitecture, + LoongArchArchitecture, UnknownArchitecture }; diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index dc33b246242..9cd8dfca067 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -153,6 +153,10 @@ static QString architecture(const ProjectExplorer::Abi &targetAbi) else architecture += "v7a"; return architecture; + case ProjectExplorer::Abi::LoongArchArchitecture: + if (targetAbi.wordWidth() == 64) + architecture += "_64"; + return architecture; default: break; } @@ -167,6 +171,7 @@ static QString architecture(const ProjectExplorer::Abi &targetAbi) case ProjectExplorer::Abi::ArmArchitecture: // ARM sub-architectures are currently not handled, which is kind of problematic case ProjectExplorer::Abi::MipsArchitecture: + case ProjectExplorer::Abi::LoongArchArchitecture: case ProjectExplorer::Abi::PowerPCArchitecture: architecture.append(QString::number(targetAbi.wordWidth())); break; diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 1f39c4c04da..a8bc46b09fa 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -566,6 +566,8 @@ void QMakeStep::abisChanged() archs << "x86_64"; else if (abi.architecture() == Abi::ArmArchitecture) archs << "arm64"; + else if (abi.architecture() == Abi::LoongArchArchitecture) + archs << "loongarch64"; } if (!archs.isEmpty()) args << prefix + '"' + archs.join(' ') + '"'; From af7bd3a37c10129420acc71e51077a6afd44f87a Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 7 Nov 2024 14:18:08 +0100 Subject: [PATCH 069/989] ProjectExplorer: Pimpl KitAspect We want to add more features and not leak the details into the header. Change-Id: I00931df8b3d6d86b0f06b8b92ee2628416dd16ee Reviewed-by: hjk --- src/plugins/projectexplorer/kitaspect.cpp | 119 +++++++++++++--------- src/plugins/projectexplorer/kitaspect.h | 22 ++-- 2 files changed, 75 insertions(+), 66 deletions(-) diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index 5a2c4e41c7b..fae5a5aef3b 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -99,107 +100,123 @@ static KitAspectFactories &kitAspectFactoriesStorage() } // namespace +class KitAspect::Private +{ +public: + Private(Kit *k, const KitAspectFactory *f) : kit(k), factory(f) {} + + Kit * const kit; + const KitAspectFactory * const factory; + QAction *mutableAction = nullptr; + Utils::Id managingPageId; + QPushButton *manageButton = nullptr; + QComboBox *comboBox = nullptr; + std::optional listAspectSpec; + Utils::Guard ignoreChanges; +}; + KitAspect::KitAspect(Kit *kit, const KitAspectFactory *factory) - : m_kit(kit), m_factory(factory) + : d(new Private(kit, factory)) { const Id id = factory->id(); - m_mutableAction = new QAction(Tr::tr("Mark as Mutable")); - m_mutableAction->setCheckable(true); - m_mutableAction->setChecked(m_kit->isMutable(id)); - m_mutableAction->setEnabled(!m_kit->isSticky(id)); - connect(m_mutableAction, &QAction::toggled, this, [this, id] { - m_kit->setMutable(id, m_mutableAction->isChecked()); + d->mutableAction = new QAction(Tr::tr("Mark as Mutable")); + d->mutableAction->setCheckable(true); + d->mutableAction->setChecked(d->kit->isMutable(id)); + d->mutableAction->setEnabled(!d->kit->isSticky(id)); + connect(d->mutableAction, &QAction::toggled, this, [this, id] { + d->kit->setMutable(id, d->mutableAction->isChecked()); }); } KitAspect::~KitAspect() { - delete m_mutableAction; + delete d->mutableAction; + delete d; } void KitAspect::refresh() { - if (!m_listAspectSpec || m_ignoreChanges.isLocked()) + if (!d->listAspectSpec || d->ignoreChanges.isLocked()) return; - const GuardLocker locker(m_ignoreChanges); - m_listAspectSpec->resetModel(); - m_comboBox->model()->sort(0); - const QVariant itemId = m_listAspectSpec->getter(*kit()); - m_comboBox->setCurrentIndex(m_comboBox->findData(itemId, IdRole)); + const GuardLocker locker(d->ignoreChanges); + d->listAspectSpec->resetModel(); + d->comboBox->model()->sort(0); + const QVariant itemId = d->listAspectSpec->getter(*kit()); + d->comboBox->setCurrentIndex(d->comboBox->findData(itemId, IdRole)); } void KitAspect::makeStickySubWidgetsReadOnly() { - if (!m_kit->isSticky(m_factory->id())) + if (!d->kit->isSticky(d->factory->id())) return; - if (m_manageButton) - m_manageButton->setEnabled(false); + if (d->manageButton) + d->manageButton->setEnabled(false); makeReadOnly(); } void KitAspect::makeReadOnly() { - if (m_comboBox) - m_comboBox->setEnabled(false); + if (d->comboBox) + d->comboBox->setEnabled(false); } void KitAspect::addToInnerLayout(Layouting::Layout &parentItem) { - if (m_comboBox) { - addMutableAction(m_comboBox); - parentItem.addItem(m_comboBox); + if (d->comboBox) { + addMutableAction(d->comboBox); + parentItem.addItem(d->comboBox); } } void KitAspect::setListAspectSpec(ListAspectSpec &&listAspectSpec) { - m_listAspectSpec = std::move(listAspectSpec); + d->listAspectSpec = std::move(listAspectSpec); - m_comboBox = createSubWidget(); - m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy()); - m_comboBox->setEnabled(true); + d->comboBox = createSubWidget(); + d->comboBox->setSizePolicy(QSizePolicy::Ignored, d->comboBox->sizePolicy().verticalPolicy()); + d->comboBox->setEnabled(true); const auto sortModel = new KitAspectSortModel(this); - sortModel->setSourceModel(m_listAspectSpec->model); - m_comboBox->setModel(sortModel); + sortModel->setSourceModel(d->listAspectSpec->model); + d->comboBox->setModel(sortModel); refresh(); const auto updateTooltip = [this] { - m_comboBox->setToolTip( - m_comboBox->itemData(m_comboBox->currentIndex(), Qt::ToolTipRole).toString()); + d->comboBox->setToolTip( + d->comboBox->itemData(d->comboBox->currentIndex(), Qt::ToolTipRole).toString()); }; updateTooltip(); - connect(m_comboBox, &QComboBox::currentIndexChanged, this, [this, updateTooltip] { - if (m_ignoreChanges.isLocked()) + connect(d->comboBox, &QComboBox::currentIndexChanged, this, [this, updateTooltip] { + if (d->ignoreChanges.isLocked()) return; updateTooltip(); - m_listAspectSpec->setter( - *kit(), m_comboBox->itemData(m_comboBox->currentIndex(), IdRole)); + d->listAspectSpec->setter( + *kit(), d->comboBox->itemData(d->comboBox->currentIndex(), IdRole)); }); - connect(m_listAspectSpec->model, &QAbstractItemModel::modelAboutToBeReset, - this, [this] { m_ignoreChanges.lock(); }); - connect(m_listAspectSpec->model, &QAbstractItemModel::modelReset, - this, [this] { m_ignoreChanges.unlock(); }); + connect(d->listAspectSpec->model, &QAbstractItemModel::modelAboutToBeReset, + this, [this] { d->ignoreChanges.lock(); }); + connect(d->listAspectSpec->model, &QAbstractItemModel::modelReset, + this, [this] { d->ignoreChanges.unlock(); }); } void KitAspect::addToLayoutImpl(Layouting::Layout &layout) { - auto label = createSubWidget(m_factory->displayName() + ':'); - label->setToolTip(m_factory->description()); + auto label = createSubWidget(d->factory->displayName() + ':'); + label->setToolTip(d->factory->description()); connect(label, &QLabel::linkActivated, this, [this](const QString &link) { emit labelLinkActivated(link); }); layout.addItem(label); addToInnerLayout(layout); - if (m_managingPageId.isValid()) { - m_manageButton = createSubWidget(msgManage()); - connect(m_manageButton, &QPushButton::clicked, [this] { - Core::ICore::showOptionsDialog(m_managingPageId, settingsPageItemToPreselect()); + if (d->managingPageId.isValid()) { + d->manageButton = createSubWidget(msgManage()); + connect(d->manageButton, &QPushButton::clicked, [this] { + Core::ICore::showOptionsDialog(d->managingPageId, settingsPageItemToPreselect()); }); - layout.addItem(m_manageButton); + layout.addItem(d->manageButton); } layout.addItem(Layouting::br); } @@ -209,14 +226,16 @@ void KitAspect::addMutableAction(QWidget *child) QTC_ASSERT(child, return); if (factory()->id() == DeviceKitAspect::id()) return; - child->addAction(m_mutableAction); + child->addAction(d->mutableAction); child->setContextMenuPolicy(Qt::ActionsContextMenu); } -QString KitAspect::msgManage() -{ - return Tr::tr("Manage..."); -} +void KitAspect::setManagingPage(Utils::Id pageId) { d->managingPageId = pageId; } + +QString KitAspect::msgManage() { return Tr::tr("Manage..."); } +Kit *KitAspect::kit() const { return d->kit; } +const KitAspectFactory *KitAspect::factory() const { return d->factory; } +QAction *KitAspect::mutableAction() const { return d->mutableAction; } KitAspectFactory::KitAspectFactory() { diff --git a/src/plugins/projectexplorer/kitaspect.h b/src/plugins/projectexplorer/kitaspect.h index 1a765ddfb90..ff00554135d 100644 --- a/src/plugins/projectexplorer/kitaspect.h +++ b/src/plugins/projectexplorer/kitaspect.h @@ -7,18 +7,14 @@ #include "task.h" #include -#include #include -#include #include #include QT_BEGIN_NAMESPACE -class QAbstractItemModel; class QAction; -class QComboBox; QT_END_NAMESPACE namespace Utils { @@ -117,11 +113,11 @@ public: void addToLayoutImpl(Layouting::Layout &layout) override; static QString msgManage(); - Kit *kit() const { return m_kit; } - const KitAspectFactory *factory() const { return m_factory; } - QAction *mutableAction() const { return m_mutableAction; } + Kit *kit() const; + const KitAspectFactory *factory() const; + QAction *mutableAction() const; void addMutableAction(QWidget *child); - void setManagingPage(Utils::Id pageId) { m_managingPageId = pageId; } + void setManagingPage(Utils::Id pageId); void makeStickySubWidgetsReadOnly(); @@ -158,14 +154,8 @@ protected: 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 Private; + Private * const d; }; } // namespace ProjectExplorer From 73b0875498b662128c18f794fa9b7e477b0571de Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 7 Nov 2024 11:50:31 +0100 Subject: [PATCH 070/989] ProjectExplorer: Rename DeviceKitAspect to RunDeviceKitAspect This makes the purpose clear and reduces the risk of accidental use instead of BuildDeviceKitAspect. Change-Id: I37a6863d37fdf7072eb3183b89f2e565ca83465d Reviewed-by: Marcus Tillmanns --- src/plugins/android/androiddeployqtstep.cpp | 4 +- src/plugins/android/androidrunner.cpp | 2 +- src/plugins/boot2qt/qdbrunconfiguration.cpp | 2 +- .../boot2qt/qdbstopapplicationstep.cpp | 2 +- .../cmakebuildconfiguration.cpp | 2 +- .../cmakeprojectmanager/cmakebuildstep.cpp | 4 +- .../debugger/analyzer/startremotedialog.cpp | 4 +- src/plugins/debugger/debuggerdialogs.cpp | 2 +- src/plugins/debugger/debuggerkitaspect.cpp | 2 +- src/plugins/debugger/debuggerplugin.cpp | 6 +-- src/plugins/docker/kitdetector.cpp | 4 +- src/plugins/ios/iosdeploystep.cpp | 4 +- src/plugins/ios/iosrunconfiguration.cpp | 6 +-- src/plugins/ios/iosrunner.cpp | 6 +-- src/plugins/perfprofiler/perfsettings.cpp | 2 +- .../perfprofiler/perftracepointdialog.cpp | 2 +- src/plugins/projectexplorer/buildmanager.cpp | 2 +- .../devicesupport/devicecheckbuildstep.cpp | 4 +- .../devicesupport/devicekitaspects.cpp | 52 +++++++++---------- .../devicesupport/devicekitaspects.h | 2 +- .../devicesupport/deviceprocessesdialog.cpp | 2 +- src/plugins/projectexplorer/kit.cpp | 4 +- src/plugins/projectexplorer/kitaspect.cpp | 2 +- .../projectexplorer/projectexplorer.cpp | 4 +- .../projectexplorer/runconfiguration.cpp | 2 +- .../runconfigurationaspects.cpp | 2 +- src/plugins/projectexplorer/runcontrol.cpp | 4 +- src/plugins/projectexplorer/target.cpp | 4 +- .../defaultpropertyprovider.cpp | 2 +- .../components/toolbar/toolbarbackend.cpp | 2 +- .../qmlprofiler/qmlprofilerattachdialog.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +- .../buildsystem/qmlbuildsystem.cpp | 2 +- src/plugins/qmlprojectmanager/qmlproject.cpp | 2 +- .../qmlprojectrunconfiguration.cpp | 2 +- src/plugins/qnx/qnxplugin.cpp | 2 +- .../appmanagerdeployconfigurationfactory.cpp | 2 +- .../appmanagerdeploypackagestep.cpp | 2 +- .../appmanagerinstallpackagestep.cpp | 4 +- .../appmanagerrunconfiguration.cpp | 4 +- .../appmanagerruncontrol.cpp | 2 +- .../abstractremotelinuxdeploystep.cpp | 2 +- .../remotelinux/deploymenttimeinfo.cpp | 2 +- src/plugins/remotelinux/genericdeploystep.cpp | 2 +- .../remotelinuxenvironmentaspect.cpp | 4 +- .../remotelinuxrunconfiguration.cpp | 2 +- src/plugins/valgrind/valgrindengine.cpp | 2 +- 47 files changed, 91 insertions(+), 91 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index ff15e9f6c48..1a3e79a1940 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -241,7 +241,7 @@ bool AndroidDeployQtStep::init() if (!info.isValid()) { const auto dev = - static_cast(DeviceKitAspect::device(kit()).get()); + static_cast(RunDeviceKitAspect::device(kit()).get()); if (!dev) { reportWarningOrError(Tr::tr("No valid deployment device is set."), Task::Error); return false; @@ -590,7 +590,7 @@ QWidget *AndroidDeployQtStep::createConfigWidget() if (appAbis.isEmpty()) return; - const IDevice::ConstPtr device = DeviceKitAspect::device(currentTarget->kit()); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(currentTarget->kit()); const AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(device.get()); if (!info.isValid()) // aborted return; diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 6e0b59051a8..44b50b04059 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -63,7 +63,7 @@ void AndroidRunner::start() if (!projectExplorerSettings().deployBeforeRun && target->project()) { qCDebug(androidRunnerLog) << "Run without deployment"; - const IDevice::ConstPtr device = DeviceKitAspect::device(target->kit()); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(target->kit()); AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(device.get()); AndroidManager::setDeviceSerialNumber(target, info.serialNumber); deviceSerialNumber = info.serialNumber; diff --git a/src/plugins/boot2qt/qdbrunconfiguration.cpp b/src/plugins/boot2qt/qdbrunconfiguration.cpp index 6b03c117898..b3f1484d5e9 100644 --- a/src/plugins/boot2qt/qdbrunconfiguration.cpp +++ b/src/plugins/boot2qt/qdbrunconfiguration.cpp @@ -55,7 +55,7 @@ public: const BuildTargetInfo bti = buildTargetInfo(); const FilePath localExecutable = bti.targetFilePath; const DeployableFile depFile = target->deploymentData().deployableForLocalFile(localExecutable); - IDevice::ConstPtr dev = DeviceKitAspect::device(target->kit()); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(target->kit()); QTC_ASSERT(dev, return); executable.setExecutable(dev->filePath(depFile.remoteFilePath())); symbolFile.setValue(localExecutable); diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp index 341691c368d..4f3e2741e62 100644 --- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp +++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp @@ -40,7 +40,7 @@ public: GroupItem QdbStopApplicationStep::deployRecipe() { const auto onSetup = [this](Process &process) { - const auto device = DeviceKitAspect::device(target()->kit()); + const auto device = RunDeviceKitAspect::device(target()->kit()); if (!device) { addErrorMessage(Tr::tr("No device to stop the application on.")); return SetupResult::StopWithError; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 00587a215d5..16136cac74e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -1547,7 +1547,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) } } - const IDevice::ConstPtr device = DeviceKitAspect::device(k); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(k); if (CMakeBuildConfiguration::isIos(k)) { if (qt && qt->qtVersion().majorVersion() >= 6) { // TODO it would be better if we could set diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 759fa6b8799..0008590f070 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -201,7 +201,7 @@ static QString initialStagingDir(Kit *kit) static bool supportsStageForInstallation(const Kit *kit) { - IDeviceConstPtr runDevice = DeviceKitAspect::device(kit); + IDeviceConstPtr runDevice = RunDeviceKitAspect::device(kit); Id runDeviceType = DeviceTypeKitAspect::deviceTypeId(kit); IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(kit); QTC_ASSERT(runDeviceType.isValid(), return false); @@ -821,7 +821,7 @@ void CMakeBuildStep::updateDeploymentData() DeploymentData deploymentData; deploymentData.setLocalInstallRoot(rootDir); - IDeviceConstPtr runDevice = DeviceKitAspect::device(buildSystem()->kit()); + IDeviceConstPtr runDevice = RunDeviceKitAspect::device(buildSystem()->kit()); if (!runDevice) return; diff --git a/src/plugins/debugger/analyzer/startremotedialog.cpp b/src/plugins/debugger/analyzer/startremotedialog.cpp index 3e7ec624cf1..c8dd079122a 100644 --- a/src/plugins/debugger/analyzer/startremotedialog.cpp +++ b/src/plugins/debugger/analyzer/startremotedialog.cpp @@ -45,7 +45,7 @@ StartRemoteDialog::StartRemoteDialog(QWidget *parent) d->kitChooser = new KitChooser(this); d->kitChooser->setKitPredicate([](const Kit *kit) { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); return kit->isValid() && device && !device->sshParameters().host().isEmpty(); }); d->executable = new QLineEdit(this); @@ -113,7 +113,7 @@ void StartRemoteDialog::validate() CommandLine StartRemoteDialog::commandLine() const { const Kit *kit = d->kitChooser->currentKit(); - const FilePath filePath = DeviceKitAspect::deviceFilePath(kit, d->executable->text()); + const FilePath filePath = RunDeviceKitAspect::deviceFilePath(kit, d->executable->text()); return {filePath, d->arguments->text(), CommandLine::Raw}; } diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 2b8278b01e0..59bd4b52145 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -401,7 +401,7 @@ void StartApplicationDialog::run(bool attachRemote) settings->endGroup(); } - IDevice::ConstPtr dev = DeviceKitAspect::device(k); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); ProcessRunData inferior = newParameters.runnable; const QString inputAddress = dialog.d->channelOverrideEdit->text(); if (!inputAddress.isEmpty()) diff --git a/src/plugins/debugger/debuggerkitaspect.cpp b/src/plugins/debugger/debuggerkitaspect.cpp index 215806a8b53..d8c02afae74 100644 --- a/src/plugins/debugger/debuggerkitaspect.cpp +++ b/src/plugins/debugger/debuggerkitaspect.cpp @@ -112,7 +112,7 @@ DebuggerKitAspect::ConfigurationErrors DebuggerKitAspect::configurationErrors(co const Abi tcAbi = ToolchainKitAspect::targetAbi(k); if (item->matchTarget(tcAbi) == DebuggerItem::DoesNotMatch) { // currently restricting the check to desktop devices, may be extended to all device types - const IDevice::ConstPtr device = DeviceKitAspect::device(k); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(k); if (device && device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) result |= DebuggerDoesNotMatch; } diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 2e523d63c84..793411a35b6 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1741,7 +1741,7 @@ void DebuggerPluginPrivate::attachToRunningApplication() dlg->setAttribute(Qt::WA_DeleteOnClose); Kit *kit = kitChooser->currentKit(); QTC_ASSERT(kit, return); - IDevice::ConstPtr device = DeviceKitAspect::device(kit); + IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); QTC_ASSERT(device, return); const ProcessInfo processInfo = dlg->currentProcess(); @@ -1781,7 +1781,7 @@ RunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, const ProcessInfo &processInfo, bool contAfterAttach) { QTC_ASSERT(kit, return nullptr); - IDevice::ConstPtr device = DeviceKitAspect::device(kit); + IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); QTC_ASSERT(device, return nullptr); if (processInfo.processId == 0) { AsynchronousMessageBox::warning(Tr::tr("Warning"), Tr::tr("Cannot attach to process with PID 0")); @@ -1844,7 +1844,7 @@ void DebuggerPluginPrivate::attachToQmlPort() setConfigValue("LastQmlServerPort", dlg.port()); setConfigValue("LastProfile", kit->id().toSetting()); - IDevice::ConstPtr device = DeviceKitAspect::device(kit); + IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); QTC_ASSERT(device, return); auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); diff --git a/src/plugins/docker/kitdetector.cpp b/src/plugins/docker/kitdetector.cpp index 8e476cdb557..460734d42cd 100644 --- a/src/plugins/docker/kitdetector.cpp +++ b/src/plugins/docker/kitdetector.cpp @@ -353,7 +353,7 @@ void KitDetectorPrivate::autoDetect() k->setValue(CMakeProjectManager::Constants::TOOL_ID, cmakeId.toSetting()); DeviceTypeKitAspect::setDeviceTypeId(k, m_device->type()); - DeviceKitAspect::setDevice(k, m_device); + RunDeviceKitAspect::setDevice(k, m_device); BuildDeviceKitAspect::setDevice(k, m_device); const Toolchains toolchainCandidates = ToolchainManager::toolchains( @@ -387,7 +387,7 @@ void KitDetectorPrivate::autoDetect() k->setSticky(ToolchainKitAspect::id(), true); k->setSticky(QtSupport::QtKitAspect::id(), true); - k->setSticky(DeviceKitAspect::id(), true); + k->setSticky(RunDeviceKitAspect::id(), true); k->setSticky(DeviceTypeKitAspect::id(), true); k->setSticky(BuildDeviceKitAspect::id(), true); }; diff --git a/src/plugins/ios/iosdeploystep.cpp b/src/plugins/ios/iosdeploystep.cpp index 5e00230b551..85b18ff59df 100644 --- a/src/plugins/ios/iosdeploystep.cpp +++ b/src/plugins/ios/iosdeploystep.cpp @@ -205,14 +205,14 @@ IosDeployStep::IosDeployStep(BuildStepList *parent, Utils::Id id) void IosDeployStep::updateDisplayNames() { - IDevice::ConstPtr dev = DeviceKitAspect::device(kit()); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(kit()); const QString devName = dev ? dev->displayName() : IosDevice::name(); setDisplayName(Tr::tr("Deploy to %1").arg(devName)); } bool IosDeployStep::init() { - m_device = DeviceKitAspect::device(kit()); + m_device = RunDeviceKitAspect::device(kit()); auto runConfig = qobject_cast( this->target()->activeRunConfiguration()); QTC_ASSERT(runConfig, return false); diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp index 6fe27834120..224ee7e313f 100644 --- a/src/plugins/ios/iosrunconfiguration.cpp +++ b/src/plugins/ios/iosrunconfiguration.cpp @@ -65,7 +65,7 @@ IosRunConfiguration::IosRunConfiguration(Target *target, Id id) executable.setDeviceSelector(target, ExecutableAspect::RunDevice); setUpdater([this, target] { - IDevice::ConstPtr dev = DeviceKitAspect::device(target->kit()); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(target->kit()); const QString devName = dev ? dev->displayName() : IosDevice::name(); setDefaultDisplayName(Tr::tr("Run on %1").arg(devName)); setDisplayName(Tr::tr("Run %1 on %2").arg(applicationName()).arg(devName)); @@ -97,7 +97,7 @@ bool IosRunConfiguration::isEnabled(Id runMode) const if (devType == Constants::IOS_SIMULATOR_TYPE) return true; - IDevice::ConstPtr dev = DeviceKitAspect::device(kit()); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(kit()); if (!dev || dev->deviceState() != IDevice::DeviceReadyToUse) return false; @@ -236,7 +236,7 @@ QString IosRunConfiguration::disabledReason(Id runMode) const Utils::Id devType = DeviceTypeKitAspect::deviceTypeId(kit()); if (devType != Constants::IOS_DEVICE_TYPE && devType != Constants::IOS_SIMULATOR_TYPE) return Tr::tr("Kit has incorrect device type for running on iOS devices."); - IDevice::ConstPtr dev = DeviceKitAspect::device(kit()); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(kit()); QString validDevName; bool hasConncetedDev = false; if (devType == Constants::IOS_DEVICE_TYPE) { diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index cc78fac2ed9..c33959e1b5d 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -74,7 +74,7 @@ static void stopRunningRunControl(RunControl *runControl) Utils::erase(activeRunControls, [](const QPointer &rc) { return !rc; }); Target *target = runControl->target(); - const Id devId = DeviceKitAspect::deviceId(target->kit()); + const Id devId = RunDeviceKitAspect::deviceId(target->kit()); const QString identifier = identifierForRunControl(runControl); // The device can only run an application at a time, if an app is running stop it. @@ -129,7 +129,7 @@ DeviceCtlRunner::DeviceCtlRunner(RunControl *runControl) QTC_ASSERT(data, return); m_bundlePath = data->bundleDirectory; m_arguments = ProcessArgs::splitArgs(runControl->commandLine().arguments(), OsTypeMac); - m_device = std::dynamic_pointer_cast(DeviceKitAspect::device(runControl->kit())); + m_device = std::dynamic_pointer_cast(RunDeviceKitAspect::device(runControl->kit())); using namespace std::chrono_literals; m_pollTimer.setInterval(500ms); // not too often since running devicectl takes time @@ -447,7 +447,7 @@ IosRunner::IosRunner(RunControl *runControl) const IosDeviceTypeAspect::Data *data = runControl->aspectData(); QTC_ASSERT(data, return); m_bundleDir = data->bundleDirectory; - m_device = DeviceKitAspect::device(runControl->kit()); + m_device = RunDeviceKitAspect::device(runControl->kit()); m_deviceType = data->deviceType; } diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp index d218dda82da..d48a43805f7 100644 --- a/src/plugins/perfprofiler/perfsettings.cpp +++ b/src/plugins/perfprofiler/perfsettings.cpp @@ -125,7 +125,7 @@ PerfConfigWidget::PerfConfigWidget(PerfSettings *settings, Target *target) IDevice::ConstPtr device; if (target) - device = DeviceKitAspect::device(target->kit()); + device = RunDeviceKitAspect::device(target->kit()); if (!device) { useTracePointsButton->setEnabled(false); diff --git a/src/plugins/perfprofiler/perftracepointdialog.cpp b/src/plugins/perfprofiler/perftracepointdialog.cpp index 66a6208c1e8..b219e8ed7b8 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.cpp +++ b/src/plugins/perfprofiler/perftracepointdialog.cpp @@ -55,7 +55,7 @@ PerfTracePointDialog::PerfTracePointDialog() const Kit *kit = target->kit(); QTC_ASSERT(kit, return); - m_device = DeviceKitAspect::device(kit); + m_device = RunDeviceKitAspect::device(kit); if (!m_device) { m_textEdit->setPlainText(Tr::tr("Error: No device available for active target.")); return; diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp index 75df07a1167..7d801bc2690 100644 --- a/src/plugins/projectexplorer/buildmanager.cpp +++ b/src/plugins/projectexplorer/buildmanager.cpp @@ -266,7 +266,7 @@ static int queue( IDevice::ConstPtr device = DeviceManager::deviceForPath(executable); for (const Target *const t : targetsForSelection(p.first, configSelection)) { if (!device) - device = DeviceKitAspect::device(t->kit()); + device = RunDeviceKitAspect::device(t->kit()); if (!device || device->type() != Constants::DESKTOP_DEVICE_TYPE) continue; for (const BuildConfiguration *const bc : diff --git a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp index 503347dd7f1..5f102c1d92e 100644 --- a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp @@ -28,7 +28,7 @@ public: bool init() final { - IDevice::ConstPtr device = DeviceKitAspect::device(kit()); + IDevice::ConstPtr device = RunDeviceKitAspect::device(kit()); if (device) return true; @@ -56,7 +56,7 @@ public: DeviceManager *dm = DeviceManager::instance(); dm->addDevice(newDevice); - DeviceKitAspect::setDevice(kit(), newDevice); + RunDeviceKitAspect::setDevice(kit(), newDevice); return true; } diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index c99a1331a43..8c314689098 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -164,11 +164,11 @@ public: const auto model = new DeviceManagerModel(DeviceManager::instance(), this); auto getter = [](const Kit &k) { - auto device = DeviceKitAspect::device(&k); + auto device = RunDeviceKitAspect::device(&k); return device ? device->id().toSetting() : QVariant{}; }; auto setter = [](Kit &k, const QVariant &id) { - DeviceKitAspect::setDeviceId(&k, Id::fromSetting(id)); + RunDeviceKitAspect::setDeviceId(&k, Id::fromSetting(id)); }; auto resetModel = [this, model] { model->setTypeFilter(DeviceTypeKitAspect::deviceTypeId(kit())); @@ -180,7 +180,7 @@ public: } private: - Id settingsPageItemToPreselect() const override { return DeviceKitAspect::deviceId(kit()); } + Id settingsPageItemToPreselect() const override { return RunDeviceKitAspect::deviceId(kit()); } }; class DeviceKitAspectFactory : public KitAspectFactory @@ -211,7 +211,7 @@ private: DeviceKitAspectFactory::DeviceKitAspectFactory() { - setId(DeviceKitAspect::id()); + setId(RunDeviceKitAspect::id()); setDisplayName(Tr::tr("Run device")); setDescription(Tr::tr("The device to run the applications on.")); setPriority(32000); @@ -236,7 +236,7 @@ QVariant DeviceKitAspectFactory::defaultValue(const Kit *k) const Tasks DeviceKitAspectFactory::validate(const Kit *k) const { - IDevice::ConstPtr dev = DeviceKitAspect::device(k); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); Tasks result; if (!dev) result.append(BuildSystemTask(Task::Warning, Tr::tr("No device set."))); @@ -251,22 +251,22 @@ Tasks DeviceKitAspectFactory::validate(const Kit *k) const void DeviceKitAspectFactory::fix(Kit *k) { - IDevice::ConstPtr dev = DeviceKitAspect::device(k); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); if (dev && !dev->isCompatibleWith(k)) { qWarning("Device is no longer compatible with kit \"%s\", removing it.", qPrintable(k->displayName())); - DeviceKitAspect::setDeviceId(k, Id()); + RunDeviceKitAspect::setDeviceId(k, Id()); } } void DeviceKitAspectFactory::setup(Kit *k) { QTC_ASSERT(DeviceManager::instance()->isLoaded(), return); - IDevice::ConstPtr dev = DeviceKitAspect::device(k); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); if (dev && dev->isCompatibleWith(k)) return; - DeviceKitAspect::setDeviceId(k, Id::fromSetting(defaultValue(k))); + RunDeviceKitAspect::setDeviceId(k, Id::fromSetting(defaultValue(k))); } KitAspect *DeviceKitAspectFactory::createKitAspect(Kit *k) const @@ -277,13 +277,13 @@ KitAspect *DeviceKitAspectFactory::createKitAspect(Kit *k) const QString DeviceKitAspectFactory::displayNamePostfix(const Kit *k) const { - IDevice::ConstPtr dev = DeviceKitAspect::device(k); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); return dev ? dev->displayName() : QString(); } KitAspectFactory::ItemList DeviceKitAspectFactory::toUserOutput(const Kit *k) const { - IDevice::ConstPtr dev = DeviceKitAspect::device(k); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); return {{Tr::tr("Device"), dev ? dev->displayName() : Tr::tr("Unconfigured") }}; } @@ -291,27 +291,27 @@ void DeviceKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expande { QTC_ASSERT(kit, return); expander->registerVariable("Device:HostAddress", Tr::tr("Host address"), [kit] { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); return device ? device->sshParameters().host() : QString(); }); expander->registerVariable("Device:SshPort", Tr::tr("SSH port"), [kit] { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); return device ? QString::number(device->sshParameters().port()) : QString(); }); expander->registerVariable("Device:UserName", Tr::tr("User name"), [kit] { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); return device ? device->sshParameters().userName() : QString(); }); expander->registerVariable("Device:KeyFile", Tr::tr("Private key file"), [kit] { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); return device ? device->sshParameters().privateKeyFile.toString() : QString(); }); expander->registerVariable("Device:Name", Tr::tr("Device name"), [kit] { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); return device ? device->displayName() : QString(); }); expander->registerFileVariables("Device::Root", Tr::tr("Device root directory"), [kit] { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); return device ? device->rootPath() : FilePath{}; }); } @@ -336,7 +336,7 @@ void DeviceKitAspectFactory::onKitsLoaded() void DeviceKitAspectFactory::deviceUpdated(Id id) { for (Kit *k : KitManager::kits()) { - if (DeviceKitAspect::deviceId(k) == id) + if (RunDeviceKitAspect::deviceId(k) == id) notifyAboutUpdate(k); } } @@ -357,34 +357,34 @@ const DeviceKitAspectFactory theDeviceKitAspectFactory; } // namespace Internal -Id DeviceKitAspect::id() +Id RunDeviceKitAspect::id() { return "PE.Profile.Device"; } -IDevice::ConstPtr DeviceKitAspect::device(const Kit *k) +IDevice::ConstPtr RunDeviceKitAspect::device(const Kit *k) { QTC_ASSERT(DeviceManager::instance()->isLoaded(), return IDevice::ConstPtr()); return DeviceManager::instance()->find(deviceId(k)); } -Id DeviceKitAspect::deviceId(const Kit *k) +Id RunDeviceKitAspect::deviceId(const Kit *k) { - return k ? Id::fromSetting(k->value(DeviceKitAspect::id())) : Id(); + return k ? Id::fromSetting(k->value(RunDeviceKitAspect::id())) : Id(); } -void DeviceKitAspect::setDevice(Kit *k, IDevice::ConstPtr dev) +void RunDeviceKitAspect::setDevice(Kit *k, IDevice::ConstPtr dev) { setDeviceId(k, dev ? dev->id() : Id()); } -void DeviceKitAspect::setDeviceId(Kit *k, Id id) +void RunDeviceKitAspect::setDeviceId(Kit *k, Id id) { QTC_ASSERT(k, return); - k->setValue(DeviceKitAspect::id(), id.toSetting()); + k->setValue(RunDeviceKitAspect::id(), id.toSetting()); } -FilePath DeviceKitAspect::deviceFilePath(const Kit *k, const QString &pathOnDevice) +FilePath RunDeviceKitAspect::deviceFilePath(const Kit *k, const QString &pathOnDevice) { if (IDevice::ConstPtr dev = device(k)) return dev->filePath(pathOnDevice); diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.h b/src/plugins/projectexplorer/devicesupport/devicekitaspects.h index 1c3907d38a5..b38acdd50fa 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.h +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.h @@ -21,7 +21,7 @@ public: static void setDeviceTypeId(Kit *k, Utils::Id type); }; -class PROJECTEXPLORER_EXPORT DeviceKitAspect +class PROJECTEXPLORER_EXPORT RunDeviceKitAspect { public: static Utils::Id id(); diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp index a231bfa21de..4321ba2e277 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp @@ -237,7 +237,7 @@ void DeviceProcessesDialogPrivate::killProcess() void DeviceProcessesDialogPrivate::updateDevice() { - setDevice(DeviceKitAspect::device(kitChooser->currentKit())); + setDevice(RunDeviceKitAspect::device(kitChooser->currentKit())); } void DeviceProcessesDialogPrivate::handleProcessKilled() diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp index 9eb18fb6b1a..8af1082c7ac 100644 --- a/src/plugins/projectexplorer/kit.cpp +++ b/src/plugins/projectexplorer/kit.cpp @@ -563,7 +563,7 @@ Environment Kit::buildEnvironment() const Environment Kit::runEnvironment() const { - IDevice::ConstPtr device = DeviceKitAspect::device(this); + IDevice::ConstPtr device = RunDeviceKitAspect::device(this); Environment env = device ? device->systemEnvironment() : Environment::systemEnvironment(); addToRunEnvironment(env); return env; @@ -678,7 +678,7 @@ void Kit::setMutable(Id id, bool b) bool Kit::isMutable(Id id) const { - if (id == DeviceKitAspect::id()) + if (id == RunDeviceKitAspect::id()) return DeviceTypeKitAspect::deviceTypeId(this) != Constants::DESKTOP_DEVICE_TYPE; return d->m_mutable.contains(id); } diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index fae5a5aef3b..827b8dd50e3 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -224,7 +224,7 @@ void KitAspect::addToLayoutImpl(Layouting::Layout &layout) void KitAspect::addMutableAction(QWidget *child) { QTC_ASSERT(child, return); - if (factory()->id() == DeviceKitAspect::id()) + if (factory()->id() == RunDeviceKitAspect::id()) return; child->addAction(d->mutableAction); child->setContextMenuPolicy(Qt::ActionsContextMenu); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 4f265650797..e0dbd19aaa6 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -321,7 +321,7 @@ static bool canOpenTerminalWithRunEnv(const Project *project, const ProjectNode IDevice::ConstPtr device = DeviceManager::deviceForPath(runConfig->runnable().command.executable()); if (!device) - device = DeviceKitAspect::device(target->kit()); + device = RunDeviceKitAspect::device(target->kit()); return device && device->canOpenTerminal(); } @@ -3843,7 +3843,7 @@ void ProjectExplorerPluginPrivate::openTerminalHereWithRunEnv() const ProcessRunData runnable = runConfig->runnable(); IDevice::ConstPtr device = DeviceManager::deviceForPath(runnable.command.executable()); if (!device) - device = DeviceKitAspect::device(target->kit()); + device = RunDeviceKitAspect::device(target->kit()); QTC_ASSERT(device && device->canOpenTerminal(), return); FilePath workingDir = device->type() == Constants::DESKTOP_DEVICE_TYPE diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 3315c2cb0f6..8a03ee407bb 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -506,7 +506,7 @@ QString RunConfigurationFactory::decoratedTargetName(const QString &targetName, QString displayName = targetName; Utils::Id devType = DeviceTypeKitAspect::deviceTypeId(target->kit()); if (devType != Constants::DESKTOP_DEVICE_TYPE) { - if (IDevice::ConstPtr dev = DeviceKitAspect::device(target->kit())) { + if (IDevice::ConstPtr dev = RunDeviceKitAspect::device(target->kit())) { if (displayName.isEmpty()) { //: Shown in Run configuration if no executable is given, %1 is device name displayName = Tr::tr("Run on %{Device:Name}"); diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index f0d5f9426b7..965131465a8 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -521,7 +521,7 @@ static IDevice::ConstPtr executionDevice(Target *target, { if (target) { if (selector == ExecutableAspect::RunDevice) - return DeviceKitAspect::device(target->kit()); + return RunDeviceKitAspect::device(target->kit()); if (selector == ExecutableAspect::BuildDevice) return BuildDeviceKitAspect::device(target->kit()); } diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index a008fdf2fd7..a1366778df1 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -435,9 +435,9 @@ void RunControl::setKit(Kit *kit) if (!d->runnable.command.isEmpty()) { setDevice(DeviceManager::deviceForPath(d->runnable.command.executable())); - QTC_ASSERT(device(), setDevice(DeviceKitAspect::device(kit))); // FIXME: QTCREATORBUG-31259 + QTC_ASSERT(device(), setDevice(RunDeviceKitAspect::device(kit))); } else { - setDevice(DeviceKitAspect::device(kit)); + setDevice(RunDeviceKitAspect::device(kit)); } } diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index d5eb1292c27..3085459cd87 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -578,7 +578,7 @@ void Target::setOverlayIcon(const QIcon &icon) QString Target::overlayIconToolTip() { - IDevice::ConstPtr current = DeviceKitAspect::device(kit()); + IDevice::ConstPtr current = RunDeviceKitAspect::device(kit()); return current ? formatDeviceInfo(current->deviceInformation()) : QString(); } @@ -854,7 +854,7 @@ ProjectConfigurationModel *Target::runConfigurationModel() const void Target::updateDeviceState() { - IDevice::ConstPtr current = DeviceKitAspect::device(kit()); + IDevice::ConstPtr current = RunDeviceKitAspect::device(kit()); QIcon overlay; static const QIcon disconnected = Icons::DEVICE_DISCONNECTED_INDICATOR_OVERLAY.icon(); diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index 9cd8dfca067..0c15c4f4a4e 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -272,7 +272,7 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor QString toolchain = toolchainType(mainTc); if (targetAbi.osFlavor() == Abi::AndroidLinuxFlavor) { - const IDevice::ConstPtr dev = DeviceKitAspect::device(k); + const IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); if (dev) { const QString sdkDir = k->value(Android::Constants::ANDROID_KIT_SDK).toString(); if (!sdkDir.isEmpty()) diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp index a25213c1fcd..e30545387f9 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -705,7 +705,7 @@ QStringList ToolBarBackend::kits() const { auto kits = Utils::filtered(ProjectExplorer::KitManager::kits(), [](ProjectExplorer::Kit *kit) { const auto qtVersion = QtSupport::QtKitAspect::qtVersion(kit); - const auto dev = ProjectExplorer::DeviceKitAspect::device(kit); + const auto dev = ProjectExplorer::RunDeviceKitAspect::device(kit); return kit->isValid() && !kit->isReplacementKit() && qtVersion && qtVersion->isValid() && dev diff --git a/src/plugins/qmlprofiler/qmlprofilerattachdialog.cpp b/src/plugins/qmlprofiler/qmlprofilerattachdialog.cpp index 679166b19c7..37b96931ab2 100644 --- a/src/plugins/qmlprofiler/qmlprofilerattachdialog.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerattachdialog.cpp @@ -33,7 +33,7 @@ QmlProfilerAttachDialog::QmlProfilerAttachDialog(QWidget *parent) : d->kitChooser = new KitChooser(this); d->kitChooser->setKitPredicate([](const Kit *kit) { - return DeviceKitAspect::device(kit) != nullptr; + return RunDeviceKitAspect::device(kit) != nullptr; }); d->kitChooser->populate(); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 68e3bb63774..da6bc556d7a 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -592,7 +592,7 @@ ProjectExplorer::RunControl *QmlProfilerTool::attachToWaitingApplication() QUrl serverUrl; - IDevice::ConstPtr device = DeviceKitAspect::device(kit); + IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); QTC_ASSERT(device, return nullptr); QUrl toolControl = device->toolControlChannel(IDevice::QmlControlChannel); serverUrl.setScheme(Utils::urlTcpScheme()); diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp index a4b66362d28..5445e9540df 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp @@ -513,7 +513,7 @@ Utils::FilePath QmlBuildSystem::targetDirectory() const Utils::FilePath result; if (DeviceTypeKitAspect::deviceTypeId(kit()) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { result = canonicalProjectDir(); - } else if (IDevice::ConstPtr device = DeviceKitAspect::device(kit())) { + } else if (IDevice::ConstPtr device = RunDeviceKitAspect::device(kit())) { if (m_projectItem) result = device->filePath(m_projectItem->targetDirectory()); } diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 95ecf8b849b..7ba18e3d03b 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -184,7 +184,7 @@ Tasks QmlProject::projectIssues(const Kit *k) const if (!version) result.append(createProjectTask(Task::TaskType::Warning, Tr::tr("No Qt version set in kit."))); - IDevice::ConstPtr dev = DeviceKitAspect::device(k); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); if (!dev) result.append(createProjectTask(Task::TaskType::Error, Tr::tr("Kit has no device."))); diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index 25ff5522bca..111185be66d 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -204,7 +204,7 @@ FilePath QmlProjectRunConfiguration::qmlRuntimeFilePath() const // We might not have a full Qt version for building, but the device // might know what is good for running. - IDevice::ConstPtr dev = DeviceKitAspect::device(kit); + IDevice::ConstPtr dev = RunDeviceKitAspect::device(kit); if (dev) { const FilePath qmlRuntime = dev->qmlRunCommand(); if (!qmlRuntime.isEmpty()) diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index 6a04084d69e..7b0a3fcfa07 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -116,7 +116,7 @@ class QnxPlugin final : public ExtensionSystem::IPlugin [attachToQnxApplication, debugSeparator] { auto isQnxKit = [](const Kit *kit) { return DeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE - && DeviceKitAspect::device(kit) && kit->isValid(); + && RunDeviceKitAspect::device(kit) && kit->isValid(); }; const bool hasValidQnxKit = KitManager::kit(isQnxKit) != nullptr; diff --git a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp index b6b3b9a0910..a2596ad45c9 100644 --- a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp @@ -24,7 +24,7 @@ namespace AppManager::Internal { static bool isNecessaryToDeploy(const Target *target) { - auto device = DeviceKitAspect::device(target->kit()); + auto device = RunDeviceKitAspect::device(target->kit()); return device && device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; } diff --git a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp index 36bb6071db9..f7e027d8b92 100644 --- a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp @@ -87,7 +87,7 @@ private: const FilePath targetDir = targetDirectory().isEmpty() ? FilePath::fromString(targetDirectory.defaultValue()) : targetDirectory(); - const FilePath target = DeviceKitAspect::device(kit())->filePath(targetDir.path()) + const FilePath target = RunDeviceKitAspect::device(kit())->filePath(targetDir.path()) .pathAppended(source.fileName()); streamer.setSource(source); streamer.setDestination(target); diff --git a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp index 28c8a53945e..a5a75613def 100644 --- a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp @@ -56,7 +56,7 @@ AppManagerInstallPackageStep::AppManagerInstallPackageStep(BuildStepList *bsl, I controller.setDefaultPathValue(getToolFilePath(Constants::APPMAN_CONTROLLER, target()->kit(), - DeviceKitAspect::device(target()->kit()))); + RunDeviceKitAspect::device(target()->kit()))); arguments.setSettingsKey(SETTINGSPREFIX "Arguments"); arguments.setResetter([] { return QLatin1String(ArgumentsDefault); }); @@ -74,7 +74,7 @@ AppManagerInstallPackageStep::AppManagerInstallPackageStep(BuildStepList *bsl, I const TargetInformation targetInformation(target()); - IDeviceConstPtr device = DeviceKitAspect::device(kit()); + IDeviceConstPtr device = RunDeviceKitAspect::device(kit()); if (device && device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { packageFile.setDefaultPathValue(targetInformation.packageFilePath); } else { diff --git a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp index e5a0e3fe4cf..f1671bfdc7e 100644 --- a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp @@ -42,7 +42,7 @@ public: const TargetInformation targetInformation = tis.at(0); controller.setValue(getToolFilePath(Constants::APPMAN_CONTROLLER, kit(), - DeviceKitAspect::device(kit()))); + RunDeviceKitAspect::device(kit()))); appId.setValue(targetInformation.manifest.id); appId.setReadOnly(true); @@ -94,7 +94,7 @@ public: virtual bool filterTarget(Target *target, const TargetInformation &ti) const { return !ti.manifest.supportsDebugging() || - DeviceKitAspect::device(target->kit())->osType() != OsType::OsTypeLinux; + RunDeviceKitAspect::device(target->kit())->osType() != OsType::OsTypeLinux; } QList availableCreators(Target *target) const diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 31c125748fb..4b2af98d469 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -209,7 +209,7 @@ public: if (targetInformation.manifest.isQmlRuntime()) { m_symbolFile = getToolFilePath(Constants::APPMAN_LAUNCHER_QML, target->kit(), - DeviceKitAspect::device(target->kit())); + RunDeviceKitAspect::device(target->kit())); } else if (targetInformation.manifest.isNativeRuntime()) { m_symbolFile = Utils::findOrDefault(target->buildSystem()->applicationTargets(), [&](const BuildTargetInfo &ti) { return ti.buildKey == targetInformation.manifest.code || ti.projectFilePath.toString() == targetInformation.manifest.code; diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp index 27ac24232d8..9077efdd629 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp @@ -47,7 +47,7 @@ AbstractRemoteLinuxDeployStep::~AbstractRemoteLinuxDeployStep() IDevice::ConstPtr AbstractRemoteLinuxDeployStep::deviceConfiguration() const { - return DeviceKitAspect::device(kit()); + return RunDeviceKitAspect::device(kit()); } void AbstractRemoteLinuxDeployStep::saveDeploymentTimeStamp(const DeployableFile &deployableFile, diff --git a/src/plugins/remotelinux/deploymenttimeinfo.cpp b/src/plugins/remotelinux/deploymenttimeinfo.cpp index d3c9b028564..084d73dc9b2 100644 --- a/src/plugins/remotelinux/deploymenttimeinfo.cpp +++ b/src/plugins/remotelinux/deploymenttimeinfo.cpp @@ -60,7 +60,7 @@ public: if (kit) { systemRoot = SysRootKitAspect::sysRoot(kit).toString(); - const IDevice::ConstPtr deviceConfiguration = DeviceKitAspect::device(kit); + const IDevice::ConstPtr deviceConfiguration = RunDeviceKitAspect::device(kit); host = deviceConfiguration->sshParameters().host(); } diff --git a/src/plugins/remotelinux/genericdeploystep.cpp b/src/plugins/remotelinux/genericdeploystep.cpp index 06318a2d5d3..5ea55a7f97f 100644 --- a/src/plugins/remotelinux/genericdeploystep.cpp +++ b/src/plugins/remotelinux/genericdeploystep.cpp @@ -55,7 +55,7 @@ public: method.addOption(Tr::tr("Use default transfer. This might be slow.")); setInternalInitializer([this]() -> expected_str { - if (BuildDeviceKitAspect::device(kit()) == DeviceKitAspect::device(kit())) { + if (BuildDeviceKitAspect::device(kit()) == RunDeviceKitAspect::device(kit())) { // rsync transfer on the same device currently not implemented // and typically not wanted. return make_unexpected( diff --git a/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp b/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp index 455aeecf3f2..bae288e3a4b 100644 --- a/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp +++ b/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp @@ -43,7 +43,7 @@ public: }); connect(fetchButton, &QPushButton::clicked, this, [aspect] { - if (IDevice::ConstPtr device = DeviceKitAspect::device(aspect->target()->kit())) { + if (IDevice::ConstPtr device = RunDeviceKitAspect::device(aspect->target()->kit())) { DeviceFileAccess *access = device->fileAccess(); QTC_ASSERT(access, return); aspect->setRemoteEnvironment(access->deviceEnvironment()); @@ -51,7 +51,7 @@ public: }); envWidget()->setOpenTerminalFunc([aspect](const Environment &env) { - IDevice::ConstPtr device = DeviceKitAspect::device(aspect->target()->kit()); + IDevice::ConstPtr device = RunDeviceKitAspect::device(aspect->target()->kit()); if (!device) { QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("Cannot Open Terminal"), diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp index 7700c42d3e5..6952ec11095 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp @@ -61,7 +61,7 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Id id) setUpdater([this, target] { const IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(target->kit()); - const IDeviceConstPtr runDevice = DeviceKitAspect::device(target->kit()); + const IDeviceConstPtr runDevice = RunDeviceKitAspect::device(target->kit()); QTC_ASSERT(buildDevice, return); QTC_ASSERT(runDevice, return); const BuildTargetInfo bti = buildTargetInfo(); diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 57f62a0c4b3..9f399f9d464 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -44,7 +44,7 @@ ValgrindToolRunner::ValgrindToolRunner(RunControl *runControl) void ValgrindToolRunner::start() { FilePath valgrindExecutable = m_settings.valgrindExecutable(); - if (IDevice::ConstPtr dev = DeviceKitAspect::device(runControl()->kit())) + if (IDevice::ConstPtr dev = RunDeviceKitAspect::device(runControl()->kit())) valgrindExecutable = dev->filePath(valgrindExecutable.path()); const FilePath found = valgrindExecutable.searchInPath(); From ee0779ac80f02bebb50e27ee660c5b02a426a30d Mon Sep 17 00:00:00 2001 From: Andrii Batyiev Date: Fri, 8 Nov 2024 09:26:44 +0200 Subject: [PATCH 071/989] LuaLS: filter out stale clients Clients on the list could be already in shutdown phase, so filter them out. Change-Id: I30768f63a89418279af02076550f408749ad04a9 Reviewed-by: Marcus Tillmanns --- .../languageclient/lualanguageclient/lualanguageclient.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp index 54b32cc574f..a4c56154f1d 100644 --- a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp +++ b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp @@ -425,15 +425,18 @@ public: QList clientsForDocument(Core::IDocument *document) { + QList result; if (m_startBehavior == BaseSettings::RequiresProject) { Project *project = ProjectManager::projectForFile(document->filePath()); const auto clients = LanguageClientManager::clientsForSettingId(m_clientSettingsId); - return Utils::filtered(clients, [project](Client *c) { + result = Utils::filtered(clients, [project](Client *c) { return c && c->project() == project; }); } + else + result = LanguageClientManager::clientsForSettingId(m_clientSettingsId); - return LanguageClientManager::clientsForSettingId(m_clientSettingsId); + return Utils::filtered(result, [](Client *c) { return c->reachable(); }); } void sendMessageForDocument(Core::IDocument *document, const sol::table &message) From bbb5693b7d55e3de3520eacd61391e5640bbd987 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 25 Sep 2024 15:03:26 +0200 Subject: [PATCH 072/989] qbs build: Add lupdate support Task-number: QBS-486 Change-Id: I1d095a298de1eb806ed977531cdf3d96da68e654 Reviewed-by: Christian Stenger --- .../qtcreator/translations/lupdaterunner.qbs | 3 + share/qtcreator/translations/translations.qbs | 94 +++++++++++++++---- 2 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 share/qtcreator/translations/lupdaterunner.qbs diff --git a/share/qtcreator/translations/lupdaterunner.qbs b/share/qtcreator/translations/lupdaterunner.qbs new file mode 100644 index 00000000000..740838c4e1a --- /dev/null +++ b/share/qtcreator/translations/lupdaterunner.qbs @@ -0,0 +1,3 @@ +QtLupdateRunner { + limitToSubProject: false +} diff --git a/share/qtcreator/translations/translations.qbs b/share/qtcreator/translations/translations.qbs index 4e4faddcc89..8dc7f3469fb 100644 --- a/share/qtcreator/translations/translations.qbs +++ b/share/qtcreator/translations/translations.qbs @@ -1,25 +1,83 @@ -import qbs 1.0 +import qbs.Utilities -Product { - name: "Translations" - type: "qm" - builtByDefault: false +Project { + Product { + name: "Translations" + builtByDefault: false - Depends { name: "Qt.core" } - Depends { name: "qtc" } + property string pythonExecutable: "python" - Group { - files: ["*.ts"] - excludeFiles: [ - "qtcreator_es.ts", - "qtcreator_hu.ts", - "qtcreator_it.ts", - ] + Depends { name: "Qt.core" } + Depends { name: "qtc" } + + Group { + name: "translations to use" + files: [ + "qtcreator_cs.ts", + "qtcreator_da.ts", + "qtcreator_de.ts", + "qtcreator_en.ts", + "qtcreator_fr.ts", + "qtcreator_hr.ts", + "qtcreator_ja.ts", + "qtcreator_pl.ts", + "qtcreator_ru.ts", + "qtcreator_sl.ts", + "qtcreator_uk.ts", + "qtcreator_zh_CN.ts", + "qtcreator_zh_TW.ts", + ] + } + + Group { + name: "translations not to use" + files: [ + "qtcreator_hu.ts", + "qtcreator_es.ts", + "qtcreator_it.ts", + ] + fileTags: [] + } + + Group { + name: "extractor scripts" + files: [ + "extract-customwizards.py", + "extract-externaltools.py", + "extract-jsonwizards.py", + "extract-snippets.py", + ] + fileTags: "ts_extractor" + } + + Group { + fileTagsFilter: product.type + qbs.install: true + qbs.installDir: qtc.ide_data_path + "/translations" + } + + Rule { + inputs: "ts_extractor" + Artifact { filePath: input.baseName + ".cpp"; fileTags: "cpp" } + prepare: { + var inputDir = project.ide_source_tree + '/'; + if (input.fileName.includes("wizards")) + inputDir += "share/qtcreator/templates/wizards"; + else if (input.fileName.contains("externaltools")) + inputDir += "src/share/qtcreator/externaltools"; + else + inputDir += "share/qtcreator/snippets"; + var cmd = new Command(product.pythonExecutable, + [input.filePath, inputDir, output.filePath]); + cmd.description = "creating " + output.fileName; + cmd.highlight = "filegen"; + return cmd; + } + } } - Group { - fileTagsFilter: product.type - qbs.install: true - qbs.installDir: qtc.ide_data_path + "/translations" + Project { + condition: Utilities.versionCompare(qbs.version, "2.6") >= 0 + references: "lupdaterunner.qbs" } } From 51d2c802c0d11e98889e007a7702f7e3ef10127e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 6 Nov 2024 16:50:23 +0100 Subject: [PATCH 073/989] QtSupport: Refactor Qt ABI extraction The format will change in Qt 6.9, so put the extraction code into a dedicated file, as not to pollute baseqtversion.cpp even more. Change-Id: Ida4fc0c0e4b92b58afe15c5ae2fa14fab56d9167 Reviewed-by: David Schulz --- src/plugins/qtsupport/CMakeLists.txt | 1 + src/plugins/qtsupport/baseqtversion.cpp | 164 +---------------- src/plugins/qtsupport/qtabiextractor.cpp | 214 +++++++++++++++++++++++ src/plugins/qtsupport/qtabiextractor.h | 20 +++ src/plugins/qtsupport/qtsupport.qbs | 5 +- 5 files changed, 243 insertions(+), 161 deletions(-) create mode 100644 src/plugins/qtsupport/qtabiextractor.cpp create mode 100644 src/plugins/qtsupport/qtabiextractor.h diff --git a/src/plugins/qtsupport/CMakeLists.txt b/src/plugins/qtsupport/CMakeLists.txt index cad1c5ef4b8..3b4716c8873 100644 --- a/src/plugins/qtsupport/CMakeLists.txt +++ b/src/plugins/qtsupport/CMakeLists.txt @@ -13,6 +13,7 @@ add_qtc_plugin(QtSupport gettingstartedwelcomepage.cpp gettingstartedwelcomepage.h profilereader.cpp profilereader.h qscxmlcgenerator.cpp qscxmlcgenerator.h + qtabiextractor.cpp qtabiextractor.h qtbuildaspects.cpp qtbuildaspects.h qtconfigwidget.cpp qtconfigwidget.h qtcppkitinfo.cpp qtcppkitinfo.h diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 41cfd80ca78..31086e823a5 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -4,6 +4,7 @@ #include "baseqtversion.h" #include "profilereader.h" +#include "qtabiextractor.h" #include "qtconfigwidget.h" #include "qtkitaspect.h" #include "qtsupportconstants.h" @@ -48,12 +49,8 @@ #include #include #include -#include #include #include -#include -#include -#include #include #include #include @@ -78,8 +75,6 @@ const char QTVERSION_ABIS[] = "Abis"; const char MKSPEC_VALUE_LIBINFIX[] = "QT_LIBINFIX"; const char MKSPEC_VALUE_NAMESPACE[] = "QT_NAMESPACE"; -Q_LOGGING_CATEGORY(abiDetect, "qtc.qtsupport.detectAbis", QtWarningMsg) - // -------------------------------------------------------------------- // QtVersionData: // -------------------------------------------------------------------- @@ -196,7 +191,6 @@ public: FilePaths qtCorePaths(); ProjectExplorer::Abis qtAbisFromLibrary(); - ProjectExplorer::Abis qtAbisFromJson(); public: QtVersion *q; @@ -755,8 +749,10 @@ void QtVersion::setQtAbis(const Abis &abis) Abis QtVersion::detectQtAbis() const { qCDebug(abiDetect) << "Detecting ABIs for" << qmakeFilePath(); - if (const Abis abis = d->qtAbisFromJson(); !abis.isEmpty()) + if (const Abis abis = qtAbisFromJson(*this, {d->data().archDataPath, d->data().dataPath}); + !abis.isEmpty()) { return abis; + } qCDebug(abiDetect) << "Got no ABI from JSON file, falling back to inspecting binaries"; return d->qtAbisFromLibrary(); } @@ -2253,158 +2249,6 @@ Abis QtVersionPrivate::qtAbisFromLibrary() return QtConcurrent::blockingMappedReduced(qtCorePaths(), filePathToAbiList, uniqueAbis); } -Abis QtVersionPrivate::qtAbisFromJson() -{ - if (q->qtVersion().majorVersion() < 6) { - qCDebug(abiDetect) << "Not attempting to read JSON file for Qt < 6"; - return {}; - } - - FilePath jsonFile; - for (const FilePath &baseDir : FilePaths{data().archDataPath, data().dataPath}) { - const FilePath candidate = baseDir.pathAppended("modules/Core.json"); - qCDebug(abiDetect) << "Checking JSON file location" << candidate; - if (candidate.exists()) { - jsonFile = candidate; - break; - } - } - if (jsonFile.isEmpty()) { - Core::MessageManager::writeSilently( - Tr::tr("Core.json not found for Qt at \"%1\"").arg(m_qmakeCommand.toUserOutput())); - return {}; - } - - const auto printErrorAndReturn = [&jsonFile](const QString &detail) { - Core::MessageManager::writeSilently( - Tr::tr("Error reading \"%1\": %2").arg(jsonFile.toUserOutput(), detail)); - return Abis(); - }; - const auto content = jsonFile.fileContents(); - if (!content) - return printErrorAndReturn(content.error()); - - QJsonParseError parseError; - const QJsonDocument jsonDoc = QJsonDocument::fromJson(content.value(), &parseError); - if (parseError.error != QJsonParseError::NoError) - return printErrorAndReturn(parseError.errorString()); - - const QJsonObject obj = jsonDoc.object().value("built_with").toObject(); - const QString osString = obj.value("target_system").toString(); - const Abi::OS os = [&osString] { - if (osString == "Linux" || osString == "Android") - return Abi::LinuxOS; - if (osString == "Darwin" || osString == "iOS") - return Abi::DarwinOS; - if (osString == "Windows") - return Abi::WindowsOS; - if (osString.endsWith("BSD")) - return Abi::BsdOS; - return Abi::UnknownOS; - }(); - - if (os == Abi::DarwinOS) - return {}; // QTBUG-129996 - - const auto [arch, width] = [](const QString &arch) { - if (arch == "x86") - return std::make_pair(Abi::X86Architecture, 32); - if (arch == "x86_64") - return std::make_pair(Abi::X86Architecture, 64); - if (arch == "arm") - return std::make_pair(Abi::ArmArchitecture, 32); - if (arch == "arm64") - return std::make_pair(Abi::ArmArchitecture, 64); - if (arch == "riscv64") - return std::make_pair(Abi::RiscVArchitecture, 64); - if (arch == "wasm") - return std::make_pair(Abi::AsmJsArchitecture, 32); - return std::make_pair(Abi::UnknownArchitecture, 0); - }(obj.value("architecture").toString()); - if (os == Abi::UnknownOS && arch != Abi::AsmJsArchitecture) - return printErrorAndReturn(Tr::tr("Could not determine target OS")); - if (arch == Abi::UnknownArchitecture) - return printErrorAndReturn(Tr::tr("Could not determine target architecture")); - - const Abi::OSFlavor flavor = [&](const QString &compilerId, const QString &compilerVersion) { - if (osString == "Android") - return Abi::AndroidLinuxFlavor; - switch (os) { - case Abi::LinuxOS: - case Abi::DarwinOS: - case Abi::BareMetalOS: - case Abi::QnxOS: - return Abi::GenericFlavor; - case Abi::BsdOS: - if (osString == "FreeBSD") - return Abi::FreeBsdFlavor; - if (osString == "NetBSD") - return Abi::NetBsdFlavor; - if (osString == "OpenBSD") - return Abi::OpenBsdFlavor; - break; - case Abi::WindowsOS: { - if (compilerId == "GNU" || compilerId == "Clang") - return Abi::WindowsMSysFlavor; - - // https://learn.microsoft.com/en-us/cpp/overview/compiler-versions - const QVersionNumber rawVersion = QVersionNumber::fromString(compilerVersion); - switch (rawVersion.majorVersion()) { - case 19: - if (rawVersion.minorVersion() >= 30) - return Abi::WindowsMsvc2022Flavor; - if (rawVersion.minorVersion() >= 20) - return Abi::WindowsMsvc2019Flavor; - if (rawVersion.minorVersion() >= 10) - return Abi::WindowsMsvc2017Flavor; - return Abi::WindowsMsvc2015Flavor; - case 18: - return Abi::WindowsMsvc2013Flavor; - case 17: - return Abi::WindowsMsvc2012Flavor; - case 16: - return Abi::WindowsMsvc2010Flavor; - case 15: - return Abi::WindowsMsvc2008Flavor; - case 14: - return Abi::WindowsMsvc2005Flavor; - } - break; - } - case Abi::UnixOS: - case Abi::VxWorks: - case Abi::UnknownOS: - break; - } - return Abi::UnknownFlavor; - }(obj.value("compiler_id").toString(), obj.value("compiler_version").toString()); - if (flavor == Abi::UnknownFlavor && arch != Abi::AsmJsArchitecture) - return printErrorAndReturn(Tr::tr("Could not determine OS sub-type")); - - const Abi::BinaryFormat format = [&] { - if (arch == Abi::AsmJsArchitecture) - return Abi::EmscriptenFormat; - switch (os) { - case Abi::BareMetalOS: - case Abi::BsdOS: - case Abi::LinuxOS: - case Abi::QnxOS: - case Abi::UnixOS: - case Abi::VxWorks: - return Abi::ElfFormat; - case Abi::DarwinOS: - return Abi::MachOFormat; - case Abi::WindowsOS: - return Abi::PEFormat; - case Abi::UnknownOS: - break; - } - return Abi::UnknownFormat; - }(); - - return {Abi(arch, os, flavor, format, width)}; -} - void QtVersion::resetCache() const { d->m_mkspecReadUpToDate = false; diff --git a/src/plugins/qtsupport/qtabiextractor.cpp b/src/plugins/qtsupport/qtabiextractor.cpp new file mode 100644 index 00000000000..3e970357275 --- /dev/null +++ b/src/plugins/qtsupport/qtabiextractor.cpp @@ -0,0 +1,214 @@ +// 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 "qtabiextractor.h" + +#include "baseqtversion.h" +#include "qtsupporttr.h" + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace QtSupport::Internal { +Q_LOGGING_CATEGORY(abiDetect, "qtc.qtsupport.detectAbis", QtWarningMsg) + +class QtAbiExtractor +{ +public: + QtAbiExtractor(const FilePath &jsonFile) : m_jsonFile(jsonFile) {} + + Abis getAbis() + { + const auto printErrorAndReturn = [this](const QString &detail) { + printError(detail); + return Abis(); + }; + const auto content = m_jsonFile.fileContents(); + if (!content) + return printErrorAndReturn(content.error()); + + QJsonParseError parseError; + const QJsonDocument jsonDoc = QJsonDocument::fromJson(content.value(), &parseError); + if (parseError.error != QJsonParseError::NoError) + return printErrorAndReturn(parseError.errorString()); + + const QJsonObject obj = jsonDoc.object().value("built_with").toObject(); + const QString osString = obj.value("target_system").toString(); + const Abi::OS os = getOs(osString); + + if (os == Abi::DarwinOS) + return {}; // QTBUG-129996 + + const auto [arch, width] = getArch(obj.value("architecture").toString()); + if (os == Abi::UnknownOS && arch != Abi::AsmJsArchitecture) + return printErrorAndReturn(Tr::tr("Could not determine target OS")); + if (arch == Abi::UnknownArchitecture) + return printErrorAndReturn(Tr::tr("Could not determine target architecture")); + + const Abi::OSFlavor flavor = getFlavor( + os, + osString, + obj.value("compiler_id").toString(), + obj.value("compiler_version").toString()); + if (flavor == Abi::UnknownFlavor && arch != Abi::AsmJsArchitecture) + return printErrorAndReturn(Tr::tr("Could not determine OS sub-type")); + + return {Abi(arch, os, flavor, getFormat(os, arch), width)}; + } + +private: + void printError(const QString &detail) { + Core::MessageManager::writeSilently( + Tr::tr("Error reading \"%1\": %2").arg(m_jsonFile.toUserOutput(), detail)); + } + + Abi::OS getOs(const QString &osString) const + { + if (osString == "Linux" || osString == "Android") + return Abi::LinuxOS; + if (osString == "Darwin" || osString == "iOS") + return Abi::DarwinOS; + if (osString == "Windows") + return Abi::WindowsOS; + if (osString.endsWith("BSD")) + return Abi::BsdOS; + return Abi::UnknownOS; + } + + std::pair getArch(const QString &archString) + { + if (archString == "x86") + return std::make_pair(Abi::X86Architecture, 32); + if (archString == "x86_64") + return std::make_pair(Abi::X86Architecture, 64); + if (archString == "arm") + return std::make_pair(Abi::ArmArchitecture, 32); + if (archString == "arm64") + return std::make_pair(Abi::ArmArchitecture, 64); + if (archString == "riscv64") + return std::make_pair(Abi::RiscVArchitecture, 64); + if (archString == "wasm") + return std::make_pair(Abi::AsmJsArchitecture, 32); + return std::make_pair(Abi::UnknownArchitecture, 0); + } + + Abi::OSFlavor getFlavor( + Abi::OS os, + const QString &osString, + const QString &compilerId, + const QString &compilerVersion) + { + if (osString == "Android") + return Abi::AndroidLinuxFlavor; + switch (os) { + case Abi::LinuxOS: + case Abi::DarwinOS: + case Abi::BareMetalOS: + case Abi::QnxOS: + return Abi::GenericFlavor; + case Abi::BsdOS: + if (osString == "FreeBSD") + return Abi::FreeBsdFlavor; + if (osString == "NetBSD") + return Abi::NetBsdFlavor; + if (osString == "OpenBSD") + return Abi::OpenBsdFlavor; + break; + case Abi::WindowsOS: { + if (compilerId == "GNU" || compilerId == "Clang") + return Abi::WindowsMSysFlavor; + + // https://learn.microsoft.com/en-us/cpp/overview/compiler-versions + const QVersionNumber rawVersion = QVersionNumber::fromString(compilerVersion); + switch (rawVersion.majorVersion()) { + case 19: + if (rawVersion.minorVersion() >= 30) + return Abi::WindowsMsvc2022Flavor; + if (rawVersion.minorVersion() >= 20) + return Abi::WindowsMsvc2019Flavor; + if (rawVersion.minorVersion() >= 10) + return Abi::WindowsMsvc2017Flavor; + return Abi::WindowsMsvc2015Flavor; + case 18: + return Abi::WindowsMsvc2013Flavor; + case 17: + return Abi::WindowsMsvc2012Flavor; + case 16: + return Abi::WindowsMsvc2010Flavor; + case 15: + return Abi::WindowsMsvc2008Flavor; + case 14: + return Abi::WindowsMsvc2005Flavor; + } + break; + } + case Abi::UnixOS: + case Abi::VxWorks: + case Abi::UnknownOS: + break; + } + return Abi::UnknownFlavor; + } + + Abi::BinaryFormat getFormat(Abi::OS os, Abi::Architecture arch) + { + if (arch == Abi::AsmJsArchitecture) + return Abi::EmscriptenFormat; + switch (os) { + case Abi::BareMetalOS: + case Abi::BsdOS: + case Abi::LinuxOS: + case Abi::QnxOS: + case Abi::UnixOS: + case Abi::VxWorks: + return Abi::ElfFormat; + case Abi::DarwinOS: + return Abi::MachOFormat; + case Abi::WindowsOS: + return Abi::PEFormat; + case Abi::UnknownOS: + break; + } + return Abi::UnknownFormat; + } + + const FilePath m_jsonFile; +}; + +Abis qtAbisFromJson(const QtVersion &qtVersion, const Utils::FilePaths &possibleLocations) +{ + if (qtVersion.qtVersion().majorVersion() < 6) { + qCDebug(abiDetect) << "Not attempting to read JSON file for Qt < 6"; + return {}; + } + + FilePath jsonFile; + for (const FilePath &baseDir : possibleLocations) { + const FilePath candidate = baseDir.pathAppended("modules/Core.json"); + qCDebug(abiDetect) << "Checking JSON file location" << candidate; + if (candidate.exists()) { + jsonFile = candidate; + break; + } + } + if (jsonFile.isEmpty()) { + Core::MessageManager::writeSilently( + Tr::tr("Core.json not found for Qt at \"%1\"") + .arg(qtVersion.qmakeFilePath().toUserOutput())); + return {}; + } + + return QtAbiExtractor(jsonFile).getAbis(); +} + +} // namespace QtSupport::Internal diff --git a/src/plugins/qtsupport/qtabiextractor.h b/src/plugins/qtsupport/qtabiextractor.h new file mode 100644 index 00000000000..eded1cd0121 --- /dev/null +++ b/src/plugins/qtsupport/qtabiextractor.h @@ -0,0 +1,20 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#pragma once + +#include +#include + +#include + +namespace QtSupport { +class QtVersion; + +namespace Internal { +Q_DECLARE_LOGGING_CATEGORY(abiDetect) + +ProjectExplorer::Abis qtAbisFromJson( + const QtVersion &qtVersion, const Utils::FilePaths &possibleLocations); + +} // namespace QtSupport +} // namespace Internal diff --git a/src/plugins/qtsupport/qtsupport.qbs b/src/plugins/qtsupport/qtsupport.qbs index 37db2552d99..964704d1572 100644 --- a/src/plugins/qtsupport/qtsupport.qbs +++ b/src/plugins/qtsupport/qtsupport.qbs @@ -60,6 +60,8 @@ QtcPlugin { "codegensettings.h", "externaleditors.cpp", "externaleditors.h", + "qtabiextractor.cpp", + "qtabiextractor.h", "qtbuildaspects.cpp", "qtbuildaspects.h", "qtconfigwidget.cpp", @@ -85,7 +87,8 @@ QtcPlugin { "qtoutputformatter.h", "qtparser.cpp", "qtparser.h", - "qtsupport_global.h", "qtsupporttr.h", + "qtsupport_global.h", + "qtsupporttr.h", "qtsupportconstants.h", "qtsupportplugin.cpp", "qttestparser.cpp", From 88fa2ba8a7a6d62046877d09184d90f5f7f2016d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 7 Nov 2024 14:56:32 +0100 Subject: [PATCH 074/989] ProjectExplorer: Make KitAspect more flexible Allow for subclasses to have more than one combo box created. Change-Id: I7e2457cdfabe30fd0272f8849555d9fd29412a3b Reviewed-by: hjk --- .../cmakeprojectmanager/cmakekitaspect.cpp | 2 +- src/plugins/debugger/debuggerkitaspect.cpp | 2 +- .../devicesupport/devicekitaspects.cpp | 6 +- src/plugins/projectexplorer/kitaspect.cpp | 74 +++++++++++-------- src/plugins/projectexplorer/kitaspect.h | 2 +- src/plugins/python/pythonkitaspect.cpp | 2 +- src/plugins/qtsupport/qtkitaspect.cpp | 2 +- 7 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp index 9af2df67d03..c75c98b2841 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp @@ -169,7 +169,7 @@ public: CMakeKitAspect::setCMakeTool(&k, Id::fromSetting(id)); }; auto resetModel = [model] { model->reset(); }; - setListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); + addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); CMakeToolManager *cmakeMgr = CMakeToolManager::instance(); connect(cmakeMgr, &CMakeToolManager::cmakeAdded, this, &CMakeKitAspectImpl::refresh); diff --git a/src/plugins/debugger/debuggerkitaspect.cpp b/src/plugins/debugger/debuggerkitaspect.cpp index d8c02afae74..3f9aeecb26e 100644 --- a/src/plugins/debugger/debuggerkitaspect.cpp +++ b/src/plugins/debugger/debuggerkitaspect.cpp @@ -82,7 +82,7 @@ public: }; auto setter = [](Kit &k, const QVariant &id) { k.setValue(DebuggerKitAspect::id(), id); }; auto resetModel = [model] { model->reset(); }; - setListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); + addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); } }; } // namespace Internal diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 8c314689098..2d42ed284a1 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -60,7 +60,7 @@ public: std::make_tuple(factory->displayName(), factory->deviceType(), factory->icon())); } }; - setListAspectSpec( + addListAspectSpec( {model, std::move(getter), std::move(setter), std::move(resetModel)}); } }; @@ -173,7 +173,7 @@ public: auto resetModel = [this, model] { model->setTypeFilter(DeviceTypeKitAspect::deviceTypeId(kit())); }; - setListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); + addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); connect(DeviceManager::instance(), &DeviceManager::updated, this, &DeviceKitAspectImpl::refresh); @@ -420,7 +420,7 @@ public: } model->setFilter(blackList); }; - setListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); + addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); connect(DeviceManager::instance(), &DeviceManager::updated, this, &BuildDeviceKitAspectImpl::refresh); diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index 827b8dd50e3..b18a3b71c4a 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -110,9 +110,18 @@ public: QAction *mutableAction = nullptr; Utils::Id managingPageId; QPushButton *manageButton = nullptr; - QComboBox *comboBox = nullptr; - std::optional listAspectSpec; Utils::Guard ignoreChanges; + + struct ListAspect + { + ListAspect(const ListAspectSpec &spec, QComboBox *comboBox) + : spec(spec) + , comboBox(comboBox) + {} + ListAspectSpec spec; + QComboBox *comboBox; + }; + QList listAspects; }; KitAspect::KitAspect(Kit *kit, const KitAspectFactory *factory) @@ -136,13 +145,15 @@ KitAspect::~KitAspect() void KitAspect::refresh() { - if (!d->listAspectSpec || d->ignoreChanges.isLocked()) + if (d->listAspects.isEmpty() || d->ignoreChanges.isLocked()) return; const GuardLocker locker(d->ignoreChanges); - d->listAspectSpec->resetModel(); - d->comboBox->model()->sort(0); - const QVariant itemId = d->listAspectSpec->getter(*kit()); - d->comboBox->setCurrentIndex(d->comboBox->findData(itemId, IdRole)); + for (const Private::ListAspect &la : std::as_const(d->listAspects)) { + la.spec.resetModel(); + la.comboBox->model()->sort(0); + const QVariant itemId = la.spec.getter(*kit()); + la.comboBox->setCurrentIndex(la.comboBox->findData(itemId, IdRole)); + } } void KitAspect::makeStickySubWidgetsReadOnly() @@ -158,46 +169,45 @@ void KitAspect::makeStickySubWidgetsReadOnly() void KitAspect::makeReadOnly() { - if (d->comboBox) - d->comboBox->setEnabled(false); + for (const Private::ListAspect &la : std::as_const(d->listAspects)) + la.comboBox->setEnabled(false); } void KitAspect::addToInnerLayout(Layouting::Layout &parentItem) { - if (d->comboBox) { - addMutableAction(d->comboBox); - parentItem.addItem(d->comboBox); + for (const Private::ListAspect &la : std::as_const(d->listAspects)) { + addMutableAction(la.comboBox); + parentItem.addItem(la.comboBox); } } -void KitAspect::setListAspectSpec(ListAspectSpec &&listAspectSpec) +void KitAspect::addListAspectSpec(const ListAspectSpec &listAspectSpec) { - d->listAspectSpec = std::move(listAspectSpec); - - d->comboBox = createSubWidget(); - d->comboBox->setSizePolicy(QSizePolicy::Ignored, d->comboBox->sizePolicy().verticalPolicy()); - d->comboBox->setEnabled(true); + const auto comboBox = createSubWidget(); + comboBox->setSizePolicy(QSizePolicy::Ignored, comboBox->sizePolicy().verticalPolicy()); + comboBox->setEnabled(true); const auto sortModel = new KitAspectSortModel(this); - sortModel->setSourceModel(d->listAspectSpec->model); - d->comboBox->setModel(sortModel); + sortModel->setSourceModel(listAspectSpec.model); + comboBox->setModel(sortModel); + d->listAspects.emplaceBack(listAspectSpec, comboBox); refresh(); - const auto updateTooltip = [this] { - d->comboBox->setToolTip( - d->comboBox->itemData(d->comboBox->currentIndex(), Qt::ToolTipRole).toString()); + const auto updateTooltip = [comboBox] { + comboBox->setToolTip( + comboBox->itemData(comboBox->currentIndex(), Qt::ToolTipRole).toString()); }; updateTooltip(); - connect(d->comboBox, &QComboBox::currentIndexChanged, this, [this, updateTooltip] { - if (d->ignoreChanges.isLocked()) - return; - updateTooltip(); - d->listAspectSpec->setter( - *kit(), d->comboBox->itemData(d->comboBox->currentIndex(), IdRole)); - }); - connect(d->listAspectSpec->model, &QAbstractItemModel::modelAboutToBeReset, + connect(comboBox, &QComboBox::currentIndexChanged, + this, [this, listAspectSpec, comboBox, updateTooltip] { + if (d->ignoreChanges.isLocked()) + return; + updateTooltip(); + listAspectSpec.setter(*kit(), comboBox->itemData(comboBox->currentIndex(), IdRole)); + }); + connect(listAspectSpec.model, &QAbstractItemModel::modelAboutToBeReset, this, [this] { d->ignoreChanges.lock(); }); - connect(d->listAspectSpec->model, &QAbstractItemModel::modelReset, + connect(listAspectSpec.model, &QAbstractItemModel::modelReset, this, [this] { d->ignoreChanges.unlock(); }); } diff --git a/src/plugins/projectexplorer/kitaspect.h b/src/plugins/projectexplorer/kitaspect.h index ff00554135d..8c74023e0b4 100644 --- a/src/plugins/projectexplorer/kitaspect.h +++ b/src/plugins/projectexplorer/kitaspect.h @@ -151,7 +151,7 @@ protected: Setter setter; ResetModel resetModel; }; - void setListAspectSpec(ListAspectSpec &&listAspectSpec); + void addListAspectSpec(const ListAspectSpec &listAspectSpec); private: class Private; diff --git a/src/plugins/python/pythonkitaspect.cpp b/src/plugins/python/pythonkitaspect.cpp index ecd1b3ad34d..62bb10e5b00 100644 --- a/src/plugins/python/pythonkitaspect.cpp +++ b/src/plugins/python/pythonkitaspect.cpp @@ -59,7 +59,7 @@ public: PythonKitAspect::setPython(&k, v.toString()); }; auto resetModel = [model] { model->reset(); }; - setListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); + addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); connect(PythonSettings::instance(), &PythonSettings::interpretersChanged, diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index f59dba58d8a..fd9711db7e5 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -71,7 +71,7 @@ public: QtKitAspect::setQtVersionId(&k, versionId.toInt()); }; auto resetModel = [model] { model->reset(); }; - setListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); + addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) { if (k == kit()) From 0c524bcdfdf48058dd6a0533c750b9c75910a424 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 7 Nov 2024 15:58:49 +0100 Subject: [PATCH 075/989] ProjectExplorer: Simplify ToolchainKitAspect Make use of base class convenience functionality. Change-Id: Icb2df4f656c739f7903544c5fb539285ca7c79fe Reviewed-by: hjk --- src/plugins/projectexplorer/kitaspect.cpp | 17 +- src/plugins/projectexplorer/kitaspect.h | 6 +- src/plugins/projectexplorer/toolchain.h | 2 +- .../projectexplorer/toolchainkitaspect.cpp | 170 +++++------------- .../projectexplorer/toolchainoptionspage.cpp | 9 +- .../projectexplorer/toolchainoptionspage.h | 1 - 6 files changed, 73 insertions(+), 132 deletions(-) diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index b18a3b71c4a..455ef5eeead 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -41,14 +41,22 @@ private: if (getValue(source_right, KitAspect::IsNoneRole).toBool()) return true; - // Criterion 2: "Quality", i.e. how likely is the respective entry to be usable. + // Criterion 2: "Type", which is is the name of some category by which the entries + // are supposed to get grouped together. + if (const QString type1 = getValue(source_left, KitAspect::TypeRole).toString(), + type2 = getValue(source_right, KitAspect::TypeRole).toString(); + type1 != type2) { + return type1 < type2; + } + + // Criterion 3: "Quality", i.e. how likely is the respective entry to be usable. if (const int qual1 = getValue(source_left, KitAspect::QualityRole).toInt(), qual2 = getValue(source_right, KitAspect::QualityRole).toInt(); qual1 != qual2) { return qual1 > qual2; } - // Criterion 3: Name. + // Criterion 4: Name. return SortModel::lessThan(source_left, source_right); } }; @@ -211,6 +219,11 @@ void KitAspect::addListAspectSpec(const ListAspectSpec &listAspectSpec) this, [this] { d->ignoreChanges.unlock(); }); } +QList KitAspect::comboBoxes() const +{ + return Utils::transform(d->listAspects, &Private::ListAspect::comboBox); +} + void KitAspect::addToLayoutImpl(Layouting::Layout &layout) { auto label = createSubWidget(d->factory->displayName() + ':'); diff --git a/src/plugins/projectexplorer/kitaspect.h b/src/plugins/projectexplorer/kitaspect.h index 8c74023e0b4..2d8953eac0e 100644 --- a/src/plugins/projectexplorer/kitaspect.h +++ b/src/plugins/projectexplorer/kitaspect.h @@ -15,6 +15,7 @@ QT_BEGIN_NAMESPACE class QAction; +class QComboBox; QT_END_NAMESPACE namespace Utils { @@ -103,7 +104,7 @@ class PROJECTEXPLORER_EXPORT KitAspect : public Utils::BaseAspect Q_OBJECT public: - enum ItemRole { IdRole = Qt::UserRole + 100, IsNoneRole, QualityRole }; + enum ItemRole { IdRole = Qt::UserRole + 100, IsNoneRole, TypeRole, QualityRole }; KitAspect(Kit *kit, const KitAspectFactory *factory); ~KitAspect(); @@ -153,6 +154,9 @@ protected: }; void addListAspectSpec(const ListAspectSpec &listAspectSpec); + // For layouting purposes only. + QList comboBoxes() const; + private: class Private; Private * const d; diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index fe0ae0e935b..5d6ab31fbca 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -294,7 +294,7 @@ public: return get(&Toolchain::makeCommand, env); } - enum class Valid { All, Some, None }; + enum class Valid { None, Some, All }; // Keep ordered from worst to best. Valid validity() const; bool isCompletelyValid() const { return validity() == Valid::All; } diff --git a/src/plugins/projectexplorer/toolchainkitaspect.cpp b/src/plugins/projectexplorer/toolchainkitaspect.cpp index 36e9249b715..6e0cc7cb53d 100644 --- a/src/plugins/projectexplorer/toolchainkitaspect.cpp +++ b/src/plugins/projectexplorer/toolchainkitaspect.cpp @@ -61,157 +61,75 @@ private: const LanguageCategory m_category; }; -class ToolchainSortModel : public SortModel -{ -public: - ToolchainSortModel(QObject *parent) : SortModel(parent) {} - - void reset() { static_cast(sourceModel())->reset(); } - -private: - bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override - { - const auto source = static_cast(sourceModel()); - const ToolchainTreeItem *item1 = source->itemForIndex(source_left); - const ToolchainTreeItem *item2 = source->itemForIndex(source_right); - QTC_ASSERT(item1 && item2, return false); - if (!item1->bundle) - return false; - if (!item2->bundle) - return true; - if (item1->bundle->type() != item2->bundle->type()) { - return caseFriendlyCompare( - item1->bundle->typeDisplayName(), item2->bundle->typeDisplayName()) - < 0; - } - return SortModel::lessThan(source_left, source_right); - } -}; - class ToolchainKitAspectImpl final : public KitAspect { public: ToolchainKitAspectImpl(Kit *k, const KitAspectFactory *factory) : KitAspect(k, factory) { - m_mainWidget = createSubWidget(); - m_mainWidget->setContentsMargins(0, 0, 0, 0); - - auto layout = new QGridLayout(m_mainWidget); - layout->setContentsMargins(0, 0, 0, 0); - layout->setColumnStretch(1, 2); - - const QList languageCategories = sorted( + m_sortedLanguageCategories = sorted( ToolchainManager::languageCategories(), [](const LanguageCategory &l1, const LanguageCategory &l2) { return ToolchainManager::displayNameOfLanguageCategory(l1) < ToolchainManager::displayNameOfLanguageCategory(l2); }); - QTC_ASSERT(!languageCategories.isEmpty(), return); - int row = 0; - for (const LanguageCategory &lc : std::as_const(languageCategories)) { - layout->addWidget( - new QLabel(ToolchainManager::displayNameOfLanguageCategory(lc) + ':'), row, 0); - auto cb = new QComboBox; - cb->setSizePolicy(QSizePolicy::Ignored, cb->sizePolicy().verticalPolicy()); - cb->setToolTip(factory->description()); - setWheelScrollingWithoutFocusBlocked(cb); - + QTC_ASSERT(!m_sortedLanguageCategories.isEmpty(), return); + for (const LanguageCategory &lc : std::as_const(m_sortedLanguageCategories)) { const auto model = new ToolchainListModel(*kit(), lc, this); - const auto sortModel = new ToolchainSortModel(this); - sortModel->setSourceModel(model); - cb->setModel(sortModel); - - m_languageComboboxMap.insert(lc, cb); - layout->addWidget(cb, row, 1); - ++row; - - connect(cb, &QComboBox::currentIndexChanged, this, [this, lc](int idx) { - currentToolchainChanged(lc, idx); - }); + auto getter = [lc](const Kit &k) { + for (const Id lang : lc) { + if (Toolchain * const currentTc = ToolchainKitAspect::toolchain(&k, lang)) + return currentTc->bundleId().toSetting(); + } + return QVariant(); + }; + auto setter = [lc](Kit &k, const QVariant &v) { + const Id bundleId = Id::fromSetting(v); + const Toolchains bundleTcs = ToolchainManager::toolchains( + [bundleId](const Toolchain *tc) { return tc->bundleId() == bundleId; }); + for (const Id lang : lc) { + Toolchain * const tc = Utils::findOrDefault(bundleTcs, [lang](const Toolchain *tc) { + return tc->language() == lang; + }); + if (tc) + ToolchainKitAspect::setToolchain(&k, tc); + else + ToolchainKitAspect::clearToolchain(&k, lang); + } + }; + auto resetModel = [model] { model->reset(); }; + addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); } - refresh(); + connect(ToolchainManager::instance(), &ToolchainManager::toolchainUpdated, + this, &KitAspect::refresh); setManagingPage(Constants::TOOLCHAIN_SETTINGS_PAGE_ID); } - ~ToolchainKitAspectImpl() override - { - delete m_mainWidget; - } - private: void addToInnerLayout(Layouting::Layout &builder) override { - addMutableAction(m_mainWidget); - builder.addItem(m_mainWidget); - } + const auto mainWidget = createSubWidget(); + mainWidget->setContentsMargins(0, 0, 0, 0); - void refresh() override - { - IDeviceConstPtr device = BuildDeviceKitAspect::device(kit()); + const auto layout = new QGridLayout(mainWidget); + layout->setContentsMargins(0, 0, 0, 0); + layout->setColumnStretch(1, 2); - const GuardLocker locker(m_ignoreChanges); - for (auto it = m_languageComboboxMap.cbegin(); it != m_languageComboboxMap.cend(); ++it) { - const LanguageCategory lc = it.key(); - const Toolchains ltcList = ToolchainManager::toolchains( - [lc](const Toolchain *tc) { return lc.contains(tc->language()); }); - - QComboBox *cb = *it; - static_cast(cb->model())->reset(); - cb->model()->sort(0); - cb->setEnabled(cb->count() > 1 && !m_isReadOnly); - - Id currentBundleId; - for (const Id lang : lc) { - if (Toolchain * const currentTc = ToolchainKitAspect::toolchain(kit(), lang)) { - currentBundleId = currentTc->bundleId(); - break; - } - } - cb->setCurrentIndex(indexOf(cb, currentBundleId)); + int row = 0; + const QList cbList = comboBoxes(); + QTC_ASSERT(cbList.size() == m_sortedLanguageCategories.size(), return); + for (const LanguageCategory &lc : std::as_const(m_sortedLanguageCategories)) { + layout->addWidget( + new QLabel(ToolchainManager::displayNameOfLanguageCategory(lc) + ':'), row, 0); + layout->addWidget(cbList.at(row), row, 1); + ++row; } + addMutableAction(mainWidget); + builder.addItem(mainWidget); } - void makeReadOnly() override - { - m_isReadOnly = true; - for (QComboBox *cb : std::as_const(m_languageComboboxMap)) - cb->setEnabled(false); - } - - void currentToolchainChanged(const LanguageCategory &languageCategory, int idx) - { - if (m_ignoreChanges.isLocked() || idx < 0) - return; - - const QAbstractItemModel *const model - = m_languageComboboxMap.value(languageCategory)->model(); - const Id bundleId = Id::fromSetting( - model->data(model->index(idx, 0), ToolchainTreeItem::BundleIdRole)); - - const Toolchains bundleTcs = ToolchainManager::toolchains( - [bundleId](const Toolchain *tc) { return tc->bundleId() == bundleId; }); - for (const Id lang : languageCategory) { - Toolchain *const tc = Utils::findOrDefault(bundleTcs, [lang](const Toolchain *tc) { - return tc->language() == lang; - }); - if (tc) - ToolchainKitAspect::setToolchain(kit(), tc); - else - ToolchainKitAspect::clearToolchain(kit(), lang); - } - } - - int indexOf(QComboBox *cb, Id bundleId) - { - return cb->findData(bundleId.toSetting(), ToolchainTreeItem::BundleIdRole); - } - - QWidget *m_mainWidget = nullptr; - QHash m_languageComboboxMap; - Guard m_ignoreChanges; - bool m_isReadOnly = false; + QList m_sortedLanguageCategories; }; class ToolchainKitAspectFactory : public KitAspectFactory diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp index db068687e1c..cc24e487ba3 100644 --- a/src/plugins/projectexplorer/toolchainoptionspage.cpp +++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp @@ -5,6 +5,7 @@ #include "abi.h" #include "devicesupport/devicemanager.h" +#include "kitaspect.h" #include "kitoptionspage.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" @@ -81,8 +82,14 @@ QVariant ToolchainTreeItem::data(int column, int role) const } } return QVariant(); - case BundleIdRole: + case KitAspect::IdRole: return bundle ? bundle->bundleId().toSetting() : QVariant(); + case KitAspect::IsNoneRole: + return !bundle; + case KitAspect::TypeRole: + return bundle ? bundle->typeDisplayName() : QString(); + case KitAspect::QualityRole: + return bundle ? int(bundle->validity()) : -1; } return {}; } diff --git a/src/plugins/projectexplorer/toolchainoptionspage.h b/src/plugins/projectexplorer/toolchainoptionspage.h index 979104c0007..d20b4701eb0 100644 --- a/src/plugins/projectexplorer/toolchainoptionspage.h +++ b/src/plugins/projectexplorer/toolchainoptionspage.h @@ -25,7 +25,6 @@ public: ToolchainTreeItem(const ToolchainBundle &bundle) : bundle(bundle) {} ToolchainTreeItem() = default; - static const int BundleIdRole = Qt::UserRole; QVariant data(int column, int role) const override; std::optional bundle; From ef8b745c56940b0aa44abb2697075a35dc0e714d Mon Sep 17 00:00:00 2001 From: Morteza Jamshidi Date: Tue, 5 Nov 2024 09:11:07 +0100 Subject: [PATCH 076/989] Add SDKs section to the preferences to download Windows App SDK Windows app sdk can be downloaded and be used by the qt_add_win_app_sdk function in CMake Task-number: QTBUG-124800 Change-Id: I77490f12dcb57a5a73e19d7209549f856fc2be9a Reviewed-by: hjk Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/CMakeLists.txt | 2 + .../devicesupport/devicekitaspects.cpp | 16 + src/plugins/projectexplorer/images/sdk.png | Bin 0 -> 4484 bytes src/plugins/projectexplorer/images/sdk@2x.png | Bin 0 -> 4523 bytes .../projectexplorer/projectexplorer.cpp | 5 + .../projectexplorer/projectexplorer.qbs | 4 +- .../projectexplorer/projectexplorer.qrc | 2 + .../projectexplorerconstants.h | 5 + .../projectexplorer/windowsconfigurations.cpp | 152 +++++ .../projectexplorer/windowsconfigurations.h | 51 ++ .../projectexplorer/windowssettingswidget.cpp | 624 ++++++++++++++++++ .../projectexplorer/windowssettingswidget.h | 10 + 12 files changed, 870 insertions(+), 1 deletion(-) create mode 100644 src/plugins/projectexplorer/images/sdk.png create mode 100644 src/plugins/projectexplorer/images/sdk@2x.png create mode 100644 src/plugins/projectexplorer/windowsconfigurations.cpp create mode 100644 src/plugins/projectexplorer/windowsconfigurations.h create mode 100644 src/plugins/projectexplorer/windowssettingswidget.cpp create mode 100644 src/plugins/projectexplorer/windowssettingswidget.h diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index a0425e82468..8a363d6d42b 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -185,6 +185,8 @@ add_qtc_plugin(ProjectExplorer windebuginterface.cpp windebuginterface.h workspaceproject.h workspaceproject.cpp xcodebuildparser.cpp xcodebuildparser.h + windowsconfigurations.cpp windowsconfigurations.h + windowssettingswidget.cpp windowssettingswidget.h ) if (TARGET clangd) diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 2d42ed284a1..1d48fb73208 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -12,7 +12,10 @@ #include "../kitmanager.h" #include "../projectexplorerconstants.h" #include "../projectexplorertr.h" +#include "../toolchainkitaspect.h" +#include "../windowsconfigurations.h" +#include #include #include #include @@ -443,6 +446,7 @@ private: ItemList toUserOutput(const Kit *k) const override; void addToMacroExpander(Kit *kit, MacroExpander *expander) const override; + void addToBuildEnvironment(const Kit *k, Utils::Environment &env) const override; void onKitsLoaded() override; void deviceUpdated(Id dataId); @@ -532,6 +536,18 @@ void BuildDeviceKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *ex }); } +void BuildDeviceKitAspectFactory::addToBuildEnvironment(const Kit *k, Utils::Environment &env) const +{ + IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k); + if (dev->osType() == Utils::OsType::OsTypeWindows + && dev->type() == Constants::DESKTOP_DEVICE_TYPE) { + if (const FilePath appSdkLocation = WindowsConfigurations::windowsAppSdkLocation(); + !appSdkLocation.isEmpty()) { + env.set(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY, appSdkLocation.path()); + } + } +} + void BuildDeviceKitAspectFactory::onKitsLoaded() { for (Kit *k : KitManager::kits()) diff --git a/src/plugins/projectexplorer/images/sdk.png b/src/plugins/projectexplorer/images/sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..e390dde83b4f6773e63229ca53ab63a95ccb0fe5 GIT binary patch literal 4484 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJoj#Y(3lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNTr9h~_)2!1MdLh&7XnX3OIx+1hW}tpE8;4$C$5w%~VXn{@4c zy7ziUtw||aQPpcDC+N-P=}c>X8?))no1+V-R@={IT6nbM&C+W#?0-Eq`H*m8S@*hjfV?y*E7Ve+hmovX)4^EAIUZB(8%)r3dlIiRm z;OXoP^AQ6>#hluSwjPHaWRAv1Z*|q?D-#er88G)vlB*ps=- zbC09V?#!$?-#eYx=$tz8{7A4>?1Uc^Ur#!mKgZjwx-!k<{Ichr&PSY9b}!XSON~{W zr^t7@%j@U8Ifsp&>z?!4dhXWuC;B{MSElk@&+JodR8^VS#K2h^642Vou~tiy?a~(c z@{j$u{)y~VDGEJsVq=4pNXIt$Km2v&*&>TC`vn>Bec2ar?KsPW`>avCr+?XPTXT)` zK{eaDD}DQ~u{^W$%rDvULC|0eZ%j|{>8U4;fL6Z z_~NSU_m96Yo(Kv*ZGPaOqCw=MH>K0d*>_d{{_eATzx=VVq7(UESNj~aDsl@LK)}Ynq98FjJGDe1DK$Ma&sORE?)^#%nJKnP;ikR@z6H*y z8JQkcMXAA6ej&+K*~ykEO7?bKHWgMCxdpkYC5Z|ZxjA{oRu#5NU~{eVimgDx`br95 zB_-LmN)f&R3eNdOsR|}~CVB?Ct`(VOMoM;E3N}S4X;wilZcrnNQqpXdGD=Dctn~HE z%ggo3jrH=2()A53EiLs8jP#9+bc<5bbc-wVN)jt{^NN*0MnKGPNi9w;$}A|!%+FH* znVFcBUs__Tq{OA5pa3jTz^4nQ4ZKUDarb&IjOm+c_qdAhI)o5R=Ruo z2EcWIf*?IJw*aiGBDVlVWl3flBCt?=1CjxI2iYMNxdm`@QB=eH4ps~fBP*Bu?z7A7gimPX0ChK5FIx+bQUiMojfNhZ2!NvX!BCZ?%L$%z(7 zMtSBHmn7yTr-F>C$Su&z%uKN|Gfqi1O*2f=H88PA)ip^@Ow&y=GcngSG_o)>voJ7A zNlHsXGQz(oGd(jeF$dXIAfr+;Q>+YAlFcj(Q&M%4Qxc7IO;XG(brTI!40O#CEmIRy zlFW@$42-}=r6gOqKEjtgC#%#Zsi!@X{%(UXMhk1$Vn_o%P-2c zRSM6{OUW-UMo5KZ=B5UhB!a@z(A?O-!otYJ$kN2r(9#r1e^_c!ab|uV$W%iEJ!43a zfFj1qzbG>`uOtzaQf-wC!NykP7FanKr6!i-7lq{K=h!NN9Hn5SX9zJ6B<-78l9-ZM zlIW6Hl4`4DWME`sWoT$+U>0IvX=P$yWn`{xU}$B4q&`0-Gp&-4YCBN&uz^InM`m$J zeo-Y@2$H9QQwt$H2sbAaq*_5i0h}$Y5|bfbC{8R(O#yoYE|r{-n3tZKVygsAurMu| zSQ3MYX^MeCqH(IOL7IWNu1QK-s;*^{WwLInNlK!nnT1hmN{TtE>BaeJCFO}lsgCKX zc_p?=?wPp-;ILBAfJT)js`~PbR8Tw^7@6oA8tNLDh8P-KnHX7_7%1t}-g_yQNoE!X zCWg8erp8ISCT7MKx)vs;mb$6NCgv7K7AA%!hL8jb4?GIJ2Tu`}Fz?yug9=1gWZLLs zL^nhMQVD9ur2r8Na&fccve5?@m4+Ca%xGwXf`Y=RB_xIKXmE`N7fB&N zlH$?SH5yzbg#by4M^hKof{P2$S4_=Iu~jNpvbT%oja<#Zz`&N|?e4@l zSe2=V(Wb;NF-2(yxVC^gh^1I!szK08C$8pO#~;Pi*z_Cd*0g?i?tL}OTkh_^m`{>x2VqBwN?8ZgkA5?DX3(VY%(w1@exuk=L7Cxy~{$Ft%hmI|q0= zJHtH0z)&%#cA~AvVF#I`@zGmdwfV{f1WyLceUs!W<1N~quyBiLRH?zvFWj?CR5bPa znz9cb>_57yxqI_EzI9CsKNugqd9dV#lIlNw%`F`tAMB8S|IYT^J;r-!Q#IZEc>+R$ z{nZ~i>FwA05pURF$70a8;slTG%*Zo`N^9;OK74&Q$N3`r@6RQsaI-PnFctP>?(*E@ zXtO&rYtHvh=QTQ~jyyjSY!y4<$Hdo@4(HGDHmj~o^Ekikd8hLcr&(P27F)kMO-`1^58ye6z}O@cH7om<9txf zw(d&b{%b7H>^$>JwtNsY*uonVQ*M&UzvB+0+dPv%@!XT{m!ox<-lu=@txWhK_9DKx zD*OH8FN`OG!cUtYIH+h4x#&&l^m6uH)xW>{?A|YbEUf56zSq@$1_r*+%#etZ2wxwo zkg&dz0$52& zwyjcxZ-9bxeo?A|iJpm`fv#&sW|@(a9hZVlQA(Oskc%7Ch@zAer{{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q3f;V7WsngNGh9-OlZ!G7N;32F6hLMs zCgqow*eWS;DJUpF4X?;8@b!fopH~bGh2;EP{ffi_eM3D1{oGuAWF5sNu4N_obrgqG z7NqJ2r55Lx7A2>;mZj#EC?gw@k_^{hP+F7&_D)K&erir?ZfaghvA&_6A&Qmmp1uKa z9iSjc&&(|V>#E2tKv7wenT7}~6yJbkz}`W2NJVY|+*}mZFu#KpgTu(mB|o_o^fEJ3tdbKg4J=I3EOd>MEKGGx49$~tEzOe5b&V}7($b7gQY1yFUm~M%uCEcb`{8|l*|+>!<1w*3&WID-Q<)+BVCgeGfUk>!xRHu^F+(k#FQj+ z;}ioUuu&<=R&M!4xrrsVN}0Kd>8bh!dFfyYP=H%G26);k8R;1yL;`XWOVaX-a&48u zGxJjN%Zm|GA(^?U!6k{H@H8|xHn6ZTGBq|aG%+!FnYA%q9v=466YD<~*{vxQY+GQ?g zVlXjHF)&CpPSrI?GceaRNl8o9wM?>1)=f1@NwhSxFiK5HF-JAMI6tkVJh3R%F+DY} z#8$~YGq(U7Rtg%>sM17LU!IW)iU$KD6J0|?T?5k)Lt{{onHVVP)82cjiK!N*NofYU zrpYN5x+ZBx#=4d%scE{&Nok2@$%(0^iOI>R&ZW?M@DyPJ^PY`9s6d28rj0&EbVC#% zm7sQ93J|d%7dJaD8+~vw4l2^2;RPyFX^5f8jD|KSC@73tLQ?pS2G?kCkrV%y)#`6aw`WP4(*h@TpUD;o7vvFwgJ=*bBl!1Yv%+tj&B;(%O8;)ED6nIzz zmG}OidUnJ8?v$h%F@vBzr(+LZ_yR@NJO7ngI3f Wohn)F=MtSjU0_dFKbLh*2~7Y9<4dpr literal 0 HcmV?d00001 diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index e0dbd19aaa6..337feee6fef 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -80,6 +80,8 @@ #include "toolchainmanager.h" #include "toolchainoptionspage.h" #include "vcsannotatetaskhandler.h" +#include "windowsconfigurations.h" +#include "windowssettingswidget.h" #include "workspaceproject.h" #ifdef Q_OS_WIN @@ -815,6 +817,9 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er setupMsvcToolchain(); setupClangClToolchain(); setupCustomToolchain(); + setupWindowsConfigurations(); + if (HostOsInfo::isWindowsHost()) + setupWindowsSettingsPage(); setupProjectTreeWidgetFactory(); diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 1740a4e2172..516190cb1c4 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -157,7 +157,9 @@ QtcPlugin { "waitforstopdialog.cpp", "waitforstopdialog.h", "windebuginterface.cpp", "windebuginterface.h", "workspaceproject.cpp", "workspaceproject.h", - "xcodebuildparser.cpp", "xcodebuildparser.h" + "xcodebuildparser.cpp", "xcodebuildparser.h", + "windowsconfigurations.cpp", "windowsconfigurations.h", + "windowssettingswidget.cpp", "windowssettingswidget.h", ] } diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index 248fe4e591b..fb523f0690a 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -88,5 +88,7 @@ testdata/multi-target-project/multi-target-project-shared.h testdata/multi-target-project/multi-target-project.pro testdata/multi-target-project/multi-target-project.qbs + images/sdk.png + images/sdk@2x.png diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index a5a70ff59b9..2b50a2b878e 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -226,6 +226,11 @@ const char SUPPORTS_RSYNC[] = "RemoteLinux.SupportsRSync"; const char SUPPORTS_SFTP[] = "RemoteLinux.SupportsSftp"; const char SSH_FORWARD_DEBUGSERVER_PORT[] = "RemoteLinux.SshForwardDebugServerPort"; +// SDKs related ids: +const char SDK_SETTINGS_CATEGORY[] = "SDKs"; +const char WINDOWS_SETTINGS_ID[] = "Windows Configurations"; +const char WINDOWS_WINAPPSDK_ROOT_ENV_KEY[] = "WIN_APP_SDK_ROOT"; + // UI texts PROJECTEXPLORER_EXPORT QString msgAutoDetected(); PROJECTEXPLORER_EXPORT QString msgAutoDetectedToolTip(); diff --git a/src/plugins/projectexplorer/windowsconfigurations.cpp b/src/plugins/projectexplorer/windowsconfigurations.cpp new file mode 100644 index 00000000000..05fc1254375 --- /dev/null +++ b/src/plugins/projectexplorer/windowsconfigurations.cpp @@ -0,0 +1,152 @@ +// 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 "windowsconfigurations.h" + +#include "projectexplorerconstants.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ProjectExplorer::Internal { + +const char SettingsGroup[] = "WindowsConfigurations"; +const char DownloadLocationKey[] = "DownloadLocation"; +const char NugetLocationKey[] = "NugetLocation"; +const char WindowsAppSdkLocationKey[] = "WindowsAppSDKLocation"; + +struct WindowsConfigData +{ + void load(const QtcSettings &settings); + void save(QtcSettings &settings) const; + + FilePath m_downloadLocation; + FilePath m_nugetLocation; + FilePath m_windowsAppSdkLocation; +}; + +static WindowsConfigData &config() +{ + static WindowsConfigData theWindowsConfig; + return theWindowsConfig; +} + +void WindowsConfigData::load(const QtcSettings &settings) +{ + // user settings + m_downloadLocation = FilePath::fromSettings(settings.value(DownloadLocationKey)); + m_nugetLocation = FilePath::fromSettings(settings.value(NugetLocationKey)); + m_windowsAppSdkLocation = FilePath::fromSettings(settings.value(WindowsAppSdkLocationKey)); + + if (m_windowsAppSdkLocation.isEmpty()) { + m_windowsAppSdkLocation = FilePath::fromString( + Environment::systemEnvironment().value(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY)); + } +} + +void WindowsConfigData::save(QtcSettings &settings) const +{ + // user settings + settings.setValue(DownloadLocationKey, m_downloadLocation.toSettings()); + settings.setValue(NugetLocationKey, m_nugetLocation.toSettings()); + settings.setValue(WindowsAppSdkLocationKey, m_windowsAppSdkLocation.toSettings()); +} + +/////////////////////////////////// +// WindowsConfigurations +/////////////////////////////////// + +WindowsConfigurations *m_instance = nullptr; + +WindowsConfigurations::WindowsConfigurations() +{ + load(); + m_instance = this; +} + +void WindowsConfigurations::applyConfig() +{ + emit m_instance->aboutToUpdate(); + m_instance->save(); + emit m_instance->updated(); +} + +WindowsConfigurations *WindowsConfigurations::instance() +{ + return m_instance; +} + +FilePath WindowsConfigurations::downloadLocation() +{ + return config().m_downloadLocation; +} + +void WindowsConfigurations::setDownloadLocation(const FilePath &downloadLocation) +{ + config().m_downloadLocation = downloadLocation; +} + +FilePath WindowsConfigurations::nugetLocation() +{ + return config().m_nugetLocation; +} + +void WindowsConfigurations::setNugetLocation(const FilePath &nugetLocation) +{ + config().m_nugetLocation = nugetLocation; +} + +FilePath WindowsConfigurations::windowsAppSdkLocation() +{ + return config().m_windowsAppSdkLocation; +} + +void WindowsConfigurations::setWindowsAppSdkLocation(const FilePath &windowsAppSdkLocation) +{ + config().m_windowsAppSdkLocation = windowsAppSdkLocation; +} + +void WindowsConfigurations::save() +{ + QtcSettings *settings = Core::ICore::settings(); + settings->beginGroup(SettingsGroup); + config().save(*settings); + settings->endGroup(); +} + +void WindowsConfigurations::load() +{ + QtcSettings *settings = Core::ICore::settings(); + settings->beginGroup(SettingsGroup); + config().load(*settings); + settings->endGroup(); +} + +void setupWindowsConfigurations() +{ + static WindowsConfigurations theWindowsConfigurations; +} + +} // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/windowsconfigurations.h b/src/plugins/projectexplorer/windowsconfigurations.h new file mode 100644 index 00000000000..440e96eb48e --- /dev/null +++ b/src/plugins/projectexplorer/windowsconfigurations.h @@ -0,0 +1,51 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include + +#include + +#include +#include + +using namespace Tasking; +using namespace Utils; + +namespace ProjectExplorer::Internal { + +class WindowsConfigurations : public QObject +{ + Q_OBJECT + +public: + static void applyConfig(); + static WindowsConfigurations *instance(); + + static FilePath downloadLocation(); + static void setDownloadLocation(const FilePath &downloadLocation); + + static FilePath nugetLocation(); + static void setNugetLocation(const FilePath &nugetLocation); + + static FilePath windowsAppSdkLocation(); + static void setWindowsAppSdkLocation(const FilePath &windowsAppSdkLocation); + +signals: + void aboutToUpdate(); + void updated(); + +private: + friend void setupWindowsConfigurations(); + WindowsConfigurations(); + + void load(); + void save(); +}; + +void setupWindowsConfigurations(); + +} // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/windowssettingswidget.cpp b/src/plugins/projectexplorer/windowssettingswidget.cpp new file mode 100644 index 00000000000..829e53096d8 --- /dev/null +++ b/src/plugins/projectexplorer/windowssettingswidget.cpp @@ -0,0 +1,624 @@ +// 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 "windowssettingswidget.h" + +#include +#include +#include + +#include "projectexplorerconstants.h" +#include "projectexplorertr.h" +#include "windowsconfigurations.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Utils; +using namespace Tasking; + +namespace ProjectExplorer::Internal { + +static Q_LOGGING_CATEGORY(windowssettingswidget, "qtc.windows.windowssettingswidget", QtWarningMsg); + +static bool isHttpRedirect(QNetworkReply *reply) +{ + const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + return statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 305 + || statusCode == 307 || statusCode == 308; +} + +// TODO: Make it a separate async task in a chain? +static std::optional saveToDisk(const FilePath &filename, QIODevice *data) +{ + const expected_str result = filename.writeFileContents(data->readAll()); + if (!result) { + return Tr::tr("Could not open \"%1\" for writing: %2.") + .arg(filename.toUserOutput(), result.error()); + } + + return {}; +} + +class SummaryWidget : public QWidget +{ + class RowData { + public: + InfoLabel *m_infoLabel = nullptr; + bool m_valid = false; + QString m_validText; + }; + +public: + SummaryWidget(const QMap &validationPoints, const QString &validText, + const QString &invalidText, DetailsWidget *detailsWidget) : + QWidget(detailsWidget), + m_validText(validText), + m_invalidText(invalidText), + m_detailsWidget(detailsWidget) + { + QTC_CHECK(m_detailsWidget); + auto layout = new QVBoxLayout(this); + layout->setContentsMargins(22, 0, 0, 12); + layout->setSpacing(4); + for (auto itr = validationPoints.cbegin(); itr != validationPoints.cend(); ++itr) { + RowData data; + data.m_infoLabel = new InfoLabel(itr.value()); + data.m_validText = itr.value(); + layout->addWidget(data.m_infoLabel); + m_validationData[itr.key()] = data; + setPointValid(itr.key(), false); + } + m_detailsWidget->setWidget(this); + setContentsMargins(0, 0, 0, 0); + } + + template + void setPointValid(int key, const expected_str &test) + { + setPointValid(key, test.has_value(), test.has_value() ? QString{} : test.error()); + } + + void setPointValid(int key, bool valid, const QString errorText = {}) + { + if (!m_validationData.contains(key)) + return; + RowData &data = m_validationData[key]; + data.m_valid = valid; + data.m_infoLabel->setType(valid ? InfoLabel::Ok : InfoLabel::NotOk); + data.m_infoLabel->setText(valid || errorText.isEmpty() ? data.m_validText : errorText); + updateUi(); + } + + bool rowsOk(const QList &keys) const + { + for (auto key : keys) { + if (!m_validationData[key].m_valid) + return false; + } + return true; + } + + bool allRowsOk() const + { + return rowsOk(m_validationData.keys()); + } + + void setInfoText(const QString &text) + { + m_infoText = text; + updateUi(); + } + + void setInProgressText(const QString &text) + { + m_detailsWidget->setIcon({}); + m_detailsWidget->setSummaryText(QString("%1...").arg(text)); + m_detailsWidget->setState(DetailsWidget::Collapsed); + } + + void setSetupOk(bool ok) + { + m_detailsWidget->setState(ok ? DetailsWidget::Collapsed : DetailsWidget::Expanded); + } + + void setState(DetailsWidget::State state) + { + m_detailsWidget->setState(state); + } + +private: + void updateUi() + { + bool ok = allRowsOk(); + m_detailsWidget->setIcon(ok ? Icons::OK.icon() : Icons::CRITICAL.icon()); + m_detailsWidget->setSummaryText(ok ? QString("%1 %2").arg(m_validText).arg(m_infoText) + : m_invalidText); + } + QString m_validText; + QString m_invalidText; + QString m_infoText; + DetailsWidget *m_detailsWidget = nullptr; + QMap m_validationData; +}; + +class WindowsSettingsWidget final : public Core::IOptionsPageWidget +{ +public: + WindowsSettingsWidget(); + +private: + void showEvent(QShowEvent *event) override; + + GroupItem downloadNugetRecipe(); + void downloadNuget(); + void downloadWindowsAppSdk(); + + void updateUI(); + + void validateDownloadPath(); + void validateNuget(); + void validateWindowsAppSdk(); + + bool m_isInitialReloadDone = false; + + SummaryWidget *m_winAppSdkSummary = nullptr; + PathChooser *m_downloadPathChooser; + PathChooser *m_nugetPathChooser; + PathChooser *m_winAppSdkPathChooser; + QNetworkAccessManager manager; + Tasking::TaskTreeRunner m_nugetDownloader; +}; + +enum WindowsAppSdkValidation { + DownloadPathExistsRow, + NugetPathExistsRow, + WindowsAppSdkPathExists +}; + +WindowsSettingsWidget::WindowsSettingsWidget() +{ + setWindowTitle(Tr::tr("Windows Configuration")); + + const QIcon downloadIcon = Icons::ONLINE.icon(); + + auto winAppSdkDetailsWidget = new DetailsWidget; + + m_downloadPathChooser = new PathChooser; + m_downloadPathChooser->setToolTip(Tr::tr("Select the path of downloads.")); + m_downloadPathChooser->setPromptDialogTitle(Tr::tr("Select download path")); + m_downloadPathChooser->setExpectedKind(PathChooser::ExistingDirectory); + m_downloadPathChooser->setFilePath(WindowsConfigurations::downloadLocation()); + + m_nugetPathChooser = new PathChooser; + m_nugetPathChooser->setToolTip(Tr::tr("Select the path of the Nuget.")); + m_nugetPathChooser->setPromptDialogTitle(Tr::tr("Select nuget.exe file")); + m_nugetPathChooser->setExpectedKind(PathChooser::Any); + m_nugetPathChooser->setFilePath(WindowsConfigurations::nugetLocation()); + + auto downloadNuget = new QPushButton(Tr::tr("Download Nuget")); + downloadNuget->setToolTip( + Tr::tr("Automatically download Nuget.\n\n" + "Nuget is needed for downloading Windows App SDK.")); + + m_winAppSdkPathChooser = new PathChooser; + m_winAppSdkPathChooser->setToolTip(Tr::tr("Select the path of the Windows App SDK.")); + + auto downloadWindowsAppSdk = new QPushButton(Tr::tr("Download WindowsAppSDK")); + downloadWindowsAppSdk->setToolTip( + Tr::tr("Automatically download Windows App Sdk with Nuget.\n\n" + "If the automatic download fails, Qt Creator proposes to open the download URL\n" + "in the system's browser for manual download.")); + + const QMap winAppSdkValidationPoints = { + { DownloadPathExistsRow, Tr::tr("Download path exists.") }, + { NugetPathExistsRow, Tr::tr("Nuget path exists.") }, + { WindowsAppSdkPathExists, Tr::tr("WindowsAppSDK path exists.") } + }; + m_winAppSdkSummary = new SummaryWidget(winAppSdkValidationPoints, + Tr::tr("Windows App SDK Settings are OK."), + Tr::tr("Windows App SDK settings have errors."), + winAppSdkDetailsWidget); + + m_winAppSdkPathChooser->setPromptDialogTitle(Tr::tr("Select Windows App SDK Path")); + if (WindowsConfigurations::windowsAppSdkLocation().isEmpty()) + WindowsConfigurations::setWindowsAppSdkLocation(WindowsConfigurations::downloadLocation()); + m_winAppSdkPathChooser->setFilePath(WindowsConfigurations::windowsAppSdkLocation()); + + using namespace Layouting; + + Column { + Layouting::Group { + title(Tr::tr("Download Path")), + Grid { + Tr::tr("Download location:"), + m_downloadPathChooser, + br, + + Span(4, winAppSdkDetailsWidget) + } + }, + Layouting::Group { + title(Tr::tr("Nuget")), + Grid { + Tr::tr("Nuget location:"), + m_nugetPathChooser, + downloadNuget, + br, + + Span(4, winAppSdkDetailsWidget) + } + }, + Layouting::Group { + title(Tr::tr("Windows App SDK Settings")), + Grid { + Tr::tr("Windows App SDK location:"), + m_winAppSdkPathChooser, + downloadWindowsAppSdk, + br, + + Span(4, winAppSdkDetailsWidget) + } + }, + st + }.attachTo(this); + + connect(m_downloadPathChooser, &PathChooser::rawPathChanged, + this, &WindowsSettingsWidget::validateDownloadPath); + connect(m_winAppSdkPathChooser, &PathChooser::rawPathChanged, + this, &WindowsSettingsWidget::validateWindowsAppSdk); + connect(m_nugetPathChooser, &PathChooser::rawPathChanged, + this, &WindowsSettingsWidget::validateNuget); + connect(downloadNuget, &QAbstractButton::clicked, + this, &WindowsSettingsWidget::downloadNuget); + connect(downloadWindowsAppSdk, &QAbstractButton::clicked, + this, &WindowsSettingsWidget::downloadWindowsAppSdk); + connect(&m_nugetDownloader, &Tasking::TaskTreeRunner::done, this, + [this](Tasking::DoneWith result) { + if (result != Tasking::DoneWith::Success) + return; + + validateNuget(); + m_nugetPathChooser->triggerChanged(); // After cloning, the path exists + updateUI(); + apply(); + }); + + setOnApply([] { WindowsConfigurations::applyConfig(); }); +} + +void WindowsSettingsWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event) + if (!m_isInitialReloadDone) { + validateDownloadPath(); + validateNuget(); + validateWindowsAppSdk(); + m_isInitialReloadDone = true; + } +} + +void WindowsSettingsWidget::validateDownloadPath() +{ + WindowsConfigurations::setDownloadLocation(m_downloadPathChooser->filePath()); + + m_winAppSdkSummary->setPointValid( + DownloadPathExistsRow, m_downloadPathChooser->filePath().exists()); + + updateUI(); +} + +void WindowsSettingsWidget::validateNuget() +{ + WindowsConfigurations::setNugetLocation(m_nugetPathChooser->filePath()); + + m_winAppSdkSummary->setPointValid(NugetPathExistsRow, m_nugetPathChooser->filePath().exists()); + + updateUI(); +} + +void WindowsSettingsWidget::validateWindowsAppSdk() +{ + WindowsConfigurations::setWindowsAppSdkLocation(m_winAppSdkPathChooser->filePath()); + + QStringList filters; + filters << "Microsoft.WindowsAppSDK.*.nupkg"; + QDir dir(WindowsConfigurations::windowsAppSdkLocation().path()); + auto results = dir.entryList(filters); + m_winAppSdkSummary->setPointValid(WindowsAppSdkPathExists, results.count() > 0); + + updateUI(); +} + +GroupItem WindowsSettingsWidget::downloadNugetRecipe() +{ + const FilePath downloadPath = m_downloadPathChooser->filePath(); + const QString nugetUrl("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"); + + const auto failDialog = [=](const QString &msgSuffix = {}) { + QStringList sl; + sl << Tr::tr("Nuget downloading failed."); + if (!msgSuffix.isEmpty()) + sl << msgSuffix; + sl << Tr::tr("Opening Nuget URL for manual download."); + QMessageBox msgBox; + msgBox.setText(sl.join(" ")); + msgBox.addButton(Tr::tr("Cancel"), QMessageBox::RejectRole); + QAbstractButton *openButton = msgBox.addButton(Tr::tr("Open Download URL"), + QMessageBox::ActionRole); + msgBox.exec(); + + if (msgBox.clickedButton() == openButton) + QDesktopServices::openUrl(QUrl::fromUserInput("https://www.nuget.org/downloads")); + openButton->deleteLater(); + }; + + struct StorageStruct + { + StorageStruct() { + progressDialog.reset(new QProgressDialog(Tr::tr("Downloading Nuget..."), + Tr::tr("Cancel"), 0, 100, + Core::ICore::dialogParent())); + progressDialog->setWindowModality(Qt::ApplicationModal); + progressDialog->setWindowTitle(Tr::tr("Downloading")); + progressDialog->setFixedSize(progressDialog->sizeHint()); + progressDialog->setAutoClose(false); + progressDialog->show(); + } + std::unique_ptr progressDialog; + std::optional fileName; + }; + + Storage storage; + + const auto onSetup = [downloadPath, failDialog] { + if (downloadPath.isEmpty()) { + failDialog(Tr::tr("The SDK Tools download URL is empty.")); + return SetupResult::StopWithError; + } + return SetupResult::Continue; + }; + + const auto onQuerySetup = [storage, nugetUrl, failDialog](NetworkQuery &query) { + query.setRequest(QNetworkRequest(QUrl(nugetUrl))); + query.setNetworkAccessManager(NetworkAccessManager::instance()); + QProgressDialog *progressDialog = storage->progressDialog.get(); + QObject::connect(&query, &NetworkQuery::downloadProgress, + progressDialog, [progressDialog](qint64 received, qint64 max) { + progressDialog->setRange(0, max); + progressDialog->setValue(received); + }); +#if QT_CONFIG(ssl) + QObject::connect(&query, &NetworkQuery::sslErrors, + &query, [queryPtr = &query, failDialog](const QList &sslErrs) { + for (const QSslError &error : sslErrs) + qCDebug(windowssettingswidget, "SSL error: %s\n", + qPrintable(error.errorString())); + failDialog(Tr::tr("Encountered SSL errors, download is aborted.")); + queryPtr->reply()->abort(); + }); +#endif + }; + const auto onQueryDone = [this, + storage, + failDialog, + downloadPath](const NetworkQuery &query, DoneWith result) { + if (result == DoneWith::Cancel) + return; + + QNetworkReply *reply = query.reply(); + QTC_ASSERT(reply, return); + const QUrl url = reply->url(); + if (result != DoneWith::Success) { + failDialog(Tr::tr("Downloading Nuget from URL %1 has failed: %2.") + .arg(url.toString(), reply->errorString())); + return; + } + if (isHttpRedirect(reply)) { + failDialog(Tr::tr("Download from %1 was redirected.").arg(url.toString())); + return; + } + const QString path = url.path(); + QString basename = QFileInfo(path).fileName(); + const FilePath fileName = downloadPath / basename; + const std::optional saveResult = saveToDisk(fileName, reply); + if (saveResult) { + failDialog(*saveResult); + return; + } + storage->fileName = fileName; + m_nugetPathChooser->setFilePath(fileName); + }; + const auto onCancelSetup = [storage] { return std::make_pair(storage->progressDialog.get(), + &QProgressDialog::canceled); }; + + return Group { + storage, + Group { + onGroupSetup(onSetup), + NetworkQueryTask(onQuerySetup, onQueryDone), + }.withCancel(onCancelSetup) + }; +} + +void WindowsSettingsWidget::downloadNuget() +{ + const FilePath downloadPath = m_downloadPathChooser->filePath(); + const FilePath nugetPath = m_nugetPathChooser->filePath(); + const QString nugetDownloadingTitle(Tr::tr("Downloading")); + + if (nugetPath.exists() && nugetPath.isFile() && !nugetPath.isEmpty()) { + QMessageBox::information( + this, + nugetDownloadingTitle, + Tr::tr( + "The selected download path (%1) for Nuget already exists.\n" + "Select a different path.") + .arg(nugetPath.toUserOutput())); + return; + } + + if (!m_winAppSdkSummary->rowsOk({DownloadPathExistsRow})) { + QMessageBox::information(this, nugetDownloadingTitle, + Tr::tr("Download path is not configured.")); + return; + } + + m_nugetDownloader.start({downloadNugetRecipe()}); +} + +void WindowsSettingsWidget::downloadWindowsAppSdk() +{ + const FilePath downloadPath = m_downloadPathChooser->filePath(); + const FilePath winAppSdkPath = m_winAppSdkPathChooser->filePath(); + const FilePath nugetPath = m_nugetPathChooser->filePath(); + const QString winAppSdkDownloadTitle(Tr::tr("Windows App SDK Downloading")); + const QString winAppSdkDownloadUrl = "https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/downloads"; + + if (m_winAppSdkSummary->rowsOk({WindowsAppSdkPathExists})) { + QMessageBox::information(this, winAppSdkDownloadTitle, + Tr::tr("Windows App SDK is already configured.")); + return; + } + + if (!m_winAppSdkSummary->rowsOk({DownloadPathExistsRow})) { + QMessageBox::information(this, winAppSdkDownloadTitle, + Tr::tr("Download path is not configured.")); + return; + } + + QProgressDialog *winAppSdkProgressDialog + = new QProgressDialog(Tr::tr("Downloading Windows App SDK..."), + Tr::tr("Cancel"), 0, 0); + winAppSdkProgressDialog->setWindowModality(Qt::ApplicationModal); + winAppSdkProgressDialog->setWindowTitle(winAppSdkDownloadTitle); + winAppSdkProgressDialog->setFixedSize(winAppSdkProgressDialog->sizeHint()); + + const QString winAppSdkLibraryName("Microsoft.WindowsAppSDK"); + Process *nugetDownloader = new Process(this); + const CommandLine gitCloneCommand(nugetPath, {"install", + winAppSdkLibraryName, + "-OutputDirectory", + downloadPath.path()}); + nugetDownloader->setCommand(gitCloneCommand); + + qCDebug(windowssettingswidget) << "Downloading Windows App SDK: " + << gitCloneCommand.toUserOutput(); + + connect(winAppSdkProgressDialog, + &QProgressDialog::canceled, nugetDownloader, &QObject::deleteLater); + + const auto failDialog = [=](const QString &msgSuffix = {}) { + QStringList sl; + sl << Tr::tr("Windows App SDK downloading failed."); + if (!msgSuffix.isEmpty()) + sl << msgSuffix; + sl << Tr::tr("Opening Windows App SDK URL for manual download."); + QMessageBox msgBox; + msgBox.setText(sl.join(" ")); + msgBox.addButton(Tr::tr("Cancel"), QMessageBox::RejectRole); + QAbstractButton *openButton = msgBox.addButton(Tr::tr("Open Download URL"), + QMessageBox::ActionRole); + msgBox.exec(); + + if (msgBox.clickedButton() == openButton) + QDesktopServices::openUrl(QUrl::fromUserInput(winAppSdkDownloadUrl)); + openButton->deleteLater(); + }; + + connect(nugetDownloader, + &Process::done, + this, + [this, winAppSdkProgressDialog, nugetDownloader, failDialog, downloadPath] { + winAppSdkProgressDialog->close(); + if (nugetDownloader->error() != QProcess::UnknownError) { + if (nugetDownloader->error() == QProcess::FailedToStart) { + failDialog(); + return; + } else { + failDialog(); + } + } + QStringList filters; + filters << "Microsoft.WindowsAppSDK.*"; + QDir dir(downloadPath.path()); + auto results = dir.entryList(filters); + if (results.count() > 0) { + dir.cd(results[0]); + m_winAppSdkPathChooser->setFilePath(FilePath::fromString(dir.path())); + } + validateWindowsAppSdk(); + m_winAppSdkPathChooser->triggerChanged(); // After cloning, the path exists + nugetDownloader->deleteLater(); + + if (!winAppSdkProgressDialog->wasCanceled() + || nugetDownloader->result() == ProcessResult::FinishedWithError) { + failDialog(); + } + updateUI(); + apply(); + }); + + winAppSdkProgressDialog->show(); + nugetDownloader->start(); +} + +void WindowsSettingsWidget::updateUI() +{ + const bool allOk = m_winAppSdkSummary->allRowsOk(); + m_winAppSdkSummary->setSetupOk(allOk); +} + +// WindowsSettingsPage + +class WindowsSettingsPage final : public Core::IOptionsPage +{ +public: + WindowsSettingsPage() + { + setId(Constants::WINDOWS_SETTINGS_ID); + setDisplayName(Tr::tr("Windows App SDK")); + setCategory(Constants::SDK_SETTINGS_CATEGORY); + setDisplayCategory(Tr::tr("SDKs")); + setWidgetCreator([] { return new WindowsSettingsWidget; }); + setCategoryIconPath(":/projectexplorer/images/sdk.png"); + } +}; + +void setupWindowsSettingsPage() +{ + static WindowsSettingsPage theWindowsSettingsPage; +} + +} // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/windowssettingswidget.h b/src/plugins/projectexplorer/windowssettingswidget.h new file mode 100644 index 00000000000..bb62398d4a9 --- /dev/null +++ b/src/plugins/projectexplorer/windowssettingswidget.h @@ -0,0 +1,10 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace ProjectExplorer::Internal { + +void setupWindowsSettingsPage(); + +} // namespace ProjectExplorer::Internal From e093c27fb7fae530783cf7e3fccd19be1b350bf1 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 8 Nov 2024 11:24:27 +0100 Subject: [PATCH 077/989] ProjectExplorer: Improve code readability in KitAspect Change-Id: I9e15b23b6979b934cc2cabda1d372b71e6382ca5 Reviewed-by: hjk --- src/plugins/projectexplorer/kitaspect.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index 455ef5eeead..7149636c19a 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -18,6 +18,8 @@ #include #include +#include + using namespace Utils; namespace ProjectExplorer { @@ -34,6 +36,11 @@ private: const auto getValue = [&](const QModelIndex &index, KitAspect::ItemRole role) { return sourceModel()->data(index, role); }; + const auto getValues = [&](KitAspect::ItemRole role, const T & /* dummy */) { + return std::make_pair( + sourceModel()->data(source_left, role).value(), + sourceModel()->data(source_right, role).value()); + }; // Criterion 1: "None" comes last. if (getValue(source_left, KitAspect::IsNoneRole).toBool()) @@ -43,18 +50,12 @@ private: // Criterion 2: "Type", which is is the name of some category by which the entries // are supposed to get grouped together. - if (const QString type1 = getValue(source_left, KitAspect::TypeRole).toString(), - type2 = getValue(source_right, KitAspect::TypeRole).toString(); - type1 != type2) { + if (const auto [type1, type2] = getValues(KitAspect::TypeRole, QString()); type1 != type2) return type1 < type2; - } // Criterion 3: "Quality", i.e. how likely is the respective entry to be usable. - if (const int qual1 = getValue(source_left, KitAspect::QualityRole).toInt(), - qual2 = getValue(source_right, KitAspect::QualityRole).toInt(); - qual1 != qual2) { + if (const auto [qual1, qual2] = getValues(KitAspect::QualityRole, int()); qual1 != qual2) return qual1 > qual2; - } // Criterion 4: Name. return SortModel::lessThan(source_left, source_right); From 4e23101d9e8865aa9362011fc94ffabe9b6d8cdd Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 8 Nov 2024 10:58:33 +0100 Subject: [PATCH 078/989] ProjectExplorer: Disable KitAspect combo boxes with zero or one entries It's annoying when the combo box appears to indicate that there is a choice, only to reveal that there is none after all when being clicked on. This used to be done only for the toolchain aspect, so the behavior is also more consistent now. Change-Id: Ie46e7896f32c1b6571462e12eac1f435568646ff Reviewed-by: hjk --- src/plugins/projectexplorer/kitaspect.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index 7149636c19a..6ef1845796d 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -131,6 +131,8 @@ public: QComboBox *comboBox; }; QList listAspects; + + bool readOnly = false; }; KitAspect::KitAspect(Kit *kit, const KitAspectFactory *factory) @@ -162,6 +164,7 @@ void KitAspect::refresh() la.comboBox->model()->sort(0); const QVariant itemId = la.spec.getter(*kit()); la.comboBox->setCurrentIndex(la.comboBox->findData(itemId, IdRole)); + la.comboBox->setEnabled(!d->readOnly && la.comboBox->count() > 1); } } @@ -173,6 +176,7 @@ void KitAspect::makeStickySubWidgetsReadOnly() if (d->manageButton) d->manageButton->setEnabled(false); + d->readOnly = true; makeReadOnly(); } From c274313f06e291a5ea7c1bfd3832111bc453373b Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 6 Nov 2024 17:34:29 +0100 Subject: [PATCH 079/989] QtSupport: Adapt ABI extraction to new format Change-Id: I41c7046342586070dd87d3de88fdce4871291479 Reviewed-by: David Schulz --- src/plugins/qtsupport/qtabiextractor.cpp | 76 +++++++++++++++++++----- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/src/plugins/qtsupport/qtabiextractor.cpp b/src/plugins/qtsupport/qtabiextractor.cpp index 3e970357275..00c4388f713 100644 --- a/src/plugins/qtsupport/qtabiextractor.cpp +++ b/src/plugins/qtsupport/qtabiextractor.cpp @@ -25,7 +25,8 @@ Q_LOGGING_CATEGORY(abiDetect, "qtc.qtsupport.detectAbis", QtWarningMsg) class QtAbiExtractor { public: - QtAbiExtractor(const FilePath &jsonFile) : m_jsonFile(jsonFile) {} + QtAbiExtractor(const QVersionNumber &qtVersion, const FilePath &jsonFile) + : m_qtVersion(qtVersion), m_jsonFile(jsonFile) {} Abis getAbis() { @@ -42,31 +43,65 @@ public: if (parseError.error != QJsonParseError::NoError) return printErrorAndReturn(parseError.errorString()); - const QJsonObject obj = jsonDoc.object().value("built_with").toObject(); + m_mainObject = jsonDoc.object(); + if (m_qtVersion < QVersionNumber(6, 9)) + extractAbisV1(); + else + extractAbisV2(); + return m_abis; + } + +private: + void extractAbisV1() + { + const QJsonObject obj = m_mainObject.value("built_with").toObject(); const QString osString = obj.value("target_system").toString(); const Abi::OS os = getOs(osString); if (os == Abi::DarwinOS) - return {}; // QTBUG-129996 + return; // QTBUG-129996 const auto [arch, width] = getArch(obj.value("architecture").toString()); if (os == Abi::UnknownOS && arch != Abi::AsmJsArchitecture) - return printErrorAndReturn(Tr::tr("Could not determine target OS")); + return printError(Tr::tr("Could not determine target OS")); if (arch == Abi::UnknownArchitecture) - return printErrorAndReturn(Tr::tr("Could not determine target architecture")); + return printError(Tr::tr("Could not determine target architecture")); - const Abi::OSFlavor flavor = getFlavor( - os, - osString, - obj.value("compiler_id").toString(), - obj.value("compiler_version").toString()); + const Abi::OSFlavor flavor + = getFlavor(os, osString, getCompilerId(obj), getCompilerVersion(obj)); if (flavor == Abi::UnknownFlavor && arch != Abi::AsmJsArchitecture) - return printErrorAndReturn(Tr::tr("Could not determine OS sub-type")); + return printError(Tr::tr("Could not determine OS sub-type")); - return {Abi(arch, os, flavor, getFormat(os, arch), width)}; + m_abis.emplaceBack(arch, os, flavor, getFormat(os, arch), width); + } + + void extractAbisV2() + { + for (const QJsonArray platforms = m_mainObject.value("platforms").toArray(); + const QJsonValue &p : platforms) { + const QJsonObject platform = p.toObject(); + const QString osString = platform.value("name").toString(); + const Abi::OS os = getOs(osString); + const QString compilerId = getCompilerId(platform); + const QString compilerVersion = getCompilerVersion(platform); + for (const QJsonArray &targets = platform.value("targets").toArray(); + const QJsonValue &t : targets) { + const QJsonObject target = t.toObject(); + const auto [arch, width] = getArch(target.value("architecture").toString()); + if (os == Abi::UnknownOS && arch != Abi::AsmJsArchitecture) + return printError(Tr::tr("Could not determine target OS")); + if (arch == Abi::UnknownArchitecture) + return printError(Tr::tr("Could not determine target architecture")); + + const Abi::OSFlavor flavor = getFlavor(os, osString, compilerId, compilerVersion); + if (flavor == Abi::UnknownFlavor && arch != Abi::AsmJsArchitecture) + return printError(Tr::tr("Could not determine OS sub-type")); + + m_abis.emplaceBack(arch, os, flavor, getFormat(os, arch), width); + } + } } -private: void printError(const QString &detail) { Core::MessageManager::writeSilently( Tr::tr("Error reading \"%1\": %2").arg(m_jsonFile.toUserOutput(), detail)); @@ -182,7 +217,20 @@ private: return Abi::UnknownFormat; } + QString getCompilerId(const QJsonObject &obj) const + { + return obj.value("compiler_id").toString(); + } + + QString getCompilerVersion(const QJsonObject &obj) const + { + return obj.value("compiler_version").toString(); + } + + const QVersionNumber m_qtVersion; const FilePath m_jsonFile; + QJsonObject m_mainObject; + Abis m_abis; }; Abis qtAbisFromJson(const QtVersion &qtVersion, const Utils::FilePaths &possibleLocations) @@ -208,7 +256,7 @@ Abis qtAbisFromJson(const QtVersion &qtVersion, const Utils::FilePaths &possible return {}; } - return QtAbiExtractor(jsonFile).getAbis(); + return QtAbiExtractor(qtVersion.qtVersion(), jsonFile).getAbis(); } } // namespace QtSupport::Internal From 43274bb2d538f2112e82e28e75e931b3874e87db Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 8 Nov 2024 09:37:46 +0100 Subject: [PATCH 080/989] ProjectExplorer: Use aspects for windows configuration storage Change-Id: I0b93af093cdb396345648c6df8382d4a906bae00 Reviewed-by: Morteza Jamshidi Reviewed-by: Christian Kandeler --- .../devicesupport/devicekitaspects.cpp | 7 +- .../projectexplorer/windowsconfigurations.cpp | 144 +++--------------- .../projectexplorer/windowsconfigurations.h | 40 ++--- .../projectexplorer/windowssettingswidget.cpp | 21 +-- 4 files changed, 45 insertions(+), 167 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 1d48fb73208..e7b949e81aa 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -536,12 +536,11 @@ void BuildDeviceKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *ex }); } -void BuildDeviceKitAspectFactory::addToBuildEnvironment(const Kit *k, Utils::Environment &env) const +void BuildDeviceKitAspectFactory::addToBuildEnvironment(const Kit *k, Environment &env) const { IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k); - if (dev->osType() == Utils::OsType::OsTypeWindows - && dev->type() == Constants::DESKTOP_DEVICE_TYPE) { - if (const FilePath appSdkLocation = WindowsConfigurations::windowsAppSdkLocation(); + if (dev->osType() == OsType::OsTypeWindows && dev->type() == Constants::DESKTOP_DEVICE_TYPE) { + if (const FilePath appSdkLocation = windowsConfigurations().windowsAppSdkLocation(); !appSdkLocation.isEmpty()) { env.set(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY, appSdkLocation.path()); } diff --git a/src/plugins/projectexplorer/windowsconfigurations.cpp b/src/plugins/projectexplorer/windowsconfigurations.cpp index 05fc1254375..b1dcf855ab6 100644 --- a/src/plugins/projectexplorer/windowsconfigurations.cpp +++ b/src/plugins/projectexplorer/windowsconfigurations.cpp @@ -5,148 +5,44 @@ #include "projectexplorerconstants.h" -#include -#include - -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +using namespace Utils; namespace ProjectExplorer::Internal { -const char SettingsGroup[] = "WindowsConfigurations"; -const char DownloadLocationKey[] = "DownloadLocation"; -const char NugetLocationKey[] = "NugetLocation"; -const char WindowsAppSdkLocationKey[] = "WindowsAppSDKLocation"; - -struct WindowsConfigData +WindowsConfigurations &windowsConfigurations() { - void load(const QtcSettings &settings); - void save(QtcSettings &settings) const; - - FilePath m_downloadLocation; - FilePath m_nugetLocation; - FilePath m_windowsAppSdkLocation; -}; - -static WindowsConfigData &config() -{ - static WindowsConfigData theWindowsConfig; - return theWindowsConfig; + static WindowsConfigurations theWindowsConfigurations; + return theWindowsConfigurations; } -void WindowsConfigData::load(const QtcSettings &settings) -{ - // user settings - m_downloadLocation = FilePath::fromSettings(settings.value(DownloadLocationKey)); - m_nugetLocation = FilePath::fromSettings(settings.value(NugetLocationKey)); - m_windowsAppSdkLocation = FilePath::fromSettings(settings.value(WindowsAppSdkLocationKey)); - - if (m_windowsAppSdkLocation.isEmpty()) { - m_windowsAppSdkLocation = FilePath::fromString( - Environment::systemEnvironment().value(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY)); - } -} - -void WindowsConfigData::save(QtcSettings &settings) const -{ - // user settings - settings.setValue(DownloadLocationKey, m_downloadLocation.toSettings()); - settings.setValue(NugetLocationKey, m_nugetLocation.toSettings()); - settings.setValue(WindowsAppSdkLocationKey, m_windowsAppSdkLocation.toSettings()); -} - -/////////////////////////////////// -// WindowsConfigurations -/////////////////////////////////// - -WindowsConfigurations *m_instance = nullptr; - WindowsConfigurations::WindowsConfigurations() { - load(); - m_instance = this; + setSettingsGroup("WindowsConfigurations"); + + downloadLocation.setSettingsKey("DownloadLocation"); + nugetLocation.setSettingsKey("NugetLocation"); + windowsAppSdkLocation.setSettingsKey("WindowsAppSDKLocation"); + + AspectContainer::readSettings(); + + if (windowsAppSdkLocation().isEmpty()) { + windowsAppSdkLocation.setValue(FilePath::fromUserInput( + Environment::systemEnvironment().value(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY))); + } } void WindowsConfigurations::applyConfig() { - emit m_instance->aboutToUpdate(); - m_instance->save(); - emit m_instance->updated(); -} - -WindowsConfigurations *WindowsConfigurations::instance() -{ - return m_instance; -} - -FilePath WindowsConfigurations::downloadLocation() -{ - return config().m_downloadLocation; -} - -void WindowsConfigurations::setDownloadLocation(const FilePath &downloadLocation) -{ - config().m_downloadLocation = downloadLocation; -} - -FilePath WindowsConfigurations::nugetLocation() -{ - return config().m_nugetLocation; -} - -void WindowsConfigurations::setNugetLocation(const FilePath &nugetLocation) -{ - config().m_nugetLocation = nugetLocation; -} - -FilePath WindowsConfigurations::windowsAppSdkLocation() -{ - return config().m_windowsAppSdkLocation; -} - -void WindowsConfigurations::setWindowsAppSdkLocation(const FilePath &windowsAppSdkLocation) -{ - config().m_windowsAppSdkLocation = windowsAppSdkLocation; -} - -void WindowsConfigurations::save() -{ - QtcSettings *settings = Core::ICore::settings(); - settings->beginGroup(SettingsGroup); - config().save(*settings); - settings->endGroup(); -} - -void WindowsConfigurations::load() -{ - QtcSettings *settings = Core::ICore::settings(); - settings->beginGroup(SettingsGroup); - config().load(*settings); - settings->endGroup(); + emit aboutToUpdate(); + AspectContainer::writeSettings(); + emit updated(); } void setupWindowsConfigurations() { - static WindowsConfigurations theWindowsConfigurations; + (void) windowsConfigurations(); } } // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/windowsconfigurations.h b/src/plugins/projectexplorer/windowsconfigurations.h index 440e96eb48e..1190499968f 100644 --- a/src/plugins/projectexplorer/windowsconfigurations.h +++ b/src/plugins/projectexplorer/windowsconfigurations.h @@ -3,49 +3,31 @@ #pragma once -#include - -#include - -#include - -#include -#include - -using namespace Tasking; -using namespace Utils; +#include namespace ProjectExplorer::Internal { -class WindowsConfigurations : public QObject +class WindowsConfigurations : public Utils::AspectContainer { Q_OBJECT + WindowsConfigurations(); + friend WindowsConfigurations &windowsConfigurations(); + public: - static void applyConfig(); - static WindowsConfigurations *instance(); + Utils::FilePathAspect downloadLocation{this}; + Utils::FilePathAspect nugetLocation{this}; + Utils::FilePathAspect windowsAppSdkLocation{this}; - static FilePath downloadLocation(); - static void setDownloadLocation(const FilePath &downloadLocation); - - static FilePath nugetLocation(); - static void setNugetLocation(const FilePath &nugetLocation); - - static FilePath windowsAppSdkLocation(); - static void setWindowsAppSdkLocation(const FilePath &windowsAppSdkLocation); + void applyConfig(); signals: void aboutToUpdate(); void updated(); - -private: - friend void setupWindowsConfigurations(); - WindowsConfigurations(); - - void load(); - void save(); }; +WindowsConfigurations &windowsConfigurations(); + void setupWindowsConfigurations(); } // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/windowssettingswidget.cpp b/src/plugins/projectexplorer/windowssettingswidget.cpp index 829e53096d8..1f5ddabff7c 100644 --- a/src/plugins/projectexplorer/windowssettingswidget.cpp +++ b/src/plugins/projectexplorer/windowssettingswidget.cpp @@ -219,13 +219,13 @@ WindowsSettingsWidget::WindowsSettingsWidget() m_downloadPathChooser->setToolTip(Tr::tr("Select the path of downloads.")); m_downloadPathChooser->setPromptDialogTitle(Tr::tr("Select download path")); m_downloadPathChooser->setExpectedKind(PathChooser::ExistingDirectory); - m_downloadPathChooser->setFilePath(WindowsConfigurations::downloadLocation()); + m_downloadPathChooser->setFilePath(windowsConfigurations().downloadLocation()); m_nugetPathChooser = new PathChooser; m_nugetPathChooser->setToolTip(Tr::tr("Select the path of the Nuget.")); m_nugetPathChooser->setPromptDialogTitle(Tr::tr("Select nuget.exe file")); m_nugetPathChooser->setExpectedKind(PathChooser::Any); - m_nugetPathChooser->setFilePath(WindowsConfigurations::nugetLocation()); + m_nugetPathChooser->setFilePath(windowsConfigurations().nugetLocation()); auto downloadNuget = new QPushButton(Tr::tr("Download Nuget")); downloadNuget->setToolTip( @@ -252,9 +252,10 @@ WindowsSettingsWidget::WindowsSettingsWidget() winAppSdkDetailsWidget); m_winAppSdkPathChooser->setPromptDialogTitle(Tr::tr("Select Windows App SDK Path")); - if (WindowsConfigurations::windowsAppSdkLocation().isEmpty()) - WindowsConfigurations::setWindowsAppSdkLocation(WindowsConfigurations::downloadLocation()); - m_winAppSdkPathChooser->setFilePath(WindowsConfigurations::windowsAppSdkLocation()); + WindowsConfigurations &settings = windowsConfigurations(); + if (settings.windowsAppSdkLocation().isEmpty()) + settings.windowsAppSdkLocation.setValue(settings.downloadLocation()); + m_winAppSdkPathChooser->setFilePath(settings.windowsAppSdkLocation()); using namespace Layouting; @@ -315,7 +316,7 @@ WindowsSettingsWidget::WindowsSettingsWidget() apply(); }); - setOnApply([] { WindowsConfigurations::applyConfig(); }); + setOnApply([] { windowsConfigurations().applyConfig(); }); } void WindowsSettingsWidget::showEvent(QShowEvent *event) @@ -331,7 +332,7 @@ void WindowsSettingsWidget::showEvent(QShowEvent *event) void WindowsSettingsWidget::validateDownloadPath() { - WindowsConfigurations::setDownloadLocation(m_downloadPathChooser->filePath()); + windowsConfigurations().downloadLocation.setValue(m_downloadPathChooser->filePath()); m_winAppSdkSummary->setPointValid( DownloadPathExistsRow, m_downloadPathChooser->filePath().exists()); @@ -341,7 +342,7 @@ void WindowsSettingsWidget::validateDownloadPath() void WindowsSettingsWidget::validateNuget() { - WindowsConfigurations::setNugetLocation(m_nugetPathChooser->filePath()); + windowsConfigurations().nugetLocation.setValue(m_nugetPathChooser->filePath()); m_winAppSdkSummary->setPointValid(NugetPathExistsRow, m_nugetPathChooser->filePath().exists()); @@ -350,11 +351,11 @@ void WindowsSettingsWidget::validateNuget() void WindowsSettingsWidget::validateWindowsAppSdk() { - WindowsConfigurations::setWindowsAppSdkLocation(m_winAppSdkPathChooser->filePath()); + windowsConfigurations().windowsAppSdkLocation.setValue(m_winAppSdkPathChooser->filePath()); QStringList filters; filters << "Microsoft.WindowsAppSDK.*.nupkg"; - QDir dir(WindowsConfigurations::windowsAppSdkLocation().path()); + QDir dir(windowsConfigurations().windowsAppSdkLocation().path()); auto results = dir.entryList(filters); m_winAppSdkSummary->setPointValid(WindowsAppSdkPathExists, results.count() > 0); From 7192d1e83eee48c2f4f54d14b9013b5092079964 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 7 Nov 2024 18:54:00 +0100 Subject: [PATCH 081/989] Modebar: Increase size of play/pause icons and overlays Fixes: QTCREATORBUG-31868 Change-Id: Iba3ac0441c50e6b29b8e404b5dfb9b4443b86b1a Reviewed-by: Eike Ziller --- .../images/debugger_continue_1_mask.png | Bin 124 -> 126 bytes .../images/debugger_continue_1_mask@2x.png | Bin 166 -> 169 bytes .../images/debugger_continue_2_mask.png | Bin 163 -> 160 bytes .../images/debugger_continue_2_mask@2x.png | Bin 278 -> 280 bytes .../images/debugger_interrupt_mask.png | Bin 126 -> 138 bytes .../images/debugger_interrupt_mask@2x.png | Bin 173 -> 178 bytes .../images/build_hammer_mask.png | Bin 300 -> 297 bytes .../images/build_hammer_mask@2x.png | Bin 501 -> 511 bytes .../images/debugger_beetle_mask.png | Bin 136 -> 143 bytes .../images/debugger_beetle_mask@2x.png | Bin 229 -> 257 bytes .../projectexplorer/images/run_mask.png | Bin 198 -> 203 bytes .../projectexplorer/images/run_mask@2x.png | Bin 347 -> 360 bytes src/tools/icons/qtcreatoricons.svg | 34 ++++++++++-------- 13 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/plugins/debugger/images/debugger_continue_1_mask.png b/src/plugins/debugger/images/debugger_continue_1_mask.png index c2196afa9539dbeaa870aa40f73f096a5780ac82..0c5272b67095ac4c9c645ddd6f59e39ff1ef020b 100644 GIT binary patch delta 68 zcmb=an_zFR<>}%WqH#XCz>%GYS^tsF0fio|M@J4EXwiCfplL~UOJ_nGTUrP2A`4aq Z$>06Dcb91HVPIfj@O1TaS?83{1OT3U8e0GW delta 66 zcmb=cnP6|L;pyTSq7j^2;KbP0l+XkKBJ~(2 diff --git a/src/plugins/debugger/images/debugger_continue_1_mask@2x.png b/src/plugins/debugger/images/debugger_continue_1_mask@2x.png index c3cb2a62becf31da536d55b0dae0c77d469963c2..6563af87bf13b838b04735b4388cd03a7c7b0b3b 100644 GIT binary patch delta 107 zcmZ3+xRP;#Yl^?8i(`mKXR?PfhlJbI9<75RlU|)Ta6mz*&EM02nPbMI;71H$hnoC5 znIbra?NoVq43a`lu9y_4df1Uu@aDXZL(LsZ9UV

Jp(wt62CL{F*i(`n#@njEW4hgrZJz5KAP6}~nW1DEO$E!)Q;eg0`A@&JEVtc$q z9K2?H&`L~bco3+%*voC1kdhInU}SFxkGIP?_i(`nz>Es{&0tP)=jLg!T&0D4z7|f_uTG4XwqqU-H5YN8-92z?{ zj|qGg-#_X9b5;o>PK}@SQ)Vxm)G+D4^-T#Y4vnAtdpZk+k9u)LyWH5>V(aU2K~Rv< n#YOqx5eJt^QfGS|7#Q|_G52=UKKq4%fq}u()z4*}Q$iB}e8DsC delta 134 zcmZ3$xR`N*N`026i(`nz>Es{&0tP)=iea6-C%v7#BqU1WghCE2_}H^RQ{!1e=qE4n zn=)&>{w-c{aNU#t-m+}MOkQ<6jUkL}#!A9Ht4>nyZn^e;9n5#+g> q(j@rcS9gFlsvjrJSS;%+BB(u;D~E- zT7J4INtoqej+t@WW5FBe^f{i}97x~&eO`4PyRb+ji;#zcz0zlunL8&crHI9`DC`zd zcyf)Y<&Rs#gf}c4Q=5e)nXdTRJ-N%C5fjs4yPIL{Z0?QK(hEvI7buqHGJT2DJ94hH zp^<-MvS`8+=bU&piQfXZ#Tu?0X}@8`zGS)Gk+8@GU)VbyS#))W+H72OQzUo&kA|+m z1rlD9K59r_nRG&+b-I$9Xydy$T@~-Xl)Jyez)nj0#<)RO^7#KWV{an^L HB{Ts5LwRgi delta 250 zcmbQiG>vJ3O8s3=7srr@!*4GdavgFIX?bYBW5rqyvCg>@qHk1iX}@0-F6d~OkeL5i zSHz}aLY&SgogDMmdiuQ|o-xQ9^IUQ?I3nQ8^V9mtoaa-eG!MMp%HfcIn^EYMP(RBq z6@|B6CXbl97foE8{a&co!=cli$&2aIx+My0y@Zsi*>`xg*Gw&T>b&EAAf)|@>IB)4 z6V;3x1bHv5VVKs-70G-ievu=eq(OBT+fKg5kG>`+l9|5fFLLryxZTP3asKSSigUhh zHP4qRrRruKsn25yI`BZt>&cww>KB#lpGzfmD7HyFI?e7?CVJD0m+dhF0|SGntDnm{ Hr-UW|3N>i6 diff --git a/src/plugins/debugger/images/debugger_interrupt_mask.png b/src/plugins/debugger/images/debugger_interrupt_mask.png index 6961370069b097774d08a354f430d50e2f51b2ce..2c0294360bb8a365e154e84a42317e3599fa1776 100644 GIT binary patch delta 81 zcmb>HVw_;_ZRY9X7@~1LxxkT~hgtuT&H;rtNhc0uFo_o?B_tFDCL{zjc3W&<$Yc{R m{p4cc%xrvwEpQGK!-X3y7hSfNu47=5f6{Y|H diff --git a/src/plugins/debugger/images/debugger_interrupt_mask@2x.png b/src/plugins/debugger/images/debugger_interrupt_mask@2x.png index dc4ae99aa0ee0101b556eebdd33352ed2cf4ace6..e507f34fc15044839ad6e46ed5277f0e6a0230b9 100644 GIT binary patch delta 116 zcmZ3>xQTIsYi@+6i(`mKXR?PfhlJbI9<75RlU|)Ta6mz*?Z|-up)(9j%RG2^RQVDl z#Z=hZgjhH52n#Vgb22keX)p#Umkc$UGF4#W+fEIe4vnS`jS~e;fvStW9xyQM3YRV` Uahb`)z`(%Z>FVdQ&MBb@0R4+5S^xk5 delta 111 zcmdnQxR!B(YeulAi(`n#@njEW4hgrZJz5KAP6}~nW1DEe((CGJz$`FBDMQCg#vw?D zL#kVdb%Ka+)3HS@jf|rGT9Tngo2Cd%^z1m1<&qMiwCQg~r{$^?4^2jf-g_qB+Vp#w R7#J8BJYD@<);T3K0RZ7AB(nej diff --git a/src/plugins/projectexplorer/images/build_hammer_mask.png b/src/plugins/projectexplorer/images/build_hammer_mask.png index e75c3e15cff86f07f755ff94d2d789b2fcbfb685..67270a3edb06b0d41b6db434917b3103eae0bfeb 100644 GIT binary patch delta 79 zcmZ3(w32Cp3gd@~st29DeGbRI`pFz#werA9rgcZAF63LSt7cwv~FnGH9xvXj^+7jmc*AA0bI_j`ag@00rW92SKVXE!AYp-UgmS6zD$a%9%B=ZcEyae|*F zOyIRP@HhQ)VxjEJJ!)5#l-qVBoRkid`}8uzrNqeJ=!xact9RPjqrD#-*~N8`W0$q) w#pyB4<*fyeGd|yW6sz<^RN3$o|3rWP1y7pnRvBDpU|?YIboFyt=akR{0G-(8`2YX_ delta 475 zcmey*{FQlvO8p*B7srr@!*8$c)n{>(IR0_{^j_g|(T_!3ob^m|uXT1f6$f$%IX=9< zqs2wjM5xv4snkRd5w2~QVizq?Q0JOHVTH$<&l-9C#nzjxo10RW-%hfxoR?l_ZGA#t zCrQOE=}Erw`t9#7KK!`#d+w8;36&a*46@#>?-iE5J!zH|b~>v5rdZ`Elc4=#r?yR< zv+Pf}HM{$<_S;{*GOX1#8#;qh_x!fCQmxq_ntHWrib~i~` z)hI{Jt0ak6r1{2f&xV}>M;SDiF-lz3zUZ;>et(SH>V%vFGxYQWPn>0NC|k^!;11M#}yP^!w&+z;-sCT*cGo)-5L;CqOvirsTUE-E&7oY4rk!Sqi$yv7O;CA!S zxp{tNvtRWXs3a_z%y6?ou!*JW)GBF6SliD9ACs2>ZjG!yU=UR`We!v@}K9fZohW3UH*Qu kcU;Z({)rMl)lXQjkpEKj^7h6s1_lNOPgg&ebxsLQ01V#TqW}N^ diff --git a/src/plugins/projectexplorer/images/debugger_beetle_mask.png b/src/plugins/projectexplorer/images/debugger_beetle_mask.png index 8242de450f2d5f423ea8e65d98a436709fbba406..1dd7470be1218e193388860f9fc166faef8dbadf 100644 GIT binary patch delta 114 zcmeBR>}Q;yk{#yh;uvCaI{AmcfI*LzWT?~1Nv#1r?wz-G{(pYugLY@ogRqW6t5b}b zIo2Fr?9#}{B=TX#p<@OA|JSma&6+L5XR0dG?<##jE9~*+7yr|O|mUrlH%{_;uvCaI{AmcfI*LzWT?~1Nv#Pj;hnd37H9pK`e(zl=iC2v`gbxh zOK3bWc5Qn2ua=F|%XcEnOr_rQQvy0P7yi)s6{4mZ`Y$rkWbXrZhEqDBA7q)r*D^3L OFnGH9xvXE`I-y_STFcT1U=xo<8bp*oY$RKl`a-++h&dFyTpq62r>C$xrxxGo(1| z^PH6X&t`&veQYRApT|n#I3s$F-O+R84xrD3PdM;r`+K+%*P$ z;W=tfZoe&iWm!AET5n`x*|DU1LhRqLeY<6kfBwW^ZKWQ=`nG1;8t%v|j~ALOv$^;6 gexS?5s}tDGo=aRlw8Bn_fq{X+)78&qol`;+0M*xBDF6Tf delta 201 zcmZoQR0!Kn3@YH?cvCv# z@b(1^w<3Exe_rfBDCY zEk9D#@3k;&)OSz#+|lsXszopr08yw`ZU6uP diff --git a/src/plugins/projectexplorer/images/run_mask.png b/src/plugins/projectexplorer/images/run_mask.png index 37d3802f3889f0b9d956edf75f0f10a7377058c5..436a65d6c7d1eb3e10018290d6e61d6697eb0ec9 100644 GIT binary patch delta 175 zcmX@cc$#s7O8q2H7sn8b)5$;l1q^sXRd0v=S6_k`gv73*b!b=CGQ+U^yqd>_H6<1({wK6}BeNu8tN@mrrtf cl~N2_{RA)aCM=xFz`(%Z>FVdQ&MBb@0GX;u{{R30 delta 170 zcmX@jc#Ls^N`0@Vi(`nz>Es{&0tP(ks<*@bD=%qjKKO};QI&^>$47HLhlXZyvcQZF z((5Pv-(D*rab^4C&`d|Nq-}r>0DZ`@uhd(*OVd zkp>1g;*YF;^8fx!B_5sInjuA}<}@CBsHA#M_07w>vsjw?3Rnb`1$$Y9nFT$&I$A7? cjC2?@Wn@LRcF)|zz`(%Z>FVdQ&MBb@0A$)pa{vGU diff --git a/src/plugins/projectexplorer/images/run_mask@2x.png b/src/plugins/projectexplorer/images/run_mask@2x.png index 0be2cd1b3ad2033077b58381ea1217f732ca6bb1..a60449c82e79b65784f76eb841b675895d1a9733 100644 GIT binary patch delta 333 zcmcc3^nz)EO1-|Pi(^Q{;kVaqy^bV^v_35V<2u7h&@r9Gaf1-|#dC)a9ZJg4(cRRV zqxg2pO{Z-JMoSZvZ*Vp#M08{*iYYDfxG*z$qU;m7EuLZ@4*dM|^qz1^MaBfSOabwt zTahRCFZK|>Va2b+Q1B(eA>;dL3nuBq5}SezkAD|T3DIFRm|k0d)qTnJ5}}5xN(~<2 z)uGFpXEQ7++{kmFhM7vFr3|2>X*eTtW3!C|EJ#&Xi1apE`Ew{q2Gii(wXWYLE zzFZfcdTTF_!leY+hR!Fd4J*#vX3%+J|5fm%;Yy?2cou<|Il>KLpJW_DzODB8e3(JW zcJ3C2UH^M69!c9--F<)De*24ofq}u()z4*}Q$iB}m!XuT delta 320 zcmaFCbem~{O1+Y&i(^Q{;kVc9vknFFuz!e{vPfZt^GE)s2TLY9AM9&tZjQA%@Sf|Q zgH6-AzIA+4m^%uzc!@78(ctJ(colx)GV>SJfGN|NYZUY=Jvq1>`3gInF zgx5BUcnSvAskn4J{u|7=Fd8 zM3}E%>qZ7fx1HHL_p@;Dy*1EY`0Sn>tv>S5|#xWqutQk3m$Zt9UY;ccfr1w}5_;*Nc}ML^C{>-n@(55He8=x~-P cdVhko_)hVm?T$Ux3=9kmp00i_>zopr07{sQQUCw| diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index df4dd352769..7714c390550 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -9073,8 +9073,9 @@ height="100%" /> + d="m 605,48.5 16,9.5 -16,9.5 z" + id="path4716" + sodipodi:nodetypes="cccc" /> + ry="3.5" /> + d="m 764.5,59 0.5,1.5 m 3.5,-1.5 -0.5,1.5 m 1,2 h 1.5 m -1.5,2 h 1.5 m -1.5,2 h 1 l 0.5,0.5 v 0.5 m -8,0 V 67 l 0.5,-0.5 h 1 m -1.5,-2 h 1.5 m -1.5,-2 h 1.5" + sodipodi:nodetypes="cccccccccccccccccccc" /> + d="m 765.5,65.5 h 2 m -2,-2 h 2" + sodipodi:nodetypes="cccc" /> + width="3" + height="14" + x="756" + y="51" /> @@ -9194,8 +9197,9 @@ height="100%" /> + d="m 765,50 7.5,8 -7.5,8 z" + id="path34590" + sodipodi:nodetypes="cccc" /> Date: Tue, 5 Nov 2024 16:32:08 +0100 Subject: [PATCH 082/989] Android: Reuse new NetworkQuery signals Reuse them also in manual test. Change-Id: Id882c4330d4de0b9a4558b08c3607eaa4683b9be Reviewed-by: Morteza Jamshidi Reviewed-by: hjk --- src/plugins/android/androidsdkdownloader.cpp | 32 ++++++++----------- .../assetdownloader/assetdownloader.cpp | 9 ++---- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/plugins/android/androidsdkdownloader.cpp b/src/plugins/android/androidsdkdownloader.cpp index e8a51d1299f..682692f7ede 100644 --- a/src/plugins/android/androidsdkdownloader.cpp +++ b/src/plugins/android/androidsdkdownloader.cpp @@ -117,27 +117,21 @@ GroupItem downloadSdkRecipe() const auto onQuerySetup = [storage](NetworkQuery &query) { query.setRequest(QNetworkRequest(AndroidConfig::sdkToolsUrl())); query.setNetworkAccessManager(NetworkAccessManager::instance()); - NetworkQuery *queryPtr = &query; QProgressDialog *progressDialog = storage->progressDialog.get(); - QObject::connect(queryPtr, &NetworkQuery::started, progressDialog, [queryPtr, progressDialog] { - QNetworkReply *reply = queryPtr->reply(); - if (!reply) - return; - QObject::connect(reply, &QNetworkReply::downloadProgress, - progressDialog, [progressDialog](qint64 received, qint64 max) { - progressDialog->setRange(0, max); - progressDialog->setValue(received); - }); -#if QT_CONFIG(ssl) - QObject::connect(reply, &QNetworkReply::sslErrors, - reply, [reply](const QList &sslErrors) { - for (const QSslError &error : sslErrors) - qCDebug(sdkDownloaderLog, "SSL error: %s\n", qPrintable(error.errorString())); - logError(Tr::tr("Encountered SSL errors, download is aborted.")); - reply->abort(); - }); -#endif + QObject::connect(&query, &NetworkQuery::downloadProgress, + progressDialog, [progressDialog](qint64 received, qint64 max) { + progressDialog->setRange(0, max); + progressDialog->setValue(received); }); +#if QT_CONFIG(ssl) + QObject::connect(&query, &NetworkQuery::sslErrors, + &query, [queryPtr = &query](const QList &sslErrors) { + for (const QSslError &error : sslErrors) + qCDebug(sdkDownloaderLog, "SSL error: %s\n", qPrintable(error.errorString())); + logError(Tr::tr("Encountered SSL errors, download is aborted.")); + queryPtr->reply()->abort(); + }); +#endif }; const auto onQueryDone = [storage](const NetworkQuery &query, DoneWith result) { if (result == DoneWith::Cancel) diff --git a/tests/manual/tasking/assetdownloader/assetdownloader.cpp b/tests/manual/tasking/assetdownloader/assetdownloader.cpp index c7bb2b3f8be..84f647054fa 100644 --- a/tests/manual/tasking/assetdownloader/assetdownloader.cpp +++ b/tests/manual/tasking/assetdownloader/assetdownloader.cpp @@ -66,12 +66,9 @@ public: { query->setNetworkAccessManager(m_manager); clearProgress(progressText); - QObject::connect(query, &NetworkQuery::started, query, [this, query] { - QNetworkReply *reply = query->reply(); - QObject::connect(reply, &QNetworkReply::downloadProgress, - query, [this](qint64 bytesReceived, qint64 totalBytes) { - updateProgress((totalBytes > 0) ? 100.0 * bytesReceived / totalBytes : 0, 100); - }); + QObject::connect(query, &NetworkQuery::downloadProgress, + query, [this](qint64 bytesReceived, qint64 totalBytes) { + updateProgress((totalBytes > 0) ? 100.0 * bytesReceived / totalBytes : 0, 100); }); } }; From 93e2d90c0854ebdbf8220c36004978659fde9972 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 7 Oct 2024 20:27:05 +0200 Subject: [PATCH 083/989] TaskTree: Internal refactorings part 1 Remove return value from childDone() and introduce RuntimeContainer::m_setupResult field instead. Rename some methods to limit unreadable overloads. Inline start(RuntimeContainer *) method, as it was used just once. Change-Id: I59c1be772b20851b91093b6a3153ff2d83fc35e4 Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 94 +++++++++++-------------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 0ca5228719a..f6d45753331 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1860,17 +1860,16 @@ public: // If returned value != Continue, childDone() needs to be called in parent container (in caller) // in order to unwind properly. - SetupResult start(RuntimeTask *node); - void stop(RuntimeTask *node); - bool invokeDoneHandler(RuntimeTask *node, DoneWith doneWith); + SetupResult startTask(RuntimeTask *node); + void stopTask(RuntimeTask *node); + bool invokeTaskDoneHandler(RuntimeTask *node, DoneWith doneWith); // Container related methods - SetupResult start(RuntimeContainer *container); - SetupResult continueStart(RuntimeContainer *container, SetupResult startAction); + SetupResult continueContainer(RuntimeContainer *container); SetupResult startChildren(RuntimeContainer *container); - SetupResult childDone(RuntimeIteration *iteration, bool success); - void stop(RuntimeContainer *container); + void childDone(RuntimeIteration *iteration, bool success); + void stopContainer(RuntimeContainer *container); bool invokeDoneHandler(RuntimeContainer *container, DoneWith doneWith); bool invokeLoopHandler(RuntimeContainer *container); @@ -1990,6 +1989,7 @@ public: int m_runningChildren = 0; bool m_shouldIterate = true; std::vector> m_iterations; // Owning. + SetupResult m_setupResult = SetupResult::Continue; }; class RuntimeTask @@ -2070,7 +2070,7 @@ void TaskTreePrivate::start() "exist in task tree. Its handlers will never be called.")); } m_runtimeRoot.reset(new RuntimeTask{*m_root}); - start(m_runtimeRoot.get()); + startTask(m_runtimeRoot.get()); bumpAsyncCount(); } @@ -2079,7 +2079,7 @@ void TaskTreePrivate::stop() QT_ASSERT(m_root, return); if (!m_runtimeRoot) return; - stop(m_runtimeRoot.get()); + stopTask(m_runtimeRoot.get()); m_runtimeRoot.reset(); emitDone(DoneWith::Cancel); } @@ -2199,26 +2199,10 @@ void RuntimeContainer::deleteFinishedIterations() } } -SetupResult TaskTreePrivate::start(RuntimeContainer *container) +SetupResult TaskTreePrivate::continueContainer(RuntimeContainer *container) { - const ContainerNode &containerNode = container->m_containerNode; - SetupResult startAction = SetupResult::Continue; - if (containerNode.m_groupHandler.m_setupHandler) { - startAction = invokeHandler(container, containerNode.m_groupHandler.m_setupHandler); - if (startAction != SetupResult::Continue) { - if (isProgressive(container)) - advanceProgress(containerNode.m_taskCount); - // Non-Continue SetupResult takes precedence over the workflow policy. - container->m_successBit = startAction == SetupResult::StopWithSuccess; - } - } - return continueStart(container, startAction); -} - -SetupResult TaskTreePrivate::continueStart(RuntimeContainer *container, SetupResult startAction) -{ - const SetupResult groupAction = startAction == SetupResult::Continue ? startChildren(container) - : startAction; + const SetupResult groupAction = container->m_setupResult == SetupResult::Continue + ? startChildren(container) : container->m_setupResult; if (groupAction == SetupResult::Continue) return groupAction; @@ -2282,19 +2266,18 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container) ++container->m_runningChildren; ++container->m_nextToStart; - const SetupResult startAction = start(newTask); + const SetupResult startAction = startTask(newTask); if (startAction == SetupResult::Continue) continue; - const SetupResult finalizeAction = childDone(iteration, - startAction == SetupResult::StopWithSuccess); - if (finalizeAction != SetupResult::Continue) - return finalizeAction; + childDone(iteration, startAction == SetupResult::StopWithSuccess); + if (container->m_setupResult != SetupResult::Continue) + return container->m_setupResult; } return SetupResult::Continue; } -SetupResult TaskTreePrivate::childDone(RuntimeIteration *iteration, bool success) +void TaskTreePrivate::childDone(RuntimeIteration *iteration, bool success) { RuntimeContainer *container = iteration->m_container; const WorkflowPolicy &workflowPolicy = container->m_containerNode.m_workflowPolicy; @@ -2303,25 +2286,23 @@ SetupResult TaskTreePrivate::childDone(RuntimeIteration *iteration, bool success || (workflowPolicy == WorkflowPolicy::StopOnError && !success); ++iteration->m_doneCount; --container->m_runningChildren; - if (shouldStop) - stop(container); - const bool updatedSuccess = container->updateSuccessBit(success); - const SetupResult startAction = shouldStop ? toSetupResult(updatedSuccess) - : SetupResult::Continue; + container->m_setupResult = shouldStop ? toSetupResult(updatedSuccess) : SetupResult::Continue; + if (shouldStop) + stopContainer(container); if (container->isStarting()) - return startAction; - return continueStart(container, startAction); + return; + continueContainer(container); } -void TaskTreePrivate::stop(RuntimeContainer *container) +void TaskTreePrivate::stopContainer(RuntimeContainer *container) { const ContainerNode &containerNode = container->m_containerNode; for (auto &iteration : container->m_iterations) { for (auto &child : iteration->m_children) { ++iteration->m_doneCount; - stop(child.get()); + stopTask(child.get()); } if (iteration->m_isProgressive) { @@ -2371,11 +2352,22 @@ bool TaskTreePrivate::invokeLoopHandler(RuntimeContainer *container) return container->m_shouldIterate; } -SetupResult TaskTreePrivate::start(RuntimeTask *node) +SetupResult TaskTreePrivate::startTask(RuntimeTask *node) { if (!node->m_taskNode.isTask()) { - node->m_container.emplace(node->m_taskNode.m_container, node); - return start(&*node->m_container); + const ContainerNode &containerNode = node->m_taskNode.m_container; + node->m_container.emplace(containerNode, node); + RuntimeContainer *container = &*node->m_container; + if (containerNode.m_groupHandler.m_setupHandler) { + container->m_setupResult = invokeHandler(container, containerNode.m_groupHandler.m_setupHandler); + if (container->m_setupResult != SetupResult::Continue) { + if (isProgressive(container)) + advanceProgress(containerNode.m_taskCount); + // Non-Continue SetupResult takes precedence over the workflow policy. + container->m_successBit = container->m_setupResult == SetupResult::StopWithSuccess; + } + } + return continueContainer(container); } const GroupItem::TaskHandler &handler = node->m_taskNode.m_taskHandler; @@ -2393,7 +2385,7 @@ SetupResult TaskTreePrivate::start(RuntimeTask *node) = std::make_shared(SetupResult::Continue); QObject::connect(node->m_task.get(), &TaskInterface::done, q, [this, node, unwindAction](DoneResult doneResult) { - const bool result = invokeDoneHandler(node, toDoneWith(doneResult)); + const bool result = invokeTaskDoneHandler(node, toDoneWith(doneResult)); QObject::disconnect(node->m_task.get(), &TaskInterface::done, q, nullptr); node->m_task.release()->deleteLater(); RuntimeIteration *parentIteration = node->m_parentIteration; @@ -2410,22 +2402,22 @@ SetupResult TaskTreePrivate::start(RuntimeTask *node) return *unwindAction; } -void TaskTreePrivate::stop(RuntimeTask *node) +void TaskTreePrivate::stopTask(RuntimeTask *node) { if (!node->m_task) { if (!node->m_container) return; - stop(&*node->m_container); + stopContainer(&*node->m_container); node->m_container->updateSuccessBit(false); invokeDoneHandler(&*node->m_container, DoneWith::Cancel); return; } - invokeDoneHandler(node, DoneWith::Cancel); + invokeTaskDoneHandler(node, DoneWith::Cancel); node->m_task.reset(); } -bool TaskTreePrivate::invokeDoneHandler(RuntimeTask *node, DoneWith doneWith) +bool TaskTreePrivate::invokeTaskDoneHandler(RuntimeTask *node, DoneWith doneWith) { DoneResult result = toDoneResult(doneWith); const GroupItem::TaskHandler &handler = node->m_taskNode.m_taskHandler; From dede1f8386646a5e602b38c83989e34dc8717a9b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 10 Oct 2024 18:28:23 +0200 Subject: [PATCH 084/989] TaskTree: Internal refactorings part 2 Get rid of return value from startChildren() method. Change-Id: I2eedd0e2bc24b482275a463769a3ddf1767eabac Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index f6d45753331..cc09646b592 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1867,7 +1867,7 @@ public: // Container related methods SetupResult continueContainer(RuntimeContainer *container); - SetupResult startChildren(RuntimeContainer *container); + void startChildren(RuntimeContainer *container); void childDone(RuntimeIteration *iteration, bool success); void stopContainer(RuntimeContainer *container); bool invokeDoneHandler(RuntimeContainer *container, DoneWith doneWith); @@ -2201,12 +2201,12 @@ void RuntimeContainer::deleteFinishedIterations() SetupResult TaskTreePrivate::continueContainer(RuntimeContainer *container) { - const SetupResult groupAction = container->m_setupResult == SetupResult::Continue - ? startChildren(container) : container->m_setupResult; - if (groupAction == SetupResult::Continue) - return groupAction; + if (container->m_setupResult == SetupResult::Continue) + startChildren(container); + if (container->m_setupResult == SetupResult::Continue) + return SetupResult::Continue; - const bool bit = container->updateSuccessBit(groupAction == SetupResult::StopWithSuccess); + const bool bit = container->updateSuccessBit(container->m_setupResult == SetupResult::StopWithSuccess); RuntimeIteration *parentIteration = container->parentIteration(); RuntimeTask *parentTask = container->m_parentTask; QT_CHECK(parentTask); @@ -2223,7 +2223,7 @@ SetupResult TaskTreePrivate::continueContainer(RuntimeContainer *container) return toSetupResult(result); } -SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container) +void TaskTreePrivate::startChildren(RuntimeContainer *container) { const ContainerNode &containerNode = container->m_containerNode; const int childCount = int(containerNode.m_children.size()); @@ -2232,7 +2232,8 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container) if (container->m_shouldIterate && !invokeLoopHandler(container)) { if (isProgressive(container)) advanceProgress(containerNode.m_taskCount); - return toSetupResult(container->m_successBit); + container->m_setupResult = toSetupResult(container->m_successBit); + return; } container->m_iterations.emplace_back( std::make_unique(container->m_iterationCount, container)); @@ -2251,9 +2252,10 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container) std::make_unique(container->m_iterationCount, container)); ++container->m_iterationCount; } else if (container->m_iterations.empty()) { - return toSetupResult(container->m_successBit); + container->m_setupResult = toSetupResult(container->m_successBit); + return; } else { - return SetupResult::Continue; + return; } } if (containerNode.m_children.size() == 0) // Empty loop body. @@ -2272,9 +2274,8 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container) childDone(iteration, startAction == SetupResult::StopWithSuccess); if (container->m_setupResult != SetupResult::Continue) - return container->m_setupResult; + return; } - return SetupResult::Continue; } void TaskTreePrivate::childDone(RuntimeIteration *iteration, bool success) From ce9a0ad3f507f09829cde7cc69d4b749f89b0d7c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 10 Oct 2024 18:44:57 +0200 Subject: [PATCH 085/989] TaskTree: Internal refactorings part 3 Remove return value from continueContainer() method. Replace temporarily optional with shared_ptr. This will be brought back in part 5 of the refactoring patch series. Change-Id: I282b1c172809d36c193cb0683b57db88b3ca1951 Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index cc09646b592..a094d0c64ab 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1866,7 +1866,7 @@ public: // Container related methods - SetupResult continueContainer(RuntimeContainer *container); + void continueContainer(RuntimeContainer *container); void startChildren(RuntimeContainer *container); void childDone(RuntimeIteration *iteration, bool success); void stopContainer(RuntimeContainer *container); @@ -2006,7 +2006,7 @@ public: const TaskNode &m_taskNode; // Not owning. RuntimeIteration *m_parentIteration = nullptr; // Not owning. - std::optional m_container = {}; // Owning. + std::shared_ptr m_container = {}; // Owning. std::unique_ptr m_task = {}; // Owning. }; @@ -2199,18 +2199,19 @@ void RuntimeContainer::deleteFinishedIterations() } } -SetupResult TaskTreePrivate::continueContainer(RuntimeContainer *container) +void TaskTreePrivate::continueContainer(RuntimeContainer *container) { if (container->m_setupResult == SetupResult::Continue) startChildren(container); if (container->m_setupResult == SetupResult::Continue) - return SetupResult::Continue; + return; const bool bit = container->updateSuccessBit(container->m_setupResult == SetupResult::StopWithSuccess); RuntimeIteration *parentIteration = container->parentIteration(); RuntimeTask *parentTask = container->m_parentTask; QT_CHECK(parentTask); const bool result = invokeDoneHandler(container, bit ? DoneWith::Success : DoneWith::Error); + container->m_setupResult = toSetupResult(result); if (parentIteration) { parentIteration->deleteChild(parentTask); if (!parentIteration->m_container->isStarting()) @@ -2220,7 +2221,6 @@ SetupResult TaskTreePrivate::continueContainer(RuntimeContainer *container) m_runtimeRoot.reset(); emitDone(result ? DoneWith::Success : DoneWith::Error); } - return toSetupResult(result); } void TaskTreePrivate::startChildren(RuntimeContainer *container) @@ -2334,8 +2334,6 @@ bool TaskTreePrivate::invokeDoneHandler(RuntimeContainer *container, DoneWith do if (groupHandler.m_doneHandler && shouldCall(groupHandler.m_callDoneIf, doneWith)) result = invokeHandler(container, groupHandler.m_doneHandler, doneWith); container->m_callStorageDoneHandlersOnDestruction = true; - // TODO: is it needed? - container->m_parentTask->m_container.reset(); return result == DoneResult::Success; } @@ -2357,18 +2355,19 @@ SetupResult TaskTreePrivate::startTask(RuntimeTask *node) { if (!node->m_taskNode.isTask()) { const ContainerNode &containerNode = node->m_taskNode.m_container; - node->m_container.emplace(containerNode, node); - RuntimeContainer *container = &*node->m_container; + node->m_container.reset(new RuntimeContainer(containerNode, node)); + auto container = node->m_container; if (containerNode.m_groupHandler.m_setupHandler) { - container->m_setupResult = invokeHandler(container, containerNode.m_groupHandler.m_setupHandler); + container->m_setupResult = invokeHandler(container.get(), containerNode.m_groupHandler.m_setupHandler); if (container->m_setupResult != SetupResult::Continue) { - if (isProgressive(container)) + if (isProgressive(container.get())) advanceProgress(containerNode.m_taskCount); // Non-Continue SetupResult takes precedence over the workflow policy. container->m_successBit = container->m_setupResult == SetupResult::StopWithSuccess; } } - return continueContainer(container); + continueContainer(container.get()); + return container->m_setupResult; } const GroupItem::TaskHandler &handler = node->m_taskNode.m_taskHandler; From efee9d0be7650b3da5dcbf81e5abe572b840ce59 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 10 Oct 2024 18:44:57 +0200 Subject: [PATCH 086/989] TaskTree: Internal refactorings part 4 Remove return values from startTask() and introduce RuntimeTask::m_setupResult field instead. Change-Id: I2bc12795d4c7ea5b17826d16d01de8bdd69217db Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 61 ++++++++++++------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index a094d0c64ab..aa83c5f1d43 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1860,7 +1860,7 @@ public: // If returned value != Continue, childDone() needs to be called in parent container (in caller) // in order to unwind properly. - SetupResult startTask(RuntimeTask *node); + void startTask(const std::shared_ptr &node); void stopTask(RuntimeTask *node); bool invokeTaskDoneHandler(RuntimeTask *node, DoneWith doneWith); @@ -1904,7 +1904,7 @@ public: QSet m_storages; QHash m_storageHandlers; std::optional m_root; - std::unique_ptr m_runtimeRoot; // Keep me last in order to destruct first + std::shared_ptr m_runtimeRoot; // Keep me last in order to destruct first }; static bool initialSuccessBit(WorkflowPolicy workflowPolicy) @@ -1939,7 +1939,7 @@ public: const bool m_isProgressive = true; RuntimeContainer *m_container = nullptr; int m_doneCount = 0; - std::vector> m_children = {}; // Owning. + std::vector> m_children = {}; // Owning. }; class RuntimeContainer @@ -1999,8 +1999,7 @@ public: { if (m_task) { // Ensures the running task's d'tor doesn't emit done() signal. QTCREATORBUG-30204. - QObject::disconnect(m_task.get(), &TaskInterface::done, - m_taskNode.m_container.m_taskTreePrivate->q, nullptr); + QObject::disconnect(m_task.get(), &TaskInterface::done, nullptr, nullptr); } } @@ -2008,6 +2007,7 @@ public: RuntimeIteration *m_parentIteration = nullptr; // Not owning. std::shared_ptr m_container = {}; // Owning. std::unique_ptr m_task = {}; // Owning. + SetupResult m_setupResult = SetupResult::Continue; }; static bool isProgressive(RuntimeContainer *container) @@ -2070,7 +2070,7 @@ void TaskTreePrivate::start() "exist in task tree. Its handlers will never be called.")); } m_runtimeRoot.reset(new RuntimeTask{*m_root}); - startTask(m_runtimeRoot.get()); + startTask(m_runtimeRoot); bumpAsyncCount(); } @@ -2212,6 +2212,7 @@ void TaskTreePrivate::continueContainer(RuntimeContainer *container) QT_CHECK(parentTask); const bool result = invokeDoneHandler(container, bit ? DoneWith::Success : DoneWith::Error); container->m_setupResult = toSetupResult(result); + container->m_parentTask->m_setupResult = container->m_setupResult; if (parentIteration) { parentIteration->deleteChild(parentTask); if (!parentIteration->m_container->isStarting()) @@ -2262,17 +2263,17 @@ void TaskTreePrivate::startChildren(RuntimeContainer *container) continue; RuntimeIteration *iteration = container->m_iterations.back().get(); - RuntimeTask *newTask = new RuntimeTask{containerNode.m_children.at(container->m_nextToStart), - iteration}; - iteration->m_children.emplace_back(newTask); + const std::shared_ptr task( + new RuntimeTask{containerNode.m_children.at(container->m_nextToStart), iteration}); + iteration->m_children.emplace_back(task); ++container->m_runningChildren; ++container->m_nextToStart; - const SetupResult startAction = startTask(newTask); - if (startAction == SetupResult::Continue) + startTask(task); + if (task->m_setupResult == SetupResult::Continue) continue; - childDone(iteration, startAction == SetupResult::StopWithSuccess); + childDone(iteration, task->m_setupResult == SetupResult::StopWithSuccess); if (container->m_setupResult != SetupResult::Continue) return; } @@ -2351,11 +2352,11 @@ bool TaskTreePrivate::invokeLoopHandler(RuntimeContainer *container) return container->m_shouldIterate; } -SetupResult TaskTreePrivate::startTask(RuntimeTask *node) +void TaskTreePrivate::startTask(const std::shared_ptr &node) { if (!node->m_taskNode.isTask()) { const ContainerNode &containerNode = node->m_taskNode.m_container; - node->m_container.reset(new RuntimeContainer(containerNode, node)); + node->m_container.reset(new RuntimeContainer(containerNode, node.get())); auto container = node->m_container; if (containerNode.m_groupHandler.m_setupHandler) { container->m_setupResult = invokeHandler(container.get(), containerNode.m_groupHandler.m_setupHandler); @@ -2367,39 +2368,35 @@ SetupResult TaskTreePrivate::startTask(RuntimeTask *node) } } continueContainer(container.get()); - return container->m_setupResult; + return; } const GroupItem::TaskHandler &handler = node->m_taskNode.m_taskHandler; node->m_task.reset(handler.m_createHandler()); - const SetupResult startAction = handler.m_setupHandler + node->m_setupResult = handler.m_setupHandler ? invokeHandler(node->m_parentIteration, handler.m_setupHandler, *node->m_task.get()) : SetupResult::Continue; - if (startAction != SetupResult::Continue) { + if (node->m_setupResult != SetupResult::Continue) { if (node->m_parentIteration->m_isProgressive) advanceProgress(1); - node->m_parentIteration->deleteChild(node); - return startAction; + node->m_parentIteration->deleteChild(node.get()); + return; } - const std::shared_ptr unwindAction - = std::make_shared(SetupResult::Continue); QObject::connect(node->m_task.get(), &TaskInterface::done, - q, [this, node, unwindAction](DoneResult doneResult) { - const bool result = invokeTaskDoneHandler(node, toDoneWith(doneResult)); + q, [this, node](DoneResult doneResult) { + const bool result = invokeTaskDoneHandler(node.get(), toDoneWith(doneResult)); + node->m_setupResult = toSetupResult(result); QObject::disconnect(node->m_task.get(), &TaskInterface::done, q, nullptr); node->m_task.release()->deleteLater(); RuntimeIteration *parentIteration = node->m_parentIteration; - parentIteration->deleteChild(node); - if (parentIteration->m_container->isStarting()) { - *unwindAction = toSetupResult(result); - } else { - childDone(parentIteration, result); - bumpAsyncCount(); - } - }); + if (parentIteration->m_container->isStarting()) + return; + parentIteration->deleteChild(node.get()); + childDone(parentIteration, result); + bumpAsyncCount(); + }); node->m_task->start(); - return *unwindAction; } void TaskTreePrivate::stopTask(RuntimeTask *node) From 84b823fd48052f153d79cfa1257b727a351e65b8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 8 Nov 2024 16:12:39 +0100 Subject: [PATCH 087/989] TaskTree: Internal refactorings part 5 Bring back the optional for runtime container. This is a continuation of part 3 from the refactoring patch series. Change-Id: Ia65bdc2c13aadfbeb89d1a367cf640f2ce5be1ad Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index aa83c5f1d43..764ec78a201 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -2005,7 +2005,7 @@ public: const TaskNode &m_taskNode; // Not owning. RuntimeIteration *m_parentIteration = nullptr; // Not owning. - std::shared_ptr m_container = {}; // Owning. + std::optional m_container = {}; // Owning. std::unique_ptr m_task = {}; // Owning. SetupResult m_setupResult = SetupResult::Continue; }; @@ -2356,18 +2356,18 @@ void TaskTreePrivate::startTask(const std::shared_ptr &node) { if (!node->m_taskNode.isTask()) { const ContainerNode &containerNode = node->m_taskNode.m_container; - node->m_container.reset(new RuntimeContainer(containerNode, node.get())); - auto container = node->m_container; + node->m_container.emplace(containerNode, node.get()); + RuntimeContainer *container = &*node->m_container; if (containerNode.m_groupHandler.m_setupHandler) { - container->m_setupResult = invokeHandler(container.get(), containerNode.m_groupHandler.m_setupHandler); + container->m_setupResult = invokeHandler(container, containerNode.m_groupHandler.m_setupHandler); if (container->m_setupResult != SetupResult::Continue) { - if (isProgressive(container.get())) + if (isProgressive(container)) advanceProgress(containerNode.m_taskCount); // Non-Continue SetupResult takes precedence over the workflow policy. container->m_successBit = container->m_setupResult == SetupResult::StopWithSuccess; } } - continueContainer(container.get()); + continueContainer(container); return; } From f3e942314b507377f6ddf20cf8c31e40e75f400f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 9 Nov 2024 08:54:36 +0100 Subject: [PATCH 088/989] TaskTree: Internal refactorings part 6 Get rid of RuntimeContainer::m_setupResult field. Reuse the one from parent task instead. Change-Id: Ic431915098e20f358a0365cf4b65e6c8a4d88b82 Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 764ec78a201..02340d6fc80 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1989,7 +1989,6 @@ public: int m_runningChildren = 0; bool m_shouldIterate = true; std::vector> m_iterations; // Owning. - SetupResult m_setupResult = SetupResult::Continue; }; class RuntimeTask @@ -2201,18 +2200,17 @@ void RuntimeContainer::deleteFinishedIterations() void TaskTreePrivate::continueContainer(RuntimeContainer *container) { - if (container->m_setupResult == SetupResult::Continue) + if (container->m_parentTask->m_setupResult == SetupResult::Continue) startChildren(container); - if (container->m_setupResult == SetupResult::Continue) + if (container->m_parentTask->m_setupResult == SetupResult::Continue) return; - const bool bit = container->updateSuccessBit(container->m_setupResult == SetupResult::StopWithSuccess); + const bool bit = container->updateSuccessBit(container->m_parentTask->m_setupResult == SetupResult::StopWithSuccess); RuntimeIteration *parentIteration = container->parentIteration(); RuntimeTask *parentTask = container->m_parentTask; QT_CHECK(parentTask); const bool result = invokeDoneHandler(container, bit ? DoneWith::Success : DoneWith::Error); - container->m_setupResult = toSetupResult(result); - container->m_parentTask->m_setupResult = container->m_setupResult; + container->m_parentTask->m_setupResult = toSetupResult(result); if (parentIteration) { parentIteration->deleteChild(parentTask); if (!parentIteration->m_container->isStarting()) @@ -2233,7 +2231,7 @@ void TaskTreePrivate::startChildren(RuntimeContainer *container) if (container->m_shouldIterate && !invokeLoopHandler(container)) { if (isProgressive(container)) advanceProgress(containerNode.m_taskCount); - container->m_setupResult = toSetupResult(container->m_successBit); + container->m_parentTask->m_setupResult = toSetupResult(container->m_successBit); return; } container->m_iterations.emplace_back( @@ -2253,7 +2251,7 @@ void TaskTreePrivate::startChildren(RuntimeContainer *container) std::make_unique(container->m_iterationCount, container)); ++container->m_iterationCount; } else if (container->m_iterations.empty()) { - container->m_setupResult = toSetupResult(container->m_successBit); + container->m_parentTask->m_setupResult = toSetupResult(container->m_successBit); return; } else { return; @@ -2274,7 +2272,7 @@ void TaskTreePrivate::startChildren(RuntimeContainer *container) continue; childDone(iteration, task->m_setupResult == SetupResult::StopWithSuccess); - if (container->m_setupResult != SetupResult::Continue) + if (container->m_parentTask->m_setupResult != SetupResult::Continue) return; } } @@ -2289,7 +2287,7 @@ void TaskTreePrivate::childDone(RuntimeIteration *iteration, bool success) ++iteration->m_doneCount; --container->m_runningChildren; const bool updatedSuccess = container->updateSuccessBit(success); - container->m_setupResult = shouldStop ? toSetupResult(updatedSuccess) : SetupResult::Continue; + container->m_parentTask->m_setupResult = shouldStop ? toSetupResult(updatedSuccess) : SetupResult::Continue; if (shouldStop) stopContainer(container); @@ -2359,12 +2357,12 @@ void TaskTreePrivate::startTask(const std::shared_ptr &node) node->m_container.emplace(containerNode, node.get()); RuntimeContainer *container = &*node->m_container; if (containerNode.m_groupHandler.m_setupHandler) { - container->m_setupResult = invokeHandler(container, containerNode.m_groupHandler.m_setupHandler); - if (container->m_setupResult != SetupResult::Continue) { + container->m_parentTask->m_setupResult = invokeHandler(container, containerNode.m_groupHandler.m_setupHandler); + if (container->m_parentTask->m_setupResult != SetupResult::Continue) { if (isProgressive(container)) advanceProgress(containerNode.m_taskCount); // Non-Continue SetupResult takes precedence over the workflow policy. - container->m_successBit = container->m_setupResult == SetupResult::StopWithSuccess; + container->m_successBit = container->m_parentTask->m_setupResult == SetupResult::StopWithSuccess; } } continueContainer(container); From ccddb7ab585b71bbf1b47e3dbc2a3d6b177f6b50 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 8 Nov 2024 12:17:38 +0100 Subject: [PATCH 089/989] Move applicable settings pages into the new "SDKs" category "Devices" was never the right place for them, and now we have a proper location. Change-Id: I3c74d7f5a8bc06e058c91a17c88b6cb4bb91da89 Reviewed-by: hjk --- doc/qtcreator/src/android/androiddev.qdoc | 6 +++--- doc/qtcreator/src/mcu/creator-mcu-dev.qdoc | 6 +++--- doc/qtcreator/src/qnx/creator-developing-qnx.qdoc | 2 +- doc/qtcreator/src/webassembly/creator-webassembly.qdoc | 2 +- src/plugins/android/androidsettingswidget.cpp | 4 +++- src/plugins/mcusupport/mcusupportoptionspage.cpp | 4 +++- src/plugins/qnx/qnxsettingspage.cpp | 4 +++- src/plugins/webassembly/webassemblysettings.cpp | 4 +++- 8 files changed, 20 insertions(+), 12 deletions(-) diff --git a/doc/qtcreator/src/android/androiddev.qdoc b/doc/qtcreator/src/android/androiddev.qdoc index 42bf54b8b44..9be6e430eaf 100644 --- a/doc/qtcreator/src/android/androiddev.qdoc +++ b/doc/qtcreator/src/android/androiddev.qdoc @@ -69,7 +69,7 @@ To set up the development environment for Android: \list 1 - \li Go to \preferences > \uicontrol Devices > \uicontrol Android. + \li Go to \preferences > \uicontrol SDKs > \uicontrol Android. \image qtcreator-preferences-android.webp {Android preferences} \li In \uicontrol {JDK location}, set the path to the JDK. \QC checks the JDK installation and reports errors. @@ -161,7 +161,7 @@ \title Manage Android NDK packages To view the \l{Android NDK} versions that \QC installed, go to \preferences > - \uicontrol Devices > \uicontrol Android. + \uicontrol SDKs > \uicontrol Android. \image qtcreator-preferences-android.webp {Android preferences} @@ -205,7 +205,7 @@ \c sdkmanager for advanced SDK management. To view the installed Android SDK packages, select \preferences > - \uicontrol Devices > \uicontrol Android > \uicontrol {SDK Manager}. + \uicontrol SDKs > \uicontrol Android > \uicontrol {SDK Manager}. \image qtcreator-android-sdk-manager.webp {Android SDK Manager} diff --git a/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc b/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc index f49e375f617..84a865b5bed 100644 --- a/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc +++ b/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc @@ -108,7 +108,7 @@ To configure a connection between \QC and your MCU board: \list 1 - \li Go to \preferences > \uicontrol Devices > \uicontrol MCU. + \li Go to \preferences > \uicontrol SDKs > \uicontrol MCU. \li In \uicontrol {\QMCU SDK}, specify the path to the directory where you installed \QMCU SDK. \image qtcreator-preferences-mcu.webp {MCU preferences} @@ -189,7 +189,7 @@ \QC automatically adds kits for all the available MCU targets if you select \uicontrol {Automatically create kits for all available targets on start} - in \preferences > \uicontrol Devices > \uicontrol MCU. + in \preferences > \uicontrol SDKs > \uicontrol MCU. \image qtcreator-preferences-kits-mcu.webp {MCU kit} @@ -197,7 +197,7 @@ the existing kits or create additional kits. To do this manually for each target, select \uicontrol {Update Kit} or \uicontrol {Create Kit}. - To add new kits, go to \preferences > \uicontrol Devices > \uicontrol MCU, + To add new kits, go to \preferences > \uicontrol SDKs > \uicontrol MCU, and select \uicontrol {Create Kit}. This adds the paths to the kit's toolkits and SDKs, and keeps them synchronized when you select \uicontrol Apply or \uicontrol OK. diff --git a/doc/qtcreator/src/qnx/creator-developing-qnx.qdoc b/doc/qtcreator/src/qnx/creator-developing-qnx.qdoc index f6990187c3d..0696fd94e15 100644 --- a/doc/qtcreator/src/qnx/creator-developing-qnx.qdoc +++ b/doc/qtcreator/src/qnx/creator-developing-qnx.qdoc @@ -40,7 +40,7 @@ \uicontrol {Start Wizard} to add a QNX Neutrino device. \li Select \uicontrol Apply to fetch the information needed for creating kits. - \li Go to \preferences > \uicontrol Devices > \uicontrol QNX. + \li Go to \preferences > \uicontrol SDKs > \uicontrol QNX. \li Select \uicontrol {Create Kit} to create a kit for a particular platform. \image qtcreator-preferences-qnx.webp {QNX Preferences} diff --git a/doc/qtcreator/src/webassembly/creator-webassembly.qdoc b/doc/qtcreator/src/webassembly/creator-webassembly.qdoc index 37526abe87d..9fbc5504c79 100644 --- a/doc/qtcreator/src/webassembly/creator-webassembly.qdoc +++ b/doc/qtcreator/src/webassembly/creator-webassembly.qdoc @@ -28,7 +28,7 @@ To set up the development environment for WebAssembly: \list 1 - \li Go to \preferences > \uicontrol Devices > \uicontrol WebAssembly. + \li Go to \preferences > \uicontrol SDKs > \uicontrol WebAssembly. \li In \uicontrol {Emscripten SDK path}, enter the root directory where you installed \c emsdk. \li \QC configures the \uicontrol {Emscripten SDK environment} for you diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index ded9916f4de..080c6d4b379 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -845,7 +845,9 @@ public: { setId(Constants::ANDROID_SETTINGS_ID); setDisplayName(Tr::tr("Android")); - setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); + setCategory(ProjectExplorer::Constants::SDK_SETTINGS_CATEGORY); + setDisplayCategory(Tr::tr("SDKs")); + setCategoryIconPath(":/projectexplorer/images/sdk.png"); setWidgetCreator([] { return new AndroidSettingsWidget; }); } }; diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index d2269a40b51..6e595d62ff2 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -371,7 +371,9 @@ McuSupportOptionsPage::McuSupportOptionsPage(McuSupportOptions &options, { setId(Utils::Id(Constants::SETTINGS_ID)); setDisplayName(Tr::tr("MCU")); - setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); + setCategory(ProjectExplorer::Constants::SDK_SETTINGS_CATEGORY); + setDisplayCategory(Tr::tr("SDKs")); + setCategoryIconPath(":/projectexplorer/images/sdk.png"); setWidgetCreator([&options, &settingsHandler] { return new McuSupportOptionsWidget(options, settingsHandler); }); diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 50aa8f5bc0c..a96ff7d8a1d 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -744,7 +744,9 @@ QnxSettingsPage::QnxSettingsPage(QObject *guard) { setId("DD.Qnx Configuration"); setDisplayName(Tr::tr("QNX")); - setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); + setCategory(ProjectExplorer::Constants::SDK_SETTINGS_CATEGORY); + setDisplayCategory(Tr::tr("SDKs")); + setCategoryIconPath(":/projectexplorer/images/sdk.png"); setWidgetCreator([] { return new QnxSettingsWidget; }); connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, diff --git a/src/plugins/webassembly/webassemblysettings.cpp b/src/plugins/webassembly/webassemblysettings.cpp index 465d7812a84..aa2554bc9c1 100644 --- a/src/plugins/webassembly/webassemblysettings.cpp +++ b/src/plugins/webassembly/webassemblysettings.cpp @@ -207,7 +207,9 @@ public: { setId(Id(Constants::SETTINGS_ID)); setDisplayName(Tr::tr("WebAssembly")); - setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); + setCategory(ProjectExplorer::Constants::SDK_SETTINGS_CATEGORY); + setDisplayCategory(Tr::tr("SDKs")); + setCategoryIconPath(":/projectexplorer/images/sdk.png"); setSettingsProvider([] { return &settings(); }); } }; From 6527738441adc4fd26fb0c7d48751d74842a7717 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 5 Nov 2024 16:31:42 +0100 Subject: [PATCH 090/989] LanguageClient: Change toMap() signature of settings classes ... from 'Store toMap() const' to 'voud toMap(Store &map)' to make it more similar to AspectContainers. Change-Id: Ia8a10d97513b54321c0bac5caa76b7a589394a78 Reviewed-by: David Schulz --- src/plugins/android/javalanguageserver.cpp | 5 ++--- src/plugins/android/javalanguageserver.h | 2 +- .../languageclient/languageclientsettings.cpp | 13 ++++++------- src/plugins/languageclient/languageclientsettings.h | 5 +++-- .../lualanguageclient/lualanguageclient.cpp | 9 ++++----- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/plugins/android/javalanguageserver.cpp b/src/plugins/android/javalanguageserver.cpp index c4bfd9bfd6d..e0117b3b3c9 100644 --- a/src/plugins/android/javalanguageserver.cpp +++ b/src/plugins/android/javalanguageserver.cpp @@ -137,11 +137,10 @@ bool JLSSettings::isValid() const return StdIOSettings::isValid() && !m_languageServer.isEmpty(); } -Store JLSSettings::toMap() const +void JLSSettings::toMap(Store &map) const { - Store map = StdIOSettings::toMap(); + StdIOSettings::toMap(map); map.insert(languageServerKey, m_languageServer.toSettings()); - return map; } void JLSSettings::fromMap(const Store &map) diff --git a/src/plugins/android/javalanguageserver.h b/src/plugins/android/javalanguageserver.h index a8d00ffcee5..e170eb254a5 100644 --- a/src/plugins/android/javalanguageserver.h +++ b/src/plugins/android/javalanguageserver.h @@ -16,7 +16,7 @@ public: bool applyFromSettingsWidget(QWidget *widget) final; QWidget *createSettingsWidget(QWidget *parent) const final; bool isValid() const final; - Utils::Store toMap() const final; + void toMap(Utils::Store &map) const final; void fromMap(const Utils::Store &map) final; LanguageClient::BaseSettings *copy() const final; LanguageClient::Client *createClient(LanguageClient::BaseClientInterface *interface) const final; diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 00862786976..361da8cd86e 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -615,9 +615,8 @@ Client *BaseSettings::createClient(BaseClientInterface *interface) const return new Client(interface); } -Store BaseSettings::toMap() const +void BaseSettings::toMap(Store &map) const { - Store map; map.insert(typeIdKey, m_settingsTypeId.toSetting()); map.insert(nameKey, m_name); map.insert(idKey, m_id); @@ -627,7 +626,6 @@ Store BaseSettings::toMap() const map.insert(filePatternKey, m_languageFilter.filePattern); map.insert(initializationOptionsKey, m_initializationOptions); map.insert(configurationKey, m_configuration); - return map; } void BaseSettings::fromMap(const Store &map) @@ -732,7 +730,9 @@ void LanguageClientSettings::toSettings(QtcSettings *settings, settings->beginGroup(settingsGroupKey); auto transform = [](const QList &settings) { return Utils::transform(settings, [](const BaseSettings *setting) { - return variantFromStore(setting->toMap()); + Store store; + setting->toMap(store); + return variantFromStore(store); }); }; auto isStdioSetting = Utils::equal(&BaseSettings::m_settingsTypeId, @@ -800,12 +800,11 @@ bool StdIOSettings::isValid() const return BaseSettings::isValid() && !m_executable.isEmpty(); } -Store StdIOSettings::toMap() const +void StdIOSettings::toMap(Store &map) const { - Store map = BaseSettings::toMap(); + BaseSettings::toMap(map); map.insert(executableKey, m_executable.toSettings()); map.insert(argumentsKey, m_arguments); - return map; } void StdIOSettings::fromMap(const Store &map) diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index f1d14b4bcd8..4d2cd757c01 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -82,7 +82,8 @@ public: virtual bool isValid() const; Client *createClient() const; Client *createClient(ProjectExplorer::Project *project) const; - virtual Utils::Store toMap() const; + + virtual void toMap(Utils::Store &map) const; virtual void fromMap(const Utils::Store &map); protected: @@ -108,7 +109,7 @@ public: QWidget *createSettingsWidget(QWidget *parent = nullptr) const override; BaseSettings *copy() const override { return new StdIOSettings(*this); } bool isValid() const override; - Utils::Store toMap() const override; + void toMap(Utils::Store &map) const override; void fromMap(const Utils::Store &map) override; QString arguments() const; Utils::CommandLine command() const; diff --git a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp index a4c56154f1d..28efc40fb95 100644 --- a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp +++ b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp @@ -189,7 +189,7 @@ public: bool applyFromSettingsWidget(QWidget *widget) override; - Utils::Store toMap() const override; + void toMap(Utils::Store &map) const override; void fromMap(const Utils::Store &map) override; QWidget *createSettingsWidget(QWidget *parent = nullptr) const override; @@ -632,15 +632,14 @@ bool LuaClientSettings::applyFromSettingsWidget(QWidget *widget) return true; } -Utils::Store LuaClientSettings::toMap() const +void LuaClientSettings::toMap(Store &store) const { - auto store = BaseSettings::toMap(); + BaseSettings::toMap(store); if (auto w = m_wrapper.lock()) w->toMap(store); - return store; } -void LuaClientSettings::fromMap(const Utils::Store &map) +void LuaClientSettings::fromMap(const Store &map) { BaseSettings::fromMap(map); if (auto w = m_wrapper.lock()) { From 7df1b1329d8f457c09c832bd2ed6fca41899d19c Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 8 Nov 2024 16:25:23 +0100 Subject: [PATCH 091/989] ProjectExplorer: Rename windowssettingswidget.{cpp,h} ... to windowappsdksettings.{h,cpp}. Plan is to merge with the windowsconfiguration.* files. Change-Id: Ie7752f5b9bfacb03bd23f0632525ba9d8decd0f7 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/CMakeLists.txt | 2 +- src/plugins/projectexplorer/projectexplorer.cpp | 4 ++-- src/plugins/projectexplorer/projectexplorer.qbs | 2 +- .../{windowssettingswidget.cpp => windowsappsdksettings.cpp} | 4 ++-- .../{windowssettingswidget.h => windowsappsdksettings.h} | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename src/plugins/projectexplorer/{windowssettingswidget.cpp => windowsappsdksettings.cpp} (99%) rename src/plugins/projectexplorer/{windowssettingswidget.h => windowsappsdksettings.h} (85%) diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index 8a363d6d42b..d45a7081def 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -186,7 +186,7 @@ add_qtc_plugin(ProjectExplorer workspaceproject.h workspaceproject.cpp xcodebuildparser.cpp xcodebuildparser.h windowsconfigurations.cpp windowsconfigurations.h - windowssettingswidget.cpp windowssettingswidget.h + windowsappsdksettings.cpp windowsappsdksettings.h ) if (TARGET clangd) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 337feee6fef..443639aa56e 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -80,8 +80,8 @@ #include "toolchainmanager.h" #include "toolchainoptionspage.h" #include "vcsannotatetaskhandler.h" +#include "windowsappsdksettings.h" #include "windowsconfigurations.h" -#include "windowssettingswidget.h" #include "workspaceproject.h" #ifdef Q_OS_WIN @@ -819,7 +819,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er setupCustomToolchain(); setupWindowsConfigurations(); if (HostOsInfo::isWindowsHost()) - setupWindowsSettingsPage(); + setupWindowsAppSdkSettingsPage(); setupProjectTreeWidgetFactory(); diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 516190cb1c4..dc8cd16582d 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -159,7 +159,7 @@ QtcPlugin { "workspaceproject.cpp", "workspaceproject.h", "xcodebuildparser.cpp", "xcodebuildparser.h", "windowsconfigurations.cpp", "windowsconfigurations.h", - "windowssettingswidget.cpp", "windowssettingswidget.h", + "windowsappsdksettings.cpp", "windowsappsdksettings.h", ] } diff --git a/src/plugins/projectexplorer/windowssettingswidget.cpp b/src/plugins/projectexplorer/windowsappsdksettings.cpp similarity index 99% rename from src/plugins/projectexplorer/windowssettingswidget.cpp rename to src/plugins/projectexplorer/windowsappsdksettings.cpp index 1f5ddabff7c..050ccdac623 100644 --- a/src/plugins/projectexplorer/windowssettingswidget.cpp +++ b/src/plugins/projectexplorer/windowsappsdksettings.cpp @@ -1,7 +1,7 @@ // 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 "windowssettingswidget.h" +#include "windowsappsdksettings.h" #include #include @@ -617,7 +617,7 @@ public: } }; -void setupWindowsSettingsPage() +void setupWindowsAppSdkSettingsPage() { static WindowsSettingsPage theWindowsSettingsPage; } diff --git a/src/plugins/projectexplorer/windowssettingswidget.h b/src/plugins/projectexplorer/windowsappsdksettings.h similarity index 85% rename from src/plugins/projectexplorer/windowssettingswidget.h rename to src/plugins/projectexplorer/windowsappsdksettings.h index bb62398d4a9..fdc15df8d83 100644 --- a/src/plugins/projectexplorer/windowssettingswidget.h +++ b/src/plugins/projectexplorer/windowsappsdksettings.h @@ -5,6 +5,6 @@ namespace ProjectExplorer::Internal { -void setupWindowsSettingsPage(); +void setupWindowsAppSdkSettingsPage(); } // namespace ProjectExplorer::Internal From 282a366eb87932244d44db9e36a60a061e4213bf Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Nov 2024 11:03:12 +0100 Subject: [PATCH 092/989] Android: Simplify #include on androidmanager.cpp Change-Id: I7f8d8d3b2e705fe1996ec8276ab0b26f678f9f97 Reviewed-by: Jarek Kobus --- src/plugins/android/androidmanager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index f11eb0b1e89..02e95f1413f 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -3,10 +3,9 @@ #include "androidmanager.h" -#include "androidavdmanager.h" #include "androidbuildapkstep.h" +#include "androidconfigurations.h" #include "androidconstants.h" -#include "androiddevice.h" #include "androidqtversion.h" #include "androidtr.h" From 34667b644a26f36a892f834f35c6d4e644c6a61e Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 8 Nov 2024 16:25:23 +0100 Subject: [PATCH 093/989] ProjectExplorer: Merge windowsconfigurations.{cpp,h} ... into windowsappsdksettings.{cpp,h} and rename WindowsConfigurations to WindowsAppSdkSettings. Change-Id: I35a6f1da7bde88f625d237c90de89c7fe05d9ca5 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/CMakeLists.txt | 3 +- .../devicesupport/devicekitaspects.cpp | 4 +- .../projectexplorer/projectexplorer.cpp | 5 +- .../projectexplorer/projectexplorer.qbs | 1 - .../projectexplorer/windowsappsdksettings.cpp | 53 ++++++++++++++----- .../projectexplorer/windowsappsdksettings.h | 17 +++++- .../projectexplorer/windowsconfigurations.cpp | 48 ----------------- .../projectexplorer/windowsconfigurations.h | 33 ------------ 8 files changed, 60 insertions(+), 104 deletions(-) delete mode 100644 src/plugins/projectexplorer/windowsconfigurations.cpp delete mode 100644 src/plugins/projectexplorer/windowsconfigurations.h diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index d45a7081def..5ee0019a6b6 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -183,10 +183,9 @@ add_qtc_plugin(ProjectExplorer vcsannotatetaskhandler.cpp vcsannotatetaskhandler.h waitforstopdialog.cpp waitforstopdialog.h windebuginterface.cpp windebuginterface.h + windowsappsdksettings.cpp windowsappsdksettings.h workspaceproject.h workspaceproject.cpp xcodebuildparser.cpp xcodebuildparser.h - windowsconfigurations.cpp windowsconfigurations.h - windowsappsdksettings.cpp windowsappsdksettings.h ) if (TARGET clangd) diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index e7b949e81aa..13ff4d83abf 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -13,7 +13,7 @@ #include "../projectexplorerconstants.h" #include "../projectexplorertr.h" #include "../toolchainkitaspect.h" -#include "../windowsconfigurations.h" +#include "../windowsappsdksettings.h" #include #include @@ -540,7 +540,7 @@ void BuildDeviceKitAspectFactory::addToBuildEnvironment(const Kit *k, Environmen { IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k); if (dev->osType() == OsType::OsTypeWindows && dev->type() == Constants::DESKTOP_DEVICE_TYPE) { - if (const FilePath appSdkLocation = windowsConfigurations().windowsAppSdkLocation(); + if (const FilePath appSdkLocation = windowsAppSdkSettings().windowsAppSdkLocation(); !appSdkLocation.isEmpty()) { env.set(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY, appSdkLocation.path()); } diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 443639aa56e..4206743e0aa 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -81,7 +81,6 @@ #include "toolchainoptionspage.h" #include "vcsannotatetaskhandler.h" #include "windowsappsdksettings.h" -#include "windowsconfigurations.h" #include "workspaceproject.h" #ifdef Q_OS_WIN @@ -817,9 +816,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er setupMsvcToolchain(); setupClangClToolchain(); setupCustomToolchain(); - setupWindowsConfigurations(); - if (HostOsInfo::isWindowsHost()) - setupWindowsAppSdkSettingsPage(); + setupWindowsAppSdkSettings(); setupProjectTreeWidgetFactory(); diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index dc8cd16582d..dc2547cf1f9 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -158,7 +158,6 @@ QtcPlugin { "windebuginterface.cpp", "windebuginterface.h", "workspaceproject.cpp", "workspaceproject.h", "xcodebuildparser.cpp", "xcodebuildparser.h", - "windowsconfigurations.cpp", "windowsconfigurations.h", "windowsappsdksettings.cpp", "windowsappsdksettings.h", ] } diff --git a/src/plugins/projectexplorer/windowsappsdksettings.cpp b/src/plugins/projectexplorer/windowsappsdksettings.cpp index 050ccdac623..d14180f9855 100644 --- a/src/plugins/projectexplorer/windowsappsdksettings.cpp +++ b/src/plugins/projectexplorer/windowsappsdksettings.cpp @@ -3,19 +3,19 @@ #include "windowsappsdksettings.h" +#include "projectexplorerconstants.h" +#include "projectexplorertr.h" + #include #include #include -#include "projectexplorerconstants.h" -#include "projectexplorertr.h" -#include "windowsconfigurations.h" - #include #include #include #include +#include #include #include #include @@ -52,6 +52,28 @@ namespace ProjectExplorer::Internal { static Q_LOGGING_CATEGORY(windowssettingswidget, "qtc.windows.windowssettingswidget", QtWarningMsg); +WindowsAppSdkSettings &windowsAppSdkSettings() +{ + static WindowsAppSdkSettings theWindowsConfigurations; + return theWindowsConfigurations; +} + +WindowsAppSdkSettings::WindowsAppSdkSettings() +{ + setSettingsGroup("WindowsConfigurations"); + + downloadLocation.setSettingsKey("DownloadLocation"); + nugetLocation.setSettingsKey("NugetLocation"); + windowsAppSdkLocation.setSettingsKey("WindowsAppSDKLocation"); + + AspectContainer::readSettings(); + + if (windowsAppSdkLocation().isEmpty()) { + windowsAppSdkLocation.setValue(FilePath::fromUserInput( + Environment::systemEnvironment().value(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY))); + } +} + static bool isHttpRedirect(QNetworkReply *reply) { const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -219,13 +241,13 @@ WindowsSettingsWidget::WindowsSettingsWidget() m_downloadPathChooser->setToolTip(Tr::tr("Select the path of downloads.")); m_downloadPathChooser->setPromptDialogTitle(Tr::tr("Select download path")); m_downloadPathChooser->setExpectedKind(PathChooser::ExistingDirectory); - m_downloadPathChooser->setFilePath(windowsConfigurations().downloadLocation()); + m_downloadPathChooser->setFilePath(windowsAppSdkSettings().downloadLocation()); m_nugetPathChooser = new PathChooser; m_nugetPathChooser->setToolTip(Tr::tr("Select the path of the Nuget.")); m_nugetPathChooser->setPromptDialogTitle(Tr::tr("Select nuget.exe file")); m_nugetPathChooser->setExpectedKind(PathChooser::Any); - m_nugetPathChooser->setFilePath(windowsConfigurations().nugetLocation()); + m_nugetPathChooser->setFilePath(windowsAppSdkSettings().nugetLocation()); auto downloadNuget = new QPushButton(Tr::tr("Download Nuget")); downloadNuget->setToolTip( @@ -252,7 +274,7 @@ WindowsSettingsWidget::WindowsSettingsWidget() winAppSdkDetailsWidget); m_winAppSdkPathChooser->setPromptDialogTitle(Tr::tr("Select Windows App SDK Path")); - WindowsConfigurations &settings = windowsConfigurations(); + WindowsAppSdkSettings &settings = windowsAppSdkSettings(); if (settings.windowsAppSdkLocation().isEmpty()) settings.windowsAppSdkLocation.setValue(settings.downloadLocation()); m_winAppSdkPathChooser->setFilePath(settings.windowsAppSdkLocation()); @@ -316,7 +338,7 @@ WindowsSettingsWidget::WindowsSettingsWidget() apply(); }); - setOnApply([] { windowsConfigurations().applyConfig(); }); + setOnApply([] { windowsAppSdkSettings().writeSettings(); }); } void WindowsSettingsWidget::showEvent(QShowEvent *event) @@ -332,7 +354,7 @@ void WindowsSettingsWidget::showEvent(QShowEvent *event) void WindowsSettingsWidget::validateDownloadPath() { - windowsConfigurations().downloadLocation.setValue(m_downloadPathChooser->filePath()); + windowsAppSdkSettings().downloadLocation.setValue(m_downloadPathChooser->filePath()); m_winAppSdkSummary->setPointValid( DownloadPathExistsRow, m_downloadPathChooser->filePath().exists()); @@ -342,7 +364,7 @@ void WindowsSettingsWidget::validateDownloadPath() void WindowsSettingsWidget::validateNuget() { - windowsConfigurations().nugetLocation.setValue(m_nugetPathChooser->filePath()); + windowsAppSdkSettings().nugetLocation.setValue(m_nugetPathChooser->filePath()); m_winAppSdkSummary->setPointValid(NugetPathExistsRow, m_nugetPathChooser->filePath().exists()); @@ -351,11 +373,11 @@ void WindowsSettingsWidget::validateNuget() void WindowsSettingsWidget::validateWindowsAppSdk() { - windowsConfigurations().windowsAppSdkLocation.setValue(m_winAppSdkPathChooser->filePath()); + windowsAppSdkSettings().windowsAppSdkLocation.setValue(m_winAppSdkPathChooser->filePath()); QStringList filters; filters << "Microsoft.WindowsAppSDK.*.nupkg"; - QDir dir(windowsConfigurations().windowsAppSdkLocation().path()); + QDir dir(windowsAppSdkSettings().windowsAppSdkLocation().path()); auto results = dir.entryList(filters); m_winAppSdkSummary->setPointValid(WindowsAppSdkPathExists, results.count() > 0); @@ -617,9 +639,14 @@ public: } }; -void setupWindowsAppSdkSettingsPage() +void setupWindowsAppSdkSettings() { + if (!HostOsInfo::isWindowsHost()) + return; + static WindowsSettingsPage theWindowsSettingsPage; + + (void) windowsAppSdkSettings(); } } // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/windowsappsdksettings.h b/src/plugins/projectexplorer/windowsappsdksettings.h index fdc15df8d83..36ada4676f7 100644 --- a/src/plugins/projectexplorer/windowsappsdksettings.h +++ b/src/plugins/projectexplorer/windowsappsdksettings.h @@ -3,8 +3,23 @@ #pragma once +#include + namespace ProjectExplorer::Internal { -void setupWindowsAppSdkSettingsPage(); +class WindowsAppSdkSettings : public Utils::AspectContainer +{ + WindowsAppSdkSettings(); + friend WindowsAppSdkSettings &windowsAppSdkSettings(); + +public: + Utils::FilePathAspect downloadLocation{this}; + Utils::FilePathAspect nugetLocation{this}; + Utils::FilePathAspect windowsAppSdkLocation{this}; +}; + +WindowsAppSdkSettings &windowsAppSdkSettings(); + +void setupWindowsAppSdkSettings(); } // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/windowsconfigurations.cpp b/src/plugins/projectexplorer/windowsconfigurations.cpp deleted file mode 100644 index b1dcf855ab6..00000000000 --- a/src/plugins/projectexplorer/windowsconfigurations.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// 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 "windowsconfigurations.h" - -#include "projectexplorerconstants.h" - -#include - -using namespace Utils; - -namespace ProjectExplorer::Internal { - -WindowsConfigurations &windowsConfigurations() -{ - static WindowsConfigurations theWindowsConfigurations; - return theWindowsConfigurations; -} - -WindowsConfigurations::WindowsConfigurations() -{ - setSettingsGroup("WindowsConfigurations"); - - downloadLocation.setSettingsKey("DownloadLocation"); - nugetLocation.setSettingsKey("NugetLocation"); - windowsAppSdkLocation.setSettingsKey("WindowsAppSDKLocation"); - - AspectContainer::readSettings(); - - if (windowsAppSdkLocation().isEmpty()) { - windowsAppSdkLocation.setValue(FilePath::fromUserInput( - Environment::systemEnvironment().value(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY))); - } -} - -void WindowsConfigurations::applyConfig() -{ - emit aboutToUpdate(); - AspectContainer::writeSettings(); - emit updated(); -} - -void setupWindowsConfigurations() -{ - (void) windowsConfigurations(); -} - -} // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/windowsconfigurations.h b/src/plugins/projectexplorer/windowsconfigurations.h deleted file mode 100644 index 1190499968f..00000000000 --- a/src/plugins/projectexplorer/windowsconfigurations.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace ProjectExplorer::Internal { - -class WindowsConfigurations : public Utils::AspectContainer -{ - Q_OBJECT - - WindowsConfigurations(); - friend WindowsConfigurations &windowsConfigurations(); - -public: - Utils::FilePathAspect downloadLocation{this}; - Utils::FilePathAspect nugetLocation{this}; - Utils::FilePathAspect windowsAppSdkLocation{this}; - - void applyConfig(); - -signals: - void aboutToUpdate(); - void updated(); -}; - -WindowsConfigurations &windowsConfigurations(); - -void setupWindowsConfigurations(); - -} // namespace ProjectExplorer::Internal From 5eaf7b10fc8bc16f1f8b923bc7b69c810796cc93 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 11 Nov 2024 12:16:01 +0100 Subject: [PATCH 094/989] Settings: Move "SDKs" category up It should be near Kits and Devices. Change-Id: I5f2588cd7ce93ea17b8733121e85d872d9b51b20 Reviewed-by: hjk --- src/plugins/projectexplorer/projectexplorerconstants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 2b50a2b878e..426316555b1 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -227,7 +227,7 @@ const char SUPPORTS_SFTP[] = "RemoteLinux.SupportsSftp"; const char SSH_FORWARD_DEBUGSERVER_PORT[] = "RemoteLinux.SshForwardDebugServerPort"; // SDKs related ids: -const char SDK_SETTINGS_CATEGORY[] = "SDKs"; +const char SDK_SETTINGS_CATEGORY[] = "AN.SDKs"; const char WINDOWS_SETTINGS_ID[] = "Windows Configurations"; const char WINDOWS_WINAPPSDK_ROOT_ENV_KEY[] = "WIN_APP_SDK_ROOT"; From da575c164e57bea07082ecd55e02c7c4453c4b3a Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Nov 2024 13:42:12 +0100 Subject: [PATCH 095/989] Android: Give PasswordInputDialog a parent And simplify setup a bit. Change-Id: Ie6f6f7e25ef43614c8b6b10bcd0a35395f495fad Reviewed-by: Jarek Kobus --- src/plugins/android/androidbuildapkstep.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index ef1a93d7577..67ea1313ceb 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -79,11 +79,10 @@ public: }; PasswordInputDialog(Context context, std::function callback, - const QString &extraContextStr, QWidget *parent = nullptr); + const QString &extraContextStr); static QString getPassword(Context context, std::function callback, - const QString &extraContextStr, bool *ok = nullptr, - QWidget *parent = nullptr); + const QString &extraContextStr, bool *ok = nullptr); private: std::function verifyCallback = [](const QString &) { return true; }; @@ -1023,9 +1022,8 @@ QAbstractItemModel *AndroidBuildApkStep::keystoreCertificates() PasswordInputDialog::PasswordInputDialog(PasswordInputDialog::Context context, std::function callback, - const QString &extraContextStr, - QWidget *parent) : - QDialog(parent, Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint), + const QString &extraContextStr) : + QDialog(Core::ICore::dialogParent(), Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint), verifyCallback(callback) { @@ -1069,14 +1067,13 @@ PasswordInputDialog::PasswordInputDialog(PasswordInputDialog::Context context, } QString PasswordInputDialog::getPassword(Context context, std::function callback, - const QString &extraContextStr, bool *ok, QWidget *parent) + const QString &extraContextStr, bool *ok) { - std::unique_ptr dlg(new PasswordInputDialog(context, callback, - extraContextStr, parent)); - bool isAccepted = dlg->exec() == QDialog::Accepted; + PasswordInputDialog dlg(context, callback, extraContextStr); + bool isAccepted = dlg.exec() == QDialog::Accepted; if (ok) *ok = isAccepted; - return isAccepted ? dlg->inputEdit->text() : ""; + return isAccepted ? dlg.inputEdit->text() : QString(); } From 132450093efba81de019eb8032ba48716063b5fc Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Nov 2024 13:51:24 +0100 Subject: [PATCH 096/989] Android: Move some helper function to their single place of use Change-Id: Ia88caffdf7e3f9b9c15e7d3fb1c041d58f5cbbc2 Reviewed-by: Jarek Kobus --- src/plugins/android/androidbuildapkstep.cpp | 63 +++++++++++++++++---- src/plugins/android/androidmanager.cpp | 45 --------------- src/plugins/android/androidmanager.h | 8 --- 3 files changed, 52 insertions(+), 64 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 67ea1313ceb..6dd1de5f677 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -56,12 +56,12 @@ #include #include -#include - using namespace ProjectExplorer; using namespace QtSupport; using namespace Utils; +using namespace std::chrono_literals; + namespace Android::Internal { static Q_LOGGING_CATEGORY(buildapkstepLog, "qtc.android.build.androidbuildapkstep", QtWarningMsg) @@ -94,6 +94,49 @@ private: this); }; +static bool checkKeystorePassword(const FilePath &keystorePath, const QString &keystorePasswd) +{ + if (keystorePasswd.isEmpty()) + return false; + const CommandLine cmd(AndroidConfig::keytoolPath(), + {"-list", "-keystore", keystorePath.toUserOutput(), + "--storepass", keystorePasswd}); + Process proc; + proc.setCommand(cmd); + proc.runBlocking(10s); + return proc.result() == ProcessResult::FinishedWithSuccess; +} + +static bool checkCertificatePassword(const FilePath &keystorePath, const QString &keystorePasswd, + const QString &alias, const QString &certificatePasswd) +{ + // assumes that the keystore password is correct + QStringList arguments = {"-certreq", "-keystore", keystorePath.toUserOutput(), + "--storepass", keystorePasswd, "-alias", alias, "-keypass"}; + if (certificatePasswd.isEmpty()) + arguments << keystorePasswd; + else + arguments << certificatePasswd; + + Process proc; + proc.setCommand({AndroidConfig::keytoolPath(), arguments}); + proc.runBlocking(10s); + return proc.result() == ProcessResult::FinishedWithSuccess; +} + +static bool checkCertificateExists(const FilePath &keystorePath, const QString &keystorePasswd, + const QString &alias) +{ + // assumes that the keystore password is correct + const QStringList arguments = {"-list", "-keystore", keystorePath.toUserOutput(), + "--storepass", keystorePasswd, "-alias", alias}; + + Process proc; + proc.setCommand({AndroidConfig::keytoolPath(), arguments}); + proc.runBlocking(10s); + return proc.result() == ProcessResult::FinishedWithSuccess; +} + // AndroidBuildApkWidget class AndroidBuildApkWidget : public QWidget @@ -627,11 +670,11 @@ bool AndroidBuildApkStep::verifyKeystorePassword() return false; } - if (AndroidManager::checkKeystorePassword(m_keystorePath, m_keystorePasswd)) + if (checkKeystorePassword(m_keystorePath, m_keystorePasswd)) return true; bool success = false; - auto verifyCallback = std::bind(&AndroidManager::checkKeystorePassword, + auto verifyCallback = std::bind(&checkKeystorePassword, m_keystorePath, std::placeholders::_1); m_keystorePasswd = PasswordInputDialog::getPassword(PasswordInputDialog::KeystorePassword, verifyCallback, "", &success); @@ -640,20 +683,19 @@ bool AndroidBuildApkStep::verifyKeystorePassword() bool AndroidBuildApkStep::verifyCertificatePassword() { - if (!AndroidManager::checkCertificateExists(m_keystorePath, m_keystorePasswd, - m_certificateAlias)) { + if (!checkCertificateExists(m_keystorePath, m_keystorePasswd, m_certificateAlias)) { reportWarningOrError(Tr::tr("Cannot sign the package. Certificate alias %1 does not exist.") .arg(m_certificateAlias), Task::Error); return false; } - if (AndroidManager::checkCertificatePassword(m_keystorePath, m_keystorePasswd, - m_certificateAlias, m_certificatePasswd)) { + if (checkCertificatePassword(m_keystorePath, m_keystorePasswd, + m_certificateAlias, m_certificatePasswd)) { return true; } bool success = false; - auto verifyCallback = std::bind(&AndroidManager::checkCertificatePassword, + auto verifyCallback = std::bind(&checkCertificatePassword, m_keystorePath, m_keystorePasswd, m_certificateAlias, std::placeholders::_1); @@ -664,8 +706,7 @@ bool AndroidBuildApkStep::verifyCertificatePassword() } -static bool copyFileIfNewer(const FilePath &sourceFilePath, - const FilePath &destinationFilePath) +static bool copyFileIfNewer(const FilePath &sourceFilePath, const FilePath &destinationFilePath) { if (sourceFilePath == destinationFilePath) return true; diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 02e95f1413f..f1e1f694f27 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -38,8 +38,6 @@ using namespace Core; using namespace ProjectExplorer; using namespace Utils; -using namespace std::chrono_literals; - namespace Android::AndroidManager { const char AndroidManifestName[] = "AndroidManifest.xml"; @@ -591,47 +589,4 @@ QString androidNameForApiLevel(int x) } } -bool checkKeystorePassword(const FilePath &keystorePath, const QString &keystorePasswd) -{ - if (keystorePasswd.isEmpty()) - return false; - const CommandLine cmd(AndroidConfig::keytoolPath(), - {"-list", "-keystore", keystorePath.toUserOutput(), - "--storepass", keystorePasswd}); - Process proc; - proc.setCommand(cmd); - proc.runBlocking(10s); - return proc.result() == ProcessResult::FinishedWithSuccess; -} - -bool checkCertificatePassword(const FilePath &keystorePath, const QString &keystorePasswd, - const QString &alias, const QString &certificatePasswd) -{ - // assumes that the keystore password is correct - QStringList arguments = {"-certreq", "-keystore", keystorePath.toUserOutput(), - "--storepass", keystorePasswd, "-alias", alias, "-keypass"}; - if (certificatePasswd.isEmpty()) - arguments << keystorePasswd; - else - arguments << certificatePasswd; - - Process proc; - proc.setCommand({AndroidConfig::keytoolPath(), arguments}); - proc.runBlocking(10s); - return proc.result() == ProcessResult::FinishedWithSuccess; -} - -bool checkCertificateExists(const FilePath &keystorePath, const QString &keystorePasswd, - const QString &alias) -{ - // assumes that the keystore password is correct - const QStringList arguments = {"-list", "-keystore", keystorePath.toUserOutput(), - "--storepass", keystorePasswd, "-alias", alias}; - - Process proc; - proc.setCommand({AndroidConfig::keytoolPath(), arguments}); - proc.runBlocking(10s); - return proc.result() == ProcessResult::FinishedWithSuccess; -} - } // namespace Android::AndroidManager diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h index a7de64ce126..00bc7d0cb56 100644 --- a/src/plugins/android/androidmanager.h +++ b/src/plugins/android/androidmanager.h @@ -58,14 +58,6 @@ bool skipInstallationAndPackageSteps(const ProjectExplorer::Target *target); QString androidNameForApiLevel(int x); -bool checkKeystorePassword(const Utils::FilePath &keystorePath, - const QString &keystorePasswd); -bool checkCertificatePassword(const Utils::FilePath &keystorePath, - const QString &keystorePasswd, - const QString &alias, const QString &certificatePasswd); -bool checkCertificateExists(const Utils::FilePath &keystorePath, - const QString &keystorePasswd, const QString &alias); - QJsonObject deploymentSettings(const ProjectExplorer::Target *target); bool isQtCreatorGenerated(const Utils::FilePath &deploymentFile); From 5ca2883f7f20cc45250f148e389bdacbdeaaddde Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 7 Nov 2024 13:29:08 +0100 Subject: [PATCH 097/989] Core: collect settings aspect display name for the action locator filter This improve the discoverability of settings inside an aspectified optionspage. Change-Id: I12f0662992b5d1c36fb9e5faa15d81f75d8ff815 Reviewed-by: Christian Stenger Reviewed-by: hjk --- src/plugins/coreplugin/actionsfilter.cpp | 92 +++++++++++++++++-- src/plugins/coreplugin/actionsfilter.h | 12 ++- .../coreplugin/dialogs/ioptionspage.cpp | 5 + src/plugins/coreplugin/dialogs/ioptionspage.h | 1 + 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/src/plugins/coreplugin/actionsfilter.cpp b/src/plugins/coreplugin/actionsfilter.cpp index a2b8e129866..edef20902fe 100644 --- a/src/plugins/coreplugin/actionsfilter.cpp +++ b/src/plugins/coreplugin/actionsfilter.cpp @@ -7,6 +7,7 @@ #include "actionmanager/actionmanager.h" #include "coreconstants.h" #include "coreplugintr.h" +#include "dialogs/ioptionspage.h" #include "icore.h" #include "locator/locatormanager.h" @@ -183,6 +184,7 @@ LocatorMatcherTasks ActionsFilter::matchers() for (QAction* action : menuBarActions()) collectEntriesForAction(action, {}, processedMenus); collectEntriesForCommands(); + collectEntriesForPreferences(); const LocatorStorage &storage = *LocatorStorage::storage(); if (storage.input().simplified().isEmpty()) { storage.reportOutput(m_entries); @@ -199,14 +201,24 @@ LocatorFilterEntry::Acceptor ActionsFilter::acceptor(const ActionFilterEntryData { static const int maxHistorySize = 30; return [this, data] { - if (!data.action) + if (!data.action && !data.optionsPageId.isValid()) return AcceptResult(); m_lastTriggered.removeAll(data); m_lastTriggered.prepend(data); - QMetaObject::invokeMethod(data.action, [action = data.action] { - if (action && action->isEnabled()) - action->trigger(); - }, Qt::QueuedConnection); + if (data.action) { + QMetaObject::invokeMethod( + data.action, + [action = data.action] { + if (action && action->isEnabled()) + action->trigger(); + }, + Qt::QueuedConnection); + } else if (data.optionsPageId.isValid()) { + QMetaObject::invokeMethod( + Core::ICore::instance(), + [id = data.optionsPageId] { Core::ICore::showOptionsDialog(id); }, + Qt::QueuedConnection); + } if (m_lastTriggered.size() > maxHistorySize) m_lastTriggered.resize(maxHistorySize); return AcceptResult(); @@ -241,7 +253,7 @@ void ActionsFilter::collectEntriesForAction(QAction *action, } else if (!text.isEmpty()) { LocatorFilterEntry filterEntry; filterEntry.displayName = text; - filterEntry.acceptor = acceptor({action, {}}); + filterEntry.acceptor = acceptor(ActionFilterEntryData{action, {}}); filterEntry.displayIcon = action->icon(); filterEntry.extraInfo = path.join(" > "); updateEntry(action, filterEntry); @@ -270,7 +282,7 @@ void ActionsFilter::collectEntriesForCommands() const QStringList path = identifier.split(QLatin1Char('.')); LocatorFilterEntry filterEntry; filterEntry.displayName = text; - filterEntry.acceptor = acceptor({action, command->id()}); + filterEntry.acceptor = acceptor(ActionFilterEntryData{action, command->id()}); filterEntry.displayIcon = action->icon(); filterEntry.displayExtra = command->keySequence().toString(QKeySequence::NativeText); if (path.size() >= 2) @@ -296,6 +308,54 @@ void ActionsFilter::collectEntriesForLastTriggered() } } +void ActionsFilter::collectEntriesForPreferences() +{ + static QHash entriesForPages; + static QMap categoryDisplay; + const QString conjunction = " > "; + for (IOptionsPage *page : IOptionsPage::allOptionsPages()) { + if (!categoryDisplay.contains(page->category()) && !page->displayCategory().isEmpty()) + categoryDisplay[page->category()] = page->displayCategory(); + } + QList oldPages = entriesForPages.keys(); + for (IOptionsPage *page : IOptionsPage::allOptionsPages()) { + oldPages.removeAll(page); + if (entriesForPages.contains(page)) + continue; + if (const std::optional aspects = page->aspects()) { + const Id optionsPageId = page->id(); + const QStringList extraInfo = {Tr::tr("Preferences"), page->displayName()}; + std::function collectContainerEntries; + collectContainerEntries = + [this, + &collectContainerEntries, + &optionsPageId, + &page](AspectContainer *container, const QStringList &extraInfo) { + for (auto aspect : container->aspects()) { + if (auto container = qobject_cast(aspect)) { + collectContainerEntries( + container, QStringList(extraInfo) << container->displayName()); + } else if (!aspect->displayName().isEmpty()) { + LocatorFilterEntry filterEntry; + filterEntry.displayName = aspect->displayName(); + filterEntry.acceptor = acceptor(ActionFilterEntryData(optionsPageId)); + filterEntry.extraInfo = extraInfo.join(" > "); + filterEntry.displayIcon = aspect->icon(); + entriesForPages[page].append(filterEntry); + } + } + }; + collectContainerEntries(*aspects, extraInfo); + if (!entriesForPages.contains(page)) + entriesForPages.insert(page, {}); + } + } + for (auto oldPage : oldPages) + entriesForPages.remove(oldPage); + for (const LocatorFilterEntries &entries : std::as_const(entriesForPages)) + m_entries.append(entries); +} + void ActionsFilter::updateEntry(const QPointer action, const LocatorFilterEntry &entry) { const int index = m_indexes.value(action, -1); @@ -358,8 +418,24 @@ void ActionsFilter::restoreState(const QJsonObject &object) const QJsonArray commands = object.value(lastTriggeredC).toArray(); for (const QJsonValue &command : commands) { if (command.isString()) - m_lastTriggered.append({nullptr, Id::fromString(command.toString())}); + m_lastTriggered.append(ActionFilterEntryData{nullptr, Id::fromString(command.toString())}); } } +ActionFilterEntryData::ActionFilterEntryData( + const QPointer &action, const Utils::Id &commandId) + : action(action) + , commandId(commandId) +{} + +ActionFilterEntryData::ActionFilterEntryData(const Utils::Id &optionsPageId) + : optionsPageId(optionsPageId) +{} + +bool operator==(const ActionFilterEntryData &a, const ActionFilterEntryData &b) +{ + return a.action == b.action && a.commandId == b.commandId + && a.optionsPageId == b.optionsPageId; +} + } // Core::Internal diff --git a/src/plugins/coreplugin/actionsfilter.h b/src/plugins/coreplugin/actionsfilter.h index 25e788abaa5..8391b81aa4d 100644 --- a/src/plugins/coreplugin/actionsfilter.h +++ b/src/plugins/coreplugin/actionsfilter.h @@ -19,12 +19,15 @@ namespace Core::Internal { class ActionFilterEntryData { public: + ActionFilterEntryData() = default; + ActionFilterEntryData(const QPointer &action, const Utils::Id &commandId); + explicit ActionFilterEntryData(const Utils::Id &optionsPageId); + QPointer action; Utils::Id commandId; - friend bool operator==(const ActionFilterEntryData &a, const ActionFilterEntryData &b) - { - return a.action == b.action && a.commandId == b.commandId; - } + Utils::Id optionsPageId; + + friend bool operator==(const ActionFilterEntryData &a, const ActionFilterEntryData &b); }; class ActionsFilter : public ILocatorFilter @@ -42,6 +45,7 @@ private: QList &processedMenus); void collectEntriesForCommands(); void collectEntriesForLastTriggered(); + void collectEntriesForPreferences(); void updateEntry(const QPointer action, const LocatorFilterEntry &entry); void updateEnabledActionCache(); diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index a1ff5a3c07b..a34bf3552f1 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -153,6 +153,11 @@ FilePath IOptionsPage::categoryIconPath() const return d->m_categoryIconPath; } +std::optional IOptionsPage::aspects() const +{ + return d->m_settingsProvider ? std::make_optional(d->m_settingsProvider()) : std::nullopt; +} + /*! Sets the \a widgetCreator callback to create page widgets on demand. The widget will be destroyed on finish(). diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index 08b533c28e7..224a536331e 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -55,6 +55,7 @@ public: Utils::Id category() const; QString displayCategory() const; Utils::FilePath categoryIconPath() const; + std::optional aspects() const; using WidgetCreator = std::function; void setWidgetCreator(const WidgetCreator &widgetCreator); From 91f55285a0db22c721bfb7a6d995a6fa7a7fa407 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Nov 2024 10:36:58 +0100 Subject: [PATCH 098/989] Debugger: Don't try to render value annotations as HTML Change-Id: I9e40ad4de7feb1006b67188306f2449931a4a5ff Reviewed-by: David Schulz --- src/plugins/debugger/sourceutils.cpp | 1 + src/plugins/texteditor/textmark.cpp | 14 +++++++++++++- src/plugins/texteditor/textmark.h | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/plugins/debugger/sourceutils.cpp b/src/plugins/debugger/sourceutils.cpp index 26bb70b43fd..bec8cc44b11 100644 --- a/src/plugins/debugger/sourceutils.cpp +++ b/src/plugins/debugger/sourceutils.cpp @@ -341,6 +341,7 @@ public: setPriority(TextEditor::TextMark::HighPriority); setToolTipProvider([] { return QString(); }); setLineAnnotation(value); + setAnnotationTextFormat(Qt::PlainText); } }; diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index 32fabea7fcd..d8dcc2ade9a 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -135,8 +135,10 @@ void TextMark::paintAnnotation(QPainter &painter, painter.fontMetrics(), fadeInOffset, fadeOutOffset); - if (m_staticAnnotationText.text() != rects.text) + if (m_staticAnnotationText.text() != rects.text) { m_staticAnnotationText.setText(rects.text); + m_staticAnnotationText.setTextFormat(m_annotationTextFormat); + } annotationRect->setRight(rects.fadeOutRect.right()); const QRectF eventRectF(eventRect); if (!(rects.fadeInRect.intersects(eventRectF) || rects.annotationRect.intersects(eventRectF) @@ -454,6 +456,16 @@ void TextMark::setSettingsPage(Id settingsPage) m_settingsPage = settingsPage; } +Qt::TextFormat TextMark::annotationTextFormat() const +{ + return m_annotationTextFormat; +} + +void TextMark::setAnnotationTextFormat(Qt::TextFormat newTextFormat) +{ + m_annotationTextFormat = newTextFormat; +} + bool TextMark::isLocationMarker() const { return m_isLocationMarker; diff --git a/src/plugins/texteditor/textmark.h b/src/plugins/texteditor/textmark.h index 0aab492c004..245b835fb31 100644 --- a/src/plugins/texteditor/textmark.h +++ b/src/plugins/texteditor/textmark.h @@ -121,6 +121,8 @@ public: bool isLocationMarker() const; void setIsLocationMarker(bool newIsLocationMarker); + Qt::TextFormat annotationTextFormat() const; + void setAnnotationTextFormat(Qt::TextFormat newTextFormat); protected: void setSettingsPage(Utils::Id settingsPage); @@ -140,6 +142,7 @@ private: std::optional m_color; bool m_visible = false; TextMarkCategory m_category; + Qt::TextFormat m_annotationTextFormat = Qt::AutoText; QString m_lineAnnotation; mutable QStaticText m_staticAnnotationText; QString m_toolTip; From 6a6cbe4d7e32fff8ad96dc6cdf87ef651eec2cef Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Nov 2024 14:16:22 +0100 Subject: [PATCH 099/989] Android: Drop support for Qt < 5.4.0 Qt 5.4.0 was release in Dec 2016, the plugin has not been tested with that for a long while. Change-Id: Ie43a164bcb5090157d827f6ef7b2fd4c205b4f57 Reviewed-by: Jarek Kobus --- src/plugins/android/androidbuildapkstep.cpp | 8 ------ src/plugins/android/androiddeployqtstep.cpp | 20 +++----------- src/plugins/android/androidmanager.h | 7 +---- .../android/createandroidmanifestwizard.cpp | 27 +++++++------------ 4 files changed, 13 insertions(+), 49 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 6dd1de5f677..1b068ed5151 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -535,14 +535,6 @@ bool AndroidBuildApkStep::init() return false; } - if (version->qtVersion() < AndroidManager::firstQtWithAndroidDeployQt) { - const QString error = Tr::tr("The minimum Qt version required for Gradle build to work is %1. " - "It is recommended to install the latest Qt version.") - .arg("5.4.0"); - reportWarningOrError(error, Task::Error); - return false; - } - const int minSDKForKit = AndroidManager::minimumSDK(kit()); if (AndroidManager::minimumSDK(target()) < minSDKForKit) { const QString error diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 1a3e79a1940..6d1e175ca07 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -155,7 +155,6 @@ private: BoolAspect m_uninstallPreviousPackage{this}; bool m_uninstallPreviousPackageRun = false; - bool m_useAndroiddeployqt = false; CommandLine m_androiddeployqtArgs; FilePath m_adbPath; FilePath m_command; @@ -174,13 +173,6 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Id id) m_uninstallPreviousPackage.setLabel(Tr::tr("Uninstall the existing app before deployment"), BoolAspect::LabelPlacement::AtCheckBox); m_uninstallPreviousPackage.setValue(false); - - const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit()); - const bool forced = qt && qt->qtVersion() < AndroidManager::firstQtWithAndroidDeployQt; - if (forced) { - m_uninstallPreviousPackage.setValue(true); - m_uninstallPreviousPackage.setEnabled(false); - } } bool AndroidDeployQtStep::init() @@ -295,8 +287,7 @@ bool AndroidDeployQtStep::init() emit addOutput(Tr::tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage); m_uninstallPreviousPackageRun = m_uninstallPreviousPackage(); - m_useAndroiddeployqt = version->qtVersion() >= AndroidManager::firstQtWithAndroidDeployQt; - if (m_useAndroiddeployqt) { + if (true) { const QString buildKey = target()->activeBuildKey(); const ProjectNode *node = target()->project()->findNodeForBuildKey(buildKey); if (!node) { @@ -344,11 +335,6 @@ bool AndroidDeployQtStep::init() m_androiddeployqtArgs.addArgs({"--sign", "foo", "bar"}); } } - } else { - m_uninstallPreviousPackageRun = true; - m_command = AndroidConfig::adbToolPath(); - m_apkPath = AndroidManager::packagePath(target()); - m_workingDirectory = bc ? AndroidManager::buildDirectory(target()): FilePath(); } m_environment = bc ? bc->environment() : Environment(); @@ -430,7 +416,7 @@ Group AndroidDeployQtStep::deployRecipe() const Storage storage; const auto onUninstallSetup = [this](Process &process) { - if (m_useAndroiddeployqt && m_apkPath.isEmpty()) + if (m_apkPath.isEmpty()) return SetupResult::StopWithSuccess; if (!m_uninstallPreviousPackageRun) return SetupResult::StopWithSuccess; @@ -462,7 +448,7 @@ Group AndroidDeployQtStep::deployRecipe() const auto onInstallSetup = [this, storage](Process &process) { CommandLine cmd(m_command); - if (m_useAndroiddeployqt && m_apkPath.isEmpty()) { + if (m_apkPath.isEmpty()) { cmd.addArgs(m_androiddeployqtArgs.arguments(), CommandLine::Raw); if (m_uninstallPreviousPackageRun) cmd.addArg("--install"); diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h index 00bc7d0cb56..8da8e0aebc2 100644 --- a/src/plugins/android/androidmanager.h +++ b/src/plugins/android/androidmanager.h @@ -17,12 +17,7 @@ class Process; } namespace Android { - -namespace AndroidManager -{ - -// With Qt 5.4, a couple of android tooling features moved over from Qt Creator to Qt. -constexpr auto firstQtWithAndroidDeployQt = {5, 4, 0}; +namespace AndroidManager { QString packageName(const ProjectExplorer::Target *target); QString activityName(const ProjectExplorer::Target *target); diff --git a/src/plugins/android/createandroidmanifestwizard.cpp b/src/plugins/android/createandroidmanifestwizard.cpp index 5d1bffd0177..aab86e74d8f 100644 --- a/src/plugins/android/createandroidmanifestwizard.cpp +++ b/src/plugins/android/createandroidmanifestwizard.cpp @@ -233,9 +233,7 @@ CreateAndroidManifestWizard::CreateAndroidManifestWizard(BuildSystem *buildSyste setWindowTitle(Tr::tr("Create Android Template Files Wizard")); const QList buildTargets = buildSystem->applicationTargets(); - QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(buildSystem->kit()); - m_allowGradleTemplates = version && - version->qtVersion() >= AndroidManager::firstQtWithAndroidDeployQt; + m_allowGradleTemplates = bool(QtSupport::QtKitAspect::qtVersion(buildSystem->kit())); if (buildTargets.isEmpty()) { // oh uhm can't create anything @@ -289,22 +287,15 @@ void CreateAndroidManifestWizard::createAndroidTemplateFiles() QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit()); if (!version) return; - if (version->qtVersion() < AndroidManager::firstQtWithAndroidDeployQt) { - FileUtils::copyRecursively(version->prefix() / "src/android/java/AndroidManifest.xml", - m_directory / "AndroidManifest.xml", - nullptr, - copy()); - } else { - FileUtils::copyRecursively(version->prefix() / "src/android/templates", - m_directory, - nullptr, - copy()); + FileUtils::copyRecursively(version->prefix() / "src/android/templates", + m_directory, + nullptr, + copy()); - if (copyGradleTemplates()) { - FilePath gradlePath = version->prefix() / "src/3rdparty/gradle"; - QTC_ASSERT(gradlePath.exists(), return); - FileUtils::copyRecursively(gradlePath, m_directory, nullptr, copy()); - } + if (copyGradleTemplates()) { + FilePath gradlePath = version->prefix() / "src/3rdparty/gradle"; + QTC_ASSERT(gradlePath.exists(), return); + FileUtils::copyRecursively(gradlePath, m_directory, nullptr, copy()); } QString androidPackageDir; From 9361deeed8f3afdd12952d91a4fa1a03042df7e5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Nov 2024 14:23:21 +0100 Subject: [PATCH 100/989] Android: Drop an if (true) and re-indent Change-Id: Ibdb75fdcfed1406c12e0772203d7a6c19f9a349f Reviewed-by: Assam Boudjelthia --- src/plugins/android/androiddeployqtstep.cpp | 79 ++++++++++----------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 6d1e175ca07..08213601f95 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -287,55 +287,54 @@ bool AndroidDeployQtStep::init() emit addOutput(Tr::tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage); m_uninstallPreviousPackageRun = m_uninstallPreviousPackage(); - if (true) { - const QString buildKey = target()->activeBuildKey(); - const ProjectNode *node = target()->project()->findNodeForBuildKey(buildKey); - if (!node) { - reportWarningOrError(Tr::tr("The deployment step's project node is invalid."), Task::Error); + + const ProjectNode *node = target()->project()->findNodeForBuildKey(buildKey); + if (!node) { + reportWarningOrError(Tr::tr("The deployment step's project node is invalid."), Task::Error); + return false; + } + m_apkPath = FilePath::fromString(node->data(Constants::AndroidApk).toString()); + if (!m_apkPath.isEmpty()) { + m_command = AndroidConfig::adbToolPath(); + AndroidManager::setManifestPath(target(), + FilePath::fromString(node->data(Constants::AndroidManifest).toString())); + } else { + FilePath jsonFile = AndroidQtVersion::androidDeploymentSettings(target()); + if (jsonFile.isEmpty()) { + reportWarningOrError(Tr::tr("Cannot find the androiddeployqt input JSON file."), + Task::Error); return false; } - m_apkPath = FilePath::fromString(node->data(Constants::AndroidApk).toString()); - if (!m_apkPath.isEmpty()) { - m_command = AndroidConfig::adbToolPath(); - AndroidManager::setManifestPath(target(), - FilePath::fromString(node->data(Constants::AndroidManifest).toString())); - } else { - FilePath jsonFile = AndroidQtVersion::androidDeploymentSettings(target()); - if (jsonFile.isEmpty()) { - reportWarningOrError(Tr::tr("Cannot find the androiddeployqt input JSON file."), - Task::Error); - return false; - } - m_command = version->hostBinPath(); - if (m_command.isEmpty()) { - reportWarningOrError(Tr::tr("Cannot find the androiddeployqt tool."), Task::Error); - return false; - } - m_command = m_command.pathAppended("androiddeployqt").withExecutableSuffix(); + m_command = version->hostBinPath(); + if (m_command.isEmpty()) { + reportWarningOrError(Tr::tr("Cannot find the androiddeployqt tool."), Task::Error); + return false; + } + m_command = m_command.pathAppended("androiddeployqt").withExecutableSuffix(); - m_workingDirectory = AndroidManager::androidBuildDirectory(target()); + m_workingDirectory = AndroidManager::androidBuildDirectory(target()); - // clang-format off - m_androiddeployqtArgs.addArgs({"--verbose", - "--output", m_workingDirectory.path(), - "--no-build", - "--input", jsonFile.path()}); - // clang-format on + // clang-format off + m_androiddeployqtArgs.addArgs({"--verbose", + "--output", m_workingDirectory.path(), + "--no-build", + "--input", jsonFile.path()}); + // clang-format on - m_androiddeployqtArgs.addArg("--gradle"); + m_androiddeployqtArgs.addArg("--gradle"); - if (buildType() == BuildConfiguration::Release) - m_androiddeployqtArgs.addArgs({"--release"}); + if (buildType() == BuildConfiguration::Release) + m_androiddeployqtArgs.addArgs({"--release"}); - if (androidBuildApkStep && androidBuildApkStep->signPackage()) { - // The androiddeployqt tool is not really written to do stand-alone installations. - // This hack forces it to use the correct filename for the apk file when installing - // as a temporary fix until androiddeployqt gets the support. Since the --sign is - // only used to get the correct file name of the apk, its parameters are ignored. - m_androiddeployqtArgs.addArgs({"--sign", "foo", "bar"}); - } + if (androidBuildApkStep && androidBuildApkStep->signPackage()) { + // The androiddeployqt tool is not really written to do stand-alone installations. + // This hack forces it to use the correct filename for the apk file when installing + // as a temporary fix until androiddeployqt gets the support. Since the --sign is + // only used to get the correct file name of the apk, its parameters are ignored. + m_androiddeployqtArgs.addArgs({"--sign", "foo", "bar"}); } } + m_environment = bc ? bc->environment() : Environment(); m_adbPath = AndroidConfig::adbToolPath(); From 36ce84cb290e989cb0ca28a7acce1d51ca283ca7 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Nov 2024 15:06:09 +0100 Subject: [PATCH 101/989] Android: Minor simplification in CreateAndroidManifestWizard Change-Id: I83452da9dee40d47e8c63ea7d77661707c5a6bc3 Reviewed-by: Jarek Kobus --- src/plugins/android/createandroidmanifestwizard.cpp | 3 +-- src/plugins/android/createandroidmanifestwizard.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/android/createandroidmanifestwizard.cpp b/src/plugins/android/createandroidmanifestwizard.cpp index aab86e74d8f..beb4448fb1e 100644 --- a/src/plugins/android/createandroidmanifestwizard.cpp +++ b/src/plugins/android/createandroidmanifestwizard.cpp @@ -233,7 +233,6 @@ CreateAndroidManifestWizard::CreateAndroidManifestWizard(BuildSystem *buildSyste setWindowTitle(Tr::tr("Create Android Template Files Wizard")); const QList buildTargets = buildSystem->applicationTargets(); - m_allowGradleTemplates = bool(QtSupport::QtKitAspect::qtVersion(buildSystem->kit())); if (buildTargets.isEmpty()) { // oh uhm can't create anything @@ -269,7 +268,7 @@ bool CreateAndroidManifestWizard::copyGradleTemplates() const bool CreateAndroidManifestWizard::allowGradleTemplates() const { - return m_allowGradleTemplates; + return bool(QtSupport::QtKitAspect::qtVersion(m_buildSystem->kit())); } void CreateAndroidManifestWizard::setCopyGradleTemplates(bool copy) diff --git a/src/plugins/android/createandroidmanifestwizard.h b/src/plugins/android/createandroidmanifestwizard.h index af9c9c3a837..b00dff4a80c 100644 --- a/src/plugins/android/createandroidmanifestwizard.h +++ b/src/plugins/android/createandroidmanifestwizard.h @@ -33,7 +33,6 @@ private: ProjectExplorer::BuildSystem *m_buildSystem; QString m_buildKey; Utils::FilePath m_directory; - bool m_allowGradleTemplates; bool m_copyGradleTemplates; }; From c401f0eabbc594d0274b11d8ed3e795425b31299 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 11 Nov 2024 13:31:00 +0100 Subject: [PATCH 102/989] Core: Make WelcomePageHelpers::tfLabel public We need labels with certain font and color in various places. Change-Id: I81085984d56a89791c0c3ccf36655dbc42c13442 Reviewed-by: Cristian Adam --- src/plugins/coreplugin/welcomepagehelper.cpp | 17 +++++++++++++++++ src/plugins/coreplugin/welcomepagehelper.h | 1 + .../extensionmanager/extensionsbrowser.cpp | 17 ----------------- .../extensionmanager/extensionsbrowser.h | 2 -- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 94594229568..7bcd93045b4 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -6,6 +6,7 @@ #include "coreplugintr.h" #include +#include #include #include #include @@ -87,6 +88,22 @@ QWidget *createRule(Qt::Orientation orientation, QWidget *parent) return rule; } +QLabel *tfLabel(const TextFormat &tf, bool singleLine) +{ + QLabel *label = singleLine ? new Utils::ElidingLabel : new QLabel; + if (singleLine) + label->setFixedHeight(tf.lineHeight()); + label->setFont(tf.font()); + label->setAlignment(Qt::Alignment(tf.drawTextFlags)); + label->setTextInteractionFlags(Qt::TextSelectableByMouse); + + QPalette pal = label->palette(); + pal.setColor(QPalette::WindowText, tf.color()); + label->setPalette(pal); + + return label; +} + } // namespace WelcomePageHelpers enum WidgetState { diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index 1fb6ff08874..7de554e84a9 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -67,6 +67,7 @@ CORE_EXPORT void drawCardBackground(QPainter *painter, const QRectF &rect, const QBrush &fill, const QPen &pen = QPen(Qt::NoPen), qreal rounding = defaultCardBackgroundRounding); CORE_EXPORT QWidget *createRule(Qt::Orientation orientation, QWidget *parent = nullptr); +CORE_EXPORT QLabel *tfLabel(const TextFormat &tf, bool singleLine = true); } // namespace WelcomePageHelpers diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index 222cd7b9542..a3e542a9905 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -741,22 +740,6 @@ void ExtensionsBrowser::fetchExtensions() d->taskTreeRunner.start(group); } -QLabel *tfLabel(const TextFormat &tf, bool singleLine) -{ - QLabel *label = singleLine ? new Utils::ElidingLabel : new QLabel; - if (singleLine) - label->setFixedHeight(tf.lineHeight()); - label->setFont(tf.font()); - label->setAlignment(Qt::Alignment(tf.drawTextFlags)); - label->setTextInteractionFlags(Qt::TextSelectableByMouse); - - QPalette pal = label->palette(); - pal.setColor(QPalette::WindowText, tf.color()); - label->setPalette(pal); - - return label; -} - const int iconRectRounding = 4; QPixmap itemIcon(const QModelIndex &index, Size size) diff --git a/src/plugins/extensionmanager/extensionsbrowser.h b/src/plugins/extensionmanager/extensionsbrowser.h index 620c581de71..3d42e3386ee 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.h +++ b/src/plugins/extensionmanager/extensionsbrowser.h @@ -41,8 +41,6 @@ private: class ExtensionsBrowserPrivate *d = nullptr; }; -QLabel *tfLabel(const Core::WelcomePageHelpers::TextFormat &tf, bool singleLine = true); - constexpr static QSize iconBgSizeSmall{50, 50}; constexpr static QSize iconBgSizeBig{68, 68}; enum Size { From 5820df1e22ac6d7a1bb4cc978203576c41283bab Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 11 Nov 2024 13:32:38 +0100 Subject: [PATCH 103/989] Core/Welcome: Use WelcomePageHelpers::tfLabel ...instead of re-implementing it. Change-Id: I69a38bd72f956282b7743e53645914b055d84215 Reviewed-by: Cristian Adam --- src/plugins/coreplugin/welcomepagehelper.cpp | 16 +++++++++------- src/plugins/welcome/welcomeplugin.cpp | 12 ++++-------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 7bcd93045b4..000cf00d191 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -1268,15 +1268,13 @@ void SectionedGridView::setSearchString(const QString &searchString) filterModel->setSearchString(searchString); } -static QLabel *createTitleLabel(const QString &text, QWidget *parent = nullptr) +static QLabel *createTitleLabel(const QString &text) { constexpr TextFormat headerTitleTF {Theme::Token_Text_Muted, StyleHelper::UiElementH4}; - auto link = new QLabel(text, parent); - link->setFont(headerTitleTF.font()); - QPalette pal = link->palette(); - pal.setColor(QPalette::WindowText, headerTitleTF.color()); - link->setPalette(pal); - return link; + auto label = tfLabel(headerTitleTF); + label->setText(text); + label->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + return label; } static QLabel *createLinkLabel(const QString &text, QWidget *parent) @@ -1309,6 +1307,10 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListsetText(section.name); + QLabel *seeAllLink = createLinkLabel(Tr::tr("Show All") + " >", this); if (gridView->maxRows().has_value()) { seeAllLink->setVisible(true); diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index 7944cc8ee21..1f5b279dd5d 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -75,14 +75,10 @@ public: ideIconLabel->setFixedHeight(lineHeight); } - auto welcomeLabel = new QLabel(Tr::tr("Welcome to %1") - .arg(QGuiApplication::applicationDisplayName())); - { - welcomeLabel->setFont(welcomeTF.font()); - QPalette pal = palette(); - pal.setColor(QPalette::WindowText, welcomeTF.color()); - welcomeLabel->setPalette(pal); - } + auto welcomeLabel = tfLabel(welcomeTF); + welcomeLabel->setText(Tr::tr("Welcome to %1") + .arg(QGuiApplication::applicationDisplayName())); + welcomeLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); using namespace Layouting; From 06622dd4f2d4dbdf9aa568245b6d912b7ac2693f Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 11 Nov 2024 14:06:32 +0100 Subject: [PATCH 104/989] Welcome: Unify spacings according to Figma Design Some spacings differed on the various Welcome pages. This unifies them following the Figma design. Fixes: QTCREATORBUG-31421 Change-Id: I9c7557bafa22e0cc68b927904a18404bd71cec72 Reviewed-by: Cristian Adam --- src/plugins/coreplugin/welcomepagehelper.cpp | 4 ++-- src/plugins/marketplace/qtmarketplacewelcomepage.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 000cf00d191..967952e02df 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -1327,7 +1327,7 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList(widget(0)); @@ -1398,7 +1398,7 @@ void SectionedGridView::zoomInSection(const Section §ion) st, backLink, Space(ExVPaddingGapXl), - customMargins(0, ExPaddingGapL, 0, VPaddingL), + customMargins(0, ExPaddingGapM, 0, ExPaddingGapM), }.emerge(); auto gridView = new GridView(zoomedInWidget); diff --git a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp index 459278cd045..cfa37c3d7c0 100644 --- a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp +++ b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp @@ -50,7 +50,7 @@ public: customMargins(0, 0, ExVPaddingGapXl, 0), }, m_sectionedProducts, - spacing(VPaddingL), + spacing(ExVPaddingGapXl), customMargins(ExVPaddingGapXl, ExVPaddingGapXl, 0, 0), }.attachTo(this); From 0e996b88109dec327932129d3b50bd3029815de5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Nov 2024 15:25:45 +0100 Subject: [PATCH 105/989] Android: Remove some signal forwarding functions Emit directly instead. Change-Id: I4893d4831b6d53029a24f02c83e622d935009d4d Reviewed-by: Jarek Kobus --- src/plugins/android/androidrunnerworker.cpp | 35 +++++++++------------ src/plugins/android/androidrunnerworker.h | 6 ---- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 4c1eb53e58c..b244dbc89c5 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -299,7 +299,7 @@ static ExecutableItem removeForwardPortRecipe(RunnerStorage *storage, const QStr process.setCommand(storage->adbCommand({"forward", "--remove", port})); }; const auto onForwardRemoveDone = [storage](const Process &process) { - storage->m_glue->addStdErr(process.cleanedStdErr().trimmed()); + emit storage->m_glue->stdErr(process.cleanedStdErr().trimmed()); return true; }; @@ -311,7 +311,7 @@ static ExecutableItem removeForwardPortRecipe(RunnerStorage *storage, const QStr storage->m_afterFinishAdbCommands.push_back("forward --remove " + port); } else { //: %1 = QML/JDB/C++ - storage->m_glue->setFinished(Tr::tr("Failed to forward %1 debugging ports.").arg(portType)); + emit storage->m_glue->finished(Tr::tr("Failed to forward %1 debugging ports.").arg(portType)); } }; @@ -447,18 +447,18 @@ static ExecutableItem logcatRecipe(const Storage &storage) const QString cleanPidMatch = pidMatch.mid(1, pidMatch.size() - 2).trimmed(); const QString output = QString(line).remove(pidMatch); if (isFatal) { - storagePtr->m_glue->addStdErr(output); + emit storagePtr->m_glue->stdErr(output); } else if (cleanPidMatch == pidString) { if (onlyError || errorMsgTypes.contains(msgType)) - storagePtr->m_glue->addStdErr(output); + emit storagePtr->m_glue->stdErr(output); else - storagePtr->m_glue->addStdOut(output); + emit storagePtr->m_glue->stdOut(output); } } else { if (onlyError || errorMsgTypes.contains(msgType)) - storagePtr->m_glue->addStdErr(line); + emit storagePtr->m_glue->stdErr(line); else - storagePtr->m_glue->addStdOut(line); + emit storagePtr->m_glue->stdOut(line); } } }; @@ -503,7 +503,7 @@ static ExecutableItem preStartRecipe(const Storage &storage) {storage->m_beforeStartAdbCommands.at(iterator.iteration()).split(' ', Qt::SkipEmptyParts)})); }; const auto onPreCommandDone = [storage](const Process &process) { - storage->m_glue->addStdErr(process.cleanedStdErr().trimmed()); + emit storage->m_glue->stdErr(process.cleanedStdErr().trimmed()); }; const auto isQmlDebug = [storage] { @@ -543,7 +543,7 @@ static ExecutableItem preStartRecipe(const Storage &storage) process.setCommand(*cmdStorage); }; const auto onActivityDone = [storage](const Process &process) { - storage->m_glue->setFinished( + emit storage->m_glue->finished( Tr::tr("Activity Manager error: %1").arg(process.cleanedStdErr().trimmed())); }; @@ -579,7 +579,7 @@ static ExecutableItem postDoneRecipe(const Storage &storage) 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); + emit storage->m_glue->finished(message); }; return Group { @@ -645,7 +645,7 @@ static ExecutableItem uploadDebugServerRecipe(const Storage &stor const auto onDebugSetupFinished = [storage] { storage->m_glue->runControl()->setQmlChannel(storage->m_qmlServer); - storage->m_glue->setStarted(s_localDebugServerPort, storage->m_processPID); + emit storage->m_glue->started(s_localDebugServerPort, storage->m_processPID); }; return Group { @@ -687,7 +687,7 @@ static ExecutableItem startNativeDebuggingRecipe(const Storage &s if (result == DoneWith::Success) *packageDirStorage = process.stdOut(); else - storage->m_glue->setFinished(Tr::tr("Failed to find application directory.")); + emit storage->m_glue->finished(Tr::tr("Failed to find application directory.")); }; // Add executable flag to package dir. Gdb can't connect to running server on device on @@ -701,7 +701,7 @@ static ExecutableItem startNativeDebuggingRecipe(const Storage &s QString msg = Tr::tr("Cannot find C++ debug server in NDK installation."); if (storage->m_useLldb) msg += "\n" + Tr::tr("The lldb-server binary has not been found."); - storage->m_glue->setFinished(msg); + emit storage->m_glue->finished(msg); return false; }; @@ -720,7 +720,7 @@ static ExecutableItem startNativeDebuggingRecipe(const Storage &s setDebugServer(debugServerFileName) } >> Else { Sync([storage] { - storage->m_glue->setFinished(Tr::tr("Cannot copy C++ debug server.")); + emit storage->m_glue->finished(Tr::tr("Cannot copy C++ debug server.")); return false; }) }; @@ -827,7 +827,7 @@ static ExecutableItem pidRecipe(const Storage &storage) qCDebug(androidRunWorkerLog) << "Process ID changed to:" << storage->m_processPID; if (!storage->m_useCppDebugger) { storage->m_glue->runControl()->setQmlChannel(storage->m_qmlServer); - storage->m_glue->setStarted(s_localDebugServerPort, storage->m_processPID); + emit storage->m_glue->started(s_localDebugServerPort, storage->m_processPID); } return DoneResult::Success; } @@ -874,11 +874,6 @@ void RunnerInterface::cancel() emit canceled(); } -void RunnerInterface::setStarted(const Port &debugServerPort, qint64 pid) -{ - emit started(debugServerPort, pid); -} - ExecutableItem runnerRecipe(const Storage &glueStorage) { const Storage storage; diff --git a/src/plugins/android/androidrunnerworker.h b/src/plugins/android/androidrunnerworker.h index 3a9d762ea66..9a0d80dff96 100644 --- a/src/plugins/android/androidrunnerworker.h +++ b/src/plugins/android/androidrunnerworker.h @@ -33,12 +33,6 @@ public: // GUI -> business logic void cancel(); - // business logic -> GUI - void setStarted(const Utils::Port &debugServerPort, qint64 pid); - void setFinished(const QString &errorMessage) { emit finished(errorMessage); } - void addStdOut(const QString &data) { emit stdOut(data); } - void addStdErr(const QString &data) { emit stdErr(data); } - signals: // GUI -> business logic void canceled(); From 16bbe6569cb4b97584ad3dc8ec57af857d1d9275 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 11 Nov 2024 16:19:52 +0100 Subject: [PATCH 106/989] Android: Avoid passing AndroidSdkManager Use signleton instead. Change-Id: Ic17919c75b7dba8c59f08b93a56edd80ce289252 Reviewed-by: hjk --- src/plugins/android/androidconfigurations.cpp | 8 ++++---- src/plugins/android/androidconfigurations.h | 4 ++-- .../android/androidsdkmanagerdialog.cpp | 18 +++++++----------- src/plugins/android/androidsdkmanagerdialog.h | 4 +--- src/plugins/android/androidsdkmodel.cpp | 11 +++++------ src/plugins/android/androidsdkmodel.h | 14 ++++---------- src/plugins/android/androidsettingswidget.cpp | 8 ++++---- src/plugins/android/avddialog.h | 2 -- 8 files changed, 27 insertions(+), 42 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 01752ef7581..92fae451fb6 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -969,7 +969,7 @@ QStringList allEssentials() return allPackages; } -QString optionalSystemImagePackage(AndroidSdkManager *sdkManager) +QString optionalSystemImagePackage() { const QStringList essentialPkgs(allEssentials()); QStringList platforms = Utils::filtered(essentialPkgs, [](const QString &item) { @@ -998,7 +998,7 @@ QString optionalSystemImagePackage(AndroidSdkManager *sdkManager) const auto imageName = QLatin1String("%1;android-%2;google_apis_playstore;%3") .arg(Constants::systemImagesPackageName).arg(apiLevel).arg(hostArch); - const SdkPlatformList sdkPlatforms = sdkManager->filteredSdkPlatforms( + const SdkPlatformList sdkPlatforms = AndroidConfigurations::sdkManager()->filteredSdkPlatforms( apiLevel, AndroidSdkPackage::AnyValidState); if (sdkPlatforms.isEmpty()) @@ -1020,10 +1020,10 @@ static QStringList packagesWithoutNdks(const QStringList &packages) }); } -bool allEssentialsInstalled(AndroidSdkManager *sdkManager) +bool allEssentialsInstalled() { QStringList essentialPkgs(allEssentials()); - const auto installedPkgs = sdkManager->installedSdkPackages(); + const auto installedPkgs = AndroidConfigurations::sdkManager()->installedSdkPackages(); for (const AndroidSdkPackage *pkg : installedPkgs) { if (essentialPkgs.contains(pkg->sdkStylePath())) essentialPkgs.removeOne(pkg->sdkStylePath()); diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index f4fc177c94f..ea67b7b0b6f 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -55,10 +55,10 @@ QVersionNumber ndkVersion(const Utils::FilePath &ndkPath); QUrl sdkToolsUrl(); QByteArray getSdkToolsSha256(); -QString optionalSystemImagePackage(Internal::AndroidSdkManager *sdkManager); +QString optionalSystemImagePackage(); QStringList allEssentials(); -bool allEssentialsInstalled(Internal::AndroidSdkManager *sdkManager); +bool allEssentialsInstalled(); bool sdkToolsOk(); Utils::FilePath openJDKLocation(); diff --git a/src/plugins/android/androidsdkmanagerdialog.cpp b/src/plugins/android/androidsdkmanagerdialog.cpp index f3ef5d68c0b..3359f85dc01 100644 --- a/src/plugins/android/androidsdkmanagerdialog.cpp +++ b/src/plugins/android/androidsdkmanagerdialog.cpp @@ -30,10 +30,9 @@ namespace Android::Internal { class OptionsDialog : public QDialog { public: - OptionsDialog(AndroidSdkManager *sdkManager, QWidget *parent) + OptionsDialog(QWidget *parent) : QDialog(parent) { - QTC_CHECK(sdkManager); resize(800, 480); setWindowTitle(Tr::tr("SDK Manager Arguments")); @@ -106,20 +105,17 @@ private: class AndroidSdkManagerDialog : public QDialog { public: - AndroidSdkManagerDialog(AndroidSdkManager *sdkManager, QWidget *parent); + AndroidSdkManagerDialog(QWidget *parent); private: AndroidSdkManager *m_sdkManager = nullptr; AndroidSdkModel *m_sdkModel = nullptr; }; -AndroidSdkManagerDialog::AndroidSdkManagerDialog(AndroidSdkManager *sdkManager, QWidget *parent) +AndroidSdkManagerDialog::AndroidSdkManagerDialog(QWidget *parent) : QDialog(parent) - , m_sdkManager(sdkManager) - , m_sdkModel(new AndroidSdkModel(m_sdkManager, this)) + , m_sdkModel(new AndroidSdkModel(this)) { - QTC_CHECK(sdkManager); - setWindowTitle(Tr::tr("Android SDK Manager")); resize(664, 396); setModal(true); @@ -234,7 +230,7 @@ AndroidSdkManagerDialog::AndroidSdkManagerDialog(AndroidSdkManager *sdkManager, connect(buttonBox, &QDialogButtonBox::rejected, this, &AndroidSdkManagerDialog::reject); connect(optionsButton, &QPushButton::clicked, this, [this] { - OptionsDialog dlg(m_sdkManager, this); + OptionsDialog dlg(this); if (dlg.exec() == QDialog::Accepted) { QStringList arguments = dlg.sdkManagerArguments(); if (arguments != AndroidConfig::sdkManagerToolArgs()) { @@ -335,9 +331,9 @@ bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour return showTopLevel || ((packageState(srcIndex) & m_packageState) && packageFound(srcIndex)); } -void executeAndroidSdkManagerDialog(AndroidSdkManager *sdkManager, QWidget *parent) +void executeAndroidSdkManagerDialog(QWidget *parent) { - AndroidSdkManagerDialog dialog(sdkManager, parent); + AndroidSdkManagerDialog dialog(parent); dialog.exec(); } diff --git a/src/plugins/android/androidsdkmanagerdialog.h b/src/plugins/android/androidsdkmanagerdialog.h index e5e10c6783b..24e4698fc07 100644 --- a/src/plugins/android/androidsdkmanagerdialog.h +++ b/src/plugins/android/androidsdkmanagerdialog.h @@ -6,8 +6,6 @@ namespace Android::Internal { -class AndroidSdkManager; - -void executeAndroidSdkManagerDialog(AndroidSdkManager *sdkManager, QWidget *parent); +void executeAndroidSdkManagerDialog(QWidget *parent); } // Android::Internal diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp index 86dbc320135..6eb4045fbfd 100644 --- a/src/plugins/android/androidsdkmodel.cpp +++ b/src/plugins/android/androidsdkmodel.cpp @@ -17,12 +17,11 @@ namespace Internal { const int packageColCount = 3; -AndroidSdkModel::AndroidSdkModel(AndroidSdkManager *sdkManager, QObject *parent) - : QAbstractItemModel(parent), - m_sdkManager(sdkManager) +AndroidSdkModel::AndroidSdkModel(QObject *parent) + : QAbstractItemModel(parent) { - QTC_CHECK(m_sdkManager); - connect(m_sdkManager, &AndroidSdkManager::packagesReloaded, this, &AndroidSdkModel::refreshData); + connect(AndroidConfigurations::sdkManager(), &AndroidSdkManager::packagesReloaded, + this, &AndroidSdkModel::refreshData); refreshData(); } @@ -275,7 +274,7 @@ void AndroidSdkModel::refreshData() m_tools.clear(); m_changeState.clear(); beginResetModel(); - for (AndroidSdkPackage *p : m_sdkManager->allSdkPackages()) { + for (AndroidSdkPackage *p : AndroidConfigurations::sdkManager()->allSdkPackages()) { if (p->type() == AndroidSdkPackage::SdkPlatformPackage) m_sdkPlatforms << static_cast(p); else diff --git a/src/plugins/android/androidsdkmodel.h b/src/plugins/android/androidsdkmodel.h index 60ecc622275..2137a3e87f1 100644 --- a/src/plugins/android/androidsdkmodel.h +++ b/src/plugins/android/androidsdkmodel.h @@ -2,16 +2,12 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once +// TODO: remove #include "androidconfigurations.h" #include -#include - -namespace Android { -namespace Internal { - -class AndroidSdkManager; +namespace Android::Internal { class AndroidSdkModel : public QAbstractItemModel { @@ -27,7 +23,7 @@ public: PackageStateRole }; - explicit AndroidSdkModel(AndroidSdkManager *sdkManager, QObject *parent = nullptr); + explicit AndroidSdkModel(QObject *parent = nullptr); // QAbstractItemModel overrides. QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; @@ -47,11 +43,9 @@ public: private: void refreshData(); - AndroidSdkManager *m_sdkManager; QList m_sdkPlatforms; QList m_tools; QSet m_changeState; }; -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 080c6d4b379..aa3f3424902 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -262,8 +262,8 @@ static expected_str testJavaC(const FilePath &jdkPath) } AndroidSettingsWidget::AndroidSettingsWidget() + : m_sdkManager(AndroidConfigurations::sdkManager()) { - m_sdkManager = AndroidConfigurations::sdkManager(); setWindowTitle(Tr::tr("Android Configuration")); const QIcon downloadIcon = Icons::ONLINE.icon(); @@ -479,7 +479,7 @@ AndroidSettingsWidget::AndroidSettingsWidget() connect(downloadOpenJdkToolButton, &QAbstractButton::clicked, this, &AndroidSettingsWidget::openOpenJDKDownloadUrl); connect(sdkManagerToolButton, &QAbstractButton::clicked, this, [this] { - executeAndroidSdkManagerDialog(m_sdkManager, this); + executeAndroidSdkManagerDialog(this); }); connect(sdkToolsAutoDownloadButton, &QAbstractButton::clicked, this, &AndroidSettingsWidget::downloadSdk); @@ -637,7 +637,7 @@ void AndroidSettingsWidget::validateSdk() m_androidSummary->setPointValid(PlatformToolsInstalledRow, // TODO: track me AndroidConfig::adbToolPath().exists()); m_androidSummary->setPointValid(AllEssentialsInstalledRow, - AndroidConfig::allEssentialsInstalled(m_sdkManager)); + AndroidConfig::allEssentialsInstalled()); m_androidSummary->setPointValid(BuildToolsInstalledRow, !AndroidConfig::buildToolsVersion().isNull()); // installedSdkPlatforms should not trigger a package reload as validate SDK is only called @@ -667,7 +667,7 @@ void AndroidSettingsWidget::validateSdk() // Add the a system image with highest API level only if there are other // essentials needed, so it would practicaly be somewhat optional. if (!missingPkgs.isEmpty()) { - const QString sysImage = AndroidConfig::optionalSystemImagePackage(m_sdkManager); + const QString sysImage = AndroidConfig::optionalSystemImagePackage(); if (!sysImage.isEmpty()) missingPkgs.append(sysImage); } diff --git a/src/plugins/android/avddialog.h b/src/plugins/android/avddialog.h index 55b8d5a4fa8..138b336c4b8 100644 --- a/src/plugins/android/avddialog.h +++ b/src/plugins/android/avddialog.h @@ -26,8 +26,6 @@ class SdkPlatform; namespace Internal { -class AndroidSdkManager; - class AvdDialog : public QDialog { public: From d46223d338cb9b1c1d078795133b7c05f3235457 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 11 Nov 2024 16:41:05 +0100 Subject: [PATCH 107/989] Android: Move more classes into Internal namespace Fix some includes. Change-Id: Iae6fe1b29e59af58a7832fc42a74dee1e7944dbe Reviewed-by: hjk --- src/plugins/android/androidavdmanager.cpp | 2 ++ src/plugins/android/androidconfigurations.cpp | 5 ++--- src/plugins/android/androidconfigurations.h | 7 +++---- src/plugins/android/androiddeviceinfo.cpp | 4 ++-- src/plugins/android/androiddeviceinfo.h | 6 +++--- .../android/androidextralibrarylistmodel.cpp | 4 ++-- .../android/androidextralibrarylistmodel.h | 4 ++-- src/plugins/android/androidglobal.h | 4 ++-- src/plugins/android/androidmanager.h | 6 ++---- ...androidmanifesteditoriconcontainerwidget.cpp | 6 ++---- .../androidmanifesteditoriconcontainerwidget.h | 6 ++---- .../android/androidmanifesteditoriconwidget.cpp | 10 +++------- .../android/androidmanifesteditoriconwidget.h | 6 ++---- src/plugins/android/androidrunconfiguration.cpp | 4 ++-- src/plugins/android/androidrunconfiguration.h | 4 ++-- src/plugins/android/androidrunnerworker.cpp | 4 +++- src/plugins/android/androidsdkmanager.h | 3 ++- src/plugins/android/androidsdkmodel.cpp | 12 ++++++------ src/plugins/android/androidsdkmodel.h | 7 ++++--- src/plugins/android/androidsdkpackage.cpp | 16 +++++++--------- src/plugins/android/androidsdkpackage.h | 17 ++++++++--------- src/plugins/android/androidtoolchain.h | 2 +- src/plugins/android/avddialog.h | 8 +++----- src/plugins/android/avdmanageroutputparser.cpp | 6 ++---- src/plugins/android/avdmanageroutputparser.h | 6 ++---- src/plugins/android/certificatesmodel.cpp | 7 +++---- src/plugins/android/certificatesmodel.h | 6 ++---- .../android/createandroidmanifestwizard.cpp | 6 ++---- src/plugins/android/javalanguageserver.cpp | 6 ++---- src/plugins/android/javalanguageserver.h | 6 ++---- 30 files changed, 82 insertions(+), 108 deletions(-) diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index cc7c3f343c9..ed392513cce 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -2,7 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "androidavdmanager.h" + #include "androidconfigurations.h" +#include "androiddeviceinfo.h" #include "androidtr.h" #include diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 92fae451fb6..186e1cb9f9b 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -84,8 +84,7 @@ std::optional tryGetFirstDirectory(const FilePath &path, const QString } } -namespace Android { -using namespace Internal; +namespace Android::Internal { #ifdef Q_OS_WIN32 #define ANDROID_BAT_SUFFIX ".bat" @@ -1626,6 +1625,6 @@ void setupAndroidConfigurations() static AndroidConfigurations theAndroidConfigurations; } -} // namespace Android +} // namespace Android::Internal #include "androidconfigurations.moc" diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index ea67b7b0b6f..d12443c30d7 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -4,7 +4,6 @@ #pragma once -#include "androiddeviceinfo.h" #include "androidsdkmanager.h" #include "androidsdkpackage.h" @@ -21,9 +20,9 @@ namespace ProjectExplorer { class Abi; } -namespace Android { +namespace Android::Internal { -namespace Internal { class AndroidSdkManager; } +class AndroidSdkManager; class CreateAvdInfo { @@ -157,7 +156,7 @@ QObject *createAndroidConfigurationsTest(); void setupAndroidConfigurations(); -} // namespace Android +} // namespace Android::Internal Q_DECLARE_METATYPE(ProjectExplorer::Abis) Q_DECLARE_METATYPE(Utils::OsType) diff --git a/src/plugins/android/androiddeviceinfo.cpp b/src/plugins/android/androiddeviceinfo.cpp index 3c00547d062..ac9e71ec786 100644 --- a/src/plugins/android/androiddeviceinfo.cpp +++ b/src/plugins/android/androiddeviceinfo.cpp @@ -3,7 +3,7 @@ #include "androiddeviceinfo.h" -namespace Android { +namespace Android::Internal { /** * Workaround for '????????????' serial numbers @@ -47,4 +47,4 @@ QDebug &operator<<(QDebug &stream, const AndroidDeviceInfo &device) return stream; } -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androiddeviceinfo.h b/src/plugins/android/androiddeviceinfo.h index 88b20126bd9..04dbe48915a 100644 --- a/src/plugins/android/androiddeviceinfo.h +++ b/src/plugins/android/androiddeviceinfo.h @@ -12,7 +12,7 @@ using namespace ProjectExplorer; -namespace Android { +namespace Android::Internal { class AndroidDeviceInfo { @@ -36,6 +36,6 @@ using AndroidDeviceInfoList = QList; QDebug &operator<<(QDebug &stream, const AndroidDeviceInfo &device); -} // namespace Android +} // namespace Android::Internal -Q_DECLARE_METATYPE(Android::AndroidDeviceInfo) +Q_DECLARE_METATYPE(Android::Internal::AndroidDeviceInfo) diff --git a/src/plugins/android/androidextralibrarylistmodel.cpp b/src/plugins/android/androidextralibrarylistmodel.cpp index 85ef4988657..ac9084def7a 100644 --- a/src/plugins/android/androidextralibrarylistmodel.cpp +++ b/src/plugins/android/androidextralibrarylistmodel.cpp @@ -17,7 +17,7 @@ using namespace ProjectExplorer; -namespace Android { +namespace Android::Internal { AndroidExtraLibraryListModel::AndroidExtraLibraryListModel(BuildSystem *buildSystem, QObject *parent) @@ -137,4 +137,4 @@ void AndroidExtraLibraryListModel::removeEntries(QModelIndexList list) m_buildSystem->setExtraData(buildKey, Constants::AndroidExtraLibs, m_entries); } -} // Android +} // Android::Internal diff --git a/src/plugins/android/androidextralibrarylistmodel.h b/src/plugins/android/androidextralibrarylistmodel.h index 6f236cb8eac..e9378631a31 100644 --- a/src/plugins/android/androidextralibrarylistmodel.h +++ b/src/plugins/android/androidextralibrarylistmodel.h @@ -9,7 +9,7 @@ namespace ProjectExplorer { class BuildSystem; } -namespace Android { +namespace Android::Internal { class AndroidExtraLibraryListModel : public QAbstractItemModel { @@ -37,4 +37,4 @@ private: QStringList m_entries; }; -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidglobal.h b/src/plugins/android/androidglobal.h index d1755401f31..e21a7ecefbd 100644 --- a/src/plugins/android/androidglobal.h +++ b/src/plugins/android/androidglobal.h @@ -11,7 +11,7 @@ #define ASSERT_STATE_GENERIC(State, expected, actual) \ AndroidGlobal::assertState(expected, actual, Q_FUNC_INFO) -namespace Android { +namespace Android::Internal { class AndroidGlobal { @@ -32,4 +32,4 @@ public: } }; -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h index 8da8e0aebc2..9c5ce74ba7d 100644 --- a/src/plugins/android/androidmanager.h +++ b/src/plugins/android/androidmanager.h @@ -16,8 +16,7 @@ class FilePath; class Process; } -namespace Android { -namespace AndroidManager { +namespace Android::AndroidManager { QString packageName(const ProjectExplorer::Target *target); QString activityName(const ProjectExplorer::Target *target); @@ -56,5 +55,4 @@ QString androidNameForApiLevel(int x); QJsonObject deploymentSettings(const ProjectExplorer::Target *target); bool isQtCreatorGenerated(const Utils::FilePath &deploymentFile); -} // namespace AndroidManager -} // namespace Android +} // namespace Android::AndroidManager diff --git a/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp b/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp index b6ccc7aeef0..ea4e05f2b30 100644 --- a/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp +++ b/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp @@ -12,8 +12,7 @@ using namespace Utils; -namespace Android { -namespace Internal { +namespace Android::Internal { const char extraExtraExtraHighDpiIconPath[] = "/res/drawable-xxxhdpi/"; const char extraExtraHighDpiIconPath[] = "/res/drawable-xxhdpi/"; @@ -170,5 +169,4 @@ bool AndroidManifestEditorIconContainerWidget::hasIcons() const return false; } -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidmanifesteditoriconcontainerwidget.h b/src/plugins/android/androidmanifesteditoriconcontainerwidget.h index 28caf07c784..77a0f7a4a75 100644 --- a/src/plugins/android/androidmanifesteditoriconcontainerwidget.h +++ b/src/plugins/android/androidmanifesteditoriconcontainerwidget.h @@ -13,8 +13,7 @@ namespace TextEditor { class TextEditorWidget; } -namespace Android { -namespace Internal { +namespace Android::Internal { class AndroidManifestEditorIconWidget; @@ -37,5 +36,4 @@ signals: void iconsModified(); }; -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidmanifesteditoriconwidget.cpp b/src/plugins/android/androidmanifesteditoriconwidget.cpp index 5e2b7ae095c..0bf460867a0 100644 --- a/src/plugins/android/androidmanifesteditoriconwidget.cpp +++ b/src/plugins/android/androidmanifesteditoriconwidget.cpp @@ -19,8 +19,7 @@ using namespace Utils; -namespace Android { -namespace Internal { +namespace Android::Internal { static Q_LOGGING_CATEGORY(androidManifestEditorLog, "qtc.android.manifestEditor", QtWarningMsg) @@ -31,9 +30,7 @@ static FilePath manifestDir(TextEditor::TextEditorWidget *textEditorWidget) } AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(QWidget *parent) : QWidget(parent) -{ - -} +{} AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget( QWidget *parent, const QSize &iconSize, const QSize &buttonSize, const QString &title, @@ -284,5 +281,4 @@ void AndroidManifestEditorIconWidget::copyIcon() } } -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidmanifesteditoriconwidget.h b/src/plugins/android/androidmanifesteditoriconwidget.h index 6fb0b274ff9..5d6b0b0647b 100644 --- a/src/plugins/android/androidmanifesteditoriconwidget.h +++ b/src/plugins/android/androidmanifesteditoriconwidget.h @@ -14,8 +14,7 @@ class QLabel; class QToolButton; QT_END_NAMESPACE -namespace Android { -namespace Internal { +namespace Android::Internal { class AndroidManifestEditorIconWidget : public QWidget { @@ -66,5 +65,4 @@ private: bool m_scaledWithoutStretching = false; }; -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index 14846d9ddf8..53e1a05779e 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -23,7 +23,7 @@ using namespace ProjectExplorer; using namespace Utils; -namespace Android { +namespace Android::Internal { class BaseStringListAspect final : public Utils::StringAspect { @@ -109,4 +109,4 @@ void setupAndroidRunConfiguration() static AndroidRunConfigurationFactory theAndroidRunConfigurationFactory; } -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidrunconfiguration.h b/src/plugins/android/androidrunconfiguration.h index 0be06985e9d..7a0a1948a54 100644 --- a/src/plugins/android/androidrunconfiguration.h +++ b/src/plugins/android/androidrunconfiguration.h @@ -5,8 +5,8 @@ #include -namespace Android { +namespace Android::Internal { void setupAndroidRunConfiguration(); -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index b244dbc89c5..8a8698262cf 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -1,10 +1,12 @@ // Copyright (C) 2018 BogDan Vatra // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "androidrunnerworker.h" + #include "androidconfigurations.h" #include "androidconstants.h" +#include "androiddeviceinfo.h" #include "androidmanager.h" -#include "androidrunnerworker.h" #include "androidtr.h" #include diff --git a/src/plugins/android/androidsdkmanager.h b/src/plugins/android/androidsdkmanager.h index f80de1bce8a..a00746c1964 100644 --- a/src/plugins/android/androidsdkmanager.h +++ b/src/plugins/android/androidsdkmanager.h @@ -18,8 +18,9 @@ namespace Android::Internal { class AndroidSdkManagerPrivate; -struct InstallationChange +class InstallationChange { +public: QStringList toInstall; QStringList toUninstall = {}; int count() const { return toInstall.count() + toUninstall.count(); } diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp index 6eb4045fbfd..cdcaf4306de 100644 --- a/src/plugins/android/androidsdkmodel.cpp +++ b/src/plugins/android/androidsdkmodel.cpp @@ -1,9 +1,11 @@ // Copyright (C) 2017 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "androidmanager.h" -#include "androidsdkmanager.h" #include "androidsdkmodel.h" + +#include "androidmanager.h" +#include "androidconfigurations.h" +#include "androidsdkmanager.h" #include "androidtr.h" #include @@ -12,8 +14,7 @@ #include -namespace Android { -namespace Internal { +namespace Android::Internal { const int packageColCount = 3; @@ -293,5 +294,4 @@ void AndroidSdkModel::refreshData() endResetModel(); } -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidsdkmodel.h b/src/plugins/android/androidsdkmodel.h index 2137a3e87f1..dc9292560d1 100644 --- a/src/plugins/android/androidsdkmodel.h +++ b/src/plugins/android/androidsdkmodel.h @@ -2,13 +2,14 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -// TODO: remove -#include "androidconfigurations.h" - #include namespace Android::Internal { +class AndroidSdkPackage; +class InstallationChange; +class SdkPlatform; + class AndroidSdkModel : public QAbstractItemModel { public: diff --git a/src/plugins/android/androidsdkpackage.cpp b/src/plugins/android/androidsdkpackage.cpp index 9d182310893..d968b29401d 100644 --- a/src/plugins/android/androidsdkpackage.cpp +++ b/src/plugins/android/androidsdkpackage.cpp @@ -4,16 +4,14 @@ #include -namespace Android { +namespace Android::Internal { AndroidSdkPackage::AndroidSdkPackage(const QVersionNumber &version, const QString &sdkStylePathStr, - QObject *parent) : - QObject(parent), - m_revision(version), - m_sdkStylePath(sdkStylePathStr) -{ - -} + QObject *parent) + : QObject(parent) + , m_revision(version) + , m_sdkStylePath(sdkStylePathStr) +{} bool AndroidSdkPackage::operator <(const AndroidSdkPackage &other) const { @@ -183,4 +181,4 @@ SystemImageList SdkPlatform::systemImages(PackageState state) const }); } -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/androidsdkpackage.h b/src/plugins/android/androidsdkpackage.h index 5baa04c75cd..32f6ed18dc8 100644 --- a/src/plugins/android/androidsdkpackage.h +++ b/src/plugins/android/androidsdkpackage.h @@ -10,19 +10,17 @@ #pragma once -namespace Android { +namespace Android::Internal { class AndroidSdkPackage; - -namespace Internal { - class SdkManagerOutputParser; - class AndroidToolOutputParser; - template - AndroidSdkPackage *parsePackage(const QStringList &, int, const QString &); -} +class AndroidToolOutputParser; +class SdkManagerOutputParser; class SdkPlatform; class SystemImage; +template +AndroidSdkPackage *parsePackage(const QStringList &, int, const QString &); + class AndroidSdkPackage : public QObject { Q_OBJECT @@ -208,6 +206,7 @@ public: bool isValid() const override { return installedLocation().exists(); } PackageType type() const override { return AndroidSdkPackage::GenericSdkPackage; } }; -} // namespace Android + +} // namespace Android::Internal diff --git a/src/plugins/android/androidtoolchain.h b/src/plugins/android/androidtoolchain.h index f336bc257b8..bf2e955141f 100644 --- a/src/plugins/android/androidtoolchain.h +++ b/src/plugins/android/androidtoolchain.h @@ -41,4 +41,4 @@ ToolchainList autodetectToolchainsFromNdks(const ToolchainList &alreadyKnown, void setupAndroidToolchain(); -} // Android +} // Android::Internal diff --git a/src/plugins/android/avddialog.h b/src/plugins/android/avddialog.h index 138b336c4b8..3cb3a3c62d4 100644 --- a/src/plugins/android/avddialog.h +++ b/src/plugins/android/avddialog.h @@ -21,10 +21,9 @@ QT_END_NAMESPACE namespace Utils { class InfoLabel; } -namespace Android { -class SdkPlatform; +namespace Android::Internal { -namespace Internal { +class SdkPlatform; class AvdDialog : public QDialog { @@ -77,5 +76,4 @@ private: Tasking::TaskTreeRunner m_taskTreeRunner; }; -} // Internal -} // Android +} // Android::Internal diff --git a/src/plugins/android/avdmanageroutputparser.cpp b/src/plugins/android/avdmanageroutputparser.cpp index 8309fee7810..ecb3f77da75 100644 --- a/src/plugins/android/avdmanageroutputparser.cpp +++ b/src/plugins/android/avdmanageroutputparser.cpp @@ -26,8 +26,7 @@ const char avdInfoAbiKey[] = "abi.type"; const char avdInfoTargetKey[] = "target"; const char avdInfoErrorKey[] = "Error:"; -namespace Android { -namespace Internal { +namespace Android::Internal { /*! Parses the \a line for a [spaces]key[spaces]value[spaces] pattern and returns @@ -164,5 +163,4 @@ QString convertNameToExtension(const QString &name) return {}; } -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/avdmanageroutputparser.h b/src/plugins/android/avdmanageroutputparser.h index 81cbe64eaa3..5bdcd2d370c 100644 --- a/src/plugins/android/avdmanageroutputparser.h +++ b/src/plugins/android/avdmanageroutputparser.h @@ -5,8 +5,7 @@ #include "androiddeviceinfo.h" -namespace Android { -namespace Internal { +namespace Android::Internal { const char avdManufacturerError[] = "no longer exists as a device"; @@ -20,5 +19,4 @@ ParsedAvdList parseAvdList(const QString &output); int platformNameToApiLevel(const QString &platformName); QString convertNameToExtension(const QString &name); -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/certificatesmodel.cpp b/src/plugins/android/certificatesmodel.cpp index 4c80fe3972a..7ba86cfafe6 100644 --- a/src/plugins/android/certificatesmodel.cpp +++ b/src/plugins/android/certificatesmodel.cpp @@ -6,13 +6,10 @@ #include -using namespace Android; -using namespace Android::Internal; +namespace Android::Internal { -namespace { const QLatin1String AliasString("Alias name:"); const QLatin1String CertificateSeparator("*******************************************"); -} CertificatesModel::CertificatesModel(const QString &rowCertificates, QObject *parent) : QAbstractListModel(parent) @@ -45,3 +42,5 @@ QVariant CertificatesModel::data(const QModelIndex &index, int role) const return m_certs[index.row()].first; return m_certs[index.row()].second; } + +} // namespace Android::Internal diff --git a/src/plugins/android/certificatesmodel.h b/src/plugins/android/certificatesmodel.h index acb371205de..5a3b933047c 100644 --- a/src/plugins/android/certificatesmodel.h +++ b/src/plugins/android/certificatesmodel.h @@ -8,8 +8,7 @@ #include #include -namespace Android { -namespace Internal { +namespace Android::Internal { class CertificatesModel: public QAbstractListModel { @@ -25,5 +24,4 @@ private: QList> m_certs; }; -} -} +} // namespace Android::Internal diff --git a/src/plugins/android/createandroidmanifestwizard.cpp b/src/plugins/android/createandroidmanifestwizard.cpp index beb4448fb1e..62c867fa423 100644 --- a/src/plugins/android/createandroidmanifestwizard.cpp +++ b/src/plugins/android/createandroidmanifestwizard.cpp @@ -34,8 +34,7 @@ using namespace ProjectExplorer; using namespace Utils; -namespace Android { -namespace Internal { +namespace Android::Internal { // // NoApplicationTargetPage @@ -333,5 +332,4 @@ void CreateAndroidManifestWizard::accept() Wizard::accept(); } -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/javalanguageserver.cpp b/src/plugins/android/javalanguageserver.cpp index e0117b3b3c9..6dbf510121a 100644 --- a/src/plugins/android/javalanguageserver.cpp +++ b/src/plugins/android/javalanguageserver.cpp @@ -33,8 +33,7 @@ using namespace Utils; constexpr char languageServerKey[] = "languageServer"; -namespace Android { -namespace Internal { +namespace Android::Internal { class JLSSettingsWidget : public QWidget { @@ -338,5 +337,4 @@ LanguageClient::Client *JLSSettings::createClient(LanguageClient::BaseClientInte return new JLSClient(interface); } -} // namespace Internal -} // namespace Android +} // namespace Android::Internal diff --git a/src/plugins/android/javalanguageserver.h b/src/plugins/android/javalanguageserver.h index e170eb254a5..b3fc8f0e282 100644 --- a/src/plugins/android/javalanguageserver.h +++ b/src/plugins/android/javalanguageserver.h @@ -5,8 +5,7 @@ #include -namespace Android { -namespace Internal { +namespace Android::Internal { class JLSSettings final : public LanguageClient::StdIOSettings { @@ -29,5 +28,4 @@ private: JLSSettings(const JLSSettings &other) = default; }; -} // namespace Internal -} // namespace Android +} // namespace Android::Internal From 092ffa597464a49f9f4dbfe1dabf52b6b676ef4a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 11 Nov 2024 17:15:17 +0100 Subject: [PATCH 108/989] Android: Move AndroidSdkManager instance into its class Provide global getter: AndroidSdkManager &sdkManager(); Change-Id: I6eec89374d2b32d09b083912443f9cc36b40fa03 Reviewed-by: hjk --- src/plugins/android/androidbuildapkstep.cpp | 14 ++++------ src/plugins/android/androidconfigurations.cpp | 15 +++------- src/plugins/android/androidconfigurations.h | 5 ---- src/plugins/android/androidmanager.cpp | 4 +-- src/plugins/android/androidsdkmanager.cpp | 6 ++++ src/plugins/android/androidsdkmanager.h | 1 + .../android/androidsdkmanagerdialog.cpp | 21 +++++++------- src/plugins/android/androidsdkmodel.cpp | 4 +-- src/plugins/android/androidsettingswidget.cpp | 28 +++++++++---------- src/plugins/android/avddialog.cpp | 3 +- 10 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 1b068ed5151..a9711314ea9 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -240,8 +240,8 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) QtSupport::QtVersion *qt = QtSupport::QtKitAspect::qtVersion(m_step->target()->kit()); const int minApiSupported = AndroidManager::defaultMinimumSDK(qt); - QStringList targets = AndroidConfig::apiLevelNamesFor(AndroidConfigurations::sdkManager()-> - filteredSdkPlatforms(minApiSupported)); + QStringList targets = AndroidConfig::apiLevelNamesFor( + sdkManager().filteredSdkPlatforms(minApiSupported)); targets.removeDuplicates(); auto targetSDKComboBox = new QComboBox(); @@ -254,8 +254,8 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) }); targetSDKComboBox->setCurrentIndex(targets.indexOf(m_step->buildTargetSdk())); - const QList buildToolsVersions = Utils::transform( - AndroidConfigurations::sdkManager()->filteredBuildTools(minApiSupported), + const QList buildToolsVersions + = Utils::transform(sdkManager().filteredBuildTools(minApiSupported), [](const BuildTools *pkg) { return pkg->revision(); }); @@ -483,8 +483,7 @@ void AndroidBuildApkWidget::updateSigningWarning() AndroidBuildApkStep::AndroidBuildApkStep(BuildStepList *parent, Utils::Id id) : AbstractProcessStep(parent, id), - m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations:: - sdkManager()->latestAndroidSdkPlatform())) + m_buildTargetSdk(AndroidConfig::apiLevelNameFor(sdkManager().latestAndroidSdkPlatform())) { setImmutable(true); setDisplayName(Tr::tr("Build Android APK")); @@ -913,8 +912,7 @@ void AndroidBuildApkStep::fromMap(const Store &map) m_buildTargetSdk = map.value(BuildTargetSdkKey).toString(); m_buildToolsVersion = QVersionNumber::fromString(map.value(BuildToolsVersionKey).toString()); if (m_buildTargetSdk.isEmpty()) { - m_buildTargetSdk = AndroidConfig::apiLevelNameFor(AndroidConfigurations:: - sdkManager()->latestAndroidSdkPlatform()); + m_buildTargetSdk = AndroidConfig::apiLevelNameFor(sdkManager().latestAndroidSdkPlatform()); } ProjectExplorer::BuildStep::fromMap(map); } diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 186e1cb9f9b..d604bec8b35 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -7,6 +7,7 @@ #include "androiddevice.h" #include "androidmanager.h" #include "androidqtversion.h" +#include "androidsdkmanager.h" #include "androidtoolchain.h" #include "androidtr.h" @@ -52,7 +53,6 @@ #include #include -#include #ifdef WITH_TESTS # include @@ -906,8 +906,7 @@ static QString essentialBuiltWithBuildToolsPackage(int builtWithApiVersion) // invalidated whenever a new minor version is released, check if any version with major // version matching builtWith apiVersion and use it as essential, otherwise use the any // other one that has an minimum major version of builtWith apiVersion. - const BuildToolsList buildTools = - AndroidConfigurations::sdkManager()->filteredBuildTools(builtWithApiVersion); + const BuildToolsList buildTools = sdkManager().filteredBuildTools(builtWithApiVersion); const BuildToolsList apiBuildTools = Utils::filtered(buildTools, [builtWithApiVersion] (const BuildTools *pkg) { return pkg->revision().majorVersion() == builtWithApiVersion; }); @@ -997,7 +996,7 @@ QString optionalSystemImagePackage() const auto imageName = QLatin1String("%1;android-%2;google_apis_playstore;%3") .arg(Constants::systemImagesPackageName).arg(apiLevel).arg(hostArch); - const SdkPlatformList sdkPlatforms = AndroidConfigurations::sdkManager()->filteredSdkPlatforms( + const SdkPlatformList sdkPlatforms = sdkManager().filteredSdkPlatforms( apiLevel, AndroidSdkPackage::AnyValidState); if (sdkPlatforms.isEmpty()) @@ -1022,7 +1021,7 @@ static QStringList packagesWithoutNdks(const QStringList &packages) bool allEssentialsInstalled() { QStringList essentialPkgs(allEssentials()); - const auto installedPkgs = AndroidConfigurations::sdkManager()->installedSdkPackages(); + const auto installedPkgs = sdkManager().installedSdkPackages(); for (const AndroidSdkPackage *pkg : installedPkgs) { if (essentialPkgs.contains(pkg->sdkStylePath())) essentialPkgs.removeOne(pkg->sdkStylePath()); @@ -1210,7 +1209,6 @@ FilePath getJdkPath() AndroidConfigurations *m_instance = nullptr; AndroidConfigurations::AndroidConfigurations() - : m_sdkManager(new AndroidSdkManager) { load(); connect(DeviceManager::instance(), &DeviceManager::devicesLoaded, @@ -1510,11 +1508,6 @@ void AndroidConfigurations::updateAutomaticKitList() KitManager::deregisterKits(unhandledKits); } -AndroidSdkManager *AndroidConfigurations::sdkManager() -{ - return m_instance->m_sdkManager.get(); -} - AndroidConfigurations *AndroidConfigurations::instance() { return m_instance; diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index d12443c30d7..a94ffd188cc 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -4,7 +4,6 @@ #pragma once -#include "androidsdkmanager.h" #include "androidsdkpackage.h" #include @@ -22,8 +21,6 @@ namespace ProjectExplorer { class Abi; } namespace Android::Internal { -class AndroidSdkManager; - class CreateAvdInfo { public: @@ -124,7 +121,6 @@ class AndroidConfigurations : public QObject Q_OBJECT public: - static Internal::AndroidSdkManager *sdkManager(); static void applyConfig(); static AndroidConfigurations *instance(); @@ -147,7 +143,6 @@ private: void save(); static void updateAndroidDevice(); - std::unique_ptr m_sdkManager; }; #ifdef WITH_TESTS diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index f1e1f694f27..6733aea4cf0 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -7,6 +7,7 @@ #include "androidconfigurations.h" #include "androidconstants.h" #include "androidqtversion.h" +#include "androidsdkmanager.h" #include "androidtr.h" #include @@ -209,8 +210,7 @@ QString buildTargetSDK(const Target *target) return androidBuildApkStep->buildTargetSdk(); } - QString fallback = AndroidConfig::apiLevelNameFor( - AndroidConfigurations::sdkManager()->latestAndroidSdkPlatform()); + QString fallback = AndroidConfig::apiLevelNameFor(sdkManager().latestAndroidSdkPlatform()); return fallback; } diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index b0cfa4bfdcb..09b07b954e5 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -630,6 +630,12 @@ void AndroidSdkManager::runUpdate() m_d->runDialogRecipe(dialogStorage, licensesRecipe(dialogStorage), updateRecipe(dialogStorage)); } +AndroidSdkManager &sdkManager() +{ + static AndroidSdkManager theAndroidSdkManager; + return theAndroidSdkManager; +} + } // namespace Android::Internal #include "androidsdkmanager.moc" diff --git a/src/plugins/android/androidsdkmanager.h b/src/plugins/android/androidsdkmanager.h index a00746c1964..e5c3d5a4252 100644 --- a/src/plugins/android/androidsdkmanager.h +++ b/src/plugins/android/androidsdkmanager.h @@ -69,5 +69,6 @@ private: }; const QRegularExpression &assertionRegExp(); +AndroidSdkManager &sdkManager(); } // namespace Android::Internal diff --git a/src/plugins/android/androidsdkmanagerdialog.cpp b/src/plugins/android/androidsdkmanagerdialog.cpp index 3359f85dc01..b8abcd6fbbe 100644 --- a/src/plugins/android/androidsdkmanagerdialog.cpp +++ b/src/plugins/android/androidsdkmanagerdialog.cpp @@ -108,7 +108,6 @@ public: AndroidSdkManagerDialog(QWidget *parent); private: - AndroidSdkManager *m_sdkManager = nullptr; AndroidSdkModel *m_sdkModel = nullptr; }; @@ -196,7 +195,7 @@ AndroidSdkManagerDialog::AndroidSdkManagerDialog(QWidget *parent) packagesView->collapseAll(); }); connect(updateInstalledButton, &QPushButton::clicked, - m_sdkManager, &AndroidSdkManager::runUpdate); + &sdkManager(), &AndroidSdkManager::runUpdate); connect(showAllRadio, &QRadioButton::toggled, this, [this, proxyModel](bool checked) { if (checked) { proxyModel->setAcceptedPackageState(AndroidSdkPackage::AnyValidState); @@ -225,7 +224,7 @@ AndroidSdkManagerDialog::AndroidSdkManagerDialog(QWidget *parent) }); connect(buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, this, [this] { - m_sdkManager->runInstallationChange(m_sdkModel->installationChange()); + sdkManager().runInstallationChange(m_sdkModel->installationChange()); }); connect(buttonBox, &QDialogButtonBox::rejected, this, &AndroidSdkManagerDialog::reject); @@ -235,25 +234,25 @@ AndroidSdkManagerDialog::AndroidSdkManagerDialog(QWidget *parent) QStringList arguments = dlg.sdkManagerArguments(); if (arguments != AndroidConfig::sdkManagerToolArgs()) { AndroidConfig::setSdkManagerToolArgs(arguments); - m_sdkManager->reloadPackages(); + sdkManager().reloadPackages(); } } }); - connect(obsoleteCheckBox, &QCheckBox::stateChanged, this, [this](int state) { + connect(obsoleteCheckBox, &QCheckBox::stateChanged, this, [](int state) { const QString obsoleteArg = "--include_obsolete"; QStringList args = AndroidConfig::sdkManagerToolArgs(); if (state == Qt::Checked && !args.contains(obsoleteArg)) { args.append(obsoleteArg); AndroidConfig::setSdkManagerToolArgs(args); - } else if (state == Qt::Unchecked && args.contains(obsoleteArg)) { + } else if (state == Qt::Unchecked && args.contains(obsoleteArg)) { args.removeAll(obsoleteArg); AndroidConfig::setSdkManagerToolArgs(args); - } - m_sdkManager->reloadPackages(); + } + sdkManager().reloadPackages(); }); - connect(channelCheckbox, &QComboBox::currentIndexChanged, this, [this](int index) { + connect(channelCheckbox, &QComboBox::currentIndexChanged, this, [](int index) { QStringList args = AndroidConfig::sdkManagerToolArgs(); QString existingArg; for (int i = 0; i < 4; ++i) { @@ -278,8 +277,8 @@ AndroidSdkManagerDialog::AndroidSdkManagerDialog(QWidget *parent) args.append(channelArg); AndroidConfig::setSdkManagerToolArgs(args); } - } - m_sdkManager->reloadPackages(); + } + sdkManager().reloadPackages(); }); } diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp index cdcaf4306de..d73731512a3 100644 --- a/src/plugins/android/androidsdkmodel.cpp +++ b/src/plugins/android/androidsdkmodel.cpp @@ -21,7 +21,7 @@ const int packageColCount = 3; AndroidSdkModel::AndroidSdkModel(QObject *parent) : QAbstractItemModel(parent) { - connect(AndroidConfigurations::sdkManager(), &AndroidSdkManager::packagesReloaded, + connect(&sdkManager(), &AndroidSdkManager::packagesReloaded, this, &AndroidSdkModel::refreshData); refreshData(); } @@ -275,7 +275,7 @@ void AndroidSdkModel::refreshData() m_tools.clear(); m_changeState.clear(); beginResetModel(); - for (AndroidSdkPackage *p : AndroidConfigurations::sdkManager()->allSdkPackages()) { + for (AndroidSdkPackage *p : sdkManager().allSdkPackages()) { if (p->type() == AndroidSdkPackage::SdkPlatformPackage) m_sdkPlatforms << static_cast(p); else diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index aa3f3424902..8224b18e644 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -180,7 +180,6 @@ private: bool isDefaultNdkSelected() const; void validateOpenSsl(); - AndroidSdkManager *m_sdkManager; Tasking::TaskTreeRunner m_sdkDownloader; bool m_isInitialReloadDone = false; @@ -262,7 +261,6 @@ static expected_str testJavaC(const FilePath &jdkPath) } AndroidSettingsWidget::AndroidSettingsWidget() - : m_sdkManager(AndroidConfigurations::sdkManager()) { setWindowTitle(Tr::tr("Android Configuration")); @@ -288,7 +286,7 @@ AndroidSettingsWidget::AndroidSettingsWidget() "be compatible with all registered Qt versions.")); auto androidDetailsWidget = new DetailsWidget; - m_sdkManager->setSpinnerTarget(androidDetailsWidget); + sdkManager().setSpinnerTarget(androidDetailsWidget); m_ndkListWidget = new QListWidget; m_ndkListWidget->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); @@ -493,11 +491,11 @@ AndroidSettingsWidget::AndroidSettingsWidget() Tr::tr("Failed to create the SDK Tools path %1.") .arg("\n\"" + sdkPath.toUserOutput() + "\"")); } - m_sdkManager->reloadPackages(); + sdkManager().reloadPackages(); updateUI(); apply(); - connect(m_sdkManager, &AndroidSdkManager::packagesReloaded, this, [this] { + connect(&sdkManager(), &AndroidSdkManager::packagesReloaded, this, [this] { downloadOpenSslRepo(true); }, Qt::SingleShotConnection); }); @@ -513,10 +511,10 @@ void AndroidSettingsWidget::showEvent(QShowEvent *event) // Reloading SDK packages (force) is still synchronous. Use zero timer // to let settings dialog open first. QTimer::singleShot(0, this, [this] { - m_sdkManager->refreshPackages(); + sdkManager().refreshPackages(); validateSdk(); // Validate SDK again after any change in SDK packages. - connect(m_sdkManager, &AndroidSdkManager::packagesReloaded, this, [this] { + connect(&sdkManager(), &AndroidSdkManager::packagesReloaded, this, [this] { m_androidSummary->setInProgressText("Packages reloaded"); m_sdkLocationPathChooser->triggerChanged(); validateSdk(); @@ -530,7 +528,7 @@ void AndroidSettingsWidget::showEvent(QShowEvent *event) void AndroidSettingsWidget::updateNdkList() { m_ndkListWidget->clear(); - const auto installedPkgs = m_sdkManager->installedNdkPackages(); + const auto installedPkgs = sdkManager().installedNdkPackages(); for (const Ndk *ndk : installedPkgs) { m_ndkListWidget->addItem(new QListWidgetItem(Icons::LOCKED.icon(), ndk->installedLocation().toUserOutput())); @@ -593,7 +591,7 @@ void AndroidSettingsWidget::validateJdk() updateUI(); if (m_isInitialReloadDone) - m_sdkManager->reloadPackages(); + sdkManager().reloadPackages(); } void AndroidSettingsWidget::validateOpenSsl() @@ -620,7 +618,7 @@ void AndroidSettingsWidget::onSdkPathChanged() currentOpenSslPath = sdkPath.pathAppended("android_openssl"); m_openSslPathChooser->setFilePath(currentOpenSslPath); // Package reload will trigger validateSdk. - m_sdkManager->refreshPackages(); + sdkManager().refreshPackages(); } void AndroidSettingsWidget::validateSdk() @@ -633,7 +631,7 @@ void AndroidSettingsWidget::validateSdk() m_androidSummary->setPointValid(SdkToolsInstalledRow, !AndroidConfig::sdkToolsVersion().isNull()); m_androidSummary->setPointValid(SdkManagerSuccessfulRow, // TODO: track me - m_sdkManager->packageListingSuccessful()); + sdkManager().packageListingSuccessful()); m_androidSummary->setPointValid(PlatformToolsInstalledRow, // TODO: track me AndroidConfig::adbToolPath().exists()); m_androidSummary->setPointValid(AllEssentialsInstalledRow, @@ -643,7 +641,7 @@ void AndroidSettingsWidget::validateSdk() // installedSdkPlatforms should not trigger a package reload as validate SDK is only called // after AndroidSdkManager::packageReloadFinished. m_androidSummary->setPointValid(PlatformSdkInstalledRow, - !m_sdkManager->installedSdkPlatforms().isEmpty()); + !sdkManager().installedSdkPlatforms().isEmpty()); const bool sdkToolsOk = m_androidSummary->rowsOk({SdkPathExistsAndWritableRow, SdkToolsInstalledRow, @@ -654,7 +652,7 @@ void AndroidSettingsWidget::validateSdk() AllEssentialsInstalledRow}); AndroidConfig::setSdkFullyConfigured(sdkToolsOk && componentsOk); if (sdkToolsOk && !componentsOk) { - const QStringList notFoundEssentials = m_sdkManager->notFoundEssentialSdkPackages(); + const QStringList notFoundEssentials = sdkManager().notFoundEssentialSdkPackages(); if (!notFoundEssentials.isEmpty()) { QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Android SDK Changes"), @@ -663,7 +661,7 @@ void AndroidSettingsWidget::validateSdk() .arg(QGuiApplication::applicationDisplayName(), notFoundEssentials.join("\", \""))); } - QStringList missingPkgs = m_sdkManager->missingEssentialSdkPackages(); + QStringList missingPkgs = sdkManager().missingEssentialSdkPackages(); // Add the a system image with highest API level only if there are other // essentials needed, so it would practicaly be somewhat optional. if (!missingPkgs.isEmpty()) { @@ -671,7 +669,7 @@ void AndroidSettingsWidget::validateSdk() if (!sysImage.isEmpty()) missingPkgs.append(sysImage); } - m_sdkManager->runInstallationChange({missingPkgs}, + sdkManager().runInstallationChange({missingPkgs}, Tr::tr("Android SDK installation is missing necessary packages. " "Do you want to install the missing packages?")); } diff --git a/src/plugins/android/avddialog.cpp b/src/plugins/android/avddialog.cpp index 57d78dab6a2..39a0780b2de 100644 --- a/src/plugins/android/avddialog.cpp +++ b/src/plugins/android/avddialog.cpp @@ -357,8 +357,7 @@ int AvdDialog::sdcardSize() const void AvdDialog::updateApiLevelComboBox() { - const SystemImageList installedSystemImages - = AndroidConfigurations::sdkManager()->installedSystemImages(); + const SystemImageList installedSystemImages = sdkManager().installedSystemImages(); DeviceType curDeviceType = m_deviceTypeToStringMap.key( m_deviceDefinitionTypeComboBox->currentText()); From 77c680bc30d654618fa08b587c0ce1bd85875f04 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 11 Nov 2024 16:29:24 +0100 Subject: [PATCH 109/989] ProjectExplorer: Let a kit aspect widget embed other kit aspect widgets ... and use this functionality to visually merge the closely related "run device" and "run device type" aspects. Change-Id: I648dcbd8e08a45b7b2ddf7380942c47f0de62cf9 Reviewed-by: hjk --- .../devicesupport/devicekitaspects.cpp | 18 ++++++++ src/plugins/projectexplorer/kitaspect.cpp | 13 +++++- src/plugins/projectexplorer/kitaspect.h | 16 +++++-- .../kitmanagerconfigwidget.cpp | 43 ++++++++++++++----- .../projectexplorer/kitmanagerconfigwidget.h | 2 +- 5 files changed, 76 insertions(+), 16 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 13ff4d83abf..59b8f8c1793 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -22,6 +22,7 @@ #include #include +#include #include @@ -184,6 +185,22 @@ public: private: Id settingsPageItemToPreselect() const override { return RunDeviceKitAspect::deviceId(kit()); } + + void addToInnerLayout(Layouting::Layout &parentItem) override + { + Layouting::Layout layout = parentItem; + if (const QList embedded = aspectsToEmbed(); !embedded.isEmpty()) { + layout = Layouting::Layout(new QHBoxLayout); + parentItem.addItem(layout); + layout.addItem(Tr::tr("Type:")); + embedded.first()->addToInnerLayout(layout); + layout.addItem(Tr::tr("Device:")); + KitAspect::addToInnerLayout(layout); + layout.addItem(Layouting::Stretch(1)); + } else { + KitAspect::addToInnerLayout(layout); + } + } }; class DeviceKitAspectFactory : public KitAspectFactory @@ -218,6 +235,7 @@ DeviceKitAspectFactory::DeviceKitAspectFactory() setDisplayName(Tr::tr("Run device")); setDescription(Tr::tr("The device to run the applications on.")); setPriority(32000); + setEmbeddableAspects({DeviceTypeKitAspect::id()}); } QVariant DeviceKitAspectFactory::defaultValue(const Kit *k) const diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index 6ef1845796d..52b8a9028d2 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -120,6 +120,7 @@ public: Utils::Id managingPageId; QPushButton *manageButton = nullptr; Utils::Guard ignoreChanges; + QList aspectsToEmbed; struct ListAspect { @@ -197,7 +198,7 @@ void KitAspect::addToInnerLayout(Layouting::Layout &parentItem) void KitAspect::addListAspectSpec(const ListAspectSpec &listAspectSpec) { const auto comboBox = createSubWidget(); - comboBox->setSizePolicy(QSizePolicy::Ignored, comboBox->sizePolicy().verticalPolicy()); + comboBox->setSizePolicy(QSizePolicy::Preferred, comboBox->sizePolicy().verticalPolicy()); comboBox->setEnabled(true); const auto sortModel = new KitAspectSortModel(this); sortModel->setSourceModel(listAspectSpec.model); @@ -260,6 +261,16 @@ void KitAspect::addMutableAction(QWidget *child) void KitAspect::setManagingPage(Utils::Id pageId) { d->managingPageId = pageId; } +void KitAspect::setAspectsToEmbed(const QList &aspects) +{ + d->aspectsToEmbed = aspects; +} + +QList KitAspect::aspectsToEmbed() const +{ + return d->aspectsToEmbed; +} + QString KitAspect::msgManage() { return Tr::tr("Manage..."); } Kit *KitAspect::kit() const { return d->kit; } const KitAspectFactory *KitAspect::factory() const { return d->factory; } diff --git a/src/plugins/projectexplorer/kitaspect.h b/src/plugins/projectexplorer/kitaspect.h index 2d8953eac0e..780495a70dc 100644 --- a/src/plugins/projectexplorer/kitaspect.h +++ b/src/plugins/projectexplorer/kitaspect.h @@ -73,6 +73,8 @@ public: virtual QSet supportedPlatforms(const Kit *k) const; virtual QSet availableFeatures(const Kit *k) const; + QList embeddableAspects() const { return m_embeddableAspects; } + virtual void addToMacroExpander(ProjectExplorer::Kit *kit, Utils::MacroExpander *expander) const; virtual void onKitsLoaded() {} @@ -89,12 +91,14 @@ protected: void setDescription(const QString &desc) { m_description = desc; } void makeEssential() { m_essential = true; } void setPriority(int priority) { m_priority = priority; } + void setEmbeddableAspects(const QList &aspects) { m_embeddableAspects = aspects; } void notifyAboutUpdate(Kit *k); private: QString m_displayName; QString m_description; Utils::Id m_id; + QList m_embeddableAspects; int m_priority = 0; // The higher the closer to the top. bool m_essential = false; }; @@ -120,11 +124,18 @@ public: void addMutableAction(QWidget *child); void setManagingPage(Utils::Id pageId); + void setAspectsToEmbed(const QList &aspects); + QList aspectsToEmbed() const; + void makeStickySubWidgetsReadOnly(); + // For layouting purposes only. + QList comboBoxes() const; + + virtual void addToInnerLayout(Layouting::Layout &parentItem); + protected: 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. @@ -154,9 +165,6 @@ protected: }; void addListAspectSpec(const ListAspectSpec &listAspectSpec); - // For layouting purposes only. - QList comboBoxes() const; - private: class Private; Private * const d; diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index c16a5b0712a..c6b2243e1e1 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #include #include @@ -103,8 +105,7 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k, bool &isDefaultKit, bool chooser->addSupportedWidget(m_nameEdit); chooser->addMacroExpanderProvider([this] { return m_modifiedKit->macroExpander(); }); - for (KitAspectFactory *factory : KitManager::kitAspectFactories()) - addAspectToWorkingCopy(page, factory); + addAspectsToWorkingCopy(page); page.attachTo(this); @@ -202,18 +203,40 @@ QString KitManagerConfigWidget::validityMessage() const return m_modifiedKit->toHtml(tmp); } -void KitManagerConfigWidget::addAspectToWorkingCopy(Layouting::Layout &parent, KitAspectFactory *factory) +void KitManagerConfigWidget::addAspectsToWorkingCopy(Layouting::Layout &parent) { - QTC_ASSERT(factory, return); - KitAspect *aspect = factory->createKitAspect(workingCopy()); - QTC_ASSERT(aspect, return); - QTC_ASSERT(!m_kitAspects.contains(aspect), return); + QHash aspectsById; + for (KitAspectFactory *factory : KitManager::kitAspectFactories()) { + QTC_ASSERT(factory, continue); - aspect->addToLayout(parent); - m_kitAspects.append(aspect); + KitAspect *aspect = factory->createKitAspect(workingCopy()); + QTC_ASSERT(aspect, continue); + QTC_ASSERT(!m_kitAspects.contains(aspect), continue); - connect(aspect->mutableAction(), &QAction::toggled, + m_kitAspects.append(aspect); + aspectsById.insert(factory->id(), aspect); + + connect(aspect->mutableAction(), &QAction::toggled, this, &KitManagerConfigWidget::dirty); + } + + QSet embedded; + for (KitAspect * const aspect : std::as_const(m_kitAspects)) { + QList embeddables; + for (const QList embeddableIds = aspect->factory()->embeddableAspects(); + const Id &embeddableId : embeddableIds) { + if (KitAspect * const embeddable = aspectsById.value(embeddableId)) { + embeddables << embeddable; + embedded << embeddable; + } + } + aspect->setAspectsToEmbed(embeddables); + } + + for (KitAspect * const aspect : std::as_const(m_kitAspects)) { + if (!embedded.contains(aspect)) + aspect->addToLayout(parent); + } } void KitManagerConfigWidget::updateVisibility() diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.h b/src/plugins/projectexplorer/kitmanagerconfigwidget.h index a93cd303eb3..d23ab59cb70 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.h +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.h @@ -38,7 +38,7 @@ public: void discard(); bool isDirty() const; QString validityMessage() const; - void addAspectToWorkingCopy(Layouting::Layout &parent, KitAspectFactory *factory); + void addAspectsToWorkingCopy(Layouting::Layout &parent); void makeStickySubWidgetsReadOnly(); Kit *workingCopy() const; From 81077fb4dc834afc53f6b1a443b23d121fc98254 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Nov 2024 11:29:46 +0100 Subject: [PATCH 110/989] Android: Replace AndroidManager namespace by the common Internal It's a bunch of helper functions, no "Manager". Change-Id: I36eb4440fe20619613a8e2a0b8e511c8b3753bb8 Reviewed-by: Jarek Kobus --- src/plugins/android/androidbuildapkstep.cpp | 28 +++++++++---------- src/plugins/android/androidconfigurations.cpp | 16 ++++------- src/plugins/android/androiddebugsupport.cpp | 18 ++++++------ src/plugins/android/androiddeployqtstep.cpp | 26 ++++++++--------- src/plugins/android/androiddevice.cpp | 2 +- src/plugins/android/androidmanager.cpp | 15 +++++----- src/plugins/android/androidmanager.h | 4 +-- src/plugins/android/androidmanifesteditor.cpp | 6 ++-- .../androidpackageinstallationstep.cpp | 6 ++-- src/plugins/android/androidqtversion.cpp | 8 +++--- src/plugins/android/androidrunner.cpp | 6 ++-- src/plugins/android/androidrunnerworker.cpp | 6 ++-- src/plugins/android/androidsdkmodel.cpp | 3 +- src/plugins/android/javalanguageserver.cpp | 2 +- 14 files changed, 70 insertions(+), 76 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index a9711314ea9..46395516b42 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -239,7 +239,7 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) // Application group QtSupport::QtVersion *qt = QtSupport::QtKitAspect::qtVersion(m_step->target()->kit()); - const int minApiSupported = AndroidManager::defaultMinimumSDK(qt); + const int minApiSupported = defaultMinimumSDK(qt); QStringList targets = AndroidConfig::apiLevelNamesFor( sdkManager().filteredSdkPlatforms(minApiSupported)); targets.removeDuplicates(); @@ -534,8 +534,8 @@ bool AndroidBuildApkStep::init() return false; } - const int minSDKForKit = AndroidManager::minimumSDK(kit()); - if (AndroidManager::minimumSDK(target()) < minSDKForKit) { + const int minSDKForKit = minimumSDK(kit()); + if (minimumSDK(target()) < minSDKForKit) { const QString error = Tr::tr("The API level set for the APK is less than the minimum required by the kit." "\nThe minimum API level required by the kit is %1.") @@ -545,8 +545,8 @@ bool AndroidBuildApkStep::init() } m_openPackageLocationForRun = openPackageLocation(); - const FilePath outputDir = AndroidManager::androidBuildDirectory(target()); - m_packagePath = AndroidManager::packagePath(target()); + const FilePath outputDir = androidBuildDirectory(target()); + m_packagePath = packagePath(target()); qCDebug(buildapkstepLog).noquote() << "APK or AAB path:" << m_packagePath.toUserOutput(); @@ -629,7 +629,7 @@ void AndroidBuildApkStep::setupOutputFormatter(OutputFormatter *formatter) if (node) sourceDirPath = FilePath::fromVariant(node->data(Constants::AndroidPackageSourceDir)); parser->setSourceDirectory(sourceDirPath.canonicalPath()); - parser->setBuildDirectory(AndroidManager::androidBuildDirectory(target())); + parser->setBuildDirectory(androidBuildDirectory(target())); formatter->addLineParser(parser); AbstractProcessStep::setupOutputFormatter(formatter); } @@ -727,10 +727,10 @@ Tasking::GroupItem AndroidBuildApkStep::runRecipe() return false; } - const auto androidAbis = AndroidManager::applicationAbis(target()); + const auto androidAbis = applicationAbis(target()); const QString buildKey = target()->activeBuildKey(); const FilePath buildDir = buildDirectory(); - const FilePath androidBuildDir = AndroidManager::androidBuildDirectory(target()); + const FilePath androidBuildDir = androidBuildDirectory(target()); for (const auto &abi : androidAbis) { FilePath androidLibsDir = androidBuildDir / "libs" / abi; if (!androidLibsDir.exists()) { @@ -764,7 +764,7 @@ Tasking::GroupItem AndroidBuildApkStep::runRecipe() } const bool inputExists = m_inputFile.exists(); - if (inputExists && !AndroidManager::isQtCreatorGenerated(m_inputFile)) + if (inputExists && !isQtCreatorGenerated(m_inputFile)) return true; // use the generated file if it was not generated by qtcreator BuildSystem *bs = buildSystem(); @@ -774,7 +774,7 @@ Tasking::GroupItem AndroidBuildApkStep::runRecipe() if (targets.isEmpty()) return inputExists; // qmake does this job for us - QJsonObject deploySettings = Android::AndroidManager::deploymentSettings(target()); + QJsonObject deploySettings = deploymentSettings(target()); QString applicationBinary; if (!version->supportsMultipleQtAbis()) { QTC_ASSERT(androidAbis.size() == 1, return false); @@ -813,7 +813,7 @@ Tasking::GroupItem AndroidBuildApkStep::runRecipe() Task::Error); return false; } - architectures[abi] = AndroidManager::archTriplet(abi); + architectures[abi] = archTriplet(abi); } } } @@ -858,7 +858,7 @@ Tasking::GroupItem AndroidBuildApkStep::runRecipe() "not building an APK."), Task::Error); return SetupResult::StopWithSuccess; } - if (AndroidManager::skipInstallationAndPackageSteps(target())) { + if (skipInstallationAndPackageSteps(target())) { reportWarningOrError(Tr::tr("Product type is not an application, not building an APK."), Task::Warning); return SetupResult::StopWithSuccess; @@ -970,7 +970,7 @@ QVariant AndroidBuildApkStep::data(Utils::Id id) const { if (id == Constants::AndroidNdkPlatform) { if (auto qtVersion = QtKitAspect::qtVersion(kit())) - return AndroidConfig::bestNdkPlatformMatch(AndroidManager::minimumSDK(target()), qtVersion); + return AndroidConfig::bestNdkPlatformMatch(minimumSDK(target()), qtVersion); return {}; } if (id == Constants::NdkLocation) { @@ -982,7 +982,7 @@ QVariant AndroidBuildApkStep::data(Utils::Id id) const return QVariant::fromValue(AndroidConfig::sdkLocation()); if (id == Constants::AndroidMkSpecAbis) - return AndroidManager::applicationAbis(target()); + return applicationAbis(target()); return AbstractProcessStep::data(id); } diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index d604bec8b35..7de8dbfd10b 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -775,13 +775,13 @@ bool isValidNdk(const QString &ndkLocation) QString bestNdkPlatformMatch(int target, const QtVersion *qtVersion) { - target = std::max(AndroidManager::defaultMinimumSDK(qtVersion), target); + target = std::max(defaultMinimumSDK(qtVersion), target); const QList platforms = availableNdkPlatforms(qtVersion); for (const int apiLevel : platforms) { if (apiLevel <= target) return QString::fromLatin1("android-%1").arg(apiLevel); } - return QString("android-%1").arg(AndroidManager::defaultMinimumSDK(qtVersion)); + return QString("android-%1").arg(defaultMinimumSDK(qtVersion)); } FilePath sdkLocation() @@ -1568,29 +1568,25 @@ void AndroidConfigurationsTest::testAndroidConfigAvailableNdkPlatforms_data() const QList abis64Bit = {31, 30, 29, 28, 27, 26, 24, 23, 22, 21}; QTest::newRow("ndkV21Plus armeabi-v7a OsTypeWindows") << ndkV21Plus - << Abis{AndroidManager::androidAbi2Abi( - ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A)} + << Abis{androidAbi2Abi(ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A)} << OsTypeWindows << abis32Bit; QTest::newRow("ndkV21Plus arm64-v8a OsTypeLinux") << ndkV21Plus - << Abis{AndroidManager::androidAbi2Abi( - ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A)} + << Abis{androidAbi2Abi(ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A)} << OsTypeLinux << abis64Bit; QTest::newRow("ndkV21Plus x86 OsTypeMac") << ndkV21Plus - << Abis{AndroidManager::androidAbi2Abi( - ProjectExplorer::Constants::ANDROID_ABI_X86)} + << Abis{androidAbi2Abi(ProjectExplorer::Constants::ANDROID_ABI_X86)} << OsTypeMac << abis32Bit; QTest::newRow("ndkV21Plus x86_64 OsTypeWindows") << ndkV21Plus - << Abis{AndroidManager::androidAbi2Abi( - ProjectExplorer::Constants::ANDROID_ABI_X86_64)} + << Abis{androidAbi2Abi(ProjectExplorer::Constants::ANDROID_ABI_X86_64)} << OsTypeWindows << abis64Bit; } diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index ca9e1efd42a..c8d655db2a1 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -104,7 +104,7 @@ void AndroidDebugSupport::start() Kit *kit = target->kit(); setStartMode(AttachToRemoteServer); - const QString packageName = AndroidManager::packageName(target); + const QString packageName = Internal::packageName(target); setRunControlName(packageName); setUseContinueInsteadOfRun(true); setAttachPid(m_runner->pid()); @@ -125,26 +125,26 @@ void AndroidDebugSupport::start() const FilePaths extraLibs = getExtraLibs(node); solibSearchPath.append(extraLibs); - FilePath buildDir = AndroidManager::buildDirectory(target); + FilePath buildDir = Internal::buildDirectory(target); const RunConfiguration *activeRunConfig = target->activeRunConfiguration(); if (activeRunConfig) solibSearchPath.append(activeRunConfig->buildTargetInfo().workingDirectory); solibSearchPath.append(buildDir); - const FilePath androidLibsPath = AndroidManager::androidBuildDirectory(target) + const FilePath androidLibsPath = androidBuildDirectory(target) .pathAppended("libs") - .pathAppended(AndroidManager::apkDevicePreferredAbi(target)); + .pathAppended(apkDevicePreferredAbi(target)); solibSearchPath.append(androidLibsPath); FilePath::removeDuplicates(solibSearchPath); setSolibSearchPath(solibSearchPath); qCDebug(androidDebugSupportLog).noquote() << "SoLibSearchPath: " << solibSearchPath; - setSymbolFile(AndroidManager::androidAppProcessDir(target).pathAppended("app_process")); + setSymbolFile(androidAppProcessDir(target).pathAppended("app_process")); setSkipExecutableValidation(true); setUseExtendedRemote(true); - QString devicePreferredAbi = AndroidManager::apkDevicePreferredAbi(target); - setAbi(AndroidManager::androidAbi2Abi(devicePreferredAbi)); + QString devicePreferredAbi = apkDevicePreferredAbi(target); + setAbi(androidAbi2Abi(devicePreferredAbi)); if (cppEngineType() == LldbEngineType) { - QString deviceSerialNumber = AndroidManager::deviceSerialNumber(target); + QString deviceSerialNumber = Internal::deviceSerialNumber(target); const int colonPos = deviceSerialNumber.indexOf(QLatin1Char(':')); if (colonPos > 0) { // When wireless debugging is used then the device serial number will include a port number @@ -163,7 +163,7 @@ void AndroidDebugSupport::start() auto qt = static_cast(qtVersion); const int minimumNdk = qt ? qt->minimumNDK() : 0; - int sdkVersion = qMax(AndroidManager::minimumSDK(kit), minimumNdk); + int sdkVersion = qMax(Internal::minimumSDK(kit), minimumNdk); if (qtVersion) { const FilePath ndkLocation = AndroidConfig::ndkLocation(qtVersion); FilePath sysRoot = ndkLocation diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 08213601f95..45eab466c6f 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -104,11 +104,11 @@ struct FileToPull static QList filesToPull(Target *target) { QList fileList; - const FilePath appProcessDir = AndroidManager::androidAppProcessDir(target); + const FilePath appProcessDir = androidAppProcessDir(target); QString linkerName("linker"); QString libDirName("lib"); - const QString preferredAbi = AndroidManager::apkDevicePreferredAbi(target); + const QString preferredAbi = apkDevicePreferredAbi(target); if (preferredAbi == ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A || preferredAbi == ProjectExplorer::Constants::ANDROID_ABI_X86_64) { fileList.append({"/system/bin/app_process64", appProcessDir / "app_process"}); @@ -186,7 +186,7 @@ bool AndroidDeployQtStep::init() m_androiddeployqtArgs = {}; - const QStringList androidABIs = AndroidManager::applicationAbis(target()); + const QStringList androidABIs = applicationAbis(target()); if (androidABIs.isEmpty()) { reportWarningOrError(Tr::tr("No Android architecture (ABI) is set by the project."), Task::Error); @@ -205,7 +205,7 @@ bool AndroidDeployQtStep::init() return false); auto androidBuildApkStep = bc->buildSteps()->firstOfType(); - const int minTargetApi = AndroidManager::minimumSDK(target()); + const int minTargetApi = minimumSDK(target()); qCDebug(deployStepLog) << "Target architecture:" << androidABIs << "Min target API" << minTargetApi; @@ -280,9 +280,9 @@ bool AndroidDeployQtStep::init() m_serialNumber = info.serialNumber; qCDebug(deployStepLog) << "Selected device info:" << info; - AndroidManager::setDeviceSerialNumber(target(), m_serialNumber); - AndroidManager::setDeviceApiLevel(target(), info.sdk); - AndroidManager::setDeviceAbis(target(), info.cpuAbi); + Internal::setDeviceSerialNumber(target(), m_serialNumber); + Internal::setDeviceApiLevel(target(), info.sdk); + Internal::setDeviceAbis(target(), info.cpuAbi); emit addOutput(Tr::tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage); @@ -296,7 +296,7 @@ bool AndroidDeployQtStep::init() m_apkPath = FilePath::fromString(node->data(Constants::AndroidApk).toString()); if (!m_apkPath.isEmpty()) { m_command = AndroidConfig::adbToolPath(); - AndroidManager::setManifestPath(target(), + Internal::setManifestPath(target(), FilePath::fromString(node->data(Constants::AndroidManifest).toString())); } else { FilePath jsonFile = AndroidQtVersion::androidDeploymentSettings(target()); @@ -312,7 +312,7 @@ bool AndroidDeployQtStep::init() } m_command = m_command.pathAppended("androiddeployqt").withExecutableSuffix(); - m_workingDirectory = AndroidManager::androidBuildDirectory(target()); + m_workingDirectory = androidBuildDirectory(target()); // clang-format off m_androiddeployqtArgs.addArgs({"--verbose", @@ -357,7 +357,7 @@ GroupItem AndroidDeployQtStep::runRecipe() } m_serialNumber = serialNumber; qCDebug(deployStepLog) << "Deployment device serial number changed:" << serialNumber; - AndroidManager::setDeviceSerialNumber(target(), serialNumber); + Internal::setDeviceSerialNumber(target(), serialNumber); return true; }; @@ -422,12 +422,12 @@ Group AndroidDeployQtStep::deployRecipe() QTC_ASSERT(target()->activeRunConfiguration(), return SetupResult::StopWithError); - const QString packageName = AndroidManager::packageName(target()); + const QString packageName = Internal::packageName(target()); if (packageName.isEmpty()) { reportWarningOrError( Tr::tr("Cannot find the package name from AndroidManifest.xml nor " "build.gradle files at \"%1\".") - .arg(AndroidManager::androidBuildDirectory(target()).toUserOutput()), + .arg(androidBuildDirectory(target()).toUserOutput()), Task::Error); return SetupResult::StopWithError; } @@ -571,7 +571,7 @@ QWidget *AndroidDeployQtStep::createConfigWidget() if (currentTarget == nullptr) return; - const QStringList appAbis = AndroidManager::applicationAbis(currentTarget); + const QStringList appAbis = applicationAbis(currentTarget); if (appAbis.isEmpty()) return; diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 8b819ff48fa..27f731180e5 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -559,7 +559,7 @@ void AndroidDevice::setAvdPath(const FilePath &path) QString AndroidDevice::androidVersion() const { - return AndroidManager::androidNameForApiLevel(sdkLevel()); + return androidNameForApiLevel(sdkLevel()); } QString AndroidDevice::deviceTypeName() const diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 6733aea4cf0..9b6a1577e21 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -34,12 +34,11 @@ #include #include -using namespace Android::Internal; using namespace Core; using namespace ProjectExplorer; using namespace Utils; -namespace Android::AndroidManager { +namespace Android::Internal { const char AndroidManifestName[] = "AndroidManifest.xml"; const char AndroidDeviceSn[] = "AndroidDeviceSerialNumber"; @@ -134,7 +133,7 @@ QString packageName(const Target *target) if (packageName.isEmpty()) { // Check AndroidManifest.xml - const auto element = documentElement(AndroidManager::manifestPath(target)); + const auto element = documentElement(manifestPath(target)); if (element) packageName = element->attribute("package"); } @@ -144,7 +143,7 @@ QString packageName(const Target *target) QString activityName(const Target *target) { - const auto element = documentElement(AndroidManager::manifestPath(target)); + const auto element = documentElement(manifestPath(target)); if (!element) return {}; return element->firstChildElement("application").firstChildElement("activity") @@ -178,7 +177,7 @@ int minimumSDK(const Target *target) const int minSdkVersion = parseMinSdk(*element); if (minSdkVersion == 0) - return AndroidManager::defaultMinimumSDK(QtSupport::QtKitAspect::qtVersion(target->kit())); + return defaultMinimumSDK(QtSupport::QtKitAspect::qtVersion(target->kit())); return minSdkVersion; } @@ -199,7 +198,7 @@ int minimumSDK(const Kit *kit) minSdkVersion = parseMinSdk(*element); } if (minSdkVersion == 0) - return AndroidManager::defaultMinimumSDK(version); + return defaultMinimumSDK(version); return minSdkVersion; } @@ -417,7 +416,7 @@ bool skipInstallationAndPackageSteps(const Target *target) // or it's been generated by Qt Creator, we can assume the project is not // an android app. const FilePath inputFile = AndroidQtVersion::androidDeploymentSettings(target); - if (!inputFile.exists() || AndroidManager::isQtCreatorGenerated(inputFile)) + if (!inputFile.exists() || isQtCreatorGenerated(inputFile)) return true; const Project *p = target->project(); @@ -589,4 +588,4 @@ QString androidNameForApiLevel(int x) } } -} // namespace Android::AndroidManager +} // namespace Android::Internal diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h index 9c5ce74ba7d..7be62c45d9e 100644 --- a/src/plugins/android/androidmanager.h +++ b/src/plugins/android/androidmanager.h @@ -16,7 +16,7 @@ class FilePath; class Process; } -namespace Android::AndroidManager { +namespace Android::Internal { QString packageName(const ProjectExplorer::Target *target); QString activityName(const ProjectExplorer::Target *target); @@ -55,4 +55,4 @@ QString androidNameForApiLevel(int x); QJsonObject deploymentSettings(const ProjectExplorer::Target *target); bool isQtCreatorGenerated(const Utils::FilePath &deploymentFile); -} // namespace Android::AndroidManager +} // namespace Android::Internal diff --git a/src/plugins/android/androidmanifesteditor.cpp b/src/plugins/android/androidmanifesteditor.cpp index 9a159082cd3..35cd6d222e1 100644 --- a/src/plugins/android/androidmanifesteditor.cpp +++ b/src/plugins/android/androidmanifesteditor.cpp @@ -698,7 +698,7 @@ void AndroidManifestEditorWidget::postSave() if (Target *target = androidTarget(docPath)) { if (BuildConfiguration *bc = target->activeBuildConfiguration()) { QString androidNdkPlatform = AndroidConfig::bestNdkPlatformMatch( - AndroidManager::minimumSDK(target), + minimumSDK(target), QtSupport::QtKitAspect::qtVersion( androidTarget(m_textEditorWidget->textDocument()->filePath())->kit())); if (m_androidNdkPlatform != androidNdkPlatform) { @@ -788,12 +788,12 @@ void AndroidManifestEditorWidget::updateSdkVersions() const Target *target = androidTarget(m_textEditorWidget->textDocument()->filePath()); if (target) { const QtSupport::QtVersion *qt = QtSupport::QtKitAspect::qtVersion(target->kit()); - minSdk = AndroidManager::defaultMinimumSDK(qt); + minSdk = defaultMinimumSDK(qt); } for (int i = minSdk; i <= targetSdk; ++i) { const QString apiStr = ::Android::Tr::tr("API %1: %2").arg(i) - .arg(AndroidManager::androidNameForApiLevel(i)); + .arg(androidNameForApiLevel(i)); m_androidMinSdkVersion->addItem(apiStr, i); m_androidTargetSdkVersion->addItem(apiStr, i); } diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp index 3c8621d4d4a..b129670b95e 100644 --- a/src/plugins/android/androidpackageinstallationstep.cpp +++ b/src/plugins/android/androidpackageinstallationstep.cpp @@ -91,7 +91,7 @@ bool AndroidPackageInstallationStep::init() processParameters()->setCommandLine(cmd); // This is useful when running an example target from a Qt module project. - processParameters()->setWorkingDirectory(AndroidManager::buildDirectory(target())); + processParameters()->setWorkingDirectory(Internal::buildDirectory(target())); m_androidDirsToClean.clear(); // don't remove gradle's cache, it takes ages to rebuild it. @@ -103,7 +103,7 @@ bool AndroidPackageInstallationStep::init() QString AndroidPackageInstallationStep::nativeAndroidBuildPath() const { - QString buildPath = AndroidManager::androidBuildDirectory(target()).toFSPathString(); + QString buildPath = androidBuildDirectory(target()).toFSPathString(); if (HostOsInfo::isWindowsHost()) if (buildEnvironment().searchInPath("sh.exe").isEmpty()) buildPath = QDir::toNativeSeparators(buildPath); @@ -124,7 +124,7 @@ Tasking::GroupItem AndroidPackageInstallationStep::runRecipe() using namespace Tasking; const auto onSetup = [this] { - if (AndroidManager::skipInstallationAndPackageSteps(target())) { + if (skipInstallationAndPackageSteps(target())) { reportWarningOrError(Tr::tr("Product type is not an application, not running the " "Make install step."), Task::Warning); return SetupResult::StopWithSuccess; diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index 880771f2c0c..fbb79620113 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -80,7 +80,7 @@ bool AndroidQtVersion::supportsMultipleQtAbis() const Abis AndroidQtVersion::detectQtAbis() const { const bool conf = AndroidConfig::sdkFullyConfigured(); - return conf ? Utils::transform(androidAbis(), &AndroidManager::androidAbi2Abi) : Abis(); + return conf ? Utils::transform(androidAbis(), &androidAbi2Abi) : Abis(); } void AndroidQtVersion::addToBuildEnvironment(const Kit *k, Utils::Environment &env) const @@ -91,7 +91,7 @@ void AndroidQtVersion::addToBuildEnvironment(const Kit *k, Utils::Environment &e env.set(QLatin1String("ANDROID_NDK_HOST"), AndroidConfig::toolchainHost(this)); env.set(QLatin1String("ANDROID_NDK_ROOT"), AndroidConfig::ndkLocation(this).toUserOutput()); env.set(QLatin1String("ANDROID_NDK_PLATFORM"), - AndroidConfig::bestNdkPlatformMatch(qMax(minimumNDK(), AndroidManager::minimumSDK(k)), this)); + AndroidConfig::bestNdkPlatformMatch(qMax(minimumNDK(), minimumSDK(k)), this)); } void AndroidQtVersion::setupQmakeRunEnvironment(Utils::Environment &env) const @@ -125,7 +125,7 @@ QString AndroidQtVersion::androidDeploymentSettingsFileName(const Target *target return {}; const QString buildKey = target->activeBuildKey(); const QString displayName = bs->buildTarget(buildKey).displayName; - const QString fileName = AndroidManager::isQt5CmakeProject(target) + const QString fileName = isQt5CmakeProject(target) ? QLatin1String("android_deployment_settings.json") : QString::fromLatin1("android-%1-deployment-settings.json") .arg(displayName); @@ -145,7 +145,7 @@ Utils::FilePath AndroidQtVersion::androidDeploymentSettings(const Target *target // If unavailable, construct the name by ourselves (CMake) const QString fileName = androidDeploymentSettingsFileName(target); - return AndroidManager::buildDirectory(target) / fileName; + return buildDirectory(target) / fileName; } AndroidQtVersion::BuiltWith AndroidQtVersion::builtWith(bool *ok) const diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 44b50b04059..65794ef6389 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -65,7 +65,7 @@ void AndroidRunner::start() const IDevice::ConstPtr device = RunDeviceKitAspect::device(target->kit()); AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(device.get()); - AndroidManager::setDeviceSerialNumber(target, info.serialNumber); + setDeviceSerialNumber(target, info.serialNumber); deviceSerialNumber = info.serialNumber; apiLevel = info.sdk; qCDebug(androidRunnerLog) << "Android Device Info changed" << deviceSerialNumber @@ -82,8 +82,8 @@ void AndroidRunner::start() }); } } else { - deviceSerialNumber = AndroidManager::deviceSerialNumber(target); - apiLevel = AndroidManager::deviceApiLevel(target); + deviceSerialNumber = Internal::deviceSerialNumber(target); + apiLevel = Internal::deviceApiLevel(target); } const auto onSetup = [this, glueStorage, deviceSerialNumber, apiLevel] { diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 8a8698262cf..3b997f93d38 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -99,7 +99,7 @@ static QString lldbServerArch2(const QString &androidAbi) static FilePath debugServer(bool useLldb, const Target *target) { QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target->kit()); - QString preferredAbi = AndroidManager::apkDevicePreferredAbi(target); + QString preferredAbi = apkDevicePreferredAbi(target); if (useLldb) { // Search suitable lldb-server binary. @@ -202,8 +202,8 @@ static void setupStorage(RunnerStorage *storage, RunnerInterface *glue) } auto target = glue->runControl()->target(); - storage->m_packageName = AndroidManager::packageName(target); - storage->m_intentName = storage->m_packageName + '/' + AndroidManager::activityName(target); + storage->m_packageName = packageName(target); + storage->m_intentName = storage->m_packageName + '/' + activityName(target); qCDebug(androidRunWorkerLog) << "Intent name:" << storage->m_intentName << "Package name:" << storage->m_packageName; qCDebug(androidRunWorkerLog) << "Device API:" << glue->apiLevel(); diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp index d73731512a3..5c33df86c7e 100644 --- a/src/plugins/android/androidsdkmodel.cpp +++ b/src/plugins/android/androidsdkmodel.cpp @@ -136,8 +136,7 @@ QVariant AndroidSdkModel::data(const QModelIndex &index, int role) const const SdkPlatform *platform = m_sdkPlatforms.at(index.row() - 1); if (role == Qt::DisplayRole) { if (index.column() == packageNameColumn) { - const QString androidName = AndroidManager::androidNameForApiLevel( - platform->apiLevel()) + const QString androidName = androidNameForApiLevel(platform->apiLevel()) + platform->extension(); if (androidName.startsWith("Android")) return androidName; diff --git a/src/plugins/android/javalanguageserver.cpp b/src/plugins/android/javalanguageserver.cpp index 6dbf510121a..20f9fe859e4 100644 --- a/src/plugins/android/javalanguageserver.cpp +++ b/src/plugins/android/javalanguageserver.cpp @@ -304,7 +304,7 @@ void JLSClient::updateProjectFiles() const QStringList classPaths = node->data(Constants::AndroidClassPaths).toStringList(); const FilePath &sdkLocation = AndroidConfig::sdkLocation(); - const QString &targetSDK = AndroidManager::buildTargetSDK(m_currentTarget); + const QString &targetSDK = buildTargetSDK(m_currentTarget); const FilePath androidJar = sdkLocation / QString("platforms/%2/android.jar") .arg(targetSDK); FilePaths libs = {androidJar}; From e6534e798be442031ba2670769efa621a7b40698 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 09:52:24 +0100 Subject: [PATCH 111/989] Android: Get rid of unused androidglobal.h Change-Id: I0b2fa21304dc30137122a9f5a325a2fbc951f3aa Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 1 - src/plugins/android/android.qbs | 1 - src/plugins/android/androidglobal.h | 35 ------------------- .../android/androidrunconfiguration.cpp | 3 +- 4 files changed, 1 insertion(+), 39 deletions(-) delete mode 100644 src/plugins/android/androidglobal.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index fdaa4cb19b0..d5c0e9b7ba3 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -16,7 +16,6 @@ add_qtc_plugin(Android androiddevice.cpp androiddevice.h androiddeviceinfo.cpp androiddeviceinfo.h androidextralibrarylistmodel.cpp androidextralibrarylistmodel.h - androidglobal.h androidmanager.cpp androidmanager.h androidmanifesteditor.cpp androidmanifesteditor.h androidmanifesteditoriconwidget.cpp androidmanifesteditoriconwidget.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 6cdaf4fc6c8..db634355af4 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -36,7 +36,6 @@ QtcPlugin { "androiddeviceinfo.h", "androidextralibrarylistmodel.cpp", "androidextralibrarylistmodel.h", - "androidglobal.h", "androidmanager.cpp", "androidmanager.h", "androidmanifesteditoriconwidget.cpp", diff --git a/src/plugins/android/androidglobal.h b/src/plugins/android/androidglobal.h deleted file mode 100644 index e21a7ecefbd..00000000000 --- a/src/plugins/android/androidglobal.h +++ /dev/null @@ -1,35 +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 - -#include - -#include -#include - -#define ASSERT_STATE_GENERIC(State, expected, actual) \ - AndroidGlobal::assertState(expected, actual, Q_FUNC_INFO) - -namespace Android::Internal { - -class AndroidGlobal -{ -public: - template static void assertState(State expected, - State actual, const char *func) - { - assertState(QList() << expected, actual, func); - } - - template static void assertState(const QList &expected, - State actual, const char *func) - { - if (!expected.contains(actual)) { - qWarning("Warning: Unexpected state %d in function %s.", - actual, func); - } - } -}; - -} // namespace Android::Internal diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index 53e1a05779e..a8aa3bc95c9 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -2,11 +2,10 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "androidconstants.h" -#include "androidglobal.h" #include "androidrunconfiguration.h" -#include "androidtoolchain.h" #include "androidtr.h" +#include #include #include #include From bdde3f1c9c1320dcf13f87bd8116313d94c8cbf0 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Nov 2024 16:24:29 +0100 Subject: [PATCH 112/989] Android: Don't re-use information from an earlier step of the same type ... in AndroidDeployQtStep. It is unclear why this is (still?) needed, the relevant accesses to the device data are very cheap, and this dependency to data outside the current run could be a source of uncertainty. Change-Id: I9fe71181cf4073285f4835e722c90ba48eebc6d7 Reviewed-by: Jarek Kobus Reviewed-by: Assam Boudjelthia --- src/plugins/android/androiddeployqtstep.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 45eab466c6f..b12220a6966 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -160,7 +160,6 @@ private: FilePath m_command; FilePath m_workingDirectory; Environment m_environment; - AndroidDeviceInfo m_deviceInfo; }; AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Id id) @@ -209,17 +208,7 @@ bool AndroidDeployQtStep::init() qCDebug(deployStepLog) << "Target architecture:" << androidABIs << "Min target API" << minTargetApi; - // Try to re-use user-provided information from an earlier step of the same type. - BuildStepList *bsl = stepList(); - QTC_ASSERT(bsl, reportWarningOrError(Tr::tr("The kit's build steps list is invalid."), Task::Error); - return false); - auto androidDeployQtStep = bsl->firstOfType(); - QTC_ASSERT(androidDeployQtStep, - reportWarningOrError(Tr::tr("The kit's deploy configuration is invalid."), Task::Error); - return false); AndroidDeviceInfo info; - if (androidDeployQtStep != this) - info = androidDeployQtStep->m_deviceInfo; const BuildSystem *bs = buildSystem(); auto selectedAbis = bs->property(Constants::AndroidAbis).toStringList(); @@ -231,7 +220,7 @@ bool AndroidDeployQtStep::init() if (selectedAbis.isEmpty()) selectedAbis.append(bs->extraData(buildKey, Constants::AndroidAbi).toString()); - if (!info.isValid()) { + if (true) { // FIXME: Simplify const auto dev = static_cast(RunDeviceKitAspect::device(kit()).get()); if (!dev) { @@ -241,7 +230,6 @@ bool AndroidDeployQtStep::init() // TODO: use AndroidDevice directly instead of AndroidDeviceInfo. info = AndroidDevice::androidDeviceInfoFromIDevice(dev); - m_deviceInfo = info; // Keep around for later steps if (!info.isValid()) { reportWarningOrError(Tr::tr("The deployment device \"%1\" is invalid.") @@ -361,7 +349,7 @@ GroupItem AndroidDeployQtStep::runRecipe() return true; }; - const LoopList iterator(m_deviceInfo.isValid() ? filesToPull(target()) : QList()); + const LoopList iterator(filesToPull(target())); const auto onRemoveFileSetup = [iterator](Async &async) { async.setConcurrentCallData(removeFile, iterator->to); }; From 7917a86c5c24a7f673c2d1ce98c0760f909a3ab0 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 12 Nov 2024 11:04:25 +0100 Subject: [PATCH 113/989] ProjectExplorer: More name disambiguation for device kit aspects Finishing 73b0875498b662128c18f794fa9b7e477b0571de. Change-Id: I225ec83400a4e70d0fe933e8529db289b46f4a81 Reviewed-by: hjk --- src/plugins/android/androidconfigurations.cpp | 8 +- src/plugins/android/androidmanifesteditor.cpp | 2 +- src/plugins/android/javalanguageserver.cpp | 2 +- src/plugins/autotest/testconfiguration.cpp | 4 +- .../cmakebuildconfiguration.cpp | 12 +- .../cmakeprojectmanager/cmakebuildstep.cpp | 2 +- .../cmakeprojectmanager/cmakebuildsystem.cpp | 2 +- .../cmakeprojectmanager/cmakekitaspect.cpp | 2 +- .../debugger/unstartedappwatcherdialog.cpp | 2 +- src/plugins/docker/kitdetector.cpp | 4 +- src/plugins/ios/iosbuildconfiguration.cpp | 6 +- src/plugins/ios/iosconfigurations.cpp | 8 +- src/plugins/ios/iosrunconfiguration.cpp | 8 +- src/plugins/mcusupport/mcukitmanager.cpp | 2 +- .../projectexplorer/buildconfiguration.cpp | 4 +- src/plugins/projectexplorer/buildstep.cpp | 2 +- .../projectexplorer/deployconfiguration.cpp | 2 +- .../devicesupport/devicecheckbuildstep.cpp | 2 +- .../devicesupport/devicekitaspects.cpp | 110 +++++++++--------- .../devicesupport/devicekitaspects.h | 2 +- .../projectexplorer/devicesupport/idevice.cpp | 2 +- src/plugins/projectexplorer/kit.cpp | 4 +- src/plugins/projectexplorer/kitmanager.cpp | 2 +- .../kitmanagerconfigwidget.cpp | 2 +- .../projectexplorer/parseissuesdialog.cpp | 2 +- src/plugins/projectexplorer/project.cpp | 2 +- .../projectexplorer/projectexplorer.cpp | 2 +- .../projectexplorer/projectimporter.cpp | 2 +- .../projectexplorer/rawprojectpart.cpp | 2 +- .../projectexplorer/runconfiguration.cpp | 4 +- src/plugins/projectexplorer/runcontrol.cpp | 4 +- src/plugins/projectexplorer/target.cpp | 2 +- .../defaultpropertyprovider.cpp | 2 +- .../qmakebuildconfiguration.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 2 +- .../qmlpreviewplugin/qmlpreviewactions.cpp | 2 +- .../qmlpreviewfileontargetfinder.cpp | 2 +- src/plugins/qmlpreview/qmlpreviewplugin.cpp | 2 +- .../buildsystem/qmlbuildsystem.cpp | 4 +- src/plugins/qmlprojectmanager/qmlproject.cpp | 2 +- .../qmlprojectrunconfiguration.cpp | 6 +- src/plugins/qnx/qnxdebugsupport.cpp | 2 +- src/plugins/qnx/qnxplugin.cpp | 2 +- src/plugins/qnx/qnxsettingspage.cpp | 6 +- src/plugins/qtsupport/baseqtversion.cpp | 2 +- src/plugins/qtsupport/qtkitaspect.cpp | 4 +- .../studiowelcome/studiowelcomeplugin.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 2 +- 48 files changed, 130 insertions(+), 130 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 7de8dbfd10b..40a7cabf10d 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1413,7 +1413,7 @@ void AndroidConfigurations::registerCustomToolchainsAndDebuggers() void AndroidConfigurations::updateAutomaticKitList() { for (Kit *k : KitManager::kits()) { - if (DeviceTypeKitAspect::deviceTypeId(k) == Constants::ANDROID_DEVICE_TYPE) { + if (RunDeviceTypeKitAspect::deviceTypeId(k) == Constants::ANDROID_DEVICE_TYPE) { if (k->value(Constants::ANDROID_KIT_NDK).isNull() || k->value(Constants::ANDROID_KIT_SDK).isNull()) { if (QtVersion *qt = QtKitAspect::qtVersion(k)) { k->setValueSilently( @@ -1425,7 +1425,7 @@ void AndroidConfigurations::updateAutomaticKitList() } const QList existingKits = Utils::filtered(KitManager::kits(), [](Kit *k) { - Id deviceTypeId = DeviceTypeKitAspect::deviceTypeId(k); + Id deviceTypeId = RunDeviceTypeKitAspect::deviceTypeId(k); if (k->isAutoDetected() && !k->isSdkProvided() && deviceTypeId == Constants::ANDROID_DEVICE_TYPE) { return true; @@ -1472,7 +1472,7 @@ void AndroidConfigurations::updateAutomaticKitList() const auto initializeKit = [&bundle, qt](Kit *k) { k->setAutoDetected(true); k->setAutoDetectionSource("AndroidConfiguration"); - DeviceTypeKitAspect::setDeviceTypeId(k, Constants::ANDROID_DEVICE_TYPE); + RunDeviceTypeKitAspect::setDeviceTypeId(k, Constants::ANDROID_DEVICE_TYPE); ToolchainKitAspect::setBundle(k, bundle); QtKitAspect::setQtVersion(k, qt); QStringList abis = static_cast(qt)->androidAbis(); @@ -1481,7 +1481,7 @@ void AndroidConfigurations::updateAutomaticKitList() BuildDeviceKitAspect::setDeviceId(k, DeviceManager::defaultDesktopDevice()->id()); k->setSticky(QtKitAspect::id(), true); - k->setSticky(DeviceTypeKitAspect::id(), true); + k->setSticky(RunDeviceTypeKitAspect::id(), true); QString versionStr = QLatin1String("Qt %{Qt:Version}"); if (!qt->isAutodetected()) diff --git a/src/plugins/android/androidmanifesteditor.cpp b/src/plugins/android/androidmanifesteditor.cpp index 35cd6d222e1..e0f0752438b 100644 --- a/src/plugins/android/androidmanifesteditor.cpp +++ b/src/plugins/android/androidmanifesteditor.cpp @@ -79,7 +79,7 @@ static Target *androidTarget(const FilePath &fileName) for (Project *project : ProjectManager::projects()) { if (Target *target = project->activeTarget()) { Kit *kit = target->kit(); - if (DeviceTypeKitAspect::deviceTypeId(kit) == Android::Constants::ANDROID_DEVICE_TYPE + if (RunDeviceTypeKitAspect::deviceTypeId(kit) == Android::Constants::ANDROID_DEVICE_TYPE && fileName.isChildOf(project->projectDirectory())) return target; } diff --git a/src/plugins/android/javalanguageserver.cpp b/src/plugins/android/javalanguageserver.cpp index 20f9fe859e4..430d4df1a7a 100644 --- a/src/plugins/android/javalanguageserver.cpp +++ b/src/plugins/android/javalanguageserver.cpp @@ -278,7 +278,7 @@ void JLSClient::updateProjectFiles() return; if (Target *target = m_currentTarget) { Kit *kit = m_currentTarget->kit(); - if (DeviceTypeKitAspect::deviceTypeId(kit) != Android::Constants::ANDROID_DEVICE_TYPE) + if (RunDeviceTypeKitAspect::deviceTypeId(kit) != Android::Constants::ANDROID_DEVICE_TYPE) return; if (ProjectNode *node = project()->findNodeForBuildKey(target->activeBuildKey())) { QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(kit); diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp index 100e8b391ae..abd166876a2 100644 --- a/src/plugins/autotest/testconfiguration.cpp +++ b/src/plugins/autotest/testconfiguration.cpp @@ -84,7 +84,7 @@ TestConfiguration::~TestConfiguration() static bool isLocal(Target *target) { Kit *kit = target ? target->kit() : nullptr; - return DeviceTypeKitAspect::deviceTypeId(kit) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; + return RunDeviceTypeKitAspect::deviceTypeId(kit) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; } static FilePath ensureExeEnding(const FilePath &file) @@ -184,7 +184,7 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode) BuildTargetInfo targetInfo = buildTargets.size() ? buildTargets.first() : BuildTargetInfo(); - if (DeviceTypeKitAspect::deviceTypeId(target->kit()) == ANDROID_DEVICE_TYPE) { + if (RunDeviceTypeKitAspect::deviceTypeId(target->kit()) == ANDROID_DEVICE_TYPE) { // Android can have test runner scripts named as displayName(.bat) const FilePath script = ensureBatEnding( targetInfo.targetFilePath.parentDir() / targetInfo.displayName); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 16136cac74e..29be8db113e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -1134,17 +1134,17 @@ bool CMakeBuildSettingsWidget::eventFilter(QObject *target, QEvent *event) static bool isWebAssembly(const Kit *k) { - return DeviceTypeKitAspect::deviceTypeId(k) == WebAssembly::Constants::WEBASSEMBLY_DEVICE_TYPE; + return RunDeviceTypeKitAspect::deviceTypeId(k) == WebAssembly::Constants::WEBASSEMBLY_DEVICE_TYPE; } static bool isVxWorks(const Kit *k) { - return DeviceTypeKitAspect::deviceTypeId(k) == VXWORKS_DEVICE_TYPE; + return RunDeviceTypeKitAspect::deviceTypeId(k) == VXWORKS_DEVICE_TYPE; } static bool isQnx(const Kit *k) { - return DeviceTypeKitAspect::deviceTypeId(k) == Qnx::Constants::QNX_QNX_OS_TYPE; + return RunDeviceTypeKitAspect::deviceTypeId(k) == Qnx::Constants::QNX_QNX_OS_TYPE; } static bool isWindowsARM64(const Kit *k) @@ -1496,7 +1496,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) m_buildSystem->setIsMultiConfig(CMakeGeneratorKitAspect::isMultiConfigGenerator(k)); // Android magic: - if (DeviceTypeKitAspect::deviceTypeId(k) == Android::Constants::ANDROID_DEVICE_TYPE) { + if (RunDeviceTypeKitAspect::deviceTypeId(k) == Android::Constants::ANDROID_DEVICE_TYPE) { auto addUniqueKeyToCmd = [&cmd] (const QString &prefix, const QString &value) -> bool { const bool isUnique = !Utils::contains(cmd.splitArguments(), [&prefix] (const QString &arg) { @@ -1555,7 +1555,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) // and build with "cmake --build . -- -arch " instead of setting the architecture // and sysroot in the CMake configuration, but that currently doesn't work with Qt/CMake // https://gitlab.kitware.com/cmake/cmake/-/issues/21276 - const Id deviceType = DeviceTypeKitAspect::deviceTypeId(k); + const Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(k); const QString sysroot = deviceType == Ios::Constants::IOS_DEVICE_TYPE ? QLatin1String("iphoneos") : QLatin1String("iphonesimulator"); @@ -1638,7 +1638,7 @@ FilePath CMakeBuildConfiguration::shadowBuildDirectory(const FilePath &projectFi bool CMakeBuildConfiguration::isIos(const Kit *k) { - const Id deviceType = DeviceTypeKitAspect::deviceTypeId(k); + const Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(k); return deviceType == Ios::Constants::IOS_DEVICE_TYPE || deviceType == Ios::Constants::IOS_SIMULATOR_TYPE; } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 0008590f070..042a23903ce 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -202,7 +202,7 @@ static QString initialStagingDir(Kit *kit) static bool supportsStageForInstallation(const Kit *kit) { IDeviceConstPtr runDevice = RunDeviceKitAspect::device(kit); - Id runDeviceType = DeviceTypeKitAspect::deviceTypeId(kit); + Id runDeviceType = RunDeviceTypeKitAspect::deviceTypeId(kit); IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(kit); QTC_ASSERT(runDeviceType.isValid(), return false); QTC_ASSERT(buildDevice, return false); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 3547e96ed10..d5ccb107cf5 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -2067,7 +2067,7 @@ const QList CMakeBuildSystem::appTargets() const QString emulator = cm.stringValueOf("CMAKE_CROSSCOMPILING_EMULATOR"); QList appTargetList; - const bool forAndroid = DeviceTypeKitAspect::deviceTypeId(kit()) + const bool forAndroid = RunDeviceTypeKitAspect::deviceTypeId(kit()) == Android::Constants::ANDROID_DEVICE_TYPE; for (const CMakeBuildTarget &ct : m_buildTargets) { if (CMakeBuildSystem::filteredOutTarget(ct)) diff --git a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp index c75c98b2841..637f6a16300 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp @@ -56,7 +56,7 @@ namespace Internal { static bool isIos(const Kit *k) { - const Id deviceType = DeviceTypeKitAspect::deviceTypeId(k); + const Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(k); return deviceType == Ios::Constants::IOS_DEVICE_TYPE || deviceType == Ios::Constants::IOS_SIMULATOR_TYPE; } diff --git a/src/plugins/debugger/unstartedappwatcherdialog.cpp b/src/plugins/debugger/unstartedappwatcherdialog.cpp index 80ba626f223..f46992ac799 100644 --- a/src/plugins/debugger/unstartedappwatcherdialog.cpp +++ b/src/plugins/debugger/unstartedappwatcherdialog.cpp @@ -40,7 +40,7 @@ static bool isLocal(RunConfiguration *runConfiguration) { Target *target = runConfiguration ? runConfiguration->target() : nullptr; Kit *kit = target ? target->kit() : nullptr; - return DeviceTypeKitAspect::deviceTypeId(kit) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; + return RunDeviceTypeKitAspect::deviceTypeId(kit) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; } /*! diff --git a/src/plugins/docker/kitdetector.cpp b/src/plugins/docker/kitdetector.cpp index 460734d42cd..f0e3f0c8026 100644 --- a/src/plugins/docker/kitdetector.cpp +++ b/src/plugins/docker/kitdetector.cpp @@ -352,7 +352,7 @@ void KitDetectorPrivate::autoDetect() if (cmakeId.isValid()) k->setValue(CMakeProjectManager::Constants::TOOL_ID, cmakeId.toSetting()); - DeviceTypeKitAspect::setDeviceTypeId(k, m_device->type()); + RunDeviceTypeKitAspect::setDeviceTypeId(k, m_device->type()); RunDeviceKitAspect::setDevice(k, m_device); BuildDeviceKitAspect::setDevice(k, m_device); @@ -388,7 +388,7 @@ void KitDetectorPrivate::autoDetect() k->setSticky(ToolchainKitAspect::id(), true); k->setSticky(QtSupport::QtKitAspect::id(), true); k->setSticky(RunDeviceKitAspect::id(), true); - k->setSticky(DeviceTypeKitAspect::id(), true); + k->setSticky(RunDeviceTypeKitAspect::id(), true); k->setSticky(BuildDeviceKitAspect::id(), true); }; diff --git a/src/plugins/ios/iosbuildconfiguration.cpp b/src/plugins/ios/iosbuildconfiguration.cpp index ba911f773e7..cdccff57fa4 100644 --- a/src/plugins/ios/iosbuildconfiguration.cpp +++ b/src/plugins/ios/iosbuildconfiguration.cpp @@ -87,7 +87,7 @@ IosSigningSettingsWidget::IosSigningSettingsWidget(BuildConfiguration *buildConf : NamedWidget(Tr::tr("iOS Settings")) , m_autoManagedSigning(autoManagedSigning) , m_signingIdentifier(signingIdentifier) - , m_isDevice(DeviceTypeKitAspect::deviceTypeId(buildConfiguration->kit()) + , m_isDevice(RunDeviceTypeKitAspect::deviceTypeId(buildConfiguration->kit()) == Constants::IOS_DEVICE_TYPE) { auto detailsWidget = new Utils::DetailsWidget(this); @@ -455,7 +455,7 @@ void IosQmakeBuildConfiguration::updateQmakeCommand() if (signingIdentifier.isEmpty() ) extraArgs << forceOverrideArg; - Utils::Id devType = DeviceTypeKitAspect::deviceTypeId(kit()); + Utils::Id devType = RunDeviceTypeKitAspect::deviceTypeId(kit()); if (devType == Constants::IOS_DEVICE_TYPE && !signingIdentifier.isEmpty()) { if (m_autoManagedSigning()) { extraArgs << qmakeIosTeamSettings + signingIdentifier; @@ -533,7 +533,7 @@ QList IosCMakeBuildConfiguration::createSubConfigWidgets() CMakeConfig IosCMakeBuildConfiguration::signingFlags() const { - if (DeviceTypeKitAspect::deviceTypeId(kit()) != Constants::IOS_DEVICE_TYPE) + if (RunDeviceTypeKitAspect::deviceTypeId(kit()) != Constants::IOS_DEVICE_TYPE) return {}; const QString signingIdentifier = m_signingIdentifier(); if (m_autoManagedSigning()) { diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index ce66978151e..b9eeea159be 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -154,7 +154,7 @@ static QHash findToolchains(const static QSet existingAutoDetectedIosKits() { return toSet(filtered(KitManager::kits(), [](Kit *kit) -> bool { - Id deviceKind = DeviceTypeKitAspect::deviceTypeId(kit); + Id deviceKind = RunDeviceTypeKitAspect::deviceTypeId(kit); return kit->isAutoDetected() && (deviceKind == Constants::IOS_DEVICE_TYPE || deviceKind == Constants::IOS_SIMULATOR_TYPE); })); @@ -169,7 +169,7 @@ static void printKits(const QSet &kits) static void setupKit(Kit *kit, Id pDeviceType, const ToolchainPair& toolchains, const QVariant &debuggerId, const FilePath &sdkPath, QtVersion *qtVersion) { - DeviceTypeKitAspect::setDeviceTypeId(kit, pDeviceType); + RunDeviceTypeKitAspect::setDeviceTypeId(kit, pDeviceType); if (toolchains.first) ToolchainKitAspect::setToolchain(kit, toolchains.first); else @@ -190,7 +190,7 @@ static void setupKit(Kit *kit, Id pDeviceType, const ToolchainPair& toolchains, kit->setSticky(QtKitAspect::id(), true); kit->setSticky(ToolchainKitAspect::id(), true); - kit->setSticky(DeviceTypeKitAspect::id(), true); + kit->setSticky(RunDeviceTypeKitAspect::id(), true); kit->setSticky(SysRootKitAspect::id(), true); kit->setSticky(DebuggerKitAspect::id(), false); @@ -272,7 +272,7 @@ void IosConfigurations::updateAutomaticKitList() Kit *kit = findOrDefault(existingKits, [&pDeviceType, &platformToolchains, &qtVersion](const Kit *kit) { // we do not compare the sdk (thus automatically upgrading it in place if a // new Xcode is used). Change? - return DeviceTypeKitAspect::deviceTypeId(kit) == pDeviceType + return RunDeviceTypeKitAspect::deviceTypeId(kit) == pDeviceType && ToolchainKitAspect::cxxToolchain(kit) == platformToolchains.second && ToolchainKitAspect::cToolchain(kit) == platformToolchains.first && QtKitAspect::qtVersion(kit) == qtVersion; diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp index 224ee7e313f..df7cc2bff64 100644 --- a/src/plugins/ios/iosrunconfiguration.cpp +++ b/src/plugins/ios/iosrunconfiguration.cpp @@ -82,7 +82,7 @@ void IosDeviceTypeAspect::deviceChanges() void IosDeviceTypeAspect::updateDeviceType() { - if (DeviceTypeKitAspect::deviceTypeId(m_runConfiguration->kit()) + if (RunDeviceTypeKitAspect::deviceTypeId(m_runConfiguration->kit()) == Constants::IOS_DEVICE_TYPE) m_deviceType = IosDeviceType(IosDeviceType::IosDevice); else if (m_deviceType.type == IosDeviceType::IosDevice) @@ -91,7 +91,7 @@ void IosDeviceTypeAspect::updateDeviceType() bool IosRunConfiguration::isEnabled(Id runMode) const { - Utils::Id devType = DeviceTypeKitAspect::deviceTypeId(kit()); + Utils::Id devType = RunDeviceTypeKitAspect::deviceTypeId(kit()); if (devType != Constants::IOS_DEVICE_TYPE && devType != Constants::IOS_SIMULATOR_TYPE) return false; if (devType == Constants::IOS_SIMULATOR_TYPE) @@ -120,7 +120,7 @@ QString IosRunConfiguration::applicationName() const FilePath IosRunConfiguration::bundleDirectory() const { - Utils::Id devType = DeviceTypeKitAspect::deviceTypeId(kit()); + Utils::Id devType = RunDeviceTypeKitAspect::deviceTypeId(kit()); bool isDevice = (devType == Constants::IOS_DEVICE_TYPE); if (!isDevice && devType != Constants::IOS_SIMULATOR_TYPE) { qCWarning(iosLog) << "unexpected device type in bundleDirForTarget: " << devType.toString(); @@ -233,7 +233,7 @@ void IosDeviceTypeAspect::toMap(Store &map) const QString IosRunConfiguration::disabledReason(Id runMode) const { - Utils::Id devType = DeviceTypeKitAspect::deviceTypeId(kit()); + Utils::Id devType = RunDeviceTypeKitAspect::deviceTypeId(kit()); if (devType != Constants::IOS_DEVICE_TYPE && devType != Constants::IOS_SIMULATOR_TYPE) return Tr::tr("Kit has incorrect device type for running on iOS devices."); IDevice::ConstPtr dev = RunDeviceKitAspect::device(kit()); diff --git a/src/plugins/mcusupport/mcukitmanager.cpp b/src/plugins/mcusupport/mcukitmanager.cpp index 5320c1a95c6..d095d5cbd6d 100644 --- a/src/plugins/mcusupport/mcukitmanager.cpp +++ b/src/plugins/mcusupport/mcukitmanager.cpp @@ -175,7 +175,7 @@ public: if (mcuTarget->toolChainPackage()->isDesktopToolchain()) return; - DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE); + RunDeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE); } static void setKitDependencies(Kit *k, diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 99bdb600475..e309c3826ac 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -760,7 +760,7 @@ bool BuildConfigurationFactory::supportsTargetDeviceType(Utils::Id id) const BuildConfigurationFactory *BuildConfigurationFactory::find(const Kit *k, const FilePath &projectPath) { QTC_ASSERT(k, return nullptr); - const Utils::Id deviceType = DeviceTypeKitAspect::deviceTypeId(k); + const Utils::Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(k); for (BuildConfigurationFactory *factory : std::as_const(g_buildConfigurationFactories)) { if (Utils::mimeTypeForFile(projectPath).matchesName(factory->m_supportedProjectMimeTypeName) && factory->supportsTargetDeviceType(deviceType)) @@ -802,7 +802,7 @@ bool BuildConfigurationFactory::canHandle(const Target *target) const if (containsType(target->project()->projectIssues(target->kit()), Task::TaskType::Error)) return false; - if (!supportsTargetDeviceType(DeviceTypeKitAspect::deviceTypeId(target->kit()))) + if (!supportsTargetDeviceType(RunDeviceTypeKitAspect::deviceTypeId(target->kit()))) return false; return true; diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 581addb5dc4..9b0f6836aef 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -278,7 +278,7 @@ bool BuildStepFactory::canHandle(BuildStepList *bsl) const if (!m_supportedDeviceTypes.isEmpty()) { Target *target = bsl->target(); QTC_ASSERT(target, return false); - Id deviceType = DeviceTypeKitAspect::deviceTypeId(target->kit()); + Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(target->kit()); if (!m_supportedDeviceTypes.contains(deviceType)) return false; } diff --git a/src/plugins/projectexplorer/deployconfiguration.cpp b/src/plugins/projectexplorer/deployconfiguration.cpp index 9fe084f187e..1ea0465f5e8 100644 --- a/src/plugins/projectexplorer/deployconfiguration.cpp +++ b/src/plugins/projectexplorer/deployconfiguration.cpp @@ -154,7 +154,7 @@ bool DeployConfigurationFactory::canHandle(Target *target) const if (!m_supportedTargetDeviceTypes.isEmpty()) { if (!m_supportedTargetDeviceTypes.contains( - DeviceTypeKitAspect::deviceTypeId(target->kit()))) + RunDeviceTypeKitAspect::deviceTypeId(target->kit()))) return false; } diff --git a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp index 5f102c1d92e..7f2989876ec 100644 --- a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp @@ -32,7 +32,7 @@ public: if (device) return true; - Utils::Id deviceTypeId = DeviceTypeKitAspect::deviceTypeId(kit()); + Utils::Id deviceTypeId = RunDeviceTypeKitAspect::deviceTypeId(kit()); IDeviceFactory *factory = IDeviceFactory::find(deviceTypeId); if (!factory || !factory->canCreate()) { emit addOutput(Tr::tr("No device configured."), OutputFormat::ErrorMessage); diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 59b8f8c1793..5d914d82f41 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -31,13 +31,13 @@ using namespace Utils; namespace ProjectExplorer { // -------------------------------------------------------------------------- -// DeviceTypeKitAspect: +// RunDeviceTypeKitAspect: // -------------------------------------------------------------------------- namespace Internal { -class DeviceTypeKitAspectImpl final : public KitAspect +class RunDeviceTypeKitAspectImpl final : public KitAspect { public: - DeviceTypeKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) + RunDeviceTypeKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) : KitAspect(workingCopy, factory) { using ItemData = std::tuple; @@ -53,9 +53,9 @@ public: return std::get<2>(d); return {}; }); - auto getter = [](const Kit &k) { return DeviceTypeKitAspect::deviceTypeId(&k).toSetting(); }; + auto getter = [](const Kit &k) { return RunDeviceTypeKitAspect::deviceTypeId(&k).toSetting(); }; auto setter = [](Kit &k, const QVariant &type) { - DeviceTypeKitAspect::setDeviceTypeId(&k, Id::fromSetting(type)); + RunDeviceTypeKitAspect::setDeviceTypeId(&k, Id::fromSetting(type)); }; auto resetModel = [model] { model->clear(); @@ -69,10 +69,10 @@ public: } }; -class DeviceTypeKitAspectFactory : public KitAspectFactory +class RunDeviceTypeKitAspectFactory : public KitAspectFactory { public: - DeviceTypeKitAspectFactory(); + RunDeviceTypeKitAspectFactory(); void setup(Kit *k) override; Tasks validate(const Kit *k) const override; @@ -83,37 +83,37 @@ public: QSet availableFeatures(const Kit *k) const override; }; -DeviceTypeKitAspectFactory::DeviceTypeKitAspectFactory() +RunDeviceTypeKitAspectFactory::RunDeviceTypeKitAspectFactory() { - setId(DeviceTypeKitAspect::id()); + setId(RunDeviceTypeKitAspect::id()); setDisplayName(Tr::tr("Run device type")); setDescription(Tr::tr("The type of device to run applications on.")); setPriority(33000); makeEssential(); } -void DeviceTypeKitAspectFactory::setup(Kit *k) +void RunDeviceTypeKitAspectFactory::setup(Kit *k) { if (k && !k->hasValue(id())) k->setValue(id(), QByteArray(Constants::DESKTOP_DEVICE_TYPE)); } -Tasks DeviceTypeKitAspectFactory::validate(const Kit *k) const +Tasks RunDeviceTypeKitAspectFactory::validate(const Kit *k) const { Q_UNUSED(k) return {}; } -KitAspect *DeviceTypeKitAspectFactory::createKitAspect(Kit *k) const +KitAspect *RunDeviceTypeKitAspectFactory::createKitAspect(Kit *k) const { QTC_ASSERT(k, return nullptr); - return new Internal::DeviceTypeKitAspectImpl(k, this); + return new Internal::RunDeviceTypeKitAspectImpl(k, this); } -KitAspectFactory::ItemList DeviceTypeKitAspectFactory::toUserOutput(const Kit *k) const +KitAspectFactory::ItemList RunDeviceTypeKitAspectFactory::toUserOutput(const Kit *k) const { QTC_ASSERT(k, return {}); - Id type = DeviceTypeKitAspect::deviceTypeId(k); + Id type = RunDeviceTypeKitAspect::deviceTypeId(k); QString typeDisplayName = Tr::tr("Unknown device type"); if (type.isValid()) { if (IDeviceFactory *factory = IDeviceFactory::find(type)) @@ -122,46 +122,46 @@ KitAspectFactory::ItemList DeviceTypeKitAspectFactory::toUserOutput(const Kit *k return {{Tr::tr("Device type"), typeDisplayName}}; } -QSet DeviceTypeKitAspectFactory::supportedPlatforms(const Kit *k) const +QSet RunDeviceTypeKitAspectFactory::supportedPlatforms(const Kit *k) const { - return {DeviceTypeKitAspect::deviceTypeId(k)}; + return {RunDeviceTypeKitAspect::deviceTypeId(k)}; } -QSet DeviceTypeKitAspectFactory::availableFeatures(const Kit *k) const +QSet RunDeviceTypeKitAspectFactory::availableFeatures(const Kit *k) const { - Id id = DeviceTypeKitAspect::deviceTypeId(k); + Id id = RunDeviceTypeKitAspect::deviceTypeId(k); if (id.isValid()) return {id.withPrefix("DeviceType.")}; return {}; } -const DeviceTypeKitAspectFactory theDeviceTypeKitAspectFactory; +const RunDeviceTypeKitAspectFactory theDeviceTypeKitAspectFactory; } // namespace Internal -const Id DeviceTypeKitAspect::id() +const Id RunDeviceTypeKitAspect::id() { return "PE.Profile.DeviceType"; } -const Id DeviceTypeKitAspect::deviceTypeId(const Kit *k) +const Id RunDeviceTypeKitAspect::deviceTypeId(const Kit *k) { - return k ? Id::fromSetting(k->value(DeviceTypeKitAspect::id())) : Id(); + return k ? Id::fromSetting(k->value(RunDeviceTypeKitAspect::id())) : Id(); } -void DeviceTypeKitAspect::setDeviceTypeId(Kit *k, Id type) +void RunDeviceTypeKitAspect::setDeviceTypeId(Kit *k, Id type) { QTC_ASSERT(k, return); - k->setValue(DeviceTypeKitAspect::id(), type.toSetting()); + k->setValue(RunDeviceTypeKitAspect::id(), type.toSetting()); } // -------------------------------------------------------------------------- -// DeviceKitAspect: +// RunDeviceKitAspect: // -------------------------------------------------------------------------- namespace Internal { -class DeviceKitAspectImpl final : public KitAspect +class RunDeviceKitAspectImpl final : public KitAspect { public: - DeviceKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) + RunDeviceKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) : KitAspect(workingCopy, factory) { setManagingPage(Constants::DEVICE_SETTINGS_PAGE_ID); @@ -175,12 +175,12 @@ public: RunDeviceKitAspect::setDeviceId(&k, Id::fromSetting(id)); }; auto resetModel = [this, model] { - model->setTypeFilter(DeviceTypeKitAspect::deviceTypeId(kit())); + model->setTypeFilter(RunDeviceTypeKitAspect::deviceTypeId(kit())); }; addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); connect(DeviceManager::instance(), &DeviceManager::updated, - this, &DeviceKitAspectImpl::refresh); + this, &RunDeviceKitAspectImpl::refresh); } private: @@ -203,10 +203,10 @@ private: } }; -class DeviceKitAspectFactory : public KitAspectFactory +class RunDeviceKitAspectFactory : public KitAspectFactory { public: - DeviceKitAspectFactory(); + RunDeviceKitAspectFactory(); private: Tasks validate(const Kit *k) const override; @@ -229,18 +229,18 @@ private: void kitUpdated(Kit *k); }; -DeviceKitAspectFactory::DeviceKitAspectFactory() +RunDeviceKitAspectFactory::RunDeviceKitAspectFactory() { setId(RunDeviceKitAspect::id()); setDisplayName(Tr::tr("Run device")); setDescription(Tr::tr("The device to run the applications on.")); setPriority(32000); - setEmbeddableAspects({DeviceTypeKitAspect::id()}); + setEmbeddableAspects({RunDeviceTypeKitAspect::id()}); } -QVariant DeviceKitAspectFactory::defaultValue(const Kit *k) const +QVariant RunDeviceKitAspectFactory::defaultValue(const Kit *k) const { - Id type = DeviceTypeKitAspect::deviceTypeId(k); + Id type = RunDeviceTypeKitAspect::deviceTypeId(k); // Use default device if that is compatible: IDevice::ConstPtr dev = DeviceManager::instance()->defaultDevice(type); if (dev && dev->isCompatibleWith(k)) @@ -255,7 +255,7 @@ QVariant DeviceKitAspectFactory::defaultValue(const Kit *k) const return {}; } -Tasks DeviceKitAspectFactory::validate(const Kit *k) const +Tasks RunDeviceKitAspectFactory::validate(const Kit *k) const { IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); Tasks result; @@ -270,7 +270,7 @@ Tasks DeviceKitAspectFactory::validate(const Kit *k) const return result; } -void DeviceKitAspectFactory::fix(Kit *k) +void RunDeviceKitAspectFactory::fix(Kit *k) { IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); if (dev && !dev->isCompatibleWith(k)) { @@ -280,7 +280,7 @@ void DeviceKitAspectFactory::fix(Kit *k) } } -void DeviceKitAspectFactory::setup(Kit *k) +void RunDeviceKitAspectFactory::setup(Kit *k) { QTC_ASSERT(DeviceManager::instance()->isLoaded(), return); IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); @@ -290,25 +290,25 @@ void DeviceKitAspectFactory::setup(Kit *k) RunDeviceKitAspect::setDeviceId(k, Id::fromSetting(defaultValue(k))); } -KitAspect *DeviceKitAspectFactory::createKitAspect(Kit *k) const +KitAspect *RunDeviceKitAspectFactory::createKitAspect(Kit *k) const { QTC_ASSERT(k, return nullptr); - return new Internal::DeviceKitAspectImpl(k, this); + return new Internal::RunDeviceKitAspectImpl(k, this); } -QString DeviceKitAspectFactory::displayNamePostfix(const Kit *k) const +QString RunDeviceKitAspectFactory::displayNamePostfix(const Kit *k) const { IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); return dev ? dev->displayName() : QString(); } -KitAspectFactory::ItemList DeviceKitAspectFactory::toUserOutput(const Kit *k) const +KitAspectFactory::ItemList RunDeviceKitAspectFactory::toUserOutput(const Kit *k) const { IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); return {{Tr::tr("Device"), dev ? dev->displayName() : Tr::tr("Unconfigured") }}; } -void DeviceKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expander) const +void RunDeviceKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expander) const { QTC_ASSERT(kit, return); expander->registerVariable("Device:HostAddress", Tr::tr("Host address"), [kit] { @@ -337,24 +337,24 @@ void DeviceKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expande }); } -void DeviceKitAspectFactory::onKitsLoaded() +void RunDeviceKitAspectFactory::onKitsLoaded() { for (Kit *k : KitManager::kits()) fix(k); DeviceManager *dm = DeviceManager::instance(); - connect(dm, &DeviceManager::deviceListReplaced, this, &DeviceKitAspectFactory::devicesChanged); - connect(dm, &DeviceManager::deviceAdded, this, &DeviceKitAspectFactory::devicesChanged); - connect(dm, &DeviceManager::deviceRemoved, this, &DeviceKitAspectFactory::devicesChanged); - connect(dm, &DeviceManager::deviceUpdated, this, &DeviceKitAspectFactory::deviceUpdated); + connect(dm, &DeviceManager::deviceListReplaced, this, &RunDeviceKitAspectFactory::devicesChanged); + connect(dm, &DeviceManager::deviceAdded, this, &RunDeviceKitAspectFactory::devicesChanged); + connect(dm, &DeviceManager::deviceRemoved, this, &RunDeviceKitAspectFactory::devicesChanged); + connect(dm, &DeviceManager::deviceUpdated, this, &RunDeviceKitAspectFactory::deviceUpdated); connect(KitManager::instance(), &KitManager::kitUpdated, - this, &DeviceKitAspectFactory::kitUpdated); + this, &RunDeviceKitAspectFactory::kitUpdated); connect(KitManager::instance(), &KitManager::unmanagedKitUpdated, - this, &DeviceKitAspectFactory::kitUpdated); + this, &RunDeviceKitAspectFactory::kitUpdated); } -void DeviceKitAspectFactory::deviceUpdated(Id id) +void RunDeviceKitAspectFactory::deviceUpdated(Id id) { for (Kit *k : KitManager::kits()) { if (RunDeviceKitAspect::deviceId(k) == id) @@ -362,18 +362,18 @@ void DeviceKitAspectFactory::deviceUpdated(Id id) } } -void DeviceKitAspectFactory::kitUpdated(Kit *k) +void RunDeviceKitAspectFactory::kitUpdated(Kit *k) { setup(k); // Set default device if necessary } -void DeviceKitAspectFactory::devicesChanged() +void RunDeviceKitAspectFactory::devicesChanged() { for (Kit *k : KitManager::kits()) setup(k); // Set default device if necessary } -const DeviceKitAspectFactory theDeviceKitAspectFactory; +const RunDeviceKitAspectFactory theDeviceKitAspectFactory; } // namespace Internal diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.h b/src/plugins/projectexplorer/devicesupport/devicekitaspects.h index b38acdd50fa..1f57aaeac92 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.h +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.h @@ -13,7 +13,7 @@ namespace Utils { class FilePath; } namespace ProjectExplorer { class Kit; -class PROJECTEXPLORER_EXPORT DeviceTypeKitAspect +class PROJECTEXPLORER_EXPORT RunDeviceTypeKitAspect { public: static const Utils::Id id(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index defb8655b70..860c271a5a7 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -420,7 +420,7 @@ Id IDevice::id() const */ bool IDevice::isCompatibleWith(const Kit *k) const { - return DeviceTypeKitAspect::deviceTypeId(k) == type(); + return RunDeviceTypeKitAspect::deviceTypeId(k) == type(); } QList IDevice::validate() const diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp index 8af1082c7ac..25f420bdd9e 100644 --- a/src/plugins/projectexplorer/kit.cpp +++ b/src/plugins/projectexplorer/kit.cpp @@ -375,7 +375,7 @@ QIcon Kit::icon() const } const Utils::Id deviceType = d->m_deviceTypeForIcon.isValid() - ? d->m_deviceTypeForIcon : DeviceTypeKitAspect::deviceTypeId(this); + ? d->m_deviceTypeForIcon : RunDeviceTypeKitAspect::deviceTypeId(this); const QIcon deviceTypeIcon = iconForDeviceType(deviceType); if (!deviceTypeIcon.isNull()) { d->m_cachedIcon = deviceTypeIcon; @@ -679,7 +679,7 @@ void Kit::setMutable(Id id, bool b) bool Kit::isMutable(Id id) const { if (id == RunDeviceKitAspect::id()) - return DeviceTypeKitAspect::deviceTypeId(this) != Constants::DESKTOP_DEVICE_TYPE; + return RunDeviceTypeKitAspect::deviceTypeId(this) != Constants::DESKTOP_DEVICE_TYPE; return d->m_mutable.contains(id); } diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index a7484dc06e5..563cf19b0a7 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -285,7 +285,7 @@ void KitManager::restoreKits() kit->setUnexpandedDisplayName(Tr::tr("Desktop (%1)").arg(it.key().toString())); else kit->setUnexpandedDisplayName(it.key().toString()); - DeviceTypeKitAspect::setDeviceTypeId(kit.get(), deviceTypeForKit(kit.get())); + RunDeviceTypeKitAspect::setDeviceTypeId(kit.get(), deviceTypeForKit(kit.get())); kit->setup(); tempList.emplace_back(std::move(kit)); } diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index c6b2243e1e1..cecd14b9c3a 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -263,7 +263,7 @@ bool KitManagerConfigWidget::isDefaultKit() const void KitManagerConfigWidget::setIcon() { - const Id deviceType = DeviceTypeKitAspect::deviceTypeId(m_modifiedKit.get()); + const Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(m_modifiedKit.get()); QList allDeviceFactories = IDeviceFactory::allDeviceFactories(); if (deviceType.isValid()) { const auto less = [deviceType](const IDeviceFactory *f1, const IDeviceFactory *f2) { diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp index 286104aae7d..af1d3928c25 100644 --- a/src/plugins/projectexplorer/parseissuesdialog.cpp +++ b/src/plugins/projectexplorer/parseissuesdialog.cpp @@ -66,7 +66,7 @@ ParseIssuesDialog::ParseIssuesDialog(QWidget *parent) : QDialog(parent), d(new P d->kitChooser.populate(); if (!d->kitChooser.hasStartupKit()) { for (const Kit * const k : KitManager::kits()) { - if (DeviceTypeKitAspect::deviceTypeId(k) == Constants::DESKTOP_DEVICE_TYPE) { + if (RunDeviceTypeKitAspect::deviceTypeId(k) == Constants::DESKTOP_DEVICE_TYPE) { d->kitChooser.setCurrentKitId(k->id()); break; } diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index a26dc987490..1400e8e86ba 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -474,7 +474,7 @@ Target *Project::createKitAndTargetFromStore(const Utils::Store &store) transform(KitManager::kits(), &Kit::unexpandedDisplayName)); kit->setUnexpandedDisplayName(kitName); - DeviceTypeKitAspect::setDeviceTypeId(kit, deviceTypeId); + RunDeviceTypeKitAspect::setDeviceTypeId(kit, deviceTypeId); kit->setup(); }); QTC_ASSERT(k, return nullptr); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 4206743e0aa..a9f26c695a5 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3193,7 +3193,7 @@ expected_str ProjectExplorerPlugin::canRunStartupProject(Utils::Id runMode } // shouldn't actually be shown to the user... - if (!RunControl::canRun(runMode, DeviceTypeKitAspect::deviceTypeId(target->kit()), + if (!RunControl::canRun(runMode, RunDeviceTypeKitAspect::deviceTypeId(target->kit()), activeRC->id())) { return make_unexpected(Tr::tr("Cannot run \"%1\".").arg(activeRC->displayName())); } diff --git a/src/plugins/projectexplorer/projectimporter.cpp b/src/plugins/projectexplorer/projectimporter.cpp index 5b5f6458d1d..239f27e89b9 100644 --- a/src/plugins/projectexplorer/projectimporter.cpp +++ b/src/plugins/projectexplorer/projectimporter.cpp @@ -173,7 +173,7 @@ Target *ProjectImporter::preferredTarget(const QList &possibleTargets) return t; if (pickedFallback) continue; - if (DeviceTypeKitAspect::deviceTypeId(t->kit()) == Constants::DESKTOP_DEVICE_TYPE) { + if (RunDeviceTypeKitAspect::deviceTypeId(t->kit()) == Constants::DESKTOP_DEVICE_TYPE) { activeTarget = t; pickedFallback = true; } diff --git a/src/plugins/projectexplorer/rawprojectpart.cpp b/src/plugins/projectexplorer/rawprojectpart.cpp index c98bbea4b42..bad242f5380 100644 --- a/src/plugins/projectexplorer/rawprojectpart.cpp +++ b/src/plugins/projectexplorer/rawprojectpart.cpp @@ -208,7 +208,7 @@ ProjectUpdateInfo::ProjectUpdateInfo(Project *project, void addTargetFlagForIos(QStringList &cFlags, QStringList &cxxFlags, const BuildSystem *bs, const std::function &getDeploymentTarget) { - const Utils::Id deviceType = DeviceTypeKitAspect::deviceTypeId(bs->target()->kit()); + const Utils::Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(bs->target()->kit()); if (deviceType != Ios::Constants::IOS_DEVICE_TYPE && deviceType != Ios::Constants::IOS_SIMULATOR_TYPE) { return; diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 8a03ee407bb..e1490c6d3b3 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -504,7 +504,7 @@ RunConfigurationFactory::~RunConfigurationFactory() QString RunConfigurationFactory::decoratedTargetName(const QString &targetName, Target *target) { QString displayName = targetName; - Utils::Id devType = DeviceTypeKitAspect::deviceTypeId(target->kit()); + Utils::Id devType = RunDeviceTypeKitAspect::deviceTypeId(target->kit()); if (devType != Constants::DESKTOP_DEVICE_TYPE) { if (IDevice::ConstPtr dev = RunDeviceKitAspect::device(target->kit())) { if (displayName.isEmpty()) { @@ -608,7 +608,7 @@ bool RunConfigurationFactory::canHandle(Target *target) const if (!m_supportedTargetDeviceTypes.isEmpty()) if (!m_supportedTargetDeviceTypes.contains( - DeviceTypeKitAspect::deviceTypeId(kit))) + RunDeviceTypeKitAspect::deviceTypeId(kit))) return false; return true; diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index a1366778df1..a7bc7a147a2 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -526,7 +526,7 @@ void RunControl::forceStop() RunWorker *RunControl::createWorker(Id runMode) { - const Id deviceType = DeviceTypeKitAspect::deviceTypeId(d->kit); + const Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(d->kit); for (RunWorkerFactory *factory : std::as_const(g_runWorkerFactories)) { if (factory->canCreate(runMode, deviceType, d->runConfigId.toString())) return factory->create(this); @@ -539,7 +539,7 @@ bool RunControl::createMainWorker() const QList candidates = filtered(g_runWorkerFactories, [this](RunWorkerFactory *factory) { return factory->canCreate(d->runMode, - DeviceTypeKitAspect::deviceTypeId(d->kit), + RunDeviceTypeKitAspect::deviceTypeId(d->kit), d->runConfigId.toString()); }); diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index 3085459cd87..eb6105273b6 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -589,7 +589,7 @@ Store Target::toMap() const Store map; map.insert(displayNameKey(), displayName()); - map.insert(deviceTypeKey(), DeviceTypeKitAspect::deviceTypeId(kit()).toSetting()); + map.insert(deviceTypeKey(), RunDeviceTypeKitAspect::deviceTypeId(kit()).toSetting()); { // FIXME: For compatibility within the 4.11 cycle, remove this block later. diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index 0c15c4f4a4e..e64e8a51523 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -58,7 +58,7 @@ static QString extractToolchainPrefix(QString *compilerName) static QString targetPlatform(const ProjectExplorer::Abi &abi, const ProjectExplorer::Kit *k) { - const Utils::Id deviceType = ProjectExplorer::DeviceTypeKitAspect::deviceTypeId(k); + const Utils::Id deviceType = ProjectExplorer::RunDeviceTypeKitAspect::deviceTypeId(k); if (deviceType == WebAssembly::Constants::WEBASSEMBLY_DEVICE_TYPE) return "wasm-emscripten"; diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index 8d149ee2f51..5eac58e8087 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -124,7 +124,7 @@ QmakeBuildConfiguration::QmakeBuildConfiguration(Target *target, Id id) setBuildDirectory(directory); - if (DeviceTypeKitAspect::deviceTypeId(target->kit()) + if (RunDeviceTypeKitAspect::deviceTypeId(target->kit()) == Android::Constants::ANDROID_DEVICE_TYPE) { buildSteps()->appendStep(Android::Constants::ANDROID_PACKAGE_INSTALL_STEP_ID); buildSteps()->appendStep(Android::Constants::ANDROID_BUILD_APK_ID); diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index a8bc46b09fa..e94a2678e45 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -522,7 +522,7 @@ void QMakeStep::separateDebugInfoChanged() static bool isIos(const Kit *k) { - const Id deviceType = DeviceTypeKitAspect::deviceTypeId(k); + const Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(k); return deviceType == Ios::Constants::IOS_DEVICE_TYPE || deviceType == Ios::Constants::IOS_SIMULATOR_TYPE; } diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp index f44cb0ab24d..93a03772103 100644 --- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp +++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp @@ -40,7 +40,7 @@ static void handleAction(const SelectionContext &context) const Kit *kit = startupTarget->kit(); if (kit && (kit->supportedPlatforms().contains(Android::Constants::ANDROID_DEVICE_TYPE) - || DeviceTypeKitAspect::deviceTypeId(kit) + || RunDeviceTypeKitAspect::deviceTypeId(kit) == Android::Constants::ANDROID_DEVICE_TYPE)) { skipDeploy = true; // In case of an android kit we don't want the live preview button to be toggled diff --git a/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp b/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp index 146195dc276..731b523b027 100644 --- a/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp +++ b/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp @@ -76,7 +76,7 @@ QString QmlPreviewFileOnTargetFinder::findPath(const QString &filePath, bool *su if (success) { // On desktop, if there is no "remote" path, then the application will load the local path. - *success = ProjectExplorer::DeviceTypeKitAspect::deviceTypeId(m_target->kit()) + *success = ProjectExplorer::RunDeviceTypeKitAspect::deviceTypeId(m_target->kit()) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; } return filePath; diff --git a/src/plugins/qmlpreview/qmlpreviewplugin.cpp b/src/plugins/qmlpreview/qmlpreviewplugin.cpp index d87d0516a1e..47e0589f5e3 100644 --- a/src/plugins/qmlpreview/qmlpreviewplugin.cpp +++ b/src/plugins/qmlpreview/qmlpreviewplugin.cpp @@ -151,7 +151,7 @@ QmlPreviewPluginPrivate::QmlPreviewPluginPrivate(QmlPreviewPlugin *parent) const Kit *kit = ProjectManager::startupTarget()->kit(); if (ProjectManager::startupTarget() && kit) skipDeploy = kit->supportedPlatforms().contains(Android::Constants::ANDROID_DEVICE_TYPE) - || DeviceTypeKitAspect::deviceTypeId(kit) == Android::Constants::ANDROID_DEVICE_TYPE; + || RunDeviceTypeKitAspect::deviceTypeId(kit) == Android::Constants::ANDROID_DEVICE_TYPE; ProjectExplorerPlugin::runStartupProject(Constants::QML_PREVIEW_RUN_MODE, skipDeploy); }); menu->addAction( diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp index 5445e9540df..80ff0532e2c 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp @@ -110,7 +110,7 @@ void QmlBuildSystem::updateDeploymentData() if (!m_projectItem) return; - if (DeviceTypeKitAspect::deviceTypeId(kit()) + if (RunDeviceTypeKitAspect::deviceTypeId(kit()) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { return; } @@ -511,7 +511,7 @@ bool QmlBuildSystem::setMainUiFileInMainFile(const Utils::FilePath &newMainUiFil Utils::FilePath QmlBuildSystem::targetDirectory() const { Utils::FilePath result; - if (DeviceTypeKitAspect::deviceTypeId(kit()) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { + if (RunDeviceTypeKitAspect::deviceTypeId(kit()) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { result = canonicalProjectDir(); } else if (IDevice::ConstPtr device = RunDeviceKitAspect::device(kit())) { if (m_projectItem) diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 7ba18e3d03b..bdcf1837532 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -108,7 +108,7 @@ Project::RestoreResult QmlProject::fromMap(const Store &map, QString *errorMessa // find a kit that matches prerequisites (prefer default one) const QList kits = Utils::filtered(KitManager::kits(), [this](const Kit *k) { return !containsType(projectIssues(k), Task::TaskType::Error) - && DeviceTypeKitAspect::deviceTypeId(k) + && RunDeviceTypeKitAspect::deviceTypeId(k) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; }); diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index 111185be66d..fd333c6f898 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -156,7 +156,7 @@ QmlProjectRunConfiguration::QmlProjectRunConfiguration(Target *target, Id id) return env; }; - const Id deviceTypeId = DeviceTypeKitAspect::deviceTypeId(target->kit()); + const Id deviceTypeId = RunDeviceTypeKitAspect::deviceTypeId(target->kit()); if (deviceTypeId == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { environment.addPreferredBaseEnvironment(Tr::tr("System Environment"), [envModifier] { return envModifier(Environment::systemEnvironment()); @@ -183,7 +183,7 @@ QString QmlProjectRunConfiguration::disabledReason(Utils::Id runMode) const return Tr::tr("No script file to execute."); const FilePath viewer = qmlRuntimeFilePath(); - if (DeviceTypeKitAspect::deviceTypeId(kit()) + if (RunDeviceTypeKitAspect::deviceTypeId(kit()) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE && !viewer.exists()) { return Tr::tr("No QML utility found."); @@ -278,7 +278,7 @@ void QmlProjectRunConfiguration::setupQtVersionAspect() const QList kits = Utils::filtered(KitManager::kits(), [&](const Kit *k) { QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(k); return (version && version->qtVersion().majorVersion() == preferedQtVersion) - && DeviceTypeKitAspect::deviceTypeId(k) + && RunDeviceTypeKitAspect::deviceTypeId(k) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; }); diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index 19109e62f20..27f2fa33ecb 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -204,7 +204,7 @@ void showAttachToProcessDialog() { auto kitChooser = new KitChooser; kitChooser->setKitPredicate([](const Kit *k) { - return k->isValid() && DeviceTypeKitAspect::deviceTypeId(k) == Constants::QNX_QNX_OS_TYPE; + return k->isValid() && RunDeviceTypeKitAspect::deviceTypeId(k) == Constants::QNX_QNX_OS_TYPE; }); QnxAttachDebugDialog dlg(kitChooser); diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index 7b0a3fcfa07..8db9af65f14 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -115,7 +115,7 @@ class QnxPlugin final : public ExtensionSystem::IPlugin connect(KitManager::instance(), &KitManager::kitsChanged, this, [attachToQnxApplication, debugSeparator] { auto isQnxKit = [](const Kit *kit) { - return DeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE + return RunDeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE && RunDeviceKitAspect::device(kit) && kit->isValid(); }; diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index a96ff7d8a1d..18ef409d222 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -183,7 +183,7 @@ void QnxConfiguration::deactivate() const QList kits = KitManager::kits(); for (Kit *kit : kits) { if (kit->isAutoDetected() - && DeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE + && RunDeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE && toolChainsToRemove.contains(ToolchainKitAspect::cxxToolchain(kit))) { KitManager::deregisterKit(kit); } @@ -264,7 +264,7 @@ void QnxConfiguration::createKit(const QnxTarget &target) if (debugger.isValid()) DebuggerKitAspect::setDebugger(k, debugger); - DeviceTypeKitAspect::setDeviceTypeId(k, Constants::QNX_QNX_OS_TYPE); + RunDeviceTypeKitAspect::setDeviceTypeId(k, Constants::QNX_QNX_OS_TYPE); // TODO: Add sysroot? k->setUnexpandedDisplayName(Tr::tr("Kit for %1 (%2)") @@ -275,7 +275,7 @@ void QnxConfiguration::createKit(const QnxTarget &target) k->setAutoDetectionSource(m_envFile.toString()); k->setSticky(ToolchainKitAspect::id(), true); - k->setSticky(DeviceTypeKitAspect::id(), true); + k->setSticky(RunDeviceTypeKitAspect::id(), true); k->setSticky(SysRootKitAspect::id(), true); k->setSticky(DebuggerKitAspect::id(), true); k->setSticky(QmakeProjectManager::Constants::KIT_INFORMATION_ID, true); diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 31086e823a5..3295121ba2d 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -426,7 +426,7 @@ Tasks QtVersion::validateKit(const Kit *k) if (qtAbis.isEmpty()) // No need to test if Qt does not know anyway... return result; - const Id dt = DeviceTypeKitAspect::deviceTypeId(k); + const Id dt = RunDeviceTypeKitAspect::deviceTypeId(k); if (dt != "DockerDeviceType") { const QSet tdt = targetDeviceTypes(); if (!tdt.isEmpty() && !tdt.contains(dt)) diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index fd9711db7e5..bde243f7ef8 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -130,7 +130,7 @@ void QtKitAspectFactory::setup(Kit *k) if (!k || k->hasValue(id())) return; const Abi tcAbi = ToolchainKitAspect::targetAbi(k); - const Id deviceType = DeviceTypeKitAspect::deviceTypeId(k); + const Id deviceType = RunDeviceTypeKitAspect::deviceTypeId(k); const QtVersions matches = QtVersionManager::versions([&tcAbi, &deviceType](const QtVersion *qt) { @@ -436,7 +436,7 @@ int QtKitAspectFactory::weight(const Kit *k) const const QtVersion * const qt = QtKitAspect::qtVersion(k); if (!qt) return 0; - if (!qt->targetDeviceTypes().contains(DeviceTypeKitAspect::deviceTypeId(k))) + if (!qt->targetDeviceTypes().contains(RunDeviceTypeKitAspect::deviceTypeId(k))) return 0; const Abi tcAbi = ToolchainKitAspect::targetAbi(k); if (qt->qtAbis().contains(tcAbi)) diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 42734452bb9..5d63bed1f71 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -708,7 +708,7 @@ bool StudioWelcomePlugin::delayedInitialize() const bool autoDetected = valid && version->isAutodetected(); return isQt6 && autoDetected - && ProjectExplorer::DeviceTypeKitAspect::deviceTypeId(k) + && RunDeviceTypeKitAspect::deviceTypeId(k) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; }); diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index f0c5f455394..a7e2ddefb93 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -689,7 +689,7 @@ void MemcheckTool::heobAction() = DeviceManager::deviceForPath(sr.command.executable()); hasLocalRc = device && device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; if (!hasLocalRc) - hasLocalRc = DeviceTypeKitAspect::deviceTypeId(kit) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; + hasLocalRc = RunDeviceTypeKitAspect::deviceTypeId(kit) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; } } } From c9857cb8f9de9a5574eb905cef485c9023f7e674 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Nov 2024 11:42:41 +0100 Subject: [PATCH 114/989] Android: Rename androidmanager.{cpp,h} to androidutils.{cpp,h} Change-Id: Ic75e3d5bf4e5e7b30bd3ef73d8be5d1ad41c22b8 Reviewed-by: Jarek Kobus --- src/plugins/android/CMakeLists.txt | 2 +- src/plugins/android/android.qbs | 4 ++-- src/plugins/android/androidbuildapkstep.cpp | 2 +- src/plugins/android/androidconfigurations.cpp | 2 +- src/plugins/android/androiddebugsupport.cpp | 2 +- src/plugins/android/androiddeployqtstep.cpp | 3 +-- src/plugins/android/androiddevice.cpp | 2 +- src/plugins/android/androidextralibrarylistmodel.cpp | 4 ++-- src/plugins/android/androidmanifesteditor.cpp | 2 +- src/plugins/android/androidpackageinstallationstep.cpp | 5 +++-- src/plugins/android/androidqtversion.cpp | 2 +- src/plugins/android/androidrunner.cpp | 2 +- src/plugins/android/androidrunnerworker.cpp | 2 +- src/plugins/android/androidsdkmodel.cpp | 3 +-- .../android/{androidmanager.cpp => androidutils.cpp} | 2 +- src/plugins/android/{androidmanager.h => androidutils.h} | 0 src/plugins/android/createandroidmanifestwizard.cpp | 7 +++---- src/plugins/android/javalanguageserver.cpp | 2 +- 18 files changed, 23 insertions(+), 25 deletions(-) rename src/plugins/android/{androidmanager.cpp => androidutils.cpp} (99%) rename src/plugins/android/{androidmanager.h => androidutils.h} (100%) diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index d5c0e9b7ba3..2eac3c8416d 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -16,7 +16,6 @@ add_qtc_plugin(Android androiddevice.cpp androiddevice.h androiddeviceinfo.cpp androiddeviceinfo.h androidextralibrarylistmodel.cpp androidextralibrarylistmodel.h - androidmanager.cpp androidmanager.h androidmanifesteditor.cpp androidmanifesteditor.h androidmanifesteditoriconwidget.cpp androidmanifesteditoriconwidget.h androidmanifesteditoriconcontainerwidget.cpp androidmanifesteditoriconcontainerwidget.h @@ -35,6 +34,7 @@ add_qtc_plugin(Android androidsettingswidget.cpp androidsettingswidget.h androidsignaloperation.cpp androidsignaloperation.h androidtoolchain.cpp androidtoolchain.h + androidutils.cpp androidutils.h avddialog.cpp avddialog.h avdmanageroutputparser.cpp avdmanageroutputparser.h certificatesmodel.cpp certificatesmodel.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index db634355af4..685f0336a9f 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -36,8 +36,6 @@ QtcPlugin { "androiddeviceinfo.h", "androidextralibrarylistmodel.cpp", "androidextralibrarylistmodel.h", - "androidmanager.cpp", - "androidmanager.h", "androidmanifesteditoriconwidget.cpp", "androidmanifesteditoriconwidget.h", "androidmanifesteditoriconcontainerwidget.cpp", @@ -73,6 +71,8 @@ QtcPlugin { "androidsignaloperation.h", "androidtoolchain.cpp", "androidtoolchain.h", + "androidutils.cpp", + "androidutils.h", "avddialog.cpp", "avddialog.h", "avdmanageroutputparser.cpp", diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 46395516b42..ea06a6349af 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -7,10 +7,10 @@ #include "androidconstants.h" #include "androidcreatekeystorecertificate.h" #include "androidextralibrarylistmodel.h" -#include "androidmanager.h" #include "androidqtversion.h" #include "androidsdkmanager.h" #include "androidtr.h" +#include "androidutils.h" #include "certificatesmodel.h" #include "createandroidmanifestwizard.h" #include "javaparser.h" diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 40a7cabf10d..e9f372d8325 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -5,11 +5,11 @@ #include "androidconfigurations.h" #include "androidconstants.h" #include "androiddevice.h" -#include "androidmanager.h" #include "androidqtversion.h" #include "androidsdkmanager.h" #include "androidtoolchain.h" #include "androidtr.h" +#include "androidutils.h" #include #include diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index c8d655db2a1..8170bb89d2d 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -6,8 +6,8 @@ #include "androidconfigurations.h" #include "androidconstants.h" #include "androidrunner.h" -#include "androidmanager.h" #include "androidqtversion.h" +#include "androidutils.h" #include #include diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index b12220a6966..43233c528ef 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -8,10 +8,9 @@ #include "androidbuildapkstep.h" #include "androidconstants.h" #include "androiddevice.h" -#include "androidmanager.h" #include "androidqtversion.h" #include "androidtr.h" -#include "androidtr.h" +#include "androidutils.h" #include #include diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 27f731180e5..67cbec430d6 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -7,9 +7,9 @@ #include "androidavdmanager.h" #include "androidconfigurations.h" #include "androidconstants.h" -#include "androidmanager.h" #include "androidsignaloperation.h" #include "androidtr.h" +#include "androidutils.h" #include "avddialog.h" #include "avdmanageroutputparser.h" diff --git a/src/plugins/android/androidextralibrarylistmodel.cpp b/src/plugins/android/androidextralibrarylistmodel.cpp index ac9084def7a..eb1218c2a39 100644 --- a/src/plugins/android/androidextralibrarylistmodel.cpp +++ b/src/plugins/android/androidextralibrarylistmodel.cpp @@ -4,8 +4,8 @@ #include "androidextralibrarylistmodel.h" -#include -#include +#include "androidconstants.h" +#include "androidutils.h" #include #include diff --git a/src/plugins/android/androidmanifesteditor.cpp b/src/plugins/android/androidmanifesteditor.cpp index e0f0752438b..1d3bad39b00 100644 --- a/src/plugins/android/androidmanifesteditor.cpp +++ b/src/plugins/android/androidmanifesteditor.cpp @@ -5,9 +5,9 @@ #include "androidconfigurations.h" #include "androidconstants.h" -#include "androidmanager.h" #include "androidmanifesteditoriconcontainerwidget.h" #include "androidtr.h" +#include "androidutils.h" #include "splashscreencontainerwidget.h" #include diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp index b129670b95e..1595180196d 100644 --- a/src/plugins/android/androidpackageinstallationstep.cpp +++ b/src/plugins/android/androidpackageinstallationstep.cpp @@ -1,10 +1,11 @@ // Copyright (C) 2016 BogDan Vatra // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "androidconstants.h" -#include "androidmanager.h" #include "androidpackageinstallationstep.h" + +#include "androidconstants.h" #include "androidtr.h" +#include "androidutils.h" #include #include diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index fbb79620113..bda3c7e8a0e 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -3,9 +3,9 @@ #include "androidconfigurations.h" #include "androidconstants.h" -#include "androidmanager.h" #include "androidqtversion.h" #include "androidtr.h" +#include "androidutils.h" #include #include diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 65794ef6389..38ad42726ab 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -7,8 +7,8 @@ #include "androidavdmanager.h" #include "androidconstants.h" #include "androiddevice.h" -#include "androidmanager.h" #include "androidrunnerworker.h" +#include "androidutils.h" #include #include diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 3b997f93d38..6e574ebfe59 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -6,8 +6,8 @@ #include "androidconfigurations.h" #include "androidconstants.h" #include "androiddeviceinfo.h" -#include "androidmanager.h" #include "androidtr.h" +#include "androidutils.h" #include #include diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp index 5c33df86c7e..650927fa324 100644 --- a/src/plugins/android/androidsdkmodel.cpp +++ b/src/plugins/android/androidsdkmodel.cpp @@ -3,10 +3,9 @@ #include "androidsdkmodel.h" -#include "androidmanager.h" -#include "androidconfigurations.h" #include "androidsdkmanager.h" #include "androidtr.h" +#include "androidutils.h" #include #include diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidutils.cpp similarity index 99% rename from src/plugins/android/androidmanager.cpp rename to src/plugins/android/androidutils.cpp index 9b6a1577e21..4f90cf63e0d 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidutils.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2016 BogDan Vatra // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "androidmanager.h" +#include "androidutils.h" #include "androidbuildapkstep.h" #include "androidconfigurations.h" diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidutils.h similarity index 100% rename from src/plugins/android/androidmanager.h rename to src/plugins/android/androidutils.h diff --git a/src/plugins/android/createandroidmanifestwizard.cpp b/src/plugins/android/createandroidmanifestwizard.cpp index 62c867fa423..40b3f3d83a4 100644 --- a/src/plugins/android/createandroidmanifestwizard.cpp +++ b/src/plugins/android/createandroidmanifestwizard.cpp @@ -1,12 +1,11 @@ // 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 "androidtr.h" #include "createandroidmanifestwizard.h" -#include -#include -#include +#include "androidtr.h" +#include "androidconstants.h" +#include "androidutils.h" #include diff --git a/src/plugins/android/javalanguageserver.cpp b/src/plugins/android/javalanguageserver.cpp index 430d4df1a7a..ff4886dcbdb 100644 --- a/src/plugins/android/javalanguageserver.cpp +++ b/src/plugins/android/javalanguageserver.cpp @@ -3,8 +3,8 @@ #include "androidconfigurations.h" #include "androidconstants.h" -#include "androidmanager.h" #include "androidtr.h" +#include "androidutils.h" #include "javalanguageserver.h" #include From 9d1cb97d67d493d26af84ed8194e437c9af42c58 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Nov 2024 11:40:29 +0100 Subject: [PATCH 115/989] Android: Move adbSelector from deviceinfo to androidutils Change-Id: I120ba155fd70ded7ae8ed4fcb93dc2bcc5de9701 Reviewed-by: Jarek Kobus --- src/plugins/android/androidavdmanager.cpp | 4 ++-- src/plugins/android/androidconfigurations.cpp | 6 +++--- src/plugins/android/androiddeployqtstep.cpp | 9 ++++----- src/plugins/android/androiddevice.cpp | 9 ++++----- src/plugins/android/androiddeviceinfo.cpp | 11 ----------- src/plugins/android/androiddeviceinfo.h | 2 -- src/plugins/android/androidrunnerworker.cpp | 7 +++++-- src/plugins/android/androidutils.cpp | 11 +++++++++++ src/plugins/android/androidutils.h | 2 ++ 9 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index ed392513cce..e0af55ff463 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -4,8 +4,8 @@ #include "androidavdmanager.h" #include "androidconfigurations.h" -#include "androiddeviceinfo.h" #include "androidtr.h" +#include "androidutils.h" #include @@ -155,7 +155,7 @@ static ExecutableItem isAvdBootedRecipe(const Storage &serialNumberStor { const auto onSetup = [serialNumberStorage](Process &process) { const CommandLine cmd{AndroidConfig::adbToolPath(), - {AndroidDeviceInfo::adbSelector(*serialNumberStorage), + {adbSelector(*serialNumberStorage), "shell", "getprop", "init.svc.bootanim"}}; qCDebug(avdManagerLog).noquote() << "Running command (isAvdBooted):" << cmd.toUserOutput(); process.setCommand(cmd); diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index e9f372d8325..85f64bf639f 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -162,7 +162,7 @@ static QString getDeviceProperty(const QString &device, const QString &property) // workaround for '????????????' serial numbers Process adbProc; adbProc.setCommand({AndroidConfig::adbToolPath(), - {AndroidDeviceInfo::adbSelector(device), "shell", "getprop", property}}); + {adbSelector(device), "shell", "getprop", property}}); adbProc.runBlocking(); if (adbProc.result() == ProcessResult::FinishedWithSuccess) return adbProc.allOutput(); @@ -722,7 +722,7 @@ QStringList getAbis(const QString &device) // First try via ro.product.cpu.abilist Process adbProc; adbProc.setCommand({adbTool, - {AndroidDeviceInfo::adbSelector(device), "shell", "getprop", "ro.product.cpu.abilist"}}); + {adbSelector(device), "shell", "getprop", "ro.product.cpu.abilist"}}); adbProc.runBlocking(); if (adbProc.result() != ProcessResult::FinishedWithSuccess) return result; @@ -736,7 +736,7 @@ QStringList getAbis(const QString &device) // Fall back to ro.product.cpu.abi, ro.product.cpu.abi2 ... for (int i = 1; i < 6; ++i) { - CommandLine cmd{adbTool, {AndroidDeviceInfo::adbSelector(device), "shell", "getprop"}}; + CommandLine cmd{adbTool, {adbSelector(device), "shell", "getprop"}}; if (i == 1) cmd.addArg("ro.product.cpu.abi"); else diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 43233c528ef..83beaaf559d 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -361,7 +361,7 @@ GroupItem AndroidDeployQtStep::runRecipe() .arg(parentDir.nativePath()); reportWarningOrError(error, Task::Error); } - const CommandLine cmd{m_adbPath, {AndroidDeviceInfo::adbSelector(m_serialNumber), + const CommandLine cmd{m_adbPath, {adbSelector(m_serialNumber), "pull", file.from, file.to.nativePath()}}; emit addOutput(Tr::tr("Package deploy: Running command \"%1\".").arg(cmd.toUserOutput()), OutputFormat::NormalMessage); @@ -421,8 +421,7 @@ Group AndroidDeployQtStep::deployRecipe() const QString msg = Tr::tr("Uninstalling the previous package \"%1\".").arg(packageName); qCDebug(deployStepLog) << msg; emit addOutput(msg, OutputFormat::NormalMessage); - const CommandLine cmd{m_adbPath, {AndroidDeviceInfo::adbSelector(m_serialNumber), - "uninstall", packageName}}; + const CommandLine cmd{m_adbPath, {adbSelector(m_serialNumber), "uninstall", packageName}}; emit addOutput(Tr::tr("Package deploy: Running command \"%1\".").arg(cmd.toUserOutput()), OutputFormat::NormalMessage); process.setCommand(cmd); @@ -445,7 +444,7 @@ Group AndroidDeployQtStep::deployRecipe() cmd.addArgs({"--device", m_serialNumber}); } else { QTC_ASSERT(target()->activeRunConfiguration(), return SetupResult::StopWithError); - cmd.addArgs(AndroidDeviceInfo::adbSelector(m_serialNumber)); + cmd.addArgs(adbSelector(m_serialNumber)); cmd.addArgs({"install", "-r", m_apkPath.nativePath()}); } @@ -587,7 +586,7 @@ QWidget *AndroidDeployQtStep::createConfigWidget() const auto onAdbSetup = [serialNumberStorage, packagePath](Process &process) { const CommandLine cmd{AndroidConfig::adbToolPath(), - {AndroidDeviceInfo::adbSelector(*serialNumberStorage), + {adbSelector(*serialNumberStorage), "install", "-r", packagePath.path()}}; process.setCommand(cmd); }; diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 67cbec430d6..2a73b837711 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -114,7 +114,7 @@ static QString displayNameFromInfo(const AndroidDeviceInfo &info) static IDevice::DeviceState getDeviceState(const QString &serial, IDevice::MachineType type) { - const QStringList args = AndroidDeviceInfo::adbSelector(serial) << "shell" << "echo 1"; + const QStringList args = adbSelector(serial) << "shell" << "echo 1"; const SdkToolResult result = runAdbCommand(args); if (result.success) return IDevice::DeviceReadyToUse; @@ -158,7 +158,7 @@ static void setEmulatorArguments(QWidget *parent) static QString emulatorName(const QString &serialNumber) { - const QStringList args = AndroidDeviceInfo::adbSelector(serialNumber) << "emu" << "avd" << "name"; + const QStringList args = adbSelector(serialNumber) << "emu" << "avd" << "name"; return runAdbCommand(args).stdOut; } @@ -238,7 +238,7 @@ static void setupWifiForDevice(const IDevice::Ptr &device, QWidget *parent) } const auto androidDev = static_cast(device.get()); - const QStringList adbSelector = AndroidDeviceInfo::adbSelector(androidDev->serialNumber()); + const QStringList adbSelector = Internal::adbSelector(androidDev->serialNumber()); // prepare port QStringList args = adbSelector; args.append({"tcpip", wifiDevicePort}); @@ -633,8 +633,7 @@ PortsGatheringMethod AndroidDevice::portsGatheringMethod() const [this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine { Q_UNUSED(protocol); return {AndroidConfig::adbToolPath(), { - AndroidDeviceInfo::adbSelector(serialNumber()), - "shell" , "netstat", "-a", "-n" + adbSelector(serialNumber()), "shell" , "netstat", "-a", "-n" }}; }, &Port::parseFromCommandOutput diff --git a/src/plugins/android/androiddeviceinfo.cpp b/src/plugins/android/androiddeviceinfo.cpp index ac9e71ec786..2c79ced2c0f 100644 --- a/src/plugins/android/androiddeviceinfo.cpp +++ b/src/plugins/android/androiddeviceinfo.cpp @@ -5,17 +5,6 @@ namespace Android::Internal { -/** - * Workaround for '????????????' serial numbers - * @return ("-d") for buggy devices, ("-s", ) for normal - */ -QStringList AndroidDeviceInfo::adbSelector(const QString &serialNumber) -{ - if (serialNumber.startsWith(QLatin1String("????"))) - return {"-d"}; - return {"-s", serialNumber}; -} - bool AndroidDeviceInfo::operator<(const AndroidDeviceInfo &other) const { if (serialNumber.contains("????") != other.serialNumber.contains("????")) diff --git a/src/plugins/android/androiddeviceinfo.h b/src/plugins/android/androiddeviceinfo.h index 04dbe48915a..6a66e821218 100644 --- a/src/plugins/android/androiddeviceinfo.h +++ b/src/plugins/android/androiddeviceinfo.h @@ -25,8 +25,6 @@ public: IDevice::MachineType type = IDevice::Emulator; Utils::FilePath avdPath; - static QStringList adbSelector(const QString &serialNumber); - bool isValid() const { return !serialNumber.isEmpty() || !avdName.isEmpty(); } bool operator<(const AndroidDeviceInfo &other) const; bool operator==(const AndroidDeviceInfo &other) const; // should be = default with C++20 diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 6e574ebfe59..fd6b363c542 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -136,16 +136,19 @@ class RunnerStorage { public: bool isPreNougat() const { return m_glue->apiLevel() > 0 && m_glue->apiLevel() <= 23; } - Utils::CommandLine adbCommand(std::initializer_list args) const + + CommandLine adbCommand(std::initializer_list args) const { CommandLine cmd{AndroidConfig::adbToolPath(), args}; - cmd.prependArgs(AndroidDeviceInfo::adbSelector(m_glue->deviceSerialNumber())); + cmd.prependArgs(adbSelector(m_glue->deviceSerialNumber())); return cmd; } + QStringList userArgs() const { return m_processUser > 0 ? QStringList{"--user", QString::number(m_processUser)} : QStringList{}; } + QStringList packageArgs() const { // run-as pwd fails on API 22 so route the pwd through shell. diff --git a/src/plugins/android/androidutils.cpp b/src/plugins/android/androidutils.cpp index 4f90cf63e0d..247fa3a7f80 100644 --- a/src/plugins/android/androidutils.cpp +++ b/src/plugins/android/androidutils.cpp @@ -588,4 +588,15 @@ QString androidNameForApiLevel(int x) } } +/** + * Workaround for '????????????' serial numbers + * @return ("-d") for buggy devices, ("-s", ) for normal + */ +QStringList adbSelector(const QString &serialNumber) +{ + if (serialNumber.startsWith(QLatin1String("????"))) + return {"-d"}; + return {"-s", serialNumber}; +} + } // namespace Android::Internal diff --git a/src/plugins/android/androidutils.h b/src/plugins/android/androidutils.h index 7be62c45d9e..3fdee8994ba 100644 --- a/src/plugins/android/androidutils.h +++ b/src/plugins/android/androidutils.h @@ -55,4 +55,6 @@ QString androidNameForApiLevel(int x); QJsonObject deploymentSettings(const ProjectExplorer::Target *target); bool isQtCreatorGenerated(const Utils::FilePath &deploymentFile); +QStringList adbSelector(const QString &serialNumber); + } // namespace Android::Internal From 8b10a1d702fd510cb2b933668cca0e20e0230e68 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Nov 2024 12:37:48 +0100 Subject: [PATCH 116/989] Android: Re-indent androiddeployqtstep.cpp Follow-up to bdde3f1c9c132. Change-Id: I5adf41bc3afc49fc3c6046c37390eb1fb9e496b7 Reviewed-by: Jarek Kobus --- src/plugins/android/androiddeployqtstep.cpp | 56 ++++++++++----------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 83beaaf559d..4c3c8712cf1 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -207,8 +207,6 @@ bool AndroidDeployQtStep::init() qCDebug(deployStepLog) << "Target architecture:" << androidABIs << "Min target API" << minTargetApi; - AndroidDeviceInfo info; - const BuildSystem *bs = buildSystem(); auto selectedAbis = bs->property(Constants::AndroidAbis).toStringList(); @@ -219,38 +217,36 @@ bool AndroidDeployQtStep::init() if (selectedAbis.isEmpty()) selectedAbis.append(bs->extraData(buildKey, Constants::AndroidAbi).toString()); - if (true) { // FIXME: Simplify - const auto dev = - static_cast(RunDeviceKitAspect::device(kit()).get()); - if (!dev) { - reportWarningOrError(Tr::tr("No valid deployment device is set."), Task::Error); - return false; - } + const auto dev = + static_cast(RunDeviceKitAspect::device(kit()).get()); + if (!dev) { + reportWarningOrError(Tr::tr("No valid deployment device is set."), Task::Error); + return false; + } - // TODO: use AndroidDevice directly instead of AndroidDeviceInfo. - info = AndroidDevice::androidDeviceInfoFromIDevice(dev); + // TODO: use AndroidDevice directly instead of AndroidDeviceInfo. + const AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(dev); - if (!info.isValid()) { - reportWarningOrError(Tr::tr("The deployment device \"%1\" is invalid.") - .arg(dev->displayName()), Task::Error); - return false; - } + if (!info.isValid()) { + reportWarningOrError(Tr::tr("The deployment device \"%1\" is invalid.") + .arg(dev->displayName()), Task::Error); + return false; + } - if (!dev->canSupportAbis(selectedAbis)) { - const QString error = Tr::tr("The deployment device \"%1\" does not support the " - "architectures used by the kit.\n" - "The kit supports \"%2\", but the device uses \"%3\".") - .arg(dev->displayName()).arg(selectedAbis.join(", ")) - .arg(dev->supportedAbis().join(", ")); - reportWarningOrError(error, Task::Error); - return false; - } + if (!dev->canSupportAbis(selectedAbis)) { + const QString error = Tr::tr("The deployment device \"%1\" does not support the " + "architectures used by the kit.\n" + "The kit supports \"%2\", but the device uses \"%3\".") + .arg(dev->displayName()).arg(selectedAbis.join(", ")) + .arg(dev->supportedAbis().join(", ")); + reportWarningOrError(error, Task::Error); + return false; + } - if (!dev->canHandleDeployments()) { - reportWarningOrError(Tr::tr("The deployment device \"%1\" is disconnected.") - .arg(dev->displayName()), Task::Error); - return false; - } + if (!dev->canHandleDeployments()) { + reportWarningOrError(Tr::tr("The deployment device \"%1\" is disconnected.") + .arg(dev->displayName()), Task::Error); + return false; } const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit()); From ed92c2d948fbd6dcaf279f99d06c3f4ac94f24e0 Mon Sep 17 00:00:00 2001 From: Masoud Jami Date: Fri, 8 Nov 2024 10:09:02 +0100 Subject: [PATCH 117/989] CppEditor: Add support for refactoring classes with concepts Add support for concepts that are used in class declartions by differentiating between "typename" template parameters and concepts. With this new patch it's possible to move (refactor) a member of a class that uses concepts to a cpp file, while respecting the concept definition. Fixes: QTCREATORBUG-31214 Change-Id: Id3e6f978e688c58c7291926823d5bddaaa587f60 Reviewed-by: Christian Kandeler --- src/libs/3rdparty/cplusplus/AST.h | 2 +- src/libs/3rdparty/cplusplus/Bind.cpp | 5 +-- .../cplusplus/CPlusPlusForwardDeclarations.h | 1 + src/libs/3rdparty/cplusplus/Control.cpp | 11 +++++++ src/libs/3rdparty/cplusplus/Control.h | 3 ++ src/libs/3rdparty/cplusplus/Symbol.h | 4 +++ src/libs/3rdparty/cplusplus/SymbolVisitor.h | 1 + src/libs/3rdparty/cplusplus/Symbols.cpp | 18 +++++++--- src/libs/3rdparty/cplusplus/Symbols.h | 23 +++++++++++++ src/libs/3rdparty/cplusplus/Templates.cpp | 13 ++++++-- src/libs/3rdparty/cplusplus/Templates.h | 1 + src/libs/cplusplus/CppDocument.cpp | 1 + src/libs/cplusplus/FindUsages.cpp | 5 +-- src/libs/cplusplus/LookupContext.cpp | 33 ++++++++++++------- src/libs/cplusplus/TypePrettyPrinter.cpp | 3 ++ src/plugins/cppeditor/cppchecksymbols.cpp | 9 ++++- src/plugins/cppeditor/cppfindreferences.cpp | 2 ++ .../quickfixes/movefunctiondefinition.cpp | 14 ++++++++ src/plugins/cppeditor/searchsymbols.cpp | 5 +++ src/plugins/cppeditor/searchsymbols.h | 1 + .../cplusplus-ast2png/cplusplus-ast2png.cpp | 1 + .../tst_typeprettyprinter.cpp | 12 +++++-- 22 files changed, 142 insertions(+), 26 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index cc39fc39888..70ee37b9f9d 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -3013,7 +3013,7 @@ public: ExpressionAST *type_id = nullptr; public: - TypenameArgument *symbol = nullptr; + TemplateTypeArgument *symbol = nullptr; public: TemplateTypeParameterAST *asTemplateTypeParameter() override { return this; } diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 84418a96383..c65ff6244a7 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -2530,9 +2530,10 @@ bool Bind::visit(TemplateTypeParameterAST *ast) const Name *name = this->name(ast->name); ExpressionTy type_id = this->expression(ast->type_id); - // ### introduce TemplateTypeArgument - TypenameArgument *arg = control()->newTypenameArgument(sourceLocation, name); + TemplateTypeArgument *arg = control()->newTemplateTypeArgument(sourceLocation, name); arg->setType(type_id); + if (ast->typeConstraint && ast->typeConstraint->conceptName) + arg->setConceptName(this->name(ast->typeConstraint->conceptName)); ast->symbol = arg; _scope->addMember(arg); diff --git a/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h b/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h index bec7e77a5c4..2eeae3a9a39 100644 --- a/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h +++ b/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h @@ -107,6 +107,7 @@ class UsingDeclaration; class Declaration; class Argument; class TypenameArgument; +class TemplateTypeArgument; class Function; class Namespace; class NamespaceAlias; diff --git a/src/libs/3rdparty/cplusplus/Control.cpp b/src/libs/3rdparty/cplusplus/Control.cpp index b10daa66298..7c13bb2daba 100644 --- a/src/libs/3rdparty/cplusplus/Control.cpp +++ b/src/libs/3rdparty/cplusplus/Control.cpp @@ -336,6 +336,14 @@ public: return argument; } + TemplateTypeArgument *newTemplateTypeArgument(unsigned sourceLocation, const Name *name) + { + TemplateTypeArgument *argument = new TemplateTypeArgument(translationUnit, sourceLocation, name); + symbols.push_back(argument); + return argument; + } + + Function *newFunction(unsigned sourceLocation, const Name *name) { Function *function = new Function(translationUnit, sourceLocation, name); @@ -698,6 +706,9 @@ Argument *Control::newArgument(int sourceLocation, const Name *name) TypenameArgument *Control::newTypenameArgument(int sourceLocation, const Name *name) { return d->newTypenameArgument(sourceLocation, name); } +TemplateTypeArgument *Control::newTemplateTypeArgument(int sourceLocation, const Name *name) +{ return d->newTemplateTypeArgument(sourceLocation, name); } + Function *Control::newFunction(int sourceLocation, const Name *name) { return d->newFunction(sourceLocation, name); } diff --git a/src/libs/3rdparty/cplusplus/Control.h b/src/libs/3rdparty/cplusplus/Control.h index 62e51c435cd..8ef7c3586b6 100644 --- a/src/libs/3rdparty/cplusplus/Control.h +++ b/src/libs/3rdparty/cplusplus/Control.h @@ -110,6 +110,9 @@ public: /// Creates a new Argument symbol. TypenameArgument *newTypenameArgument(int sourceLocation, const Name *name = nullptr); + /// Creates a new Argument symbol. + TemplateTypeArgument *newTemplateTypeArgument(int sourceLocation, const Name *name = nullptr); + /// Creates a new Function symbol. Function *newFunction(int sourceLocation, const Name *name = nullptr); diff --git a/src/libs/3rdparty/cplusplus/Symbol.h b/src/libs/3rdparty/cplusplus/Symbol.h index dc07ced907d..d0076f7c33f 100644 --- a/src/libs/3rdparty/cplusplus/Symbol.h +++ b/src/libs/3rdparty/cplusplus/Symbol.h @@ -149,6 +149,7 @@ public: virtual const Declaration *asDeclaration() const { return nullptr; } virtual const Argument *asArgument() const { return nullptr; } virtual const TypenameArgument *asTypenameArgument() const { return nullptr; } + virtual const TemplateTypeArgument *asTemplateTypeArgument() const { return nullptr; } virtual const BaseClass *asBaseClass() const { return nullptr; } virtual const ForwardClassDeclaration *asForwardClassDeclaration() const { return nullptr; } virtual const QtPropertyDeclaration *asQtPropertyDeclaration() const { return nullptr; } @@ -200,6 +201,9 @@ public: /// Returns this Symbol as a Typename argument. virtual TypenameArgument *asTypenameArgument() { return nullptr; } + /// Returns this Symbol as a Template Type argument. + virtual TemplateTypeArgument *asTemplateTypeArgument() { return nullptr; } + /// Returns this Symbol as a BaseClass. virtual BaseClass *asBaseClass() { return nullptr; } diff --git a/src/libs/3rdparty/cplusplus/SymbolVisitor.h b/src/libs/3rdparty/cplusplus/SymbolVisitor.h index 4ed81c657c7..103ed014185 100644 --- a/src/libs/3rdparty/cplusplus/SymbolVisitor.h +++ b/src/libs/3rdparty/cplusplus/SymbolVisitor.h @@ -45,6 +45,7 @@ public: virtual bool visit(Declaration *) { return true; } virtual bool visit(Argument *) { return true; } virtual bool visit(TypenameArgument *) { return true; } + virtual bool visit(TemplateTypeArgument *) { return true; } virtual bool visit(BaseClass *) { return true; } virtual bool visit(Enum *) { return true; } virtual bool visit(Function *) { return true; } diff --git a/src/libs/3rdparty/cplusplus/Symbols.cpp b/src/libs/3rdparty/cplusplus/Symbols.cpp index 05b5f597937..0fa39417aa6 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.cpp +++ b/src/libs/3rdparty/cplusplus/Symbols.cpp @@ -129,10 +129,9 @@ Declaration::Declaration(Clone *clone, Subst *subst, Declaration *original) return; const Name *firstTemplParamName = nullptr; - if (const TypenameArgument *templParam = - templSpec->templateParameterAt(0)->asTypenameArgument()) { - firstTemplParamName = templParam->name(); - } + if (Symbol *param = templSpec->templateParameterAt(0); + param->asTypenameArgument() || param->asTemplateTypeArgument()) + firstTemplParamName = param->name(); if (!firstTemplParamName) return; @@ -231,6 +230,17 @@ void TypenameArgument::visitSymbol0(SymbolVisitor *visitor) { visitor->visit(this); } +TemplateTypeArgument::TemplateTypeArgument(TranslationUnit *translationUnit, int sourceLocation, const Name *name) + : Symbol(translationUnit, sourceLocation, name) +{ } + +TemplateTypeArgument::TemplateTypeArgument(Clone *clone, Subst *subst, TemplateTypeArgument *original) + : Symbol(clone, subst, original) +{ } + +void TemplateTypeArgument::visitSymbol0(SymbolVisitor *visitor) +{ visitor->visit(this); } + Function::Function(TranslationUnit *translationUnit, int sourceLocation, const Name *name) : Scope(translationUnit, sourceLocation, name), _flags(0) diff --git a/src/libs/3rdparty/cplusplus/Symbols.h b/src/libs/3rdparty/cplusplus/Symbols.h index c9267e4fdde..ccca5048995 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.h +++ b/src/libs/3rdparty/cplusplus/Symbols.h @@ -185,6 +185,29 @@ private: bool _isClassDeclarator; }; + +class CPLUSPLUS_EXPORT TemplateTypeArgument final : public Symbol +{ +public: + TemplateTypeArgument(TranslationUnit *translationUnit, int sourceLocation, const Name *name); + TemplateTypeArgument(Clone *clone, Subst *subst, TemplateTypeArgument *original); + ~TemplateTypeArgument() = default; + void setType(const FullySpecifiedType &type) { _type = type; } + + const TemplateTypeArgument *asTemplateTypeArgument() const override { return this; } + TemplateTypeArgument *asTemplateTypeArgument() override { return this; } + FullySpecifiedType type() const override { return _type; } + + const Name *conceptName() const { return _conceptName; } + void setConceptName(const Name *conceptName) { _conceptName = conceptName; } + +protected: + void visitSymbol0(SymbolVisitor *visitor) override; +private: + FullySpecifiedType _type; + const Name *_conceptName; +}; + class CPLUSPLUS_EXPORT Block final : public Scope { public: diff --git a/src/libs/3rdparty/cplusplus/Templates.cpp b/src/libs/3rdparty/cplusplus/Templates.cpp index 4a222e03633..bbefcc6692e 100644 --- a/src/libs/3rdparty/cplusplus/Templates.cpp +++ b/src/libs/3rdparty/cplusplus/Templates.cpp @@ -254,6 +254,15 @@ bool CloneSymbol::visit(TypenameArgument *symbol) return false; } +bool CloneSymbol::visit(TemplateTypeArgument *symbol) +{ + TemplateTypeArgument *arg = new TemplateTypeArgument(_clone, _subst, symbol); + _symbol = arg; + _control->addSymbol(arg); + return false; +} + + bool CloneSymbol::visit(BaseClass *symbol) { BaseClass *bc = new BaseClass(_clone, _subst, symbol); @@ -532,8 +541,8 @@ Symbol *Clone::instantiate(Template *templ, const FullySpecifiedType *const args if (argc < templ->templateParameterCount()) { for (int i = argc; i < templ->templateParameterCount(); ++i) { Symbol *formal = templ->templateParameterAt(i); - if (TypenameArgument *tn = formal->asTypenameArgument()) - subst.bind(name(formal->name(), &subst), type(tn->type(), &subst)); + if (formal->asTypenameArgument() || formal->asTemplateTypeArgument()) + subst.bind(name(formal->name(), &subst), type(formal->type(), &subst)); } } if (Symbol *inst = symbol(templ->declaration(), &subst)) { diff --git a/src/libs/3rdparty/cplusplus/Templates.h b/src/libs/3rdparty/cplusplus/Templates.h index 8196f4e0c39..5a0df3dd28a 100644 --- a/src/libs/3rdparty/cplusplus/Templates.h +++ b/src/libs/3rdparty/cplusplus/Templates.h @@ -147,6 +147,7 @@ protected: bool visit(Declaration *symbol) override; bool visit(Argument *symbol) override; bool visit(TypenameArgument *symbol) override; + bool visit(TemplateTypeArgument *symbol) override; bool visit(BaseClass *symbol) override; bool visit(Enum *symbol) override; bool visit(Function *symbol) override; diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 0b0d3669250..bbb5563bfb2 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -130,6 +130,7 @@ protected: bool visit(NamespaceAlias *) override { return false; } bool visit(Argument *) override { return false; } bool visit(TypenameArgument *) override { return false; } + bool visit(TemplateTypeArgument *) override { return false; } bool visit(BaseClass *) override { return false; } bool visit(ForwardClassDeclaration *) override { return false; } diff --git a/src/libs/cplusplus/FindUsages.cpp b/src/libs/cplusplus/FindUsages.cpp index add09fc93f0..e2672bf1451 100644 --- a/src/libs/cplusplus/FindUsages.cpp +++ b/src/libs/cplusplus/FindUsages.cpp @@ -552,7 +552,7 @@ bool FindUsages::checkCandidates(const QList &candidates) const const LookupItem &r = candidates.at(i); if (Symbol *s = r.declaration()) { - if (_declSymbol->asTypenameArgument()) { + if (_declSymbol->asTypenameArgument() || _declSymbol->asTemplateTypeArgument()) { if (s != _declSymbol) return false; } @@ -585,7 +585,8 @@ bool FindUsages::checkCandidates(const QList &candidates) const if (scopeOfTemplEnclosingCandidateSymbol != scopeOfTemplEnclosingDeclSymbol) return false; - } else if (enclosingScope->asTemplate() && ! _declSymbol->asTypenameArgument()) { + } else if (enclosingScope->asTemplate() && + ! (_declSymbol->asTypenameArgument() || _declSymbol->asTemplateTypeArgument())) { if (declEnclosingScope->asTemplate()) { if (enclosingScope->enclosingScope() != declEnclosingScope->enclosingScope()) return false; diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 9142d350929..4a25a873389 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -185,7 +185,7 @@ LookupContext &LookupContext::operator=(const LookupContext &other) QList LookupContext::fullyQualifiedName(Symbol *symbol, InlineNamespacePolicy policy) { - if (symbol->asTypenameArgument()) + if (symbol->asTypenameArgument() || symbol->asTemplateTypeArgument()) return {symbol->name()}; QList qualifiedName = path(symbol->enclosingScope(), policy); addNames(symbol->name(), &qualifiedName, /*add all names*/ true); @@ -1028,9 +1028,10 @@ static ClassOrNamespace *findSpecializationWithMatchingTemplateArgument(const Na const int argumentCountOfSpecialization = templateSpecialization->templateParameterCount(); for (int i = 0; i < argumentCountOfSpecialization; ++i) { - if (TypenameArgument *tParam - = templateSpecialization->templateParameterAt(i)->asTypenameArgument()) { - if (const Name *name = tParam->name()) { + if (Symbol *param = templateSpecialization->templateParameterAt(i); + param->asTypenameArgument() || + param->asTemplateTypeArgument()) { + if (const Name *name = param->name()) { if (compareName(name, argumentName)) return reference; } @@ -1274,9 +1275,10 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, templSpecId->templateArgumentCount() : 0; Clone cloner(_control.get()); for (int i = 0; i < argumentCountOfSpecialization; ++i) { - const TypenameArgument *tParam - = templateSpecialization->templateParameterAt(i)->asTypenameArgument(); - if (!tParam) + + Symbol *tParam = templateSpecialization->templateParameterAt(i); + if (!tParam->asTypenameArgument() && + !tParam->asTemplateTypeArgument()) continue; const Name *name = tParam->name(); if (!name) @@ -2026,8 +2028,11 @@ Symbol *CreateBindings::instantiateTemplateFunction(const Name *instantiationNam // check if all template parameters have default arguments (only check first parameter) if (specialization->templateParameterCount() == 0) return nullptr; - TypenameArgument *parameter = specialization->templateParameterAt(0)->asTypenameArgument(); - if (!parameter || !parameter->type().isValid()) + + if (Symbol *tParam = specialization->templateParameterAt(0); + (!tParam->asTypenameArgument() && + !tParam->asTemplateTypeArgument()) || + !tParam->type().isValid()) return nullptr; } @@ -2036,11 +2041,15 @@ Symbol *CreateBindings::instantiateTemplateFunction(const Name *instantiationNam Clone cloner(_control.get()); Subst subst(_control.get()); for (int i = 0; i < argumentCountOfSpecialization; ++i) { - const TypenameArgument *tParam - = specialization->templateParameterAt(i)->asTypenameArgument(); - if (!tParam) + + + Symbol *tParam = specialization->templateParameterAt(i); + if (!tParam->asTypenameArgument() && + !tParam->asTemplateTypeArgument()) continue; + const Name *name = tParam->name(); + if (!name) continue; diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp index 0e7ba193427..c8b08058abd 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.cpp +++ b/src/libs/cplusplus/TypePrettyPrinter.cpp @@ -448,6 +448,9 @@ void TypePrettyPrinter::visit(Function *type) if (name.isEmpty()) name.append('T').append(QString::number(i + 1)); templateScope.append(name); + } else if (TemplateTypeArgument *arg = param->asTemplateTypeArgument()) { + templateScope.append(_overview->prettyName(arg->conceptName())) + .append(' ').append(_overview->prettyName(arg->name())); } else if (Argument *arg = param->asArgument()) { templateScope.append(operator()(arg->type(), _overview->prettyName(arg->name()))); diff --git a/src/plugins/cppeditor/cppchecksymbols.cpp b/src/plugins/cppeditor/cppchecksymbols.cpp index d62f5bce75b..2be8e9f4cdb 100644 --- a/src/plugins/cppeditor/cppchecksymbols.cpp +++ b/src/plugins/cppeditor/cppchecksymbols.cpp @@ -178,6 +178,12 @@ protected: return true; } + bool visit(TemplateTypeArgument *symbol) override + { + addType(symbol->name()); + return true; + } + bool visit(Enum *symbol) override { addType(symbol->name()); @@ -1250,7 +1256,8 @@ bool CheckSymbols::maybeAddTypeOrStatic(const QList &candidates, Nam if (c->isTypedef() || c->asNamespace() || c->isStatic() || //consider also static variable c->asClass() || c->asEnum() || isTemplateClass(c) || - c->asForwardClassDeclaration() || c->asTypenameArgument() || c->enclosingEnum()) { + c->asForwardClassDeclaration() || c->asTypenameArgument() || + c->asTemplateTypeArgument() || c->enclosingEnum()) { int line, column; getTokenStartPosition(startToken, &line, &column); const unsigned length = tok.utf16chars(); diff --git a/src/plugins/cppeditor/cppfindreferences.cpp b/src/plugins/cppeditor/cppfindreferences.cpp index 2c8d7146b4d..6a1865949a3 100644 --- a/src/plugins/cppeditor/cppfindreferences.cpp +++ b/src/plugins/cppeditor/cppfindreferences.cpp @@ -150,6 +150,8 @@ static QByteArray typeId(CPlusPlus::Symbol *symbol) return QByteArray("a"); } else if (symbol->asTypenameArgument()) { return QByteArray("ta"); + } else if (symbol->asTemplateTypeArgument()) { + return QByteArray("tta"); } else if (symbol->asBaseClass()) { return QByteArray("bc"); } else if (symbol->asForwardClassDeclaration()) { diff --git a/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp b/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp index 86c8885cbdd..6b982decc78 100644 --- a/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp +++ b/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp @@ -1189,6 +1189,20 @@ private slots: QuickFixOperationTest(singleDocument(original, expected), &factory); } + void testConcept() + { + QByteArray original = + "template\n" + "class Foo { T operator@->() const { return nullptr; } };\n"; + QByteArray expected = + "template\n" + "class Foo { T operator->() const; };\n\n" + "template\nT Foo::operator->() const { return nullptr; }\n"; + + MoveFuncDefOutside factory; + QuickFixOperationTest(singleDocument(original, expected), &factory); + } + void testMemberFunctionTemplate() { const QByteArray original = R"( diff --git a/src/plugins/cppeditor/searchsymbols.cpp b/src/plugins/cppeditor/searchsymbols.cpp index ef2a4ed05fa..324364b699f 100644 --- a/src/plugins/cppeditor/searchsymbols.cpp +++ b/src/plugins/cppeditor/searchsymbols.cpp @@ -162,6 +162,11 @@ bool SearchSymbols::visit(TypenameArgument *) return false; } +bool SearchSymbols::visit(TemplateTypeArgument *) +{ + return false; +} + bool SearchSymbols::visit(BaseClass *) { return false; diff --git a/src/plugins/cppeditor/searchsymbols.h b/src/plugins/cppeditor/searchsymbols.h index 624cc2ee3d0..eb53cac4ca1 100644 --- a/src/plugins/cppeditor/searchsymbols.h +++ b/src/plugins/cppeditor/searchsymbols.h @@ -44,6 +44,7 @@ protected: bool visit(CPlusPlus::Declaration *) override; bool visit(CPlusPlus::Argument *) override; bool visit(CPlusPlus::TypenameArgument *) override; + bool visit(CPlusPlus::TemplateTypeArgument *) override; bool visit(CPlusPlus::BaseClass *) override; bool visit(CPlusPlus::Enum *) override; bool visit(CPlusPlus::Function *) override; diff --git a/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp b/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp index 8f7d256d0af..ea90a50b970 100644 --- a/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp +++ b/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp @@ -306,6 +306,7 @@ protected: virtual bool visit(Argument *symbol) { simpleNode(symbol); return true; } virtual bool visit(TypenameArgument *symbol) { simpleNode(symbol); return true; } + virtual bool visit(TemplateTypeArgument *symbol) { simpleNode(symbol); return true; } virtual bool visit(BaseClass *symbol) { out << _id[symbol].constData() << " [label=\"BaseClass\\n"; diff --git a/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp b/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp index c1460fd7778..01746371f7d 100644 --- a/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp +++ b/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp @@ -44,6 +44,13 @@ static TypenameArgument *typenameArg(const QString &name, bool isClassDeclarator return arg; } +static TemplateTypeArgument *tempTypeArg(const QString &name, const QString &conceptName) +{ + TemplateTypeArgument *arg = new TemplateTypeArgument(0, 0, nameId(name)); + arg->setConceptName(nameId(conceptName)); + return arg; +} + static Declaration *decl(const FullySpecifiedType &ty) { Declaration *d = new Declaration(0, 0, nameId("")); @@ -89,6 +96,7 @@ static FullySpecifiedType templTy(FullySpecifiedType declTy, bool isClassDeclara { Template *templ = new Template(0, 0, nameId("")); templ->addMember(typenameArg("T", isClassDeclarator)); + templ->addMember(tempTypeArg("C", "ConceptType")); templ->addMember(decl(declTy)); if (Function *func = declTy->asFunctionType()) func->setEnclosingScope(templ); @@ -432,8 +440,8 @@ void tst_TypePrettyPrinter::basic_data() addRow(fnTy("foo", ref(voidTy()), ptr(voidTy())), Overview::BindToTypeName, "void& foo(void*)", "foo"); addRow(fnTy("foo", ref(voidTy()), ptr(voidTy())), bindToAll, "void&foo(void*)", "foo"); - addRow(templTy(fnTy("foo", voidTy(), voidTy()), true), bindToNothing, "template\nvoid foo()", "foo"); - addRow(templTy(fnTy("foo", voidTy(), voidTy()), false), bindToNothing, "template\nvoid foo()", "foo"); + addRow(templTy(fnTy("foo", voidTy(), voidTy()), true), bindToNothing, "template\nvoid foo()", "foo"); + addRow(templTy(fnTy("foo", voidTy(), voidTy()), false), bindToNothing, "template\nvoid foo()", "foo"); } void tst_TypePrettyPrinter::basic() From 87cbafe97c3a666c0526b7f33bfa6c3453acacaf Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Nov 2024 12:37:48 +0100 Subject: [PATCH 118/989] Android: Code cosmetics in androiddeployqtstep.cpp Remove Q_OBJECT, use 'final', use dynamic_cast instead of static_cast to proactively cover more unexpected situations, unused functions. Change-Id: I195718f33b7aca49a4529fba7c3fdfed02c46c86 Reviewed-by: Jarek Kobus --- src/plugins/android/androiddeployqtstep.cpp | 35 +++++++-------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 4c3c8712cf1..24487c87f7f 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -12,18 +12,15 @@ #include "androidtr.h" #include "androidutils.h" -#include #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -127,23 +124,19 @@ static QList filesToPull(Target *target) return fileList; } -class AndroidDeployQtStep : public BuildStep +class AndroidDeployQtStep final : public BuildStep { - Q_OBJECT - public: AndroidDeployQtStep(BuildStepList *bc, Id id); private: - bool init() override; + bool init() final; GroupItem runRecipe() final; Group deployRecipe(); - QWidget *createConfigWidget() override; + QWidget *createConfigWidget() final; - void processReadyReadStdOutput(DeployErrorFlags &errorCode); void stdOutput(const QString &line); - void processReadyReadStdError(DeployErrorFlags &errorCode); void stdError(const QString &line); void reportWarningOrError(const QString &message, Task::TaskType type); @@ -175,8 +168,8 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Id id) bool AndroidDeployQtStep::init() { - QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(kit()); - if (!version) { + QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit()); + if (!qtVersion) { reportWarningOrError(Tr::tr("The Qt version for kit %1 is invalid.").arg(kit()->displayName()), Task::Error); return false; @@ -202,13 +195,12 @@ bool AndroidDeployQtStep::init() Task::Error); return false); - auto androidBuildApkStep = bc->buildSteps()->firstOfType(); const int minTargetApi = minimumSDK(target()); qCDebug(deployStepLog) << "Target architecture:" << androidABIs << "Min target API" << minTargetApi; const BuildSystem *bs = buildSystem(); - auto selectedAbis = bs->property(Constants::AndroidAbis).toStringList(); + QStringList selectedAbis = bs->property(Constants::AndroidAbis).toStringList(); const QString buildKey = target()->activeBuildKey(); if (selectedAbis.isEmpty()) @@ -217,8 +209,7 @@ bool AndroidDeployQtStep::init() if (selectedAbis.isEmpty()) selectedAbis.append(bs->extraData(buildKey, Constants::AndroidAbi).toString()); - const auto dev = - static_cast(RunDeviceKitAspect::device(kit()).get()); + const auto dev = dynamic_cast(RunDeviceKitAspect::device(kit()).get()); if (!dev) { reportWarningOrError(Tr::tr("No valid deployment device is set."), Task::Error); return false; @@ -249,9 +240,8 @@ bool AndroidDeployQtStep::init() return false; } - const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit()); - if (qt && qt->supportsMultipleQtAbis() && !info.cpuAbi.isEmpty() && - !selectedAbis.contains(info.cpuAbi.first())) { + if (qtVersion->supportsMultipleQtAbis() && !info.cpuAbi.isEmpty() + && !selectedAbis.contains(info.cpuAbi.first())) { TaskHub::addTask(DeploymentTask(Task::Warning, Tr::tr("Android: The main ABI of the deployment device (%1) is not selected. The app " "execution or debugging might not work properly. Add it from Projects > Build > " @@ -288,7 +278,7 @@ bool AndroidDeployQtStep::init() Task::Error); return false; } - m_command = version->hostBinPath(); + m_command = qtVersion->hostBinPath(); if (m_command.isEmpty()) { reportWarningOrError(Tr::tr("Cannot find the androiddeployqt tool."), Task::Error); return false; @@ -309,6 +299,7 @@ bool AndroidDeployQtStep::init() if (buildType() == BuildConfiguration::Release) m_androiddeployqtArgs.addArgs({"--release"}); + auto androidBuildApkStep = bc->buildSteps()->firstOfType(); if (androidBuildApkStep && androidBuildApkStep->signPackage()) { // The androiddeployqt tool is not really written to do stand-alone installations. // This hack forces it to use the correct filename for the apk file when installing @@ -318,7 +309,7 @@ bool AndroidDeployQtStep::init() } } - m_environment = bc ? bc->environment() : Environment(); + m_environment = bc->environment(); m_adbPath = AndroidConfig::adbToolPath(); return true; @@ -675,5 +666,3 @@ void setupAndroidDeployQtStep() } } // Android::Internal - -#include "androiddeployqtstep.moc" From 7ffebd0c2d3ab0c8b9a23366d0a4ac6e874c87d2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 13:10:44 +0100 Subject: [PATCH 119/989] Android: Move startAvdRecipe into androidutils.h Change-Id: Ie4189e690e0eb6def815b8970e2e2f51e5cac17d Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 1 - src/plugins/android/android.qbs | 2 - src/plugins/android/androidavdmanager.cpp | 220 -------------------- src/plugins/android/androidavdmanager.h | 12 -- src/plugins/android/androiddeployqtstep.cpp | 5 +- src/plugins/android/androiddevice.cpp | 3 +- src/plugins/android/androidrunner.cpp | 3 +- src/plugins/android/androidutils.cpp | 200 ++++++++++++++++++ src/plugins/android/androidutils.h | 8 +- 9 files changed, 211 insertions(+), 243 deletions(-) delete mode 100644 src/plugins/android/androidavdmanager.cpp delete mode 100644 src/plugins/android/androidavdmanager.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 2eac3c8416d..995588aa1a2 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -6,7 +6,6 @@ add_qtc_plugin(Android SOURCES android.qrc androidtr.h - androidavdmanager.cpp androidavdmanager.h androidbuildapkstep.cpp androidbuildapkstep.h androidconfigurations.cpp androidconfigurations.h androidconstants.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 685f0336a9f..3935429feaf 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -17,8 +17,6 @@ QtcPlugin { files: [ "androidtr.h", "android.qrc", - "androidavdmanager.cpp", - "androidavdmanager.h", "androidconfigurations.cpp", "androidconfigurations.h", "androidconstants.h", diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp deleted file mode 100644 index e0af55ff463..00000000000 --- a/src/plugins/android/androidavdmanager.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "androidavdmanager.h" - -#include "androidconfigurations.h" -#include "androidtr.h" -#include "androidutils.h" - -#include - -#include -#include - -#include -#include - -#include -#include - -using namespace Tasking; -using namespace Utils; -using namespace std::chrono_literals; - -namespace Android::Internal::AndroidAvdManager { - -static Q_LOGGING_CATEGORY(avdManagerLog, "qtc.android.avdManager", QtWarningMsg) - -static void startAvdDetached(QPromise &promise, const CommandLine &avdCommand) -{ - qCDebug(avdManagerLog).noquote() << "Running command (startAvdDetached):" << avdCommand.toUserOutput(); - if (!Process::startDetached(avdCommand, {}, DetachedChannelMode::Discard)) - promise.future().cancel(); -} - -static CommandLine avdCommand(const QString &avdName, bool is32BitUserSpace) -{ - CommandLine cmd(AndroidConfig::emulatorToolPath()); - if (is32BitUserSpace) - cmd.addArg("-force-32bit"); - cmd.addArgs(AndroidConfig::emulatorArgs(), CommandLine::Raw); - cmd.addArgs({"-avd", avdName}); - return cmd; -} - -static ExecutableItem startAvdAsyncRecipe(const QString &avdName) -{ - const Storage is32Storage; - - const auto onSetup = [] { - const FilePath emulatorPath = AndroidConfig::emulatorToolPath(); - if (emulatorPath.exists()) - return SetupResult::Continue; - - QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("Emulator Tool Is Missing"), - Tr::tr("Install the missing emulator tool (%1) to the " - "installed Android SDK.").arg(emulatorPath.displayName())); - return SetupResult::StopWithError; - }; - - const auto onGetConfSetup = [](Process &process) { - if (!HostOsInfo::isLinuxHost() || QSysInfo::WordSize != 32) - return SetupResult::StopWithSuccess; // is64 - - process.setCommand({"getconf", {"LONG_BIT"}}); - return SetupResult::Continue; - }; - const auto onGetConfDone = [is32Storage](const Process &process, DoneWith result) { - if (result == DoneWith::Success) - *is32Storage = process.allOutput().trimmed() == "32"; - else - *is32Storage = true; - return true; - }; - - const auto onAvdSetup = [avdName, is32Storage](Async &async) { - async.setConcurrentCallData(startAvdDetached, avdCommand(avdName, *is32Storage)); - }; - const auto onAvdDone = [avdName] { - QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("AVD Start Error"), - Tr::tr("Failed to start AVD emulator for \"%1\" device.").arg(avdName)); - }; - - return Group { - is32Storage, - onGroupSetup(onSetup), - ProcessTask(onGetConfSetup, onGetConfDone), - AsyncTask(onAvdSetup, onAvdDone, CallDoneIf::Error) - }; -} - -static ExecutableItem serialNumberRecipe(const QString &avdName, const Storage &serialNumberStorage) -{ - const Storage outputStorage; - const Storage currentSerialNumberStorage; - const LoopUntil iterator([outputStorage](int iteration) { return iteration < outputStorage->size(); }); - - const auto onSocketSetup = [iterator, outputStorage, currentSerialNumberStorage](TcpSocket &socket) { - const QString line = outputStorage->at(iterator.iteration()); - if (line.startsWith("* daemon")) - return SetupResult::StopWithError; - - const QString serialNumber = line.left(line.indexOf('\t')).trimmed(); - if (!serialNumber.startsWith("emulator")) - return SetupResult::StopWithError; - - const int index = serialNumber.indexOf(QLatin1String("-")); - if (index == -1) - return SetupResult::StopWithError; - - bool ok; - const int port = serialNumber.mid(index + 1).toInt(&ok); - if (!ok) - return SetupResult::StopWithError; - - *currentSerialNumberStorage = serialNumber; - - socket.setAddress(QHostAddress(QHostAddress::LocalHost)); - socket.setPort(port); - socket.setWriteData("avd name\nexit\n"); - return SetupResult::Continue; - }; - const auto onSocketDone = [avdName, currentSerialNumberStorage, serialNumberStorage](const TcpSocket &socket) { - const QByteArrayList response = socket.socket()->readAll().split('\n'); - // The input "avd name" might not be echoed as-is, but contain ASCII control sequences. - for (int i = response.size() - 1; i > 1; --i) { - if (!response.at(i).startsWith("OK")) - continue; - - const QString currentAvdName = QString::fromLatin1(response.at(i - 1)).trimmed(); - if (avdName != currentAvdName) - break; - - *serialNumberStorage = *currentSerialNumberStorage; - return DoneResult::Success; - } - return DoneResult::Error; - }; - - return Group { - outputStorage, - AndroidConfig::devicesCommandOutputRecipe(outputStorage), - For (iterator) >> Do { - parallel, - stopOnSuccess, - Group { - currentSerialNumberStorage, - TcpSocketTask(onSocketSetup, onSocketDone) - } - } - }; -} - -static ExecutableItem isAvdBootedRecipe(const Storage &serialNumberStorage) -{ - const auto onSetup = [serialNumberStorage](Process &process) { - const CommandLine cmd{AndroidConfig::adbToolPath(), - {adbSelector(*serialNumberStorage), - "shell", "getprop", "init.svc.bootanim"}}; - qCDebug(avdManagerLog).noquote() << "Running command (isAvdBooted):" << cmd.toUserOutput(); - process.setCommand(cmd); - }; - const auto onDone = [](const Process &process, DoneWith result) { - return result == DoneWith::Success && process.allOutput().trimmed() == "stopped"; - }; - return ProcessTask(onSetup, onDone); -} - -static ExecutableItem waitForAvdRecipe(const QString &avdName, const Storage &serialNumberStorage) -{ - const Storage outputStorage; - const Storage stopStorage; - - const auto onIsConnectedDone = [stopStorage, outputStorage, serialNumberStorage] { - const QString serialNumber = *serialNumberStorage; - for (const QString &line : *outputStorage) { - // skip the daemon logs - if (!line.startsWith("* daemon") && line.left(line.indexOf('\t')).trimmed() == serialNumber) - return DoneResult::Error; - } - serialNumberStorage->clear(); - *stopStorage = true; - return DoneResult::Success; - }; - - const auto onWaitForBootedDone = [stopStorage] { return !*stopStorage; }; - - return Group { - Forever { - stopOnSuccess, - serialNumberRecipe(avdName, serialNumberStorage), - TimeoutTask([](std::chrono::milliseconds &timeout) { timeout = 100ms; }, DoneResult::Error) - }.withTimeout(30s), - Forever { - stopStorage, - stopOnSuccess, - isAvdBootedRecipe(serialNumberStorage), - TimeoutTask([](std::chrono::milliseconds &timeout) { timeout = 100ms; }, DoneResult::Error), - Group { - outputStorage, - AndroidConfig::devicesCommandOutputRecipe(outputStorage), - onGroupDone(onIsConnectedDone, CallDoneIf::Success) - }, - onGroupDone(onWaitForBootedDone) - }.withTimeout(120s) - }; -} - -ExecutableItem startAvdRecipe(const QString &avdName, const Storage &serialNumberStorage) -{ - return Group { - If (serialNumberRecipe(avdName, serialNumberStorage) || startAvdAsyncRecipe(avdName)) >> Then { - waitForAvdRecipe(avdName, serialNumberStorage) - } >> Else { - errorItem - } - }; -} - -} // namespace Android::Internal::AndroidAvdManager diff --git a/src/plugins/android/androidavdmanager.h b/src/plugins/android/androidavdmanager.h deleted file mode 100644 index b88f6758345..00000000000 --- a/src/plugins/android/androidavdmanager.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#pragma once - -#include - -namespace Android::Internal::AndroidAvdManager { - -Tasking::ExecutableItem startAvdRecipe( - const QString &avdName, const Tasking::Storage &serialNumberStorage); - -} // namespace Android::Internal::AndroidAvdManager diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 24487c87f7f..0db55016889 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -4,7 +4,6 @@ #include "androiddeployqtstep.h" -#include "androidavdmanager.h" #include "androidbuildapkstep.h" #include "androidconstants.h" #include "androiddevice.h" @@ -370,7 +369,7 @@ GroupItem AndroidDeployQtStep::runRecipe() return Group { If (!Sync(isAvdNameEmpty)) >> Then { serialNumberStorage, - AndroidAvdManager::startAvdRecipe(m_avdName, serialNumberStorage), + startAvdRecipe(m_avdName, serialNumberStorage), onGroupDone(onSerialNumberDone) }, deployRecipe(), @@ -591,7 +590,7 @@ QWidget *AndroidDeployQtStep::createConfigWidget() serialNumberStorage, Group { onGroupSetup(onSetup), - AndroidAvdManager::startAvdRecipe(info.avdName, serialNumberStorage), + startAvdRecipe(info.avdName, serialNumberStorage), onGroupDone(onDone) }, ProcessTask(onAdbSetup, onAdbDone) diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 2a73b837711..84977d53962 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -4,7 +4,6 @@ #include "androiddevice.h" -#include "androidavdmanager.h" #include "androidconfigurations.h" #include "androidconstants.h" #include "androidsignaloperation.h" @@ -604,7 +603,7 @@ void AndroidDevice::startAvd() const Group root { serialNumberStorage, - AndroidAvdManager::startAvdRecipe(avdName(), serialNumberStorage), + startAvdRecipe(avdName(), serialNumberStorage), onGroupDone(onDone, CallDoneIf::Success) }; diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 38ad42726ab..ce641ea6a33 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -4,7 +4,6 @@ #include "androidrunner.h" -#include "androidavdmanager.h" #include "androidconstants.h" #include "androiddevice.h" #include "androidrunnerworker.h" @@ -76,7 +75,7 @@ void AndroidRunner::start() avdRecipe = Group { serialNumberStorage, - AndroidAvdManager::startAvdRecipe(info.avdName, serialNumberStorage) + startAvdRecipe(info.avdName, serialNumberStorage) }.withCancel([glueStorage] { return std::make_pair(glueStorage.activeStorage(), &RunnerInterface::canceled); }); diff --git a/src/plugins/android/androidutils.cpp b/src/plugins/android/androidutils.cpp index 247fa3a7f80..7bd230fb9ed 100644 --- a/src/plugins/android/androidutils.cpp +++ b/src/plugins/android/androidutils.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -23,7 +24,11 @@ #include +#include +#include + #include +#include #include #include @@ -36,8 +41,11 @@ using namespace Core; using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; +using namespace std::chrono_literals; + namespace Android::Internal { const char AndroidManifestName[] = "AndroidManifest.xml"; @@ -599,4 +607,196 @@ QStringList adbSelector(const QString &serialNumber) return {"-s", serialNumber}; } +static void startAvdDetached(QPromise &promise, const CommandLine &avdCommand) +{ + qCDebug(androidManagerLog).noquote() << "Running command (startAvdDetached):" << avdCommand.toUserOutput(); + if (!Process::startDetached(avdCommand, {}, DetachedChannelMode::Discard)) + promise.future().cancel(); +} + +static CommandLine avdCommand(const QString &avdName, bool is32BitUserSpace) +{ + CommandLine cmd(AndroidConfig::emulatorToolPath()); + if (is32BitUserSpace) + cmd.addArg("-force-32bit"); + cmd.addArgs(AndroidConfig::emulatorArgs(), CommandLine::Raw); + cmd.addArgs({"-avd", avdName}); + return cmd; +} + +static ExecutableItem startAvdAsyncRecipe(const QString &avdName) +{ + const Storage is32Storage; + + const auto onSetup = [] { + const FilePath emulatorPath = AndroidConfig::emulatorToolPath(); + if (emulatorPath.exists()) + return SetupResult::Continue; + + QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("Emulator Tool Is Missing"), + Tr::tr("Install the missing emulator tool (%1) to the " + "installed Android SDK.").arg(emulatorPath.displayName())); + return SetupResult::StopWithError; + }; + + const auto onGetConfSetup = [](Process &process) { + if (!HostOsInfo::isLinuxHost() || QSysInfo::WordSize != 32) + return SetupResult::StopWithSuccess; // is64 + + process.setCommand({"getconf", {"LONG_BIT"}}); + return SetupResult::Continue; + }; + const auto onGetConfDone = [is32Storage](const Process &process, DoneWith result) { + if (result == DoneWith::Success) + *is32Storage = process.allOutput().trimmed() == "32"; + else + *is32Storage = true; + return true; + }; + + const auto onAvdSetup = [avdName, is32Storage](Async &async) { + async.setConcurrentCallData(startAvdDetached, avdCommand(avdName, *is32Storage)); + }; + const auto onAvdDone = [avdName] { + QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("AVD Start Error"), + Tr::tr("Failed to start AVD emulator for \"%1\" device.").arg(avdName)); + }; + + return Group { + is32Storage, + onGroupSetup(onSetup), + ProcessTask(onGetConfSetup, onGetConfDone), + AsyncTask(onAvdSetup, onAvdDone, CallDoneIf::Error) + }; +} + +static ExecutableItem serialNumberRecipe(const QString &avdName, const Storage &serialNumberStorage) +{ + const Storage outputStorage; + const Storage currentSerialNumberStorage; + const LoopUntil iterator([outputStorage](int iteration) { return iteration < outputStorage->size(); }); + + const auto onSocketSetup = [iterator, outputStorage, currentSerialNumberStorage](TcpSocket &socket) { + const QString line = outputStorage->at(iterator.iteration()); + if (line.startsWith("* daemon")) + return SetupResult::StopWithError; + + const QString serialNumber = line.left(line.indexOf('\t')).trimmed(); + if (!serialNumber.startsWith("emulator")) + return SetupResult::StopWithError; + + const int index = serialNumber.indexOf(QLatin1String("-")); + if (index == -1) + return SetupResult::StopWithError; + + bool ok; + const int port = serialNumber.mid(index + 1).toInt(&ok); + if (!ok) + return SetupResult::StopWithError; + + *currentSerialNumberStorage = serialNumber; + + socket.setAddress(QHostAddress(QHostAddress::LocalHost)); + socket.setPort(port); + socket.setWriteData("avd name\nexit\n"); + return SetupResult::Continue; + }; + const auto onSocketDone = [avdName, currentSerialNumberStorage, serialNumberStorage](const TcpSocket &socket) { + const QByteArrayList response = socket.socket()->readAll().split('\n'); + // The input "avd name" might not be echoed as-is, but contain ASCII control sequences. + for (int i = response.size() - 1; i > 1; --i) { + if (!response.at(i).startsWith("OK")) + continue; + + const QString currentAvdName = QString::fromLatin1(response.at(i - 1)).trimmed(); + if (avdName != currentAvdName) + break; + + *serialNumberStorage = *currentSerialNumberStorage; + return DoneResult::Success; + } + return DoneResult::Error; + }; + + return Group { + outputStorage, + AndroidConfig::devicesCommandOutputRecipe(outputStorage), + For (iterator) >> Do { + parallel, + stopOnSuccess, + Group { + currentSerialNumberStorage, + TcpSocketTask(onSocketSetup, onSocketDone) + } + } + }; +} + +static ExecutableItem isAvdBootedRecipe(const Storage &serialNumberStorage) +{ + const auto onSetup = [serialNumberStorage](Process &process) { + const CommandLine cmd{AndroidConfig::adbToolPath(), + {adbSelector(*serialNumberStorage), + "shell", "getprop", "init.svc.bootanim"}}; + qCDebug(androidManagerLog).noquote() << "Running command (isAvdBooted):" << cmd.toUserOutput(); + process.setCommand(cmd); + }; + const auto onDone = [](const Process &process, DoneWith result) { + return result == DoneWith::Success && process.allOutput().trimmed() == "stopped"; + }; + return ProcessTask(onSetup, onDone); +} + +static ExecutableItem waitForAvdRecipe(const QString &avdName, const Storage &serialNumberStorage) +{ + const Storage outputStorage; + const Storage stopStorage; + + const auto onIsConnectedDone = [stopStorage, outputStorage, serialNumberStorage] { + const QString serialNumber = *serialNumberStorage; + for (const QString &line : *outputStorage) { + // skip the daemon logs + if (!line.startsWith("* daemon") && line.left(line.indexOf('\t')).trimmed() == serialNumber) + return DoneResult::Error; + } + serialNumberStorage->clear(); + *stopStorage = true; + return DoneResult::Success; + }; + + const auto onWaitForBootedDone = [stopStorage] { return !*stopStorage; }; + + return Group { + Forever { + stopOnSuccess, + serialNumberRecipe(avdName, serialNumberStorage), + TimeoutTask([](std::chrono::milliseconds &timeout) { timeout = 100ms; }, DoneResult::Error) + }.withTimeout(30s), + Forever { + stopStorage, + stopOnSuccess, + isAvdBootedRecipe(serialNumberStorage), + TimeoutTask([](std::chrono::milliseconds &timeout) { timeout = 100ms; }, DoneResult::Error), + Group { + outputStorage, + AndroidConfig::devicesCommandOutputRecipe(outputStorage), + onGroupDone(onIsConnectedDone, CallDoneIf::Success) + }, + onGroupDone(onWaitForBootedDone) + }.withTimeout(120s) + }; +} + +ExecutableItem startAvdRecipe(const QString &avdName, const Storage &serialNumberStorage) +{ + return Group { + If (serialNumberRecipe(avdName, serialNumberStorage) || startAvdAsyncRecipe(avdName)) >> Then { + waitForAvdRecipe(avdName, serialNumberStorage) + } >> Else { + errorItem + } + }; +} + + } // namespace Android::Internal diff --git a/src/plugins/android/androidutils.h b/src/plugins/android/androidutils.h index 3fdee8994ba..5768ec3dc45 100644 --- a/src/plugins/android/androidutils.h +++ b/src/plugins/android/androidutils.h @@ -3,9 +3,12 @@ #pragma once -#include #include +#include + +#include + namespace ProjectExplorer { class Kit; class Target; @@ -57,4 +60,7 @@ bool isQtCreatorGenerated(const Utils::FilePath &deploymentFile); QStringList adbSelector(const QString &serialNumber); +Tasking::ExecutableItem startAvdRecipe( + const QString &avdName, const Tasking::Storage &serialNumberStorage); + } // namespace Android::Internal From 1e40c06a2b2b23ab38d14be10da14590c0d9a593 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 13:38:35 +0100 Subject: [PATCH 120/989] Android: Remove Q_OBJECT from AndroidCreateKeystoreCertificate Change-Id: Iac52cc32ca29bad8acaad9d2d08ef504e81e66e1 Reviewed-by: hjk --- src/plugins/android/androidcreatekeystorecertificate.cpp | 4 ++-- src/plugins/android/androidcreatekeystorecertificate.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/android/androidcreatekeystorecertificate.cpp b/src/plugins/android/androidcreatekeystorecertificate.cpp index 555dd6de855..ed36c9f4656 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.cpp +++ b/src/plugins/android/androidcreatekeystorecertificate.cpp @@ -1,8 +1,9 @@ // Copyright (C) 2016 BogDan Vatra // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "androidconfigurations.h" #include "androidcreatekeystorecertificate.h" + +#include "androidconfigurations.h" #include "androidtr.h" #include @@ -11,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/src/plugins/android/androidcreatekeystorecertificate.h b/src/plugins/android/androidcreatekeystorecertificate.h index 4521c5630f4..23ab38d5156 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.h +++ b/src/plugins/android/androidcreatekeystorecertificate.h @@ -19,7 +19,6 @@ namespace Android::Internal { class AndroidCreateKeystoreCertificate : public QDialog { - Q_OBJECT enum PasswordStatus { Invalid, From 6886577ac710752aeb2147fb92b44b59f9a44020 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 13:54:34 +0100 Subject: [PATCH 121/989] Android: Inline AndroidManifestEditorIconContainerWidget Simplify its name. Change-Id: I2f9fc651c49d593305b040768c15918101c2c51c Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 1 - src/plugins/android/android.qbs | 2 - src/plugins/android/androidmanifesteditor.cpp | 206 ++++++++++++++++-- ...droidmanifesteditoriconcontainerwidget.cpp | 172 --------------- ...androidmanifesteditoriconcontainerwidget.h | 39 ---- 5 files changed, 190 insertions(+), 230 deletions(-) delete mode 100644 src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp delete mode 100644 src/plugins/android/androidmanifesteditoriconcontainerwidget.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 995588aa1a2..1868535d1bc 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -17,7 +17,6 @@ add_qtc_plugin(Android androidextralibrarylistmodel.cpp androidextralibrarylistmodel.h androidmanifesteditor.cpp androidmanifesteditor.h androidmanifesteditoriconwidget.cpp androidmanifesteditoriconwidget.h - androidmanifesteditoriconcontainerwidget.cpp androidmanifesteditoriconcontainerwidget.h androidpackageinstallationstep.cpp androidpackageinstallationstep.h androidplugin.cpp androidqmltoolingsupport.cpp androidqmltoolingsupport.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 3935429feaf..850801ca28c 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -36,8 +36,6 @@ QtcPlugin { "androidextralibrarylistmodel.h", "androidmanifesteditoriconwidget.cpp", "androidmanifesteditoriconwidget.h", - "androidmanifesteditoriconcontainerwidget.cpp", - "androidmanifesteditoriconcontainerwidget.h", "androidmanifesteditor.cpp", "androidmanifesteditor.h", "androidpackageinstallationstep.cpp", diff --git a/src/plugins/android/androidmanifesteditor.cpp b/src/plugins/android/androidmanifesteditor.cpp index 1d3bad39b00..5bd79c198aa 100644 --- a/src/plugins/android/androidmanifesteditor.cpp +++ b/src/plugins/android/androidmanifesteditor.cpp @@ -5,7 +5,7 @@ #include "androidconfigurations.h" #include "androidconstants.h" -#include "androidmanifesteditoriconcontainerwidget.h" +#include "androidmanifesteditoriconwidget.h" #include "androidtr.h" #include "androidutils.h" #include "splashscreencontainerwidget.h" @@ -62,10 +62,182 @@ #include using namespace ProjectExplorer; +using namespace TextEditor; using namespace Utils; namespace Android::Internal { +const char extraExtraExtraHighDpiIconPath[] = "/res/drawable-xxxhdpi/"; +const char extraExtraHighDpiIconPath[] = "/res/drawable-xxhdpi/"; +const char extraHighDpiIconPath[] = "/res/drawable-xhdpi/"; +const char highDpiIconPath[] = "/res/drawable-hdpi/"; +const char mediumDpiIconPath[] = "/res/drawable-mdpi/"; +const char lowDpiIconPath[] = "/res/drawable-ldpi/"; +const char imageSuffix[] = ".png"; +const QSize lowDpiIconSize{32, 32}; +const QSize mediumDpiIconSize{48, 48}; +const QSize highDpiIconSize{72, 72}; +const QSize extraHighDpiIconSize{96, 96}; +const QSize extraExtraHighDpiIconSize{144, 144}; +const QSize extraExtraExtraHighDpiIconSize{192, 192}; + +class IconContainerWidget : public QWidget +{ + Q_OBJECT + +public: + explicit IconContainerWidget(QWidget *parent, TextEditorWidget *textEditorWidget); + void setIconFileName(const QString &name); + QString iconFileName() const; + void loadIcons(); + bool hasIcons() const; +private: + QList m_iconButtons; + QString m_iconFileName = QLatin1String("icon"); + bool m_hasIcons = false; +signals: + void iconsModified(); +}; + +IconContainerWidget::IconContainerWidget(QWidget *parent, TextEditorWidget *textEditorWidget) + : QWidget(parent) +{ + auto iconLayout = new QHBoxLayout(this); + auto masterIconButton = new AndroidManifestEditorIconWidget(this, + lowDpiIconSize, + lowDpiIconSize, + Tr::tr("Master icon"), + Tr::tr("Select master icon.")); + masterIconButton->setIcon(Icon::fromTheme("document-open")); + iconLayout->addWidget(masterIconButton); + iconLayout->addStretch(1); + + QFrame *line = new QFrame(this); + line->setFrameShape(QFrame::VLine); + line->setFrameShadow(QFrame::Sunken); + iconLayout->addWidget(line); + iconLayout->addStretch(1); + + QString iconFileName = m_iconFileName + imageSuffix; + + auto lIconButton = new AndroidManifestEditorIconWidget(this, + lowDpiIconSize, + lowDpiIconSize, + Tr::tr("LDPI icon"), + Tr::tr("Select an icon suitable for low-density (ldpi) screens (~120dpi)."), + textEditorWidget, + lowDpiIconPath, + iconFileName); + iconLayout->addWidget(lIconButton); + m_iconButtons.push_back(lIconButton); + iconLayout->addStretch(1); + + auto mIconButton = new AndroidManifestEditorIconWidget(this, + mediumDpiIconSize, + mediumDpiIconSize, + Tr::tr("MDPI icon"), + Tr::tr("Select an icon for medium-density (mdpi) screens (~160dpi)."), + textEditorWidget, + mediumDpiIconPath, + iconFileName); + iconLayout->addWidget(mIconButton); + m_iconButtons.push_back(mIconButton); + iconLayout->addStretch(1); + + auto hIconButton = new AndroidManifestEditorIconWidget(this, + highDpiIconSize, + highDpiIconSize, + Tr::tr("HDPI icon"), + Tr::tr("Select an icon for high-density (hdpi) screens (~240dpi)."), + textEditorWidget, + highDpiIconPath, + iconFileName); + iconLayout->addWidget(hIconButton); + m_iconButtons.push_back(hIconButton); + iconLayout->addStretch(1); + + auto xhIconButton = new AndroidManifestEditorIconWidget(this, + extraHighDpiIconSize, + extraHighDpiIconSize, + Tr::tr("XHDPI icon"), + Tr::tr("Select an icon for extra-high-density (xhdpi) screens (~320dpi)."), + textEditorWidget, + extraHighDpiIconPath, + iconFileName); + iconLayout->addWidget(xhIconButton); + m_iconButtons.push_back(xhIconButton); + iconLayout->addStretch(1); + + auto xxhIconButton = new AndroidManifestEditorIconWidget(this, + extraExtraHighDpiIconSize, + extraExtraHighDpiIconSize, + Tr::tr("XXHDPI icon"), + Tr::tr("Select an icon for extra-extra-high-density (xxhdpi) screens (~480dpi)."), + textEditorWidget, + extraExtraHighDpiIconPath, + iconFileName); + iconLayout->addWidget(xxhIconButton); + m_iconButtons.push_back(xxhIconButton); + iconLayout->addStretch(1); + + auto xxxhIconButton = new AndroidManifestEditorIconWidget(this, + extraExtraExtraHighDpiIconSize, + extraExtraExtraHighDpiIconSize, + Tr::tr("XXXHDPI icon"), + Tr::tr("Select an icon for extra-extra-extra-high-density (xxxhdpi) screens (~640dpi)."), + textEditorWidget, + extraExtraExtraHighDpiIconPath, + iconFileName); + iconLayout->addWidget(xxxhIconButton); + m_iconButtons.push_back(xxxhIconButton); + iconLayout->addStretch(3); + + auto handleIconModification = [this] { + bool iconsMaybeChanged = hasIcons(); + if (m_hasIcons != iconsMaybeChanged) + emit iconsModified(); + m_hasIcons = iconsMaybeChanged; + }; + for (auto &&iconButton : m_iconButtons) { + connect(masterIconButton, &AndroidManifestEditorIconWidget::iconSelected, + iconButton, &AndroidManifestEditorIconWidget::setIconFromPath); + connect(iconButton, &AndroidManifestEditorIconWidget::iconRemoved, + this, handleIconModification); + connect(iconButton, &AndroidManifestEditorIconWidget::iconSelected, + this, handleIconModification); + } + connect(masterIconButton, &AndroidManifestEditorIconWidget::iconSelected, + this, handleIconModification); +} + +void IconContainerWidget::setIconFileName(const QString &name) +{ + m_iconFileName = name; +} + +QString IconContainerWidget::iconFileName() const +{ + return m_iconFileName; +} + +void IconContainerWidget::loadIcons() +{ + for (auto &&iconButton : m_iconButtons) { + iconButton->setTargetIconFileName(m_iconFileName + imageSuffix); + iconButton->loadIcon(); + } + m_hasIcons = hasIcons(); +} + +bool IconContainerWidget::hasIcons() const +{ + for (auto &&iconButton : m_iconButtons) { + if (iconButton->hasIcon()) + return true; + } + return false; +} + const char infoBarId[] = "Android.AndroidManifestEditor.InfoBar"; static bool checkPackageName(const QString &packageName) @@ -124,7 +296,7 @@ public: void preSave(); void postSave(); - TextEditor::TextEditorWidget *textEditorWidget() const; + TextEditorWidget *textEditorWidget() const; void setDirty(bool dirty = true); @@ -190,7 +362,7 @@ private: QLineEdit *m_activityNameLineEdit; QComboBox *m_styleExtractMethod; QComboBox *m_screenOrientation; - AndroidManifestEditorIconContainerWidget *m_iconButtons; + IconContainerWidget *m_iconButtons; SplashScreenContainerWidget *m_splashButtons; // Permissions @@ -203,12 +375,12 @@ private: QComboBox *m_permissionsComboBox; QTimer m_timerParseCheck; - TextEditor::TextEditorWidget *m_textEditorWidget; + TextEditorWidget *m_textEditorWidget; QString m_androidNdkPlatform; QTabWidget *m_advanvedTabWidget = nullptr; }; -class AndroidManifestTextEditorWidget : public TextEditor::TextEditorWidget +class AndroidManifestTextEditorWidget : public TextEditorWidget { public: explicit AndroidManifestTextEditorWidget(AndroidManifestEditorWidget *parent); @@ -220,7 +392,7 @@ private: AndroidManifestEditorWidget::AndroidManifestEditorWidget() { m_textEditorWidget = new AndroidManifestTextEditorWidget(this); - m_textEditorWidget->setOptionalActions(TextEditor::OptionalActions::UnCommentSelection); + m_textEditorWidget->setOptionalActions(OptionalActions::UnCommentSelection); initializePage(); @@ -232,9 +404,9 @@ AndroidManifestEditorWidget::AndroidManifestEditorWidget() connect(m_textEditorWidget->document(), &QTextDocument::contentsChanged, this, &AndroidManifestEditorWidget::startParseCheck); - connect(m_textEditorWidget->textDocument(), &TextEditor::TextDocument::reloadFinished, + connect(m_textEditorWidget->textDocument(), &TextDocument::reloadFinished, this, [this](bool success) { if (success) updateAfterFileLoad(); }); - connect(m_textEditorWidget->textDocument(), &TextEditor::TextDocument::openFinishedSuccessfully, + connect(m_textEditorWidget->textDocument(), &TextDocument::openFinishedSuccessfully, this, &AndroidManifestEditorWidget::updateAfterFileLoad); } @@ -572,7 +744,7 @@ QGroupBox *AndroidManifestEditorWidget::createAdvancedGroupBox(QWidget *parent) m_advanvedTabWidget = new QTabWidget(otherGroupBox); auto formLayout = new QFormLayout(); - m_iconButtons = new AndroidManifestEditorIconContainerWidget(otherGroupBox, m_textEditorWidget); + m_iconButtons = new IconContainerWidget(otherGroupBox, m_textEditorWidget); m_advanvedTabWidget->addTab(m_iconButtons, ::Android::Tr::tr("Application icon")); m_splashButtons = new SplashScreenContainerWidget(otherGroupBox, @@ -581,7 +753,7 @@ QGroupBox *AndroidManifestEditorWidget::createAdvancedGroupBox(QWidget *parent) connect(m_splashButtons, &SplashScreenContainerWidget::splashScreensModified, this, [this] { setDirty(); }); - connect(m_iconButtons, &AndroidManifestEditorIconContainerWidget::iconsModified, + connect(m_iconButtons, &IconContainerWidget::iconsModified, this, [this] { setDirty(); }); formLayout->addRow(m_advanvedTabWidget); @@ -710,7 +882,7 @@ void AndroidManifestEditorWidget::postSave() } } -TextEditor::TextEditorWidget *AndroidManifestEditorWidget::textEditorWidget() const +TextEditorWidget *AndroidManifestEditorWidget::textEditorWidget() const { return m_textEditorWidget; } @@ -1495,7 +1667,7 @@ int PermissionsModel::rowCount(const QModelIndex &parent) const // AndroidManifestDocument -class AndroidManifestDocument : public TextEditor::TextDocument +class AndroidManifestDocument : public TextDocument { public: explicit AndroidManifestDocument(AndroidManifestEditorWidget *editorWidget) @@ -1528,9 +1700,9 @@ private: // AndroidManifestEditorWidget AndroidManifestTextEditorWidget::AndroidManifestTextEditorWidget(AndroidManifestEditorWidget *parent) - : TextEditor::TextEditorWidget(parent) + : TextEditorWidget(parent) { - setTextDocument(TextEditor::TextDocumentPtr(new AndroidManifestDocument(parent))); + setTextDocument(TextDocumentPtr(new AndroidManifestDocument(parent))); textDocument()->setMimeType(QLatin1String(Constants::ANDROID_MANIFEST_MIME_TYPE)); setupGenericHighlighter(); setMarksVisible(false); @@ -1553,7 +1725,7 @@ public: QWidget *toolBar() override; Core::IDocument *document() const override; - TextEditor::TextEditorWidget *textEditor() const; + TextEditorWidget *textEditor() const; int currentLine() const override; int currentColumn() const override; @@ -1606,7 +1778,7 @@ Core::IDocument *AndroidManifestEditor::document() const return textEditor()->textDocument(); } -TextEditor::TextEditorWidget *AndroidManifestEditor::textEditor() const +TextEditorWidget *AndroidManifestEditor::textEditor() const { return ownWidget()->textEditorWidget(); } @@ -1664,3 +1836,5 @@ void setupAndroidManifestEditor() } } // Android::Internal + +#include "androidmanifesteditor.moc" diff --git a/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp b/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp deleted file mode 100644 index ea4e05f2b30..00000000000 --- a/src/plugins/android/androidmanifesteditoriconcontainerwidget.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "androidmanifesteditoriconcontainerwidget.h" -#include "androidmanifesteditoriconwidget.h" -#include "androidtr.h" - -#include - -#include -#include - -using namespace Utils; - -namespace Android::Internal { - -const char extraExtraExtraHighDpiIconPath[] = "/res/drawable-xxxhdpi/"; -const char extraExtraHighDpiIconPath[] = "/res/drawable-xxhdpi/"; -const char extraHighDpiIconPath[] = "/res/drawable-xhdpi/"; -const char highDpiIconPath[] = "/res/drawable-hdpi/"; -const char mediumDpiIconPath[] = "/res/drawable-mdpi/"; -const char lowDpiIconPath[] = "/res/drawable-ldpi/"; -const char imageSuffix[] = ".png"; -const QSize lowDpiIconSize{32, 32}; -const QSize mediumDpiIconSize{48, 48}; -const QSize highDpiIconSize{72, 72}; -const QSize extraHighDpiIconSize{96, 96}; -const QSize extraExtraHighDpiIconSize{144, 144}; -const QSize extraExtraExtraHighDpiIconSize{192, 192}; - -AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidget( - QWidget *parent, - TextEditor::TextEditorWidget *textEditorWidget) - : QWidget(parent) -{ - auto iconLayout = new QHBoxLayout(this); - auto masterIconButton = new AndroidManifestEditorIconWidget(this, - lowDpiIconSize, - lowDpiIconSize, - Tr::tr("Master icon"), - Tr::tr("Select master icon.")); - masterIconButton->setIcon(Icon::fromTheme("document-open")); - iconLayout->addWidget(masterIconButton); - iconLayout->addStretch(1); - - QFrame *line = new QFrame(this); - line->setFrameShape(QFrame::VLine); - line->setFrameShadow(QFrame::Sunken); - iconLayout->addWidget(line); - iconLayout->addStretch(1); - - QString iconFileName = m_iconFileName + imageSuffix; - - auto lIconButton = new AndroidManifestEditorIconWidget(this, - lowDpiIconSize, - lowDpiIconSize, - Tr::tr("LDPI icon"), - Tr::tr("Select an icon suitable for low-density (ldpi) screens (~120dpi)."), - textEditorWidget, - lowDpiIconPath, - iconFileName); - iconLayout->addWidget(lIconButton); - m_iconButtons.push_back(lIconButton); - iconLayout->addStretch(1); - - auto mIconButton = new AndroidManifestEditorIconWidget(this, - mediumDpiIconSize, - mediumDpiIconSize, - Tr::tr("MDPI icon"), - Tr::tr("Select an icon for medium-density (mdpi) screens (~160dpi)."), - textEditorWidget, - mediumDpiIconPath, - iconFileName); - iconLayout->addWidget(mIconButton); - m_iconButtons.push_back(mIconButton); - iconLayout->addStretch(1); - - auto hIconButton = new AndroidManifestEditorIconWidget(this, - highDpiIconSize, - highDpiIconSize, - Tr::tr("HDPI icon"), - Tr::tr("Select an icon for high-density (hdpi) screens (~240dpi)."), - textEditorWidget, - highDpiIconPath, - iconFileName); - iconLayout->addWidget(hIconButton); - m_iconButtons.push_back(hIconButton); - iconLayout->addStretch(1); - - auto xhIconButton = new AndroidManifestEditorIconWidget(this, - extraHighDpiIconSize, - extraHighDpiIconSize, - Tr::tr("XHDPI icon"), - Tr::tr("Select an icon for extra-high-density (xhdpi) screens (~320dpi)."), - textEditorWidget, - extraHighDpiIconPath, - iconFileName); - iconLayout->addWidget(xhIconButton); - m_iconButtons.push_back(xhIconButton); - iconLayout->addStretch(1); - - auto xxhIconButton = new AndroidManifestEditorIconWidget(this, - extraExtraHighDpiIconSize, - extraExtraHighDpiIconSize, - Tr::tr("XXHDPI icon"), - Tr::tr("Select an icon for extra-extra-high-density (xxhdpi) screens (~480dpi)."), - textEditorWidget, - extraExtraHighDpiIconPath, - iconFileName); - iconLayout->addWidget(xxhIconButton); - m_iconButtons.push_back(xxhIconButton); - iconLayout->addStretch(1); - - auto xxxhIconButton = new AndroidManifestEditorIconWidget(this, - extraExtraExtraHighDpiIconSize, - extraExtraExtraHighDpiIconSize, - Tr::tr("XXXHDPI icon"), - Tr::tr("Select an icon for extra-extra-extra-high-density (xxxhdpi) screens (~640dpi)."), - textEditorWidget, - extraExtraExtraHighDpiIconPath, - iconFileName); - iconLayout->addWidget(xxxhIconButton); - m_iconButtons.push_back(xxxhIconButton); - iconLayout->addStretch(3); - - auto handleIconModification = [this] { - bool iconsMaybeChanged = hasIcons(); - if (m_hasIcons != iconsMaybeChanged) - emit iconsModified(); - m_hasIcons = iconsMaybeChanged; - }; - for (auto &&iconButton : m_iconButtons) { - connect(masterIconButton, &AndroidManifestEditorIconWidget::iconSelected, - iconButton, &AndroidManifestEditorIconWidget::setIconFromPath); - connect(iconButton, &AndroidManifestEditorIconWidget::iconRemoved, - this, handleIconModification); - connect(iconButton, &AndroidManifestEditorIconWidget::iconSelected, - this, handleIconModification); - } - connect(masterIconButton, &AndroidManifestEditorIconWidget::iconSelected, - this, handleIconModification); -} - -void AndroidManifestEditorIconContainerWidget::setIconFileName(const QString &name) -{ - m_iconFileName = name; -} - -QString AndroidManifestEditorIconContainerWidget::iconFileName() const -{ - return m_iconFileName; -} - -void AndroidManifestEditorIconContainerWidget::loadIcons() -{ - for (auto &&iconButton : m_iconButtons) { - iconButton->setTargetIconFileName(m_iconFileName + imageSuffix); - iconButton->loadIcon(); - } - m_hasIcons = hasIcons(); -} - -bool AndroidManifestEditorIconContainerWidget::hasIcons() const -{ - for (auto &&iconButton : m_iconButtons) { - if (iconButton->hasIcon()) - return true; - } - return false; -} - -} // namespace Android::Internal diff --git a/src/plugins/android/androidmanifesteditoriconcontainerwidget.h b/src/plugins/android/androidmanifesteditoriconcontainerwidget.h deleted file mode 100644 index 77a0f7a4a75..00000000000 --- a/src/plugins/android/androidmanifesteditoriconcontainerwidget.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include -#include - -#include - -namespace TextEditor { - class TextEditorWidget; -} - -namespace Android::Internal { - -class AndroidManifestEditorIconWidget; - -class AndroidManifestEditorIconContainerWidget : public QWidget -{ - Q_OBJECT - -public: - explicit AndroidManifestEditorIconContainerWidget(QWidget *parent, - TextEditor::TextEditorWidget *textEditorWidget); - void setIconFileName(const QString &name); - QString iconFileName() const; - void loadIcons(); - bool hasIcons() const; -private: - QList m_iconButtons; - QString m_iconFileName = QLatin1String("icon"); - bool m_hasIcons = false; -signals: - void iconsModified(); -}; - -} // namespace Android::Internal From 05cab84f90a3476f966be57be7310d0d86b5f5a7 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 8 Nov 2024 12:34:58 +0100 Subject: [PATCH 122/989] Debugger: set focus to editor after switching perspective Fixes: QTCREATORBUG-31971 Change-Id: I48e1ee87affe4542fcfcfc5a440e2bd267e1dd67 Reviewed-by: hjk --- src/plugins/debugger/debuggermainwindow.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index 0d7f6775644..0de2d4197c0 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -741,6 +741,11 @@ void PerspectivePrivate::populatePerspective() ICore::addAdditionalContext(context()); restoreLayout(); + + if (!m_centralWidget) { + if (IEditor *editor = EditorManager::currentEditor()) + editor->widget()->setFocus(); + } } // Perspective From 29797bef415164c586cf836013321657d327e95d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 14:11:54 +0100 Subject: [PATCH 123/989] Android: Inline AndroidManifestEditorIconWidget Simplify its name. Inline some short methods. Change-Id: Ie1f25de1de3e5f03122cddcd1ce66ca45a9ea4b6 Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 1 - src/plugins/android/android.qbs | 2 - src/plugins/android/androidmanifesteditor.cpp | 407 ++++++++++++++---- .../androidmanifesteditoriconwidget.cpp | 284 ------------ .../android/androidmanifesteditoriconwidget.h | 68 --- 5 files changed, 329 insertions(+), 433 deletions(-) delete mode 100644 src/plugins/android/androidmanifesteditoriconwidget.cpp delete mode 100644 src/plugins/android/androidmanifesteditoriconwidget.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 1868535d1bc..142f54bc5f9 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -16,7 +16,6 @@ add_qtc_plugin(Android androiddeviceinfo.cpp androiddeviceinfo.h androidextralibrarylistmodel.cpp androidextralibrarylistmodel.h androidmanifesteditor.cpp androidmanifesteditor.h - androidmanifesteditoriconwidget.cpp androidmanifesteditoriconwidget.h androidpackageinstallationstep.cpp androidpackageinstallationstep.h androidplugin.cpp androidqmltoolingsupport.cpp androidqmltoolingsupport.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 850801ca28c..8dd5bf303e4 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -34,8 +34,6 @@ QtcPlugin { "androiddeviceinfo.h", "androidextralibrarylistmodel.cpp", "androidextralibrarylistmodel.h", - "androidmanifesteditoriconwidget.cpp", - "androidmanifesteditoriconwidget.h", "androidmanifesteditor.cpp", "androidmanifesteditor.h", "androidpackageinstallationstep.cpp", diff --git a/src/plugins/android/androidmanifesteditor.cpp b/src/plugins/android/androidmanifesteditor.cpp index 5bd79c198aa..e2deb3288f0 100644 --- a/src/plugins/android/androidmanifesteditor.cpp +++ b/src/plugins/android/androidmanifesteditor.cpp @@ -5,7 +5,6 @@ #include "androidconfigurations.h" #include "androidconstants.h" -#include "androidmanifesteditoriconwidget.h" #include "androidtr.h" #include "androidutils.h" #include "splashscreencontainerwidget.h" @@ -48,6 +47,8 @@ #include #include #include +#include +#include #include #include #include @@ -65,8 +66,270 @@ using namespace ProjectExplorer; using namespace TextEditor; using namespace Utils; +static Q_LOGGING_CATEGORY(androidManifestEditorLog, "qtc.android.manifestEditor", QtWarningMsg) + namespace Android::Internal { +static FilePath manifestDir(TextEditorWidget *textEditorWidget) +{ + // Get the manifest file's directory from its filepath. + return textEditorWidget->textDocument()->filePath().absolutePath(); +} + +class IconWidget : public QWidget +{ + Q_OBJECT + +public: + IconWidget(QWidget *parent, + const QSize &iconSize, + const QSize &buttonSize, + const QString &title, + const QString &tooltip, + TextEditorWidget *textEditorWidget = nullptr, + const QString &targetIconPath = {}, + const QString &targetIconFileName = {}); + void setIcon(const QIcon &icon) { m_button->setIcon(icon); } + void clearIcon() + { + removeIcon(); + emit iconRemoved(); + } + + void loadIcon() + { + const FilePath baseDir = manifestDir(m_textEditorWidget); + setIconFromPath(baseDir / m_targetIconPath / m_targetIconFileName); + } + void setIconFromPath(const FilePath &iconPath); + bool hasIcon() const { return !m_iconPath.isEmpty(); } + void setScaledToOriginalAspectRatio(bool scaled) { m_scaledToOriginalAspectRatio = scaled; } + void setScaledWithoutStretching(bool scaled) { m_scaledWithoutStretching = scaled; } + void setTargetIconFileName(const QString &fileName) { m_targetIconFileName = fileName; } + void setTargetIconPath(const QString &targetIconPath) { m_targetIconPath = targetIconPath; } + QString targetIconFileName() const { return m_targetIconFileName; } + QString targetIconPath() const { return m_targetIconPath; } + +signals: + void iconSelected(const FilePath &path); + void iconRemoved(); + +private: + void selectIcon(); + void removeIcon(); + void copyIcon(); + void setScaleWarningLabelVisible(bool visible) + { + if (m_scaleWarningLabel) + m_scaleWarningLabel->setVisible(visible); + } + QToolButton *m_button = nullptr; + QSize m_iconSize; + QSize m_buttonSize; + QLabel *m_scaleWarningLabel = nullptr; + TextEditorWidget *m_textEditorWidget = nullptr; + FilePath m_iconPath; + QString m_targetIconPath; + QString m_targetIconFileName; + QString m_iconSelectionText; + bool m_scaledToOriginalAspectRatio = false; + bool m_scaledWithoutStretching = false; +}; + +IconWidget::IconWidget(QWidget *parent, + const QSize &iconSize, + const QSize &buttonSize, + const QString &title, + const QString &tooltip, + TextEditorWidget *textEditorWidget, + const QString &targetIconPath, + const QString &targetIconFileName) + : QWidget(parent) + , m_iconSize(iconSize) + , m_buttonSize(buttonSize) + , m_textEditorWidget(textEditorWidget) + , m_targetIconPath(targetIconPath) + , m_targetIconFileName(targetIconFileName) +{ + auto iconLayout = new QVBoxLayout(this); + auto iconTitle = new QLabel(title, this); + auto iconButtonLayout = new QGridLayout(); + m_button = new QToolButton(this); + m_button->setMinimumSize(buttonSize); + m_button->setMaximumSize(buttonSize); + m_button->setToolTip(tooltip); + m_button->setIconSize(buttonSize); + QSize clearAndWarningSize(16, 16); + QToolButton *clearButton = nullptr; + if (textEditorWidget) { + clearButton = new QToolButton(this); + clearButton->setMinimumSize(clearAndWarningSize); + clearButton->setMaximumSize(clearAndWarningSize); + clearButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon()); + } + if (textEditorWidget) { + m_scaleWarningLabel = new QLabel(this); + m_scaleWarningLabel->setMinimumSize(clearAndWarningSize); + m_scaleWarningLabel->setMaximumSize(clearAndWarningSize); + m_scaleWarningLabel->setPixmap(Utils::Icons::WARNING.icon().pixmap(clearAndWarningSize)); + m_scaleWarningLabel->setToolTip(Tr::tr("Icon scaled up.")); + m_scaleWarningLabel->setVisible(false); + } + auto label = new QLabel(Tr::tr("Click to select..."), parent); + iconLayout->addWidget(iconTitle); + iconLayout->setAlignment(iconTitle, Qt::AlignHCenter); + iconLayout->addStretch(50); + iconButtonLayout->setColumnMinimumWidth(0, 16); + iconButtonLayout->addWidget(m_button, 0, 1, 1, 3); + iconButtonLayout->setAlignment(m_button, Qt::AlignVCenter); + if (textEditorWidget) { + iconButtonLayout->addWidget(clearButton, 0, 4, 1, 1); + iconButtonLayout->setAlignment(clearButton, Qt::AlignTop); + } + if (textEditorWidget) { + iconButtonLayout->addWidget(m_scaleWarningLabel, 0, 0, 1, 1); + iconButtonLayout->setAlignment(m_scaleWarningLabel, Qt::AlignTop); + } + iconLayout->addLayout(iconButtonLayout); + iconLayout->setAlignment(iconButtonLayout, Qt::AlignHCenter); + iconLayout->addStretch(50); + iconLayout->addWidget(label); + iconLayout->setAlignment(label, Qt::AlignHCenter); + this->setLayout(iconLayout); + connect(m_button, &QAbstractButton::clicked, this, &IconWidget::selectIcon); + if (clearButton) + connect(clearButton, &QAbstractButton::clicked, this, &IconWidget::clearIcon); + m_iconSelectionText = tooltip; +} + +void IconWidget::setIconFromPath(const FilePath &iconPath) +{ + if (!m_textEditorWidget) + return; + m_iconPath = iconPath; + FilePath baseDir = manifestDir(m_textEditorWidget); + QImage original(iconPath.toFSPathString()); + if (!original.isNull() && m_scaledToOriginalAspectRatio) { + if ((original.width() > original.height() && m_buttonSize.height() > m_buttonSize.width()) + || (original.height() > original.width() && m_buttonSize.width() > m_buttonSize.height())) { + auto width = m_buttonSize.height(); + auto height = m_buttonSize.width(); + m_buttonSize = QSize(width, height); + m_button->setMinimumSize(m_buttonSize); + m_button->setMaximumSize(m_buttonSize); + m_button->setIconSize(m_buttonSize); + auto targetWidth = m_iconSize.height(); + auto targetHeight = m_iconSize.width(); + m_iconSize = QSize(targetWidth, targetHeight); + } + } + copyIcon(); + FilePath iconFile = baseDir / m_targetIconPath / m_targetIconFileName; + m_button->setIcon(QIcon(iconFile.toFSPathString())); +} + +void IconWidget::selectIcon() +{ + FilePath file = FileUtils::getOpenFilePath( + this, + m_iconSelectionText, + FileUtils::homePath(), + //: %1 expands to wildcard list for file dialog, do not change order + Tr::tr("Images %1") + .arg("(*.png *.jpg *.jpeg *.webp *.svg)")); // TODO: See SplashContainterWidget + if (file.isEmpty()) + return; + setIconFromPath(file); + emit iconSelected(file); +} + +void IconWidget::removeIcon() +{ + const FilePath baseDir = manifestDir(m_textEditorWidget); + const FilePath targetPath = baseDir / m_targetIconPath / m_targetIconFileName; + if (targetPath.isEmpty()) { + qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon."; + return; + } + targetPath.removeFile(); + m_iconPath.clear(); + setScaleWarningLabelVisible(false); + m_button->setIcon(QIcon()); +} + +static QImage scaleWithoutStretching(const QImage& original, const QSize& targetSize) +{ + QImage ret(targetSize, QImage::Format_ARGB32); + ret.fill(Qt::white); + if (targetSize.height() > targetSize.width()) { + // portrait target, scale to width and paint in the vertical middle + QImage scaled = original.scaledToWidth(targetSize.width()); + int heightDiffHalf = (targetSize.height() - scaled.height()) / 2; + QPainter painter(&ret); + QRect targetRect(0, heightDiffHalf, targetSize.width(), scaled.height()); + QRect sourceRect(0, 0, scaled.width(), scaled.height()); + painter.drawImage(targetRect, scaled, sourceRect); + } else if (targetSize.width() > targetSize.height()) { + // landscape target, scale to height and paint in the horizontal middle + QImage scaled = original.scaledToHeight(targetSize.height()); + int widthDiffHalf = (targetSize.width() - scaled.width()) / 2; + QPainter painter(&ret); + QRect targetRect(widthDiffHalf, 0, scaled.width(), targetSize.height()); + QRect sourceRect(0, 0, scaled.width(), scaled.height()); + painter.drawImage(targetRect, scaled, sourceRect); + } else + ret = original.scaled(targetSize.width(), targetSize.height(), + Qt::KeepAspectRatio, Qt::SmoothTransformation); + return ret; +} + +static bool similarFilesExist(const FilePath &path) +{ + const FilePaths entries = path.parentDir().dirEntries({{path.completeBaseName() + ".*"}}); + return !entries.empty(); +} + +void IconWidget::copyIcon() +{ + if (m_targetIconPath.isEmpty()) + return; + + const FilePath baseDir = manifestDir(m_textEditorWidget); + const FilePath targetPath = baseDir / m_targetIconPath / m_targetIconFileName; + if (targetPath.isEmpty()) { + qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon."; + return; + } + QImage original(m_iconPath.toFSPathString()); + if (m_iconPath != targetPath) + removeIcon(); + if (original.isNull()) { + if (!similarFilesExist(m_iconPath)) + m_iconPath.clear(); + return; + } + if (m_iconPath == targetPath) + return; + if (!targetPath.isEmpty() && !original.isNull()) { + if (!targetPath.absolutePath().ensureWritableDir()) { + qCDebug(androidManifestEditorLog) << "Cannot create icon target path."; + m_iconPath.clear(); + return; + } + QImage scaled; + if (!m_scaledWithoutStretching) + scaled = original.scaled(m_iconSize.width(), m_iconSize.height(), + Qt::KeepAspectRatio, Qt::SmoothTransformation); + else + scaled = scaleWithoutStretching(original, m_iconSize); + setScaleWarningLabelVisible(scaled.width() > original.width() || scaled.height() > original.height()); + scaled.save(targetPath.toFSPathString()); + m_iconPath = targetPath; + } else { + m_iconPath.clear(); + } +} + const char extraExtraExtraHighDpiIconPath[] = "/res/drawable-xxxhdpi/"; const char extraExtraHighDpiIconPath[] = "/res/drawable-xxhdpi/"; const char extraHighDpiIconPath[] = "/res/drawable-xhdpi/"; @@ -87,27 +350,29 @@ class IconContainerWidget : public QWidget public: explicit IconContainerWidget(QWidget *parent, TextEditorWidget *textEditorWidget); - void setIconFileName(const QString &name); - QString iconFileName() const; + void setIconFileName(const QString &name) { m_iconFileName = name; } + QString iconFileName() const { return m_iconFileName; } void loadIcons(); bool hasIcons() const; -private: - QList m_iconButtons; - QString m_iconFileName = QLatin1String("icon"); - bool m_hasIcons = false; + signals: void iconsModified(); + +private: + QList m_iconButtons; + QString m_iconFileName = QLatin1String("icon"); + bool m_hasIcons = false; }; IconContainerWidget::IconContainerWidget(QWidget *parent, TextEditorWidget *textEditorWidget) : QWidget(parent) { auto iconLayout = new QHBoxLayout(this); - auto masterIconButton = new AndroidManifestEditorIconWidget(this, - lowDpiIconSize, - lowDpiIconSize, - Tr::tr("Master icon"), - Tr::tr("Select master icon.")); + auto masterIconButton = new IconWidget(this, + lowDpiIconSize, + lowDpiIconSize, + Tr::tr("Master icon"), + Tr::tr("Select master icon.")); masterIconButton->setIcon(Icon::fromTheme("document-open")); iconLayout->addWidget(masterIconButton); iconLayout->addStretch(1); @@ -120,74 +385,74 @@ IconContainerWidget::IconContainerWidget(QWidget *parent, TextEditorWidget *text QString iconFileName = m_iconFileName + imageSuffix; - auto lIconButton = new AndroidManifestEditorIconWidget(this, - lowDpiIconSize, - lowDpiIconSize, - Tr::tr("LDPI icon"), - Tr::tr("Select an icon suitable for low-density (ldpi) screens (~120dpi)."), - textEditorWidget, - lowDpiIconPath, - iconFileName); + auto lIconButton = new IconWidget(this, + lowDpiIconSize, + lowDpiIconSize, + Tr::tr("LDPI icon"), + Tr::tr("Select an icon suitable for low-density (ldpi) screens (~120dpi)."), + textEditorWidget, + lowDpiIconPath, + iconFileName); iconLayout->addWidget(lIconButton); m_iconButtons.push_back(lIconButton); iconLayout->addStretch(1); - auto mIconButton = new AndroidManifestEditorIconWidget(this, - mediumDpiIconSize, - mediumDpiIconSize, - Tr::tr("MDPI icon"), - Tr::tr("Select an icon for medium-density (mdpi) screens (~160dpi)."), - textEditorWidget, - mediumDpiIconPath, - iconFileName); + auto mIconButton = new IconWidget(this, + mediumDpiIconSize, + mediumDpiIconSize, + Tr::tr("MDPI icon"), + Tr::tr("Select an icon for medium-density (mdpi) screens (~160dpi)."), + textEditorWidget, + mediumDpiIconPath, + iconFileName); iconLayout->addWidget(mIconButton); m_iconButtons.push_back(mIconButton); iconLayout->addStretch(1); - auto hIconButton = new AndroidManifestEditorIconWidget(this, - highDpiIconSize, - highDpiIconSize, - Tr::tr("HDPI icon"), - Tr::tr("Select an icon for high-density (hdpi) screens (~240dpi)."), - textEditorWidget, - highDpiIconPath, - iconFileName); + auto hIconButton = new IconWidget(this, + highDpiIconSize, + highDpiIconSize, + Tr::tr("HDPI icon"), + Tr::tr("Select an icon for high-density (hdpi) screens (~240dpi)."), + textEditorWidget, + highDpiIconPath, + iconFileName); iconLayout->addWidget(hIconButton); m_iconButtons.push_back(hIconButton); iconLayout->addStretch(1); - auto xhIconButton = new AndroidManifestEditorIconWidget(this, - extraHighDpiIconSize, - extraHighDpiIconSize, - Tr::tr("XHDPI icon"), - Tr::tr("Select an icon for extra-high-density (xhdpi) screens (~320dpi)."), - textEditorWidget, - extraHighDpiIconPath, - iconFileName); + auto xhIconButton = new IconWidget(this, + extraHighDpiIconSize, + extraHighDpiIconSize, + Tr::tr("XHDPI icon"), + Tr::tr("Select an icon for extra-high-density (xhdpi) screens (~320dpi)."), + textEditorWidget, + extraHighDpiIconPath, + iconFileName); iconLayout->addWidget(xhIconButton); m_iconButtons.push_back(xhIconButton); iconLayout->addStretch(1); - auto xxhIconButton = new AndroidManifestEditorIconWidget(this, - extraExtraHighDpiIconSize, - extraExtraHighDpiIconSize, - Tr::tr("XXHDPI icon"), - Tr::tr("Select an icon for extra-extra-high-density (xxhdpi) screens (~480dpi)."), - textEditorWidget, - extraExtraHighDpiIconPath, - iconFileName); + auto xxhIconButton = new IconWidget(this, + extraExtraHighDpiIconSize, + extraExtraHighDpiIconSize, + Tr::tr("XXHDPI icon"), + Tr::tr("Select an icon for extra-extra-high-density (xxhdpi) screens (~480dpi)."), + textEditorWidget, + extraExtraHighDpiIconPath, + iconFileName); iconLayout->addWidget(xxhIconButton); m_iconButtons.push_back(xxhIconButton); iconLayout->addStretch(1); - auto xxxhIconButton = new AndroidManifestEditorIconWidget(this, - extraExtraExtraHighDpiIconSize, - extraExtraExtraHighDpiIconSize, - Tr::tr("XXXHDPI icon"), - Tr::tr("Select an icon for extra-extra-extra-high-density (xxxhdpi) screens (~640dpi)."), - textEditorWidget, - extraExtraExtraHighDpiIconPath, - iconFileName); + auto xxxhIconButton = new IconWidget(this, + extraExtraExtraHighDpiIconSize, + extraExtraExtraHighDpiIconSize, + Tr::tr("XXXHDPI icon"), + Tr::tr("Select an icon for extra-extra-extra-high-density (xxxhdpi) screens (~640dpi)."), + textEditorWidget, + extraExtraExtraHighDpiIconPath, + iconFileName); iconLayout->addWidget(xxxhIconButton); m_iconButtons.push_back(xxxhIconButton); iconLayout->addStretch(3); @@ -199,25 +464,11 @@ IconContainerWidget::IconContainerWidget(QWidget *parent, TextEditorWidget *text m_hasIcons = iconsMaybeChanged; }; for (auto &&iconButton : m_iconButtons) { - connect(masterIconButton, &AndroidManifestEditorIconWidget::iconSelected, - iconButton, &AndroidManifestEditorIconWidget::setIconFromPath); - connect(iconButton, &AndroidManifestEditorIconWidget::iconRemoved, - this, handleIconModification); - connect(iconButton, &AndroidManifestEditorIconWidget::iconSelected, - this, handleIconModification); + connect(masterIconButton, &IconWidget::iconSelected, iconButton, &IconWidget::setIconFromPath); + connect(iconButton, &IconWidget::iconRemoved, this, handleIconModification); + connect(iconButton, &IconWidget::iconSelected, this, handleIconModification); } - connect(masterIconButton, &AndroidManifestEditorIconWidget::iconSelected, - this, handleIconModification); -} - -void IconContainerWidget::setIconFileName(const QString &name) -{ - m_iconFileName = name; -} - -QString IconContainerWidget::iconFileName() const -{ - return m_iconFileName; + connect(masterIconButton, &IconWidget::iconSelected, this, handleIconModification); } void IconContainerWidget::loadIcons() diff --git a/src/plugins/android/androidmanifesteditoriconwidget.cpp b/src/plugins/android/androidmanifesteditoriconwidget.cpp deleted file mode 100644 index 0bf460867a0..00000000000 --- a/src/plugins/android/androidmanifesteditoriconwidget.cpp +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "androidmanifesteditoriconwidget.h" -#include "androidtr.h" - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace Utils; - -namespace Android::Internal { - -static Q_LOGGING_CATEGORY(androidManifestEditorLog, "qtc.android.manifestEditor", QtWarningMsg) - -static FilePath manifestDir(TextEditor::TextEditorWidget *textEditorWidget) -{ - // Get the manifest file's directory from its filepath. - return textEditorWidget->textDocument()->filePath().absolutePath(); -} - -AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(QWidget *parent) : QWidget(parent) -{} - -AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget( - QWidget *parent, const QSize &iconSize, const QSize &buttonSize, const QString &title, - const QString &tooltip, - TextEditor::TextEditorWidget *textEditorWidget, - const QString &targetIconPath, - const QString &targetIconFileName) - : QWidget(parent), m_iconSize(iconSize), m_buttonSize(buttonSize), - m_textEditorWidget(textEditorWidget), - m_targetIconPath(targetIconPath), m_targetIconFileName(targetIconFileName) -{ - auto iconLayout = new QVBoxLayout(this); - auto iconTitle = new QLabel(title, this); - auto iconButtonLayout = new QGridLayout(); - m_button = new QToolButton(this); - m_button->setMinimumSize(buttonSize); - m_button->setMaximumSize(buttonSize); - m_button->setToolTip(tooltip); - m_button->setIconSize(buttonSize); - QSize clearAndWarningSize(16, 16); - QToolButton *clearButton = nullptr; - if (textEditorWidget) { - clearButton = new QToolButton(this); - clearButton->setMinimumSize(clearAndWarningSize); - clearButton->setMaximumSize(clearAndWarningSize); - clearButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon()); - } - if (textEditorWidget) { - m_scaleWarningLabel = new QLabel(this); - m_scaleWarningLabel->setMinimumSize(clearAndWarningSize); - m_scaleWarningLabel->setMaximumSize(clearAndWarningSize); - m_scaleWarningLabel->setPixmap(Utils::Icons::WARNING.icon().pixmap(clearAndWarningSize)); - m_scaleWarningLabel->setToolTip(Tr::tr("Icon scaled up.")); - m_scaleWarningLabel->setVisible(false); - } - auto label = new QLabel(Tr::tr("Click to select..."), parent); - iconLayout->addWidget(iconTitle); - iconLayout->setAlignment(iconTitle, Qt::AlignHCenter); - iconLayout->addStretch(50); - iconButtonLayout->setColumnMinimumWidth(0, 16); - iconButtonLayout->addWidget(m_button, 0, 1, 1, 3); - iconButtonLayout->setAlignment(m_button, Qt::AlignVCenter); - if (textEditorWidget) { - iconButtonLayout->addWidget(clearButton, 0, 4, 1, 1); - iconButtonLayout->setAlignment(clearButton, Qt::AlignTop); - } - if (textEditorWidget) { - iconButtonLayout->addWidget(m_scaleWarningLabel, 0, 0, 1, 1); - iconButtonLayout->setAlignment(m_scaleWarningLabel, Qt::AlignTop); - } - iconLayout->addLayout(iconButtonLayout); - iconLayout->setAlignment(iconButtonLayout, Qt::AlignHCenter); - iconLayout->addStretch(50); - iconLayout->addWidget(label); - iconLayout->setAlignment(label, Qt::AlignHCenter); - this->setLayout(iconLayout); - connect(m_button, &QAbstractButton::clicked, - this, &AndroidManifestEditorIconWidget::selectIcon); - if (clearButton) - connect(clearButton, &QAbstractButton::clicked, - this, &AndroidManifestEditorIconWidget::clearIcon); - m_iconSelectionText = tooltip; -} - -void AndroidManifestEditorIconWidget::setIcon(const QIcon &icon) -{ - m_button->setIcon(icon); -} - -void AndroidManifestEditorIconWidget::clearIcon() -{ - removeIcon(); - emit iconRemoved(); -} - -void AndroidManifestEditorIconWidget::loadIcon() -{ - const FilePath baseDir = manifestDir(m_textEditorWidget); - setIconFromPath(baseDir / m_targetIconPath / m_targetIconFileName); -} - -void AndroidManifestEditorIconWidget::setIconFromPath(const FilePath &iconPath) -{ - if (!m_textEditorWidget) - return; - m_iconPath = iconPath; - FilePath baseDir = manifestDir(m_textEditorWidget); - QImage original(iconPath.toFSPathString()); - if (!original.isNull() && m_scaledToOriginalAspectRatio) { - if ((original.width() > original.height() && m_buttonSize.height() > m_buttonSize.width()) - || (original.height() > original.width() && m_buttonSize.width() > m_buttonSize.height())) { - auto width = m_buttonSize.height(); - auto height = m_buttonSize.width(); - m_buttonSize = QSize(width, height); - m_button->setMinimumSize(m_buttonSize); - m_button->setMaximumSize(m_buttonSize); - m_button->setIconSize(m_buttonSize); - auto targetWidth = m_iconSize.height(); - auto targetHeight = m_iconSize.width(); - m_iconSize = QSize(targetWidth, targetHeight); - } - } - copyIcon(); - FilePath iconFile = baseDir / m_targetIconPath / m_targetIconFileName; - m_button->setIcon(QIcon(iconFile.toFSPathString())); -} - -void AndroidManifestEditorIconWidget::selectIcon() -{ - FilePath file = FileUtils::getOpenFilePath( - this, - m_iconSelectionText, - FileUtils::homePath(), - //: %1 expands to wildcard list for file dialog, do not change order - Tr::tr("Images %1") - .arg("(*.png *.jpg *.jpeg *.webp *.svg)")); // TODO: See SplashContainterWidget - if (file.isEmpty()) - return; - setIconFromPath(file); - emit iconSelected(file); -} - -void AndroidManifestEditorIconWidget::removeIcon() -{ - const FilePath baseDir = manifestDir(m_textEditorWidget); - const FilePath targetPath = baseDir / m_targetIconPath / m_targetIconFileName; - if (targetPath.isEmpty()) { - qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon."; - return; - } - targetPath.removeFile(); - m_iconPath.clear(); - setScaleWarningLabelVisible(false); - m_button->setIcon(QIcon()); -} - -bool AndroidManifestEditorIconWidget::hasIcon() const -{ - return !m_iconPath.isEmpty(); -} - -void AndroidManifestEditorIconWidget::setScaledToOriginalAspectRatio(bool scaled) -{ - m_scaledToOriginalAspectRatio = scaled; -} - -void AndroidManifestEditorIconWidget::setScaledWithoutStretching(bool scaled) -{ - m_scaledWithoutStretching = scaled; -} - -void AndroidManifestEditorIconWidget::setTargetIconFileName(const QString &targetIconFileName) -{ - m_targetIconFileName = targetIconFileName; -} - -void AndroidManifestEditorIconWidget::setTargetIconPath(const QString &targetIconPath) -{ - m_targetIconPath = targetIconPath; -} - -QString AndroidManifestEditorIconWidget::targetIconFileName() const -{ - return m_targetIconFileName; -} - -QString AndroidManifestEditorIconWidget::targetIconPath() const -{ - return m_targetIconPath; -} - -void AndroidManifestEditorIconWidget::setScaleWarningLabelVisible(bool visible) -{ - if (m_scaleWarningLabel) - m_scaleWarningLabel->setVisible(visible); -} - -static QImage scaleWithoutStretching(const QImage& original, const QSize& targetSize) -{ - QImage ret(targetSize, QImage::Format_ARGB32); - ret.fill(Qt::white); - if (targetSize.height() > targetSize.width()) { - // portrait target, scale to width and paint in the vertical middle - QImage scaled = original.scaledToWidth(targetSize.width()); - int heightDiffHalf = (targetSize.height() - scaled.height()) / 2; - QPainter painter(&ret); - QRect targetRect(0, heightDiffHalf, targetSize.width(), scaled.height()); - QRect sourceRect(0, 0, scaled.width(), scaled.height()); - painter.drawImage(targetRect, scaled, sourceRect); - } else if (targetSize.width() > targetSize.height()) { - // landscape target, scale to height and paint in the horizontal middle - QImage scaled = original.scaledToHeight(targetSize.height()); - int widthDiffHalf = (targetSize.width() - scaled.width()) / 2; - QPainter painter(&ret); - QRect targetRect(widthDiffHalf, 0, scaled.width(), targetSize.height()); - QRect sourceRect(0, 0, scaled.width(), scaled.height()); - painter.drawImage(targetRect, scaled, sourceRect); - } else - ret = original.scaled(targetSize.width(), targetSize.height(), - Qt::KeepAspectRatio, Qt::SmoothTransformation); - return ret; -} - -static bool similarFilesExist(const FilePath &path) -{ - const FilePaths entries = path.parentDir().dirEntries({{path.completeBaseName() + ".*"}}); - return !entries.empty(); -} - -void AndroidManifestEditorIconWidget::copyIcon() -{ - if (m_targetIconPath.isEmpty()) - return; - - const FilePath baseDir = manifestDir(m_textEditorWidget); - const FilePath targetPath = baseDir / m_targetIconPath / m_targetIconFileName; - if (targetPath.isEmpty()) { - qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon."; - return; - } - QImage original(m_iconPath.toFSPathString()); - if (m_iconPath != targetPath) - removeIcon(); - if (original.isNull()) { - if (!similarFilesExist(m_iconPath)) - m_iconPath.clear(); - return; - } - if (m_iconPath == targetPath) - return; - if (!targetPath.isEmpty() && !original.isNull()) { - if (!targetPath.absolutePath().ensureWritableDir()) { - qCDebug(androidManifestEditorLog) << "Cannot create icon target path."; - m_iconPath.clear(); - return; - } - QImage scaled; - if (!m_scaledWithoutStretching) - scaled = original.scaled(m_iconSize.width(), m_iconSize.height(), - Qt::KeepAspectRatio, Qt::SmoothTransformation); - else - scaled = scaleWithoutStretching(original, m_iconSize); - setScaleWarningLabelVisible(scaled.width() > original.width() || scaled.height() > original.height()); - scaled.save(targetPath.toFSPathString()); - m_iconPath = targetPath; - } else { - m_iconPath.clear(); - } -} - -} // namespace Android::Internal diff --git a/src/plugins/android/androidmanifesteditoriconwidget.h b/src/plugins/android/androidmanifesteditoriconwidget.h deleted file mode 100644 index 5d6b0b0647b..00000000000 --- a/src/plugins/android/androidmanifesteditoriconwidget.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -#include - -namespace TextEditor { class TextEditorWidget; } - -QT_BEGIN_NAMESPACE -class QLabel; -class QToolButton; -QT_END_NAMESPACE - -namespace Android::Internal { - -class AndroidManifestEditorIconWidget : public QWidget -{ - Q_OBJECT - -public: - explicit AndroidManifestEditorIconWidget(QWidget *parent); - AndroidManifestEditorIconWidget(QWidget *parent, - const QSize &iconSize, - const QSize &buttonSize, - const QString &title, - const QString &tooltip, - TextEditor::TextEditorWidget *textEditorWidget = nullptr, - const QString &targetIconPath = {}, - const QString &targetIconFileName = {}); - void setIcon(const QIcon &icon); - void clearIcon(); - void loadIcon(); - void setIconFromPath(const Utils::FilePath &iconPath); - bool hasIcon() const; - void setScaledToOriginalAspectRatio(bool scaled); - void setScaledWithoutStretching(bool scaled); - void setTargetIconFileName(const QString &targetIconFileName); - void setTargetIconPath(const QString &targetIconPath); - QString targetIconFileName() const; - QString targetIconPath() const; - -signals: - void iconSelected(const Utils::FilePath &path); - void iconRemoved(); - -private: - void selectIcon(); - void removeIcon(); - void copyIcon(); - void setScaleWarningLabelVisible(bool visible); -private: - QToolButton *m_button = nullptr; - QSize m_iconSize; - QSize m_buttonSize; - QLabel *m_scaleWarningLabel = nullptr; - TextEditor::TextEditorWidget *m_textEditorWidget = nullptr; - Utils::FilePath m_iconPath; - QString m_targetIconPath; - QString m_targetIconFileName; - QString m_iconSelectionText; - bool m_scaledToOriginalAspectRatio = false; - bool m_scaledWithoutStretching = false; -}; - -} // namespace Android::Internal From d27c799f95d1d47b889051b61edc3a14b106e281 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 14:20:21 +0100 Subject: [PATCH 124/989] Android: Inline AndroidExtraLibraryListModel Simplify its name. Change-Id: Ida184d791827588a8b8bb574183d0e8b28514bb6 Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 1 - src/plugins/android/android.qbs | 2 - src/plugins/android/androidbuildapkstep.cpp | 130 +++++++++++++++- .../android/androidextralibrarylistmodel.cpp | 140 ------------------ .../android/androidextralibrarylistmodel.h | 40 ----- 5 files changed, 126 insertions(+), 187 deletions(-) delete mode 100644 src/plugins/android/androidextralibrarylistmodel.cpp delete mode 100644 src/plugins/android/androidextralibrarylistmodel.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 142f54bc5f9..206ec703da5 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -14,7 +14,6 @@ add_qtc_plugin(Android androiddeployqtstep.cpp androiddeployqtstep.h androiddevice.cpp androiddevice.h androiddeviceinfo.cpp androiddeviceinfo.h - androidextralibrarylistmodel.cpp androidextralibrarylistmodel.h androidmanifesteditor.cpp androidmanifesteditor.h androidpackageinstallationstep.cpp androidpackageinstallationstep.h androidplugin.cpp diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 8dd5bf303e4..056c07737c6 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -32,8 +32,6 @@ QtcPlugin { "androiddevice.h", "androiddeviceinfo.cpp", "androiddeviceinfo.h", - "androidextralibrarylistmodel.cpp", - "androidextralibrarylistmodel.h", "androidmanifesteditor.cpp", "androidmanifesteditor.h", "androidpackageinstallationstep.cpp", diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index ea06a6349af..2582afc4b1f 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -6,7 +6,6 @@ #include "androidconfigurations.h" #include "androidconstants.h" #include "androidcreatekeystorecertificate.h" -#include "androidextralibrarylistmodel.h" #include "androidqtversion.h" #include "androidsdkmanager.h" #include "androidtr.h" @@ -66,6 +65,128 @@ namespace Android::Internal { static Q_LOGGING_CATEGORY(buildapkstepLog, "qtc.android.build.androidbuildapkstep", QtWarningMsg) +class LibraryListModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + LibraryListModel(ProjectExplorer::BuildSystem *buildSystem, QObject *parent); + + QModelIndex index(int row, int column, const QModelIndex &) const override + { return createIndex(row, column); } + QModelIndex parent(const QModelIndex &) const override { return {}; } + int rowCount(const QModelIndex &) const override { return m_entries.size(); } + int columnCount(const QModelIndex &) const override { return 1; } + QVariant data(const QModelIndex &index, int role) const override; + + void removeEntries(QModelIndexList list); + void addEntries(const QStringList &list); + +signals: + void enabledChanged(bool); + +private: + void updateModel(); + + ProjectExplorer::BuildSystem *m_buildSystem; + QStringList m_entries; +}; + +LibraryListModel::LibraryListModel(BuildSystem *buildSystem, QObject *parent) + : QAbstractItemModel(parent) + , m_buildSystem(buildSystem) +{ + updateModel(); + + connect(buildSystem, &BuildSystem::parsingStarted, this, &LibraryListModel::updateModel); + connect(buildSystem, &BuildSystem::parsingFinished, this, &LibraryListModel::updateModel); + // Causes target()->activeBuildKey() result and consequently the node data + // extracted below to change. + connect(buildSystem->target(), &Target::activeRunConfigurationChanged, + this, &LibraryListModel::updateModel); +} + +QVariant LibraryListModel::data(const QModelIndex &index, int role) const +{ + QTC_ASSERT(index.row() >= 0 && index.row() < m_entries.size(), return {}); + if (role == Qt::DisplayRole) + return QDir::cleanPath(m_entries.at(index.row())); + return {}; +} + +void LibraryListModel::addEntries(const QStringList &list) +{ + const QString buildKey = m_buildSystem->target()->activeBuildKey(); + const ProjectNode *node = m_buildSystem->target()->project()->findNodeForBuildKey(buildKey); + QTC_ASSERT(node, return); + + beginInsertRows(QModelIndex(), m_entries.size(), m_entries.size() + list.size()); + + const QDir dir = node->filePath().toFileInfo().absoluteDir(); + for (const QString &path : list) + m_entries += "$$PWD/" + dir.relativeFilePath(path); + + m_buildSystem->setExtraData(buildKey, Constants::AndroidExtraLibs, m_entries); + endInsertRows(); +} + +static bool greaterModelIndexByRow(const QModelIndex &a, const QModelIndex &b) +{ + return a.row() > b.row(); +} + +void LibraryListModel::removeEntries(QModelIndexList list) +{ + if (list.isEmpty()) + return; + + std::sort(list.begin(), list.end(), greaterModelIndexByRow); + + int i = 0; + while (i < list.size()) { + int lastRow = list.at(i++).row(); + int firstRow = lastRow; + while (i < list.size() && firstRow - list.at(i).row() <= 1) + firstRow = list.at(i++).row(); + + beginRemoveRows(QModelIndex(), firstRow, lastRow); + int count = lastRow - firstRow + 1; + while (count-- > 0) + m_entries.removeAt(firstRow); + endRemoveRows(); + } + + const QString buildKey = m_buildSystem->target()->activeBuildKey(); + m_buildSystem->setExtraData(buildKey, Constants::AndroidExtraLibs, m_entries); +} + +void LibraryListModel::updateModel() +{ + const QString buildKey = m_buildSystem->target()->activeBuildKey(); + const ProjectNode *node = m_buildSystem->target()->project()->findNodeForBuildKey(buildKey); + if (!node) + return; + + if (node->parseInProgress()) { + emit enabledChanged(false); + return; + } + + bool enabled; + beginResetModel(); + if (node->validParse()) { + m_entries = node->data(Constants::AndroidExtraLibs).toStringList(); + enabled = true; + } else { + // parsing error + m_entries.clear(); + enabled = false; + } + endResetModel(); + + emit enabledChanged(enabled); +} + const char KeystoreLocationKey[] = "KeystoreLocation"; const char BuildTargetSdkKey[] = "BuildTargetSdk"; const char BuildToolsVersionKey[] = "BuildToolsVersion"; @@ -319,8 +440,8 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) auto additionalLibrariesGroup = new QGroupBox(Tr::tr("Additional Libraries")); additionalLibrariesGroup->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - auto libsModel = new AndroidExtraLibraryListModel(m_step->buildSystem(), this); - connect(libsModel, &AndroidExtraLibraryListModel::enabledChanged, this, + auto libsModel = new LibraryListModel(m_step->buildSystem(), this); + connect(libsModel, &LibraryListModel::enabledChanged, this, [this, additionalLibrariesGroup](const bool enabled) { additionalLibrariesGroup->setEnabled(enabled); m_openSslCheckBox->setChecked(isOpenSslLibsIncluded()); @@ -1107,7 +1228,6 @@ QString PasswordInputDialog::getPassword(Context context, std::functiontext() : QString(); } - // AndroidBuildApkStepFactory class AndroidBuildApkStepFactory final : public BuildStepFactory @@ -1129,3 +1249,5 @@ void setupAndroidBuildApkStep() } } // Android::Internal + +#include "androidbuildapkstep.moc" diff --git a/src/plugins/android/androidextralibrarylistmodel.cpp b/src/plugins/android/androidextralibrarylistmodel.cpp deleted file mode 100644 index eb1218c2a39..00000000000 --- a/src/plugins/android/androidextralibrarylistmodel.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (C) 2016 BogDan Vatra -// 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 "androidextralibrarylistmodel.h" - -#include "androidconstants.h" -#include "androidutils.h" - -#include -#include -#include -#include -#include - -#include - -using namespace ProjectExplorer; - -namespace Android::Internal { - -AndroidExtraLibraryListModel::AndroidExtraLibraryListModel(BuildSystem *buildSystem, - QObject *parent) - : QAbstractItemModel(parent), - m_buildSystem(buildSystem) -{ - updateModel(); - - connect(buildSystem, &BuildSystem::parsingStarted, - this, &AndroidExtraLibraryListModel::updateModel); - connect(buildSystem, &BuildSystem::parsingFinished, - this, &AndroidExtraLibraryListModel::updateModel); - // Causes target()->activeBuildKey() result and consequently the node data - // extracted below to change. - connect(buildSystem->target(), &Target::activeRunConfigurationChanged, - this, &AndroidExtraLibraryListModel::updateModel); -} - -QModelIndex AndroidExtraLibraryListModel::index(int row, int column, const QModelIndex &) const -{ - return createIndex(row, column); -} - -QModelIndex AndroidExtraLibraryListModel::parent(const QModelIndex &) const -{ - return {}; -} - -int AndroidExtraLibraryListModel::rowCount(const QModelIndex &) const -{ - return m_entries.size(); -} - -int AndroidExtraLibraryListModel::columnCount(const QModelIndex &) const -{ - return 1; -} - -QVariant AndroidExtraLibraryListModel::data(const QModelIndex &index, int role) const -{ - QTC_ASSERT(index.row() >= 0 && index.row() < m_entries.size(), return {}); - if (role == Qt::DisplayRole) - return QDir::cleanPath(m_entries.at(index.row())); - return {}; -} - -void AndroidExtraLibraryListModel::updateModel() -{ - const QString buildKey = m_buildSystem->target()->activeBuildKey(); - const ProjectNode *node = m_buildSystem->target()->project()->findNodeForBuildKey(buildKey); - if (!node) - return; - - if (node->parseInProgress()) { - emit enabledChanged(false); - return; - } - - bool enabled; - beginResetModel(); - if (node->validParse()) { - m_entries = node->data(Constants::AndroidExtraLibs).toStringList(); - enabled = true; - } else { - // parsing error - m_entries.clear(); - enabled = false; - } - endResetModel(); - - emit enabledChanged(enabled); -} - -void AndroidExtraLibraryListModel::addEntries(const QStringList &list) -{ - const QString buildKey = m_buildSystem->target()->activeBuildKey(); - const ProjectNode *node = m_buildSystem->target()->project()->findNodeForBuildKey(buildKey); - QTC_ASSERT(node, return); - - beginInsertRows(QModelIndex(), m_entries.size(), m_entries.size() + list.size()); - - const QDir dir = node->filePath().toFileInfo().absoluteDir(); - for (const QString &path : list) - m_entries += "$$PWD/" + dir.relativeFilePath(path); - - m_buildSystem->setExtraData(buildKey, Constants::AndroidExtraLibs, m_entries); - endInsertRows(); -} - -bool greaterModelIndexByRow(const QModelIndex &a, const QModelIndex &b) -{ - return a.row() > b.row(); -} - -void AndroidExtraLibraryListModel::removeEntries(QModelIndexList list) -{ - if (list.isEmpty()) - return; - - std::sort(list.begin(), list.end(), greaterModelIndexByRow); - - int i = 0; - while (i < list.size()) { - int lastRow = list.at(i++).row(); - int firstRow = lastRow; - while (i < list.size() && firstRow - list.at(i).row() <= 1) - firstRow = list.at(i++).row(); - - beginRemoveRows(QModelIndex(), firstRow, lastRow); - int count = lastRow - firstRow + 1; - while (count-- > 0) - m_entries.removeAt(firstRow); - endRemoveRows(); - } - - const QString buildKey = m_buildSystem->target()->activeBuildKey(); - m_buildSystem->setExtraData(buildKey, Constants::AndroidExtraLibs, m_entries); -} - -} // Android::Internal diff --git a/src/plugins/android/androidextralibrarylistmodel.h b/src/plugins/android/androidextralibrarylistmodel.h deleted file mode 100644 index e9378631a31..00000000000 --- a/src/plugins/android/androidextralibrarylistmodel.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2016 BogDan Vatra -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include - -namespace ProjectExplorer { class BuildSystem; } - -namespace Android::Internal { - -class AndroidExtraLibraryListModel : public QAbstractItemModel -{ - Q_OBJECT - -public: - AndroidExtraLibraryListModel(ProjectExplorer::BuildSystem *buildSystem, QObject *parent); - - QModelIndex index(int row, int column, const QModelIndex &parent) const override; - QModelIndex parent(const QModelIndex &child) const override; - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - - void removeEntries(QModelIndexList list); - void addEntries(const QStringList &list); - -signals: - void enabledChanged(bool); - -private: - void updateModel(); - - ProjectExplorer::BuildSystem *m_buildSystem; - QStringList m_entries; -}; - -} // namespace Android::Internal From 4a24d0b9092300b3bb298a0e2793f6ac8e0da084 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Nov 2024 13:47:11 +0100 Subject: [PATCH 125/989] Android: Code cosmetics in avdmanageroutputparser* Change-Id: I43f722d54198e9621762c148fa84e4cf37d8fe61 Reviewed-by: Jarek Kobus --- .../android/avdmanageroutputparser.cpp | 27 ++++++++++--------- src/plugins/android/avdmanageroutputparser.h | 2 -- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/plugins/android/avdmanageroutputparser.cpp b/src/plugins/android/avdmanageroutputparser.cpp index ecb3f77da75..2357b90dfe1 100644 --- a/src/plugins/android/avdmanageroutputparser.cpp +++ b/src/plugins/android/avdmanageroutputparser.cpp @@ -15,9 +15,11 @@ #include #include -namespace { -Q_LOGGING_CATEGORY(avdOutputParserLog, "qtc.android.avdOutputParser", QtWarningMsg) -} +using namespace Utils; + +namespace Android::Internal { + +static Q_LOGGING_CATEGORY(avdOutputParserLog, "qtc.android.avdOutputParser", QtWarningMsg) // Avd list keys to parse avd const char avdInfoNameKey[] = "Name:"; @@ -26,15 +28,15 @@ const char avdInfoAbiKey[] = "abi.type"; const char avdInfoTargetKey[] = "target"; const char avdInfoErrorKey[] = "Error:"; -namespace Android::Internal { +const char avdManufacturerError[] = "no longer exists as a device"; /*! Parses the \a line for a [spaces]key[spaces]value[spaces] pattern and returns \c true if the key is found, \c false otherwise. The value is copied into \a value. */ -static bool valueForKey(QString key, const QString &line, QString *value = nullptr) +static bool valueForKey(const QString &key, const QString &line, QString *value = nullptr) { - auto trimmedInput = line.trimmed(); + const QString trimmedInput = line.trimmed(); if (trimmedInput.startsWith(key)) { if (value) *value = trimmedInput.section(key, 1, 1).trimmed(); @@ -54,11 +56,11 @@ static std::optional parseAvd(const QStringList &deviceInfo) } else if (valueForKey(avdInfoNameKey, line, &value)) { avd.avdName = value; } else if (valueForKey(avdInfoPathKey, line, &value)) { - const Utils::FilePath avdPath = Utils::FilePath::fromUserInput(value); + const FilePath avdPath = FilePath::fromUserInput(value); avd.avdPath = avdPath; if (avdPath.exists()) { // Get ABI. - const Utils::FilePath configFile = avdPath.pathAppended("config.ini"); + const FilePath configFile = avdPath.pathAppended("config.ini"); QSettings config(configFile.toFSPathString(), QSettings::IniFormat); value = config.value(avdInfoAbiKey).toString(); if (!value.isEmpty()) @@ -68,8 +70,7 @@ static std::optional parseAvd(const QStringList &deviceInfo) // Get Target const QString avdInfoFileName = avd.avdName + ".ini"; - const Utils::FilePath avdInfoFile = avdPath.parentDir().pathAppended( - avdInfoFileName); + const FilePath avdInfoFile = avdPath.parentDir().pathAppended(avdInfoFileName); QSettings avdInfo(avdInfoFile.toFSPathString(), QSettings::IniFormat); value = avdInfo.value(avdInfoTargetKey).toString(); if (!value.isEmpty()) @@ -88,16 +89,16 @@ static std::optional parseAvd(const QStringList &deviceInfo) ParsedAvdList parseAvdList(const QString &output) { AndroidDeviceInfoList avdList; - Utils::FilePaths errorPaths; + FilePaths errorPaths; QStringList avdInfo; - using ErrorPath = Utils::FilePath; + using ErrorPath = FilePath; using AvdResult = std::variant; const auto parseAvdInfo = [](const QStringList &avdInfo) { if (!avdInfo.filter(avdManufacturerError).isEmpty()) { for (const QString &line : avdInfo) { QString value; if (valueForKey(avdInfoPathKey, line, &value)) - return AvdResult(Utils::FilePath::fromString(value)); // error path + return AvdResult(FilePath::fromString(value)); // error path } } else if (std::optional avd = parseAvd(avdInfo)) { // armeabi-v7a devices can also run armeabi code diff --git a/src/plugins/android/avdmanageroutputparser.h b/src/plugins/android/avdmanageroutputparser.h index 5bdcd2d370c..df72b3d6cb8 100644 --- a/src/plugins/android/avdmanageroutputparser.h +++ b/src/plugins/android/avdmanageroutputparser.h @@ -7,8 +7,6 @@ namespace Android::Internal { -const char avdManufacturerError[] = "no longer exists as a device"; - struct ParsedAvdList { AndroidDeviceInfoList avdList; From dde4b3e6969778322a9353b3d1497ad13b6cbb2b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 09:42:59 +0100 Subject: [PATCH 126/989] Android: Delete old packages when sdk command failed Fixes: QTCREATORBUG-31990 Change-Id: I50cb2f1e26ecb11a86206d1900ae519b05ba21b3 Reviewed-by: Assam Boudjelthia --- src/plugins/android/androidsdkmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 09b07b954e5..8725db518a9 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -538,6 +538,8 @@ void AndroidSdkManagerPrivate::reloadSdkPackages() if (AndroidConfig::sdkToolsVersion().isNull()) { // Configuration has invalid sdk path or corrupt installation. + qDeleteAll(m_allPackages); + m_allPackages.clear(); emit m_sdkManager.packagesReloaded(); return; } From 0244e45f131c3f54f7c0d1aa702b155a720afeb9 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 1 Nov 2024 15:45:17 +0100 Subject: [PATCH 127/989] Core: Code cosmetics in ThemeChooser Change-Id: I1f4b92b10ed9e3e04e28b7bb7312519ad2741af3 Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/coreplugin.cpp | 1 + src/plugins/coreplugin/themechooser.cpp | 74 +++++++++---------------- src/plugins/coreplugin/themechooser.h | 22 +++----- 3 files changed, 33 insertions(+), 64 deletions(-) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 263b6e89fde..08e249403fb 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -4,6 +4,7 @@ #include "coreplugin.h" #include "coreplugintr.h" #include "designmode.h" +#include "dialogs/ioptionspage.h" #include "editmode.h" #include "foldernavigationwidget.h" #include "icore.h" diff --git a/src/plugins/coreplugin/themechooser.cpp b/src/plugins/coreplugin/themechooser.cpp index 2056bd8d06b..2605c30b047 100644 --- a/src/plugins/coreplugin/themechooser.cpp +++ b/src/plugins/coreplugin/themechooser.cpp @@ -13,8 +13,6 @@ #include #include -#include -#include #include #include #include @@ -23,16 +21,14 @@ using namespace Utils; -static const char themeNameKey[] = "ThemeName"; +namespace Core::Internal { -namespace Core { -namespace Internal { +const char themeNameKey[] = "ThemeName"; ThemeEntry::ThemeEntry(Id id, const QString &filePath) : m_id(id) , m_filePath(filePath) -{ -} +{} Id ThemeEntry::id() const { @@ -54,20 +50,17 @@ QString ThemeEntry::filePath() const return m_filePath; } -class ThemeListModel : public QAbstractListModel +class ThemeListModel final : public QAbstractListModel { public: - ThemeListModel(QObject *parent = nullptr): - QAbstractListModel(parent) - { - } + ThemeListModel() = default; - int rowCount(const QModelIndex &parent) const override + int rowCount(const QModelIndex &parent) const final { return parent.isValid() ? 0 : m_themes.size(); } - QVariant data(const QModelIndex &index, int role) const override + QVariant data(const QModelIndex &index, int role) const final { if (role == Qt::DisplayRole) return m_themes.at(index.row()).displayName(); @@ -97,48 +90,32 @@ private: QList m_themes; }; - class ThemeChooserPrivate { public: - ThemeChooserPrivate(QWidget *widget); - ~ThemeChooserPrivate(); - -public: - ThemeListModel *m_themeListModel; + ThemeListModel m_themeListModel; QComboBox *m_themeComboBox; }; -ThemeChooserPrivate::ThemeChooserPrivate(QWidget *widget) - : m_themeListModel(new ThemeListModel) - , m_themeComboBox(new QComboBox) +ThemeChooser::ThemeChooser() + : d(new ThemeChooserPrivate) { - auto layout = new QHBoxLayout(widget); - layout->addWidget(m_themeComboBox); - auto overriddenLabel = new QLabel; - overriddenLabel->setText(Tr::tr("Current theme: %1").arg(creatorTheme()->displayName())); - layout->addWidget(overriddenLabel); - layout->setContentsMargins(0, 0, 0, 0); - auto horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - layout->addSpacerItem(horizontalSpacer); - m_themeComboBox->setModel(m_themeListModel); + d->m_themeComboBox = new QComboBox; + const QList themes = ThemeEntry::availableThemes(); - const Id themeSetting = ThemeEntry::themeSetting(); - const int selected = Utils::indexOf(themes, Utils::equal(&ThemeEntry::id, themeSetting)); - m_themeListModel->setThemes(themes); + d->m_themeListModel.setThemes(themes); + + d->m_themeComboBox->setModel(&d->m_themeListModel); + const int selected = + Utils::indexOf(themes, Utils::equal(&ThemeEntry::id, ThemeEntry::themeSetting())); if (selected >= 0) - m_themeComboBox->setCurrentIndex(selected); -} + d->m_themeComboBox->setCurrentIndex(selected); -ThemeChooserPrivate::~ThemeChooserPrivate() -{ - delete m_themeListModel; -} - -ThemeChooser::ThemeChooser(QWidget *parent) : - QWidget(parent) -{ - d = new ThemeChooserPrivate(this); + auto layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(d->m_themeComboBox); + layout->addWidget(new QLabel(Tr::tr("Current theme: %1").arg(creatorTheme()->displayName()))); + layout->addSpacerItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum)); } ThemeChooser::~ThemeChooser() @@ -157,7 +134,7 @@ void ThemeChooser::apply() const int index = d->m_themeComboBox->currentIndex(); if (index == -1) return; - const QString themeId = d->m_themeListModel->themeAt(index).id().toString(); + const QString themeId = d->m_themeListModel.themeAt(index).id().toString(); QtcSettings *settings = ICore::settings(); const QString currentThemeId = ThemeEntry::themeSetting().toString(); if (currentThemeId != themeId) { @@ -230,5 +207,4 @@ Theme *ThemeEntry::createTheme(Id id) return theme; } -} // namespace Internal -} // namespace Core +} // namespace Core::Internal diff --git a/src/plugins/coreplugin/themechooser.h b/src/plugins/coreplugin/themechooser.h index 360be3100c0..0c28101f35e 100644 --- a/src/plugins/coreplugin/themechooser.h +++ b/src/plugins/coreplugin/themechooser.h @@ -3,20 +3,15 @@ #pragma once -#include "dialogs/ioptionspage.h" - #include #include namespace Utils { class Theme; } -namespace Core { -namespace Internal { +namespace Core::Internal { -class ThemeChooserPrivate; - -class ThemeEntry +class ThemeEntry final { public: ThemeEntry() = default; @@ -35,19 +30,16 @@ private: mutable QString m_displayName; }; -class ThemeChooser : public QWidget +class ThemeChooser final : public QWidget { - Q_OBJECT - public: - ThemeChooser(QWidget *parent = nullptr); - ~ThemeChooser() override; + ThemeChooser(); + ~ThemeChooser() final; void apply(); private: - ThemeChooserPrivate *d; + class ThemeChooserPrivate *d; }; -} // namespace Internal -} // namespace Core +} // namespace Core::Internal From 641faec0f4109604dbd3b4256ef2b60673f30c07 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 15:24:13 +0100 Subject: [PATCH 128/989] Android: Inline CertificatesModel Change-Id: I098da61a38674572dc36dc05c893806a71a88981 Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 1 - src/plugins/android/android.qbs | 2 - src/plugins/android/androidbuildapkstep.cpp | 44 +++++++++++++++++++- src/plugins/android/certificatesmodel.cpp | 46 --------------------- src/plugins/android/certificatesmodel.h | 27 ------------ 5 files changed, 43 insertions(+), 77 deletions(-) delete mode 100644 src/plugins/android/certificatesmodel.cpp delete mode 100644 src/plugins/android/certificatesmodel.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 206ec703da5..97cb5e50729 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -33,7 +33,6 @@ add_qtc_plugin(Android androidutils.cpp androidutils.h avddialog.cpp avddialog.h avdmanageroutputparser.cpp avdmanageroutputparser.h - certificatesmodel.cpp certificatesmodel.h createandroidmanifestwizard.cpp createandroidmanifestwizard.h javaeditor.cpp javaeditor.h javaindenter.cpp javaindenter.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 056c07737c6..96be929f86f 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -69,8 +69,6 @@ QtcPlugin { "avddialog.h", "avdmanageroutputparser.cpp", "avdmanageroutputparser.h", - "certificatesmodel.cpp", - "certificatesmodel.h", "createandroidmanifestwizard.h", "createandroidmanifestwizard.cpp", "javaeditor.cpp", diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 2582afc4b1f..2421bd76a54 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -10,7 +10,6 @@ #include "androidsdkmanager.h" #include "androidtr.h" #include "androidutils.h" -#include "certificatesmodel.h" #include "createandroidmanifestwizard.h" #include "javaparser.h" @@ -65,6 +64,49 @@ namespace Android::Internal { static Q_LOGGING_CATEGORY(buildapkstepLog, "qtc.android.build.androidbuildapkstep", QtWarningMsg) +const QLatin1String AliasString("Alias name:"); +const QLatin1String CertificateSeparator("*******************************************"); + +class CertificatesModel : public QAbstractListModel +{ +public: + CertificatesModel(const QString &rowCertificates, QObject *parent) + : QAbstractListModel(parent) + { + int from = rowCertificates.indexOf(AliasString); + QPair item; + while (from > -1) { + from += 11;// strlen(AliasString); + const int eol = rowCertificates.indexOf(QLatin1Char('\n'), from); + item.first = rowCertificates.mid(from, eol - from).trimmed(); + const int eoc = rowCertificates.indexOf(CertificateSeparator, eol); + item.second = rowCertificates.mid(eol + 1, eoc - eol - 2).trimmed(); + from = rowCertificates.indexOf(AliasString, eoc); + m_certs.push_back(item); + } + } + +protected: + int rowCount(const QModelIndex &parent = {}) const override + { + if (parent.isValid()) + return 0; + return m_certs.size(); + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override + { + if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::ToolTipRole)) + return {}; + if (role == Qt::DisplayRole) + return m_certs[index.row()].first; + return m_certs[index.row()].second; + } + +private: + QList> m_certs; +}; + class LibraryListModel : public QAbstractItemModel { Q_OBJECT diff --git a/src/plugins/android/certificatesmodel.cpp b/src/plugins/android/certificatesmodel.cpp deleted file mode 100644 index 7ba86cfafe6..00000000000 --- a/src/plugins/android/certificatesmodel.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2016 BogDan Vatra -// 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 "certificatesmodel.h" - -#include - -namespace Android::Internal { - -const QLatin1String AliasString("Alias name:"); -const QLatin1String CertificateSeparator("*******************************************"); - -CertificatesModel::CertificatesModel(const QString &rowCertificates, QObject *parent) - : QAbstractListModel(parent) -{ - int from = rowCertificates.indexOf(AliasString); - QPair item; - while (from > -1) { - from += 11;// strlen(AliasString); - const int eol = rowCertificates.indexOf(QLatin1Char('\n'), from); - item.first = rowCertificates.mid(from, eol - from).trimmed(); - const int eoc = rowCertificates.indexOf(CertificateSeparator, eol); - item.second = rowCertificates.mid(eol + 1, eoc - eol - 2).trimmed(); - from = rowCertificates.indexOf(AliasString, eoc); - m_certs.push_back(item); - } -} - -int CertificatesModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) - return 0; - return m_certs.size(); -} - -QVariant CertificatesModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::ToolTipRole)) - return {}; - if (role == Qt::DisplayRole) - return m_certs[index.row()].first; - return m_certs[index.row()].second; -} - -} // namespace Android::Internal diff --git a/src/plugins/android/certificatesmodel.h b/src/plugins/android/certificatesmodel.h deleted file mode 100644 index 5a3b933047c..00000000000 --- a/src/plugins/android/certificatesmodel.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2016 BogDan Vatra -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include -#include - -namespace Android::Internal { - -class CertificatesModel: public QAbstractListModel -{ -public: - CertificatesModel(const QString &rowCertificates, QObject *parent); - -protected: - int rowCount(const QModelIndex &parent = {}) const override; - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - -private: - QList> m_certs; -}; - -} // namespace Android::Internal From c45684db94f35e6b50766d01ed9cb20746423234 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 16:05:40 +0100 Subject: [PATCH 129/989] Android: Give CreateAndroidManifestWizard a parent Change-Id: I245aeec688e244ef01c8502dd7afc5b37de0c46e Reviewed-by: hjk --- src/plugins/android/createandroidmanifestwizard.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/createandroidmanifestwizard.cpp b/src/plugins/android/createandroidmanifestwizard.cpp index 40b3f3d83a4..de79f197e02 100644 --- a/src/plugins/android/createandroidmanifestwizard.cpp +++ b/src/plugins/android/createandroidmanifestwizard.cpp @@ -8,6 +8,7 @@ #include "androidutils.h" #include +#include #include #include @@ -226,7 +227,8 @@ void ChooseDirectoryPage::initializePage() // CreateAndroidManifestWizard // CreateAndroidManifestWizard::CreateAndroidManifestWizard(BuildSystem *buildSystem) - : m_buildSystem(buildSystem) + : Wizard(Core::ICore::dialogParent()) + , m_buildSystem(buildSystem) { setWindowTitle(Tr::tr("Create Android Template Files Wizard")); From a42fad9a8bff50d118b11539c55a402f58667d37 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 16:16:09 +0100 Subject: [PATCH 130/989] Android: Hide CreateAndroidManifestWizard in cpp Rename it to manifestwizard.h. Provide executeManifestWizard() global function. Change-Id: Ibe27d7b1fdb346dc10c04d0e0476d719091f5bb3 Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 2 +- src/plugins/android/android.qbs | 4 +- src/plugins/android/androidbuildapkstep.cpp | 5 +- .../android/createandroidmanifestwizard.h | 39 ------- ...dmanifestwizard.cpp => manifestwizard.cpp} | 108 ++++++------------ src/plugins/android/manifestwizard.h | 12 ++ 6 files changed, 55 insertions(+), 115 deletions(-) delete mode 100644 src/plugins/android/createandroidmanifestwizard.h rename src/plugins/android/{createandroidmanifestwizard.cpp => manifestwizard.cpp} (87%) create mode 100644 src/plugins/android/manifestwizard.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 97cb5e50729..68fe8ea2504 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -33,11 +33,11 @@ add_qtc_plugin(Android androidutils.cpp androidutils.h avddialog.cpp avddialog.h avdmanageroutputparser.cpp avdmanageroutputparser.h - createandroidmanifestwizard.cpp createandroidmanifestwizard.h javaeditor.cpp javaeditor.h javaindenter.cpp javaindenter.h javalanguageserver.cpp javalanguageserver.h javaparser.cpp javaparser.h + manifestwizard.cpp manifestwizard.h splashscreencontainerwidget.cpp splashscreencontainerwidget.h sdkmanageroutputparser.cpp sdkmanageroutputparser.h ) diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 96be929f86f..5382ef596c0 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -69,8 +69,6 @@ QtcPlugin { "avddialog.h", "avdmanageroutputparser.cpp", "avdmanageroutputparser.h", - "createandroidmanifestwizard.h", - "createandroidmanifestwizard.cpp", "javaeditor.cpp", "javaeditor.h", "javaindenter.cpp", @@ -79,6 +77,8 @@ QtcPlugin { "javalanguageserver.h", "javaparser.cpp", "javaparser.h", + "manifestwizard.h", + "manifestwizard.cpp", "splashscreencontainerwidget.cpp", "splashscreencontainerwidget.h", "sdkmanageroutputparser.cpp", diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 2421bd76a54..4cb750cbdc2 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -10,7 +10,7 @@ #include "androidsdkmanager.h" #include "androidtr.h" #include "androidutils.h" -#include "createandroidmanifestwizard.h" +#include "manifestwizard.h" #include "javaparser.h" #include @@ -442,8 +442,7 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) createAndroidTemplatesButton->setToolTip( Tr::tr("Create an Android package for Custom Java code, assets, and Gradle configurations.")); connect(createAndroidTemplatesButton, &QAbstractButton::clicked, this, [this] { - CreateAndroidManifestWizard wizard(m_step->buildSystem()); - wizard.exec(); + executeManifestWizard(m_step->buildSystem()); }); Group applicationGroup { diff --git a/src/plugins/android/createandroidmanifestwizard.h b/src/plugins/android/createandroidmanifestwizard.h deleted file mode 100644 index b00dff4a80c..00000000000 --- a/src/plugins/android/createandroidmanifestwizard.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include - -namespace ProjectExplorer { class BuildSystem; } - -namespace Android::Internal { - -class CreateAndroidManifestWizard : public Utils::Wizard -{ -public: - CreateAndroidManifestWizard(ProjectExplorer::BuildSystem *buildSystem); - - QString buildKey() const; - void setBuildKey(const QString &buildKey); - - void accept() override; - bool copyGradleTemplates() const; - bool allowGradleTemplates() const; - - void setDirectory(const Utils::FilePath &directory); - void setCopyGradleTemplates(bool copy); - - ProjectExplorer::BuildSystem *buildSystem() const; - -private: - void createAndroidManifestFile(); - void createAndroidTemplateFiles(); - ProjectExplorer::BuildSystem *m_buildSystem; - QString m_buildKey; - Utils::FilePath m_directory; - bool m_copyGradleTemplates; -}; - -} // Android::Internal diff --git a/src/plugins/android/createandroidmanifestwizard.cpp b/src/plugins/android/manifestwizard.cpp similarity index 87% rename from src/plugins/android/createandroidmanifestwizard.cpp rename to src/plugins/android/manifestwizard.cpp index de79f197e02..3627c118173 100644 --- a/src/plugins/android/createandroidmanifestwizard.cpp +++ b/src/plugins/android/manifestwizard.cpp @@ -1,10 +1,10 @@ // 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 "createandroidmanifestwizard.h" +#include "manifestwizard.h" -#include "androidtr.h" #include "androidconstants.h" +#include "androidtr.h" #include "androidutils.h" #include @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -36,9 +37,35 @@ using namespace Utils; namespace Android::Internal { -// -// NoApplicationTargetPage -// +class CreateAndroidManifestWizard : public Wizard +{ +public: + CreateAndroidManifestWizard(BuildSystem *buildSystem); + + QString buildKey() const { return m_buildKey; } + void setBuildKey(const QString &buildKey) { m_buildKey = buildKey; } + + void accept() override + { + createAndroidTemplateFiles(); + Wizard::accept(); + } + bool copyGradleTemplates() const { return m_copyGradleTemplates; } + bool allowGradleTemplates() const + { return bool(QtSupport::QtKitAspect::qtVersion(m_buildSystem->kit())); } + void setDirectory(const FilePath &directory) { m_directory = directory; } + void setCopyGradleTemplates(bool copy) { m_copyGradleTemplates = copy; } + + BuildSystem *buildSystem() const { return m_buildSystem; } + +private: + void createAndroidManifestFile(); + void createAndroidTemplateFiles(); + BuildSystem *m_buildSystem; + QString m_buildKey; + FilePath m_directory; + bool m_copyGradleTemplates; +}; class NoApplicationTargetPage : public QWizardPage { @@ -56,18 +83,14 @@ NoApplicationTargetPage::NoApplicationTargetPage(CreateAndroidManifestWizard *) setTitle(Tr::tr("No Application Build Target")); } - -// -// ChooseProFilePage -// - class ChooseProFilePage : public QWizardPage { public: explicit ChooseProFilePage(CreateAndroidManifestWizard *wizard); private: - void nodeSelected(int index); + void nodeSelected() + { m_wizard->setBuildKey(m_comboBox->itemData(m_comboBox->currentIndex()).toString()); } CreateAndroidManifestWizard *m_wizard; QComboBox *m_comboBox; @@ -93,24 +116,13 @@ ChooseProFilePage::ChooseProFilePage(CreateAndroidManifestWizard *wizard) m_comboBox->setCurrentIndex(m_comboBox->count() - 1); } - nodeSelected(m_comboBox->currentIndex()); + nodeSelected(); connect(m_comboBox, &QComboBox::currentIndexChanged, this, &ChooseProFilePage::nodeSelected); fl->addRow(Tr::tr("Build target:"), m_comboBox); setTitle(Tr::tr("Select a build target")); } -void ChooseProFilePage::nodeSelected(int index) -{ - Q_UNUSED(index) - m_wizard->setBuildKey(m_comboBox->itemData(m_comboBox->currentIndex()).toString()); -} - - -// -// ChooseDirectoryPage -// - class ChooseDirectoryPage : public QWizardPage { public: @@ -118,7 +130,7 @@ public: private: void initializePage() final; - bool isComplete() const final; + bool isComplete() const final { return m_complete; } void checkPackageSourceDir(); CreateAndroidManifestWizard *m_wizard; @@ -184,11 +196,6 @@ void ChooseDirectoryPage::checkPackageSourceDir() } } -bool ChooseDirectoryPage::isComplete() const -{ - return m_complete; -} - void ChooseDirectoryPage::initializePage() { const Target *target = m_wizard->buildSystem()->target(); @@ -223,9 +230,6 @@ void ChooseDirectoryPage::initializePage() m_wizard->setDirectory(m_androidPackageSourceDir->filePath()); } -// -// CreateAndroidManifestWizard -// CreateAndroidManifestWizard::CreateAndroidManifestWizard(BuildSystem *buildSystem) : Wizard(Core::ICore::dialogParent()) , m_buildSystem(buildSystem) @@ -246,36 +250,6 @@ CreateAndroidManifestWizard::CreateAndroidManifestWizard(BuildSystem *buildSyste } } -QString CreateAndroidManifestWizard::buildKey() const -{ - return m_buildKey; -} - -void CreateAndroidManifestWizard::setBuildKey(const QString &buildKey) -{ - m_buildKey = buildKey; -} - -void CreateAndroidManifestWizard::setDirectory(const FilePath &directory) -{ - m_directory = directory; -} - -bool CreateAndroidManifestWizard::copyGradleTemplates() const -{ - return m_copyGradleTemplates; -} - -bool CreateAndroidManifestWizard::allowGradleTemplates() const -{ - return bool(QtSupport::QtKitAspect::qtVersion(m_buildSystem->kit())); -} - -void CreateAndroidManifestWizard::setCopyGradleTemplates(bool copy) -{ - m_copyGradleTemplates = copy; -} - void CreateAndroidManifestWizard::createAndroidTemplateFiles() { if (m_directory.isEmpty()) @@ -322,15 +296,9 @@ void CreateAndroidManifestWizard::createAndroidTemplateFiles() Core::EditorManager::openEditor(m_directory / "AndroidManifest.xml"); } -BuildSystem *CreateAndroidManifestWizard::buildSystem() const +void executeManifestWizard(BuildSystem *buildSystem) { - return m_buildSystem; -} - -void CreateAndroidManifestWizard::accept() -{ - createAndroidTemplateFiles(); - Wizard::accept(); + CreateAndroidManifestWizard(buildSystem).exec(); } } // namespace Android::Internal diff --git a/src/plugins/android/manifestwizard.h b/src/plugins/android/manifestwizard.h new file mode 100644 index 00000000000..8a94e146282 --- /dev/null +++ b/src/plugins/android/manifestwizard.h @@ -0,0 +1,12 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace ProjectExplorer { class BuildSystem; } + +namespace Android::Internal { + +void executeManifestWizard(ProjectExplorer::BuildSystem *buildSystem); + +} // Android::Internal From 3eec07c71755f86aaee413ccbbc5c70cf1959b37 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 16:23:18 +0100 Subject: [PATCH 131/989] Android: Hide m_packages field in private section Change-Id: I26719e1a6c654c4e42e59c88c695c9722b3aa253 Reviewed-by: hjk --- src/plugins/android/sdkmanageroutputparser.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/android/sdkmanageroutputparser.h b/src/plugins/android/sdkmanageroutputparser.h index 5dd9b23366d..7d958db95d5 100644 --- a/src/plugins/android/sdkmanageroutputparser.h +++ b/src/plugins/android/sdkmanageroutputparser.h @@ -36,8 +36,6 @@ public: SdkManagerOutputParser(AndroidSdkPackageList &container) : m_packages(container) {} void parsePackageListing(const QString &output); - AndroidSdkPackageList &m_packages; - private: void compilePackageAssociations(); void parsePackageData(MarkerTag packageMarker, const QStringList &data); @@ -52,6 +50,7 @@ private: AndroidSdkPackage *parseGenericTools(const QStringList &data) const; MarkerTag parseMarkers(const QString &line); + AndroidSdkPackageList &m_packages; MarkerTag m_currentSection = MarkerTag::None; QHash m_systemImages; friend class SdkManagerOutputParserTest; From 20dd57c3b27c7d9ca0fdd9c71499625be1bfd48d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 16:33:43 +0100 Subject: [PATCH 132/989] Android: Introduce KeystoreData And use it in AndroidCreateKeystoreCertificate. Change-Id: I529cec970a60c6162b5f5fde9219767a01bdaca0 Reviewed-by: hjk --- src/plugins/android/androidbuildapkstep.cpp | 11 ++++--- .../androidcreatekeystorecertificate.cpp | 31 ++++++------------- .../androidcreatekeystorecertificate.h | 14 ++++++--- 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 4cb750cbdc2..d9615d3f6b2 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -355,11 +355,12 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) AndroidCreateKeystoreCertificate d; if (d.exec() != QDialog::Accepted) return; - keystoreLocationChooser->setFilePath(d.keystoreFilePath()); - m_step->setKeystorePath(d.keystoreFilePath()); - m_step->setKeystorePassword(d.keystorePassword()); - m_step->setCertificateAlias(d.certificateAlias()); - m_step->setCertificatePassword(d.certificatePassword()); + const KeystoreData data = d.keystoreData(); + keystoreLocationChooser->setFilePath(data.keystoreFilePath); + m_step->setKeystorePath(data.keystoreFilePath); + m_step->setKeystorePassword(data.keystorePassword); + m_step->setCertificateAlias(data.certificateAlias); + m_step->setCertificatePassword(data.certificatePassword); setCertificates(); }); diff --git a/src/plugins/android/androidcreatekeystorecertificate.cpp b/src/plugins/android/androidcreatekeystorecertificate.cpp index ed36c9f4656..61b5decbb22 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.cpp +++ b/src/plugins/android/androidcreatekeystorecertificate.cpp @@ -145,26 +145,12 @@ AndroidCreateKeystoreCertificate::AndroidCreateKeystoreCertificate(QWidget *pare AndroidCreateKeystoreCertificate::~AndroidCreateKeystoreCertificate() = default; -FilePath AndroidCreateKeystoreCertificate::keystoreFilePath() const +KeystoreData AndroidCreateKeystoreCertificate::keystoreData() const { - return m_keystoreFilePath; -} - -QString AndroidCreateKeystoreCertificate::keystorePassword() const -{ - return m_keystorePassLineEdit->text(); -} - -QString AndroidCreateKeystoreCertificate::certificateAlias() const -{ - return m_certificateAliasLineEdit->text(); -} - -QString AndroidCreateKeystoreCertificate::certificatePassword() const -{ - return (m_samePasswordCheckBox->checkState() == Qt::Checked) - ? keystorePassword() - : m_certificatePassLineEdit->text(); + const QString certPassword = m_samePasswordCheckBox->checkState() == Qt::Checked + ? m_keystorePassLineEdit->text() : m_certificatePassLineEdit->text(); + return {m_keystoreFilePath, m_keystorePassLineEdit->text(), m_certificateAliasLineEdit->text(), + certPassword}; } AndroidCreateKeystoreCertificate::PasswordStatus AndroidCreateKeystoreCertificate::checkKeystorePassword() @@ -263,15 +249,16 @@ void AndroidCreateKeystoreCertificate::buttonBoxAccepted() if (!m_stateNameLineEdit->text().isEmpty()) distinguishedNames += QLatin1String(", S=") + m_stateNameLineEdit->text().replace(',', QLatin1String("\\,")); + const KeystoreData data = keystoreData(); // clang-format off const CommandLine command(AndroidConfig::keytoolPath(), {"-genkey", "-keyalg", "RSA", "-keystore", m_keystoreFilePath.path(), - "-storepass", keystorePassword(), - "-alias", certificateAlias(), + "-storepass", data.keystorePassword, + "-alias", data.certificateAlias, "-keysize", m_keySizeSpinBox->text(), "-validity", m_validitySpinBox->text(), - "-keypass", certificatePassword(), + "-keypass", data.certificatePassword, "-dname", distinguishedNames}); // clang-format off diff --git a/src/plugins/android/androidcreatekeystorecertificate.h b/src/plugins/android/androidcreatekeystorecertificate.h index 23ab38d5156..81c6369c5bc 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.h +++ b/src/plugins/android/androidcreatekeystorecertificate.h @@ -17,6 +17,15 @@ namespace Utils { class InfoLabel; } namespace Android::Internal { +class KeystoreData +{ +public: + Utils::FilePath keystoreFilePath; + QString keystorePassword; + QString certificateAlias; + QString certificatePassword; +}; + class AndroidCreateKeystoreCertificate : public QDialog { enum PasswordStatus @@ -30,10 +39,7 @@ public: explicit AndroidCreateKeystoreCertificate(QWidget *parent = nullptr); ~AndroidCreateKeystoreCertificate() override; - Utils::FilePath keystoreFilePath() const; - QString keystorePassword() const; - QString certificateAlias() const; - QString certificatePassword() const; + KeystoreData keystoreData() const; private: PasswordStatus checkKeystorePassword(); From 53b76a000c267e9396ef90dc5a9d904d852f4e44 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 16:36:51 +0100 Subject: [PATCH 133/989] Android: Give AndroidCreateKeystoreCertificate a parent Change-Id: Ia973c42c41bbe0f536279d1535fba68439c8d25b Reviewed-by: hjk --- src/plugins/android/androidcreatekeystorecertificate.cpp | 8 ++++---- src/plugins/android/androidcreatekeystorecertificate.h | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/android/androidcreatekeystorecertificate.cpp b/src/plugins/android/androidcreatekeystorecertificate.cpp index 61b5decbb22..b49fba7f9bd 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.cpp +++ b/src/plugins/android/androidcreatekeystorecertificate.cpp @@ -6,6 +6,8 @@ #include "androidconfigurations.h" #include "androidtr.h" +#include + #include #include #include @@ -22,8 +24,8 @@ using namespace Utils; namespace Android::Internal { -AndroidCreateKeystoreCertificate::AndroidCreateKeystoreCertificate(QWidget *parent) - : QDialog(parent) +AndroidCreateKeystoreCertificate::AndroidCreateKeystoreCertificate() + : QDialog(Core::ICore::dialogParent()) { resize(638, 473); setWindowTitle(Tr::tr("Create a keystore and a certificate")); @@ -143,8 +145,6 @@ AndroidCreateKeystoreCertificate::AndroidCreateKeystoreCertificate(QWidget *pare m_keystoreRetypePassLineEdit, QOverload<>::of(&QWidget::setFocus)); } -AndroidCreateKeystoreCertificate::~AndroidCreateKeystoreCertificate() = default; - KeystoreData AndroidCreateKeystoreCertificate::keystoreData() const { const QString certPassword = m_samePasswordCheckBox->checkState() == Qt::Checked diff --git a/src/plugins/android/androidcreatekeystorecertificate.h b/src/plugins/android/androidcreatekeystorecertificate.h index 81c6369c5bc..bd8ffd5a961 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.h +++ b/src/plugins/android/androidcreatekeystorecertificate.h @@ -36,8 +36,7 @@ class AndroidCreateKeystoreCertificate : public QDialog }; public: - explicit AndroidCreateKeystoreCertificate(QWidget *parent = nullptr); - ~AndroidCreateKeystoreCertificate() override; + explicit AndroidCreateKeystoreCertificate(); KeystoreData keystoreData() const; @@ -74,4 +73,6 @@ private: Utils::InfoLabel *m_infoLabel; }; +KeystoreData executeKeystoreCertificateDialog(); + } // Android::Internal From 1ebe00d19ec132bae29f38e27cb6c26576a801e8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 16:45:25 +0100 Subject: [PATCH 134/989] Android: Hide AndroidCreateKeystoreCertificate in cpp Rename it to keystorecertificatedialog.h. Provide executeKeystoreCertificateDialog() global function. Change-Id: I2b019c8fc242f4f453de370085da93be8f404338 Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 2 +- src/plugins/android/android.qbs | 4 +- src/plugins/android/androidbuildapkstep.cpp | 17 ++-- .../androidcreatekeystorecertificate.h | 78 ------------------- ...cate.cpp => keystorecertificatedialog.cpp} | 57 +++++++++++++- .../android/keystorecertificatedialog.h | 21 +++++ 6 files changed, 88 insertions(+), 91 deletions(-) delete mode 100644 src/plugins/android/androidcreatekeystorecertificate.h rename src/plugins/android/{androidcreatekeystorecertificate.cpp => keystorecertificatedialog.cpp} (88%) create mode 100644 src/plugins/android/keystorecertificatedialog.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 68fe8ea2504..bfa038b1476 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -9,7 +9,6 @@ add_qtc_plugin(Android androidbuildapkstep.cpp androidbuildapkstep.h androidconfigurations.cpp androidconfigurations.h androidconstants.h - androidcreatekeystorecertificate.cpp androidcreatekeystorecertificate.h androiddebugsupport.cpp androiddebugsupport.h androiddeployqtstep.cpp androiddeployqtstep.h androiddevice.cpp androiddevice.h @@ -37,6 +36,7 @@ add_qtc_plugin(Android javaindenter.cpp javaindenter.h javalanguageserver.cpp javalanguageserver.h javaparser.cpp javaparser.h + keystorecertificatedialog.cpp keystorecertificatedialog.h manifestwizard.cpp manifestwizard.h splashscreencontainerwidget.cpp splashscreencontainerwidget.h sdkmanageroutputparser.cpp sdkmanageroutputparser.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 5382ef596c0..785dc5b0564 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -20,8 +20,6 @@ QtcPlugin { "androidconfigurations.cpp", "androidconfigurations.h", "androidconstants.h", - "androidcreatekeystorecertificate.cpp", - "androidcreatekeystorecertificate.h", "androidbuildapkstep.cpp", "androidbuildapkstep.h", "androiddeployqtstep.cpp", @@ -77,6 +75,8 @@ QtcPlugin { "javalanguageserver.h", "javaparser.cpp", "javaparser.h", + "keystorecertificatedialog.cpp", + "keystorecertificatedialog.h", "manifestwizard.h", "manifestwizard.cpp", "splashscreencontainerwidget.cpp", diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index d9615d3f6b2..4c99a617e23 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -5,11 +5,11 @@ #include "androidbuildapkstep.h" #include "androidconfigurations.h" #include "androidconstants.h" -#include "androidcreatekeystorecertificate.h" #include "androidqtversion.h" #include "androidsdkmanager.h" #include "androidtr.h" #include "androidutils.h" +#include "keystorecertificatedialog.h" #include "manifestwizard.h" #include "javaparser.h" @@ -352,15 +352,14 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) auto keystoreCreateButton = new QPushButton(Tr::tr("Create...")); connect(keystoreCreateButton, &QAbstractButton::clicked, this, [this, keystoreLocationChooser] { - AndroidCreateKeystoreCertificate d; - if (d.exec() != QDialog::Accepted) + const auto data = executeKeystoreCertificateDialog(); + if (!data) return; - const KeystoreData data = d.keystoreData(); - keystoreLocationChooser->setFilePath(data.keystoreFilePath); - m_step->setKeystorePath(data.keystoreFilePath); - m_step->setKeystorePassword(data.keystorePassword); - m_step->setCertificateAlias(data.certificateAlias); - m_step->setCertificatePassword(data.certificatePassword); + keystoreLocationChooser->setFilePath(data->keystoreFilePath); + m_step->setKeystorePath(data->keystoreFilePath); + m_step->setKeystorePassword(data->keystorePassword); + m_step->setCertificateAlias(data->certificateAlias); + m_step->setCertificatePassword(data->certificatePassword); setCertificates(); }); diff --git a/src/plugins/android/androidcreatekeystorecertificate.h b/src/plugins/android/androidcreatekeystorecertificate.h deleted file mode 100644 index bd8ffd5a961..00000000000 --- a/src/plugins/android/androidcreatekeystorecertificate.h +++ /dev/null @@ -1,78 +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 - -#include - -#include - -QT_BEGIN_NAMESPACE -class QCheckBox; -class QLineEdit; -class QSpinBox; -QT_END_NAMESPACE - -namespace Utils { class InfoLabel; } - -namespace Android::Internal { - -class KeystoreData -{ -public: - Utils::FilePath keystoreFilePath; - QString keystorePassword; - QString certificateAlias; - QString certificatePassword; -}; - -class AndroidCreateKeystoreCertificate : public QDialog -{ - enum PasswordStatus - { - Invalid, - NoMatch, - Match - }; - -public: - explicit AndroidCreateKeystoreCertificate(); - - KeystoreData keystoreData() const; - -private: - PasswordStatus checkKeystorePassword(); - PasswordStatus checkCertificatePassword(); - bool checkCertificateAlias(); - bool checkCountryCode(); - - void keystoreShowPassStateChanged(int state); - void certificateShowPassStateChanged(int state); - void buttonBoxAccepted(); - void samePasswordStateChanged(int state); - - bool validateUserInput(); - - Utils::FilePath m_keystoreFilePath; - - QLineEdit *m_commonNameLineEdit; - QLineEdit *m_organizationUnitLineEdit; - QLineEdit *m_organizationNameLineEdit; - QLineEdit *m_localityNameLineEdit; - QLineEdit *m_stateNameLineEdit; - QLineEdit *m_countryLineEdit; - QLineEdit *m_certificateRetypePassLineEdit; - QCheckBox *m_certificateShowPassCheckBox; - QSpinBox *m_validitySpinBox; - QLineEdit *m_certificateAliasLineEdit; - QLineEdit *m_certificatePassLineEdit; - QSpinBox *m_keySizeSpinBox; - QCheckBox *m_samePasswordCheckBox; - QLineEdit *m_keystorePassLineEdit; - QLineEdit *m_keystoreRetypePassLineEdit; - Utils::InfoLabel *m_infoLabel; -}; - -KeystoreData executeKeystoreCertificateDialog(); - -} // Android::Internal diff --git a/src/plugins/android/androidcreatekeystorecertificate.cpp b/src/plugins/android/keystorecertificatedialog.cpp similarity index 88% rename from src/plugins/android/androidcreatekeystorecertificate.cpp rename to src/plugins/android/keystorecertificatedialog.cpp index b49fba7f9bd..df746b8e84a 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.cpp +++ b/src/plugins/android/keystorecertificatedialog.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2016 BogDan Vatra // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "androidcreatekeystorecertificate.h" +#include "keystorecertificatedialog.h" #include "androidconfigurations.h" #include "androidtr.h" @@ -24,6 +24,53 @@ using namespace Utils; namespace Android::Internal { +class AndroidCreateKeystoreCertificate : public QDialog +{ + enum PasswordStatus + { + Invalid, + NoMatch, + Match + }; + +public: + explicit AndroidCreateKeystoreCertificate(); + + KeystoreData keystoreData() const; + +private: + PasswordStatus checkKeystorePassword(); + PasswordStatus checkCertificatePassword(); + bool checkCertificateAlias(); + bool checkCountryCode(); + + void keystoreShowPassStateChanged(int state); + void certificateShowPassStateChanged(int state); + void buttonBoxAccepted(); + void samePasswordStateChanged(int state); + + bool validateUserInput(); + + Utils::FilePath m_keystoreFilePath; + + QLineEdit *m_commonNameLineEdit; + QLineEdit *m_organizationUnitLineEdit; + QLineEdit *m_organizationNameLineEdit; + QLineEdit *m_localityNameLineEdit; + QLineEdit *m_stateNameLineEdit; + QLineEdit *m_countryLineEdit; + QLineEdit *m_certificateRetypePassLineEdit; + QCheckBox *m_certificateShowPassCheckBox; + QSpinBox *m_validitySpinBox; + QLineEdit *m_certificateAliasLineEdit; + QLineEdit *m_certificatePassLineEdit; + QSpinBox *m_keySizeSpinBox; + QCheckBox *m_samePasswordCheckBox; + QLineEdit *m_keystorePassLineEdit; + QLineEdit *m_keystoreRetypePassLineEdit; + Utils::InfoLabel *m_infoLabel; +}; + AndroidCreateKeystoreCertificate::AndroidCreateKeystoreCertificate() : QDialog(Core::ICore::dialogParent()) { @@ -329,4 +376,12 @@ bool AndroidCreateKeystoreCertificate::validateUserInput() return true; } +std::optional executeKeystoreCertificateDialog() +{ + AndroidCreateKeystoreCertificate dialog; + if (dialog.exec() != QDialog::Accepted) + return {}; + return dialog.keystoreData(); +} + } // Android::Internal diff --git a/src/plugins/android/keystorecertificatedialog.h b/src/plugins/android/keystorecertificatedialog.h new file mode 100644 index 00000000000..b0bd66aaf19 --- /dev/null +++ b/src/plugins/android/keystorecertificatedialog.h @@ -0,0 +1,21 @@ +// Copyright (C) 2016 BogDan Vatra +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Android::Internal { + +class KeystoreData +{ +public: + Utils::FilePath keystoreFilePath; + QString keystorePassword; + QString certificateAlias; + QString certificatePassword; +}; + +std::optional executeKeystoreCertificateDialog(); + +} // Android::Internal From 11f97c1f2bbeed342f0f8115a928ecdcba0fcb10 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 15:43:12 +0100 Subject: [PATCH 135/989] Android: Inline AndroidSdkModel Change-Id: I2946a318ed01cee0e5efc7c04eb902ae7d06978e Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 1 - src/plugins/android/android.qbs | 2 - .../android/androidsdkmanagerdialog.cpp | 303 +++++++++++++++++- src/plugins/android/androidsdkmodel.cpp | 295 ----------------- src/plugins/android/androidsdkmodel.h | 52 --- 5 files changed, 302 insertions(+), 351 deletions(-) delete mode 100644 src/plugins/android/androidsdkmodel.cpp delete mode 100644 src/plugins/android/androidsdkmodel.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index bfa038b1476..443b0c58f66 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -24,7 +24,6 @@ add_qtc_plugin(Android androidsdkdownloader.cpp androidsdkdownloader.h androidsdkmanager.cpp androidsdkmanager.h androidsdkmanagerdialog.cpp androidsdkmanagerdialog.h - androidsdkmodel.cpp androidsdkmodel.h androidsdkpackage.cpp androidsdkpackage.h androidsettingswidget.cpp androidsettingswidget.h androidsignaloperation.cpp androidsignaloperation.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 785dc5b0564..9c85bcf68b8 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -51,8 +51,6 @@ QtcPlugin { "androidsdkmanager.h", "androidsdkmanagerdialog.cpp", "androidsdkmanagerdialog.h", - "androidsdkmodel.cpp", - "androidsdkmodel.h", "androidsdkpackage.cpp", "androidsdkpackage.h", "androidsettingswidget.cpp", diff --git a/src/plugins/android/androidsdkmanagerdialog.cpp b/src/plugins/android/androidsdkmanagerdialog.cpp index b8abcd6fbbe..4b5deacabc9 100644 --- a/src/plugins/android/androidsdkmanagerdialog.cpp +++ b/src/plugins/android/androidsdkmanagerdialog.cpp @@ -4,8 +4,8 @@ #include "androidconfigurations.h" #include "androidsdkmanager.h" #include "androidsdkmanagerdialog.h" -#include "androidsdkmodel.h" #include "androidtr.h" +#include "androidutils.h" #include #include @@ -27,6 +27,307 @@ using namespace std::placeholders; namespace Android::Internal { +class AndroidSdkModel : public QAbstractItemModel +{ +public: + enum PackageColumn { + packageNameColumn = 0, + apiLevelColumn, + packageRevisionColumn + }; + + enum ExtraRoles { + PackageTypeRole = Qt::UserRole + 1, + PackageStateRole + }; + + explicit AndroidSdkModel(QObject *parent) + : QAbstractItemModel(parent) + { + connect(&sdkManager(), &AndroidSdkManager::packagesReloaded, + this, &AndroidSdkModel::refreshData); + refreshData(); + } + + // QAbstractItemModel overrides. + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &) const override { return 3; } + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override + { + static QHash roles{{PackageTypeRole, "PackageRole"}, + {PackageStateRole, "PackageState"}}; + return roles; + } + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + + void resetSelection() + { + beginResetModel(); + m_changeState.clear(); + endResetModel(); + } + InstallationChange installationChange() const; + +private: + void refreshData(); + + QList m_sdkPlatforms; + QList m_tools; + QSet m_changeState; +}; + +QVariant AndroidSdkModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + Q_UNUSED(orientation) + QVariant data; + if (role == Qt::DisplayRole) { + switch (section) { + case packageNameColumn: + data = Tr::tr("Package"); + break; + case packageRevisionColumn: + data = Tr::tr("Revision"); + break; + case apiLevelColumn: + data = Tr::tr("API"); + break; + default: + break; + } + } + return data; +} + +QModelIndex AndroidSdkModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid()) { + // Packages under top items. + if (parent.row() == 0) { + // Tools packages + if (row < m_tools.count()) + return createIndex(row, column, const_cast(m_tools.at(row))); + } else if (parent.row() < m_sdkPlatforms.count() + 1) { + // Platform packages + const SdkPlatform *sdkPlatform = m_sdkPlatforms.at(parent.row() - 1); + SystemImageList images = sdkPlatform->systemImages(AndroidSdkPackage::AnyValidState); + if (row < images.count() + 1) { + if (row == 0) + return createIndex(row, column, const_cast(sdkPlatform)); + else + return createIndex(row, column, images.at(row - 1)); + } + } + } else if (row < m_sdkPlatforms.count() + 1) { + return createIndex(row, column); // Top level items (Tools & platform) + } + + return {}; +} + +QModelIndex AndroidSdkModel::parent(const QModelIndex &index) const +{ + void *ip = index.internalPointer(); + if (!ip) + return {}; + + auto package = static_cast(ip); + if (package->type() == AndroidSdkPackage::SystemImagePackage) { + auto image = static_cast(package); + int row = m_sdkPlatforms.indexOf(const_cast(image->platform())); + if (row > -1) + return createIndex(row + 1, 0); + } else if (package->type() == AndroidSdkPackage::SdkPlatformPackage) { + int row = m_sdkPlatforms.indexOf(static_cast(package)); + if (row > -1) + return createIndex(row + 1, 0); + } else { + return createIndex(0, 0); // Tools + } + + return {}; +} + +int AndroidSdkModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) + return m_sdkPlatforms.count() + 1; + + if (!parent.internalPointer()) { + if (parent.row() == 0) // Tools + return m_tools.count(); + + if (parent.row() <= m_sdkPlatforms.count()) { + const SdkPlatform * platform = m_sdkPlatforms.at(parent.row() - 1); + return platform->systemImages(AndroidSdkPackage::AnyValidState).count() + 1; + } + } + + return 0; +} + +QVariant AndroidSdkModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return {}; + + if (!index.parent().isValid()) { + // Top level tools + if (index.row() == 0) { + return role == Qt::DisplayRole && index.column() == packageNameColumn ? + QVariant(Tr::tr("Tools")) : QVariant(); + } + // Top level platforms + const SdkPlatform *platform = m_sdkPlatforms.at(index.row() - 1); + if (role == Qt::DisplayRole) { + if (index.column() == packageNameColumn) { + const QString androidName = androidNameForApiLevel(platform->apiLevel()) + + platform->extension(); + if (androidName.startsWith("Android")) + return androidName; + else + return platform->displayText(); + } else if (index.column() == apiLevelColumn) { + return platform->apiLevel(); + } + } + return {}; + } + + auto p = static_cast(index.internalPointer()); + QString apiLevelStr; + if (p->type() == AndroidSdkPackage::SdkPlatformPackage) + apiLevelStr = QString::number(static_cast(p)->apiLevel()); + + if (p->type() == AndroidSdkPackage::SystemImagePackage) + apiLevelStr = QString::number(static_cast(p)->platform()->apiLevel()); + + if (role == Qt::DisplayRole) { + switch (index.column()) { + case packageNameColumn: + return p->type() == AndroidSdkPackage::SdkPlatformPackage ? + Tr::tr("SDK Platform") : p->displayText(); + case packageRevisionColumn: + return p->revision().toString(); + case apiLevelColumn: + return apiLevelStr; + default: + break; + } + } + + if (index.column() == packageNameColumn) { + if (role == Qt::CheckStateRole) { + if (p->state() == AndroidSdkPackage::Installed) + return m_changeState.contains(p) ? Qt::Unchecked : Qt::Checked; + else + return m_changeState.contains(p) ? Qt::Checked : Qt::Unchecked; + } + + if (role == Qt::FontRole) { + QFont font; + if (m_changeState.contains(p)) + font.setBold(true); + return font; + } + } + + if (role == Qt::TextAlignmentRole && index.column() == packageRevisionColumn) + return Qt::AlignRight; + + if (role == Qt::ToolTipRole) + return QString("%1 - (%2)").arg(p->descriptionText()).arg(p->sdkStylePath()); + + if (role == PackageTypeRole) + return p->type(); + + if (role == PackageStateRole) + return p->state(); + + return {}; +} + +Qt::ItemFlags AndroidSdkModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags f = QAbstractItemModel::flags(index); + if (index.column() == packageNameColumn) + f |= Qt::ItemIsUserCheckable; + + void *ip = index.internalPointer(); + if (ip && index.column() == packageNameColumn) { + auto package = static_cast(ip); + if (package->state() == AndroidSdkPackage::Installed + && package->type() == AndroidSdkPackage::SdkToolsPackage) { + f &= ~Qt::ItemIsEnabled; + } + } + return f; +} + +bool AndroidSdkModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + void *ip = index.internalPointer(); + if (ip && role == Qt::CheckStateRole) { + auto package = static_cast(ip); + if (value.toInt() == Qt::Checked && package->state() != AndroidSdkPackage::Installed) { + m_changeState << package; + emit dataChanged(index, index, {Qt::CheckStateRole}); + } else if (m_changeState.remove(package)) { + emit dataChanged(index, index, {Qt::CheckStateRole}); + } else if (value.toInt() == Qt::Unchecked) { + m_changeState.insert(package); + emit dataChanged(index, index, {Qt::CheckStateRole}); + } + return true; + } + return false; +} + +InstallationChange AndroidSdkModel::installationChange() const +{ + if (m_changeState.isEmpty()) + return {}; + + InstallationChange change; + for (const AndroidSdkPackage *package : m_changeState) { + if (package->state() == AndroidSdkPackage::Installed) + change.toUninstall << package->sdkStylePath(); + else + change.toInstall << package->sdkStylePath(); + } + return change; +} + +void AndroidSdkModel::refreshData() +{ + m_sdkPlatforms.clear(); + m_tools.clear(); + m_changeState.clear(); + beginResetModel(); + for (AndroidSdkPackage *p : sdkManager().allSdkPackages()) { + if (p->type() == AndroidSdkPackage::SdkPlatformPackage) + m_sdkPlatforms << static_cast(p); + else + m_tools << p; + } + Utils::sort(m_sdkPlatforms, [](const SdkPlatform *p1, const SdkPlatform *p2) { + return p1->apiLevel() > p2->apiLevel(); + }); + + Utils::sort(m_tools, [](const AndroidSdkPackage *p1, const AndroidSdkPackage *p2) { + if (p1->state() == p2->state()) + return p1->type() == p2->type() ? p1->revision() > p2->revision() : p1->type() > p2->type(); + else + return p1->state() < p2->state(); + }); + endResetModel(); +} + class OptionsDialog : public QDialog { public: diff --git a/src/plugins/android/androidsdkmodel.cpp b/src/plugins/android/androidsdkmodel.cpp deleted file mode 100644 index 650927fa324..00000000000 --- a/src/plugins/android/androidsdkmodel.cpp +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "androidsdkmodel.h" - -#include "androidsdkmanager.h" -#include "androidtr.h" -#include "androidutils.h" - -#include -#include -#include - -#include - -namespace Android::Internal { - -const int packageColCount = 3; - -AndroidSdkModel::AndroidSdkModel(QObject *parent) - : QAbstractItemModel(parent) -{ - connect(&sdkManager(), &AndroidSdkManager::packagesReloaded, - this, &AndroidSdkModel::refreshData); - refreshData(); -} - -QVariant AndroidSdkModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - Q_UNUSED(orientation) - QVariant data; - if (role == Qt::DisplayRole) { - switch (section) { - case packageNameColumn: - data = Tr::tr("Package"); - break; - case packageRevisionColumn: - data = Tr::tr("Revision"); - break; - case apiLevelColumn: - data = Tr::tr("API"); - break; - default: - break; - } - } - return data; -} - -QModelIndex AndroidSdkModel::index(int row, int column, const QModelIndex &parent) const -{ - if (parent.isValid()) { - // Packages under top items. - if (parent.row() == 0) { - // Tools packages - if (row < m_tools.count()) - return createIndex(row, column, const_cast(m_tools.at(row))); - } else if (parent.row() < m_sdkPlatforms.count() + 1) { - // Platform packages - const SdkPlatform *sdkPlatform = m_sdkPlatforms.at(parent.row() - 1); - SystemImageList images = sdkPlatform->systemImages(AndroidSdkPackage::AnyValidState); - if (row < images.count() + 1) { - if (row == 0) - return createIndex(row, column, const_cast(sdkPlatform)); - else - return createIndex(row, column, images.at(row - 1)); - } - } - } else if (row < m_sdkPlatforms.count() + 1) { - return createIndex(row, column); // Top level items (Tools & platform) - } - - return {}; -} - -QModelIndex AndroidSdkModel::parent(const QModelIndex &index) const -{ - void *ip = index.internalPointer(); - if (!ip) - return {}; - - auto package = static_cast(ip); - if (package->type() == AndroidSdkPackage::SystemImagePackage) { - auto image = static_cast(package); - int row = m_sdkPlatforms.indexOf(const_cast(image->platform())); - if (row > -1) - return createIndex(row + 1, 0); - } else if (package->type() == AndroidSdkPackage::SdkPlatformPackage) { - int row = m_sdkPlatforms.indexOf(static_cast(package)); - if (row > -1) - return createIndex(row + 1, 0); - } else { - return createIndex(0, 0); // Tools - } - - return {}; -} - -int AndroidSdkModel::rowCount(const QModelIndex &parent) const -{ - if (!parent.isValid()) - return m_sdkPlatforms.count() + 1; - - if (!parent.internalPointer()) { - if (parent.row() == 0) // Tools - return m_tools.count(); - - if (parent.row() <= m_sdkPlatforms.count()) { - const SdkPlatform * platform = m_sdkPlatforms.at(parent.row() - 1); - return platform->systemImages(AndroidSdkPackage::AnyValidState).count() + 1; - } - } - - return 0; -} - -int AndroidSdkModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent) - return packageColCount; -} - -QVariant AndroidSdkModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return {}; - - if (!index.parent().isValid()) { - // Top level tools - if (index.row() == 0) { - return role == Qt::DisplayRole && index.column() == packageNameColumn ? - QVariant(Tr::tr("Tools")) : QVariant(); - } - // Top level platforms - const SdkPlatform *platform = m_sdkPlatforms.at(index.row() - 1); - if (role == Qt::DisplayRole) { - if (index.column() == packageNameColumn) { - const QString androidName = androidNameForApiLevel(platform->apiLevel()) - + platform->extension(); - if (androidName.startsWith("Android")) - return androidName; - else - return platform->displayText(); - } else if (index.column() == apiLevelColumn) { - return platform->apiLevel(); - } - } - return {}; - } - - auto p = static_cast(index.internalPointer()); - QString apiLevelStr; - if (p->type() == AndroidSdkPackage::SdkPlatformPackage) - apiLevelStr = QString::number(static_cast(p)->apiLevel()); - - if (p->type() == AndroidSdkPackage::SystemImagePackage) - apiLevelStr = QString::number(static_cast(p)->platform()->apiLevel()); - - if (role == Qt::DisplayRole) { - switch (index.column()) { - case packageNameColumn: - return p->type() == AndroidSdkPackage::SdkPlatformPackage ? - Tr::tr("SDK Platform") : p->displayText(); - case packageRevisionColumn: - return p->revision().toString(); - case apiLevelColumn: - return apiLevelStr; - default: - break; - } - } - - if (index.column() == packageNameColumn) { - if (role == Qt::CheckStateRole) { - if (p->state() == AndroidSdkPackage::Installed) - return m_changeState.contains(p) ? Qt::Unchecked : Qt::Checked; - else - return m_changeState.contains(p) ? Qt::Checked : Qt::Unchecked; - } - - if (role == Qt::FontRole) { - QFont font; - if (m_changeState.contains(p)) - font.setBold(true); - return font; - } - } - - if (role == Qt::TextAlignmentRole && index.column() == packageRevisionColumn) - return Qt::AlignRight; - - if (role == Qt::ToolTipRole) - return QString("%1 - (%2)").arg(p->descriptionText()).arg(p->sdkStylePath()); - - if (role == PackageTypeRole) - return p->type(); - - if (role == PackageStateRole) - return p->state(); - - return {}; -} - -QHash AndroidSdkModel::roleNames() const -{ - QHash roles; - roles[PackageTypeRole] = "PackageRole"; - roles[PackageStateRole] = "PackageState"; - return roles; -} - -Qt::ItemFlags AndroidSdkModel::flags(const QModelIndex &index) const -{ - Qt::ItemFlags f = QAbstractItemModel::flags(index); - if (index.column() == packageNameColumn) - f |= Qt::ItemIsUserCheckable; - - void *ip = index.internalPointer(); - if (ip && index.column() == packageNameColumn) { - auto package = static_cast(ip); - if (package->state() == AndroidSdkPackage::Installed - && package->type() == AndroidSdkPackage::SdkToolsPackage) { - f &= ~Qt::ItemIsEnabled; - } - } - return f; -} - -bool AndroidSdkModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - void *ip = index.internalPointer(); - if (ip && role == Qt::CheckStateRole) { - auto package = static_cast(ip); - if (value.toInt() == Qt::Checked && package->state() != AndroidSdkPackage::Installed) { - m_changeState << package; - emit dataChanged(index, index, {Qt::CheckStateRole}); - } else if (m_changeState.remove(package)) { - emit dataChanged(index, index, {Qt::CheckStateRole}); - } else if (value.toInt() == Qt::Unchecked) { - m_changeState.insert(package); - emit dataChanged(index, index, {Qt::CheckStateRole}); - } - return true; - } - return false; -} - -InstallationChange AndroidSdkModel::installationChange() const -{ - if (m_changeState.isEmpty()) - return {}; - - InstallationChange change; - for (const AndroidSdkPackage *package : m_changeState) { - if (package->state() == AndroidSdkPackage::Installed) - change.toUninstall << package->sdkStylePath(); - else - change.toInstall << package->sdkStylePath(); - } - return change; -} - -void AndroidSdkModel::resetSelection() -{ - beginResetModel(); - m_changeState.clear(); - endResetModel(); -} - -void AndroidSdkModel::refreshData() -{ - m_sdkPlatforms.clear(); - m_tools.clear(); - m_changeState.clear(); - beginResetModel(); - for (AndroidSdkPackage *p : sdkManager().allSdkPackages()) { - if (p->type() == AndroidSdkPackage::SdkPlatformPackage) - m_sdkPlatforms << static_cast(p); - else - m_tools << p; - } - Utils::sort(m_sdkPlatforms, [](const SdkPlatform *p1, const SdkPlatform *p2) { - return p1->apiLevel() > p2->apiLevel(); - }); - - Utils::sort(m_tools, [](const AndroidSdkPackage *p1, const AndroidSdkPackage *p2) { - if (p1->state() == p2->state()) - return p1->type() == p2->type() ? p1->revision() > p2->revision() : p1->type() > p2->type(); - else - return p1->state() < p2->state(); - }); - endResetModel(); -} - -} // namespace Android::Internal diff --git a/src/plugins/android/androidsdkmodel.h b/src/plugins/android/androidsdkmodel.h deleted file mode 100644 index dc9292560d1..00000000000 --- a/src/plugins/android/androidsdkmodel.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#pragma once - -#include - -namespace Android::Internal { - -class AndroidSdkPackage; -class InstallationChange; -class SdkPlatform; - -class AndroidSdkModel : public QAbstractItemModel -{ -public: - enum PackageColumn { - packageNameColumn = 0, - apiLevelColumn, - packageRevisionColumn - }; - - enum ExtraRoles { - PackageTypeRole = Qt::UserRole + 1, - PackageStateRole - }; - - explicit AndroidSdkModel(QObject *parent = nullptr); - - // QAbstractItemModel overrides. - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - QModelIndex index(int row, int column, - const QModelIndex &parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex &index) const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - QHash roleNames() const override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role) override; - - void resetSelection(); - InstallationChange installationChange() const; - -private: - void refreshData(); - - QList m_sdkPlatforms; - QList m_tools; - QSet m_changeState; -}; - -} // namespace Android::Internal From 8e7aa9e81d83757a20ec35ab39ea3b88f1fded4d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 12 Nov 2024 18:03:58 +0100 Subject: [PATCH 136/989] Android: Get rid of unused signal Change-Id: I14c3a7f12dbe260c0508de747ebf632bab9c0c7b Reviewed-by: hjk --- src/plugins/android/androidconfigurations.cpp | 1 - src/plugins/android/androidconfigurations.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 85f64bf639f..8d80ebb5dfa 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1225,7 +1225,6 @@ void AndroidConfigurations::applyConfig() registerNewToolchains(); updateAutomaticKitList(); removeOldToolchains(); - emit m_instance->updated(); } static bool matchKit(const ToolchainBundle &bundle, const Kit &kit) diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index a94ffd188cc..1805fa552c8 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -133,7 +133,6 @@ public: signals: void aboutToUpdate(); - void updated(); private: friend void setupAndroidConfigurations(); From 9507288cf49ce81aebdf65f8283c30e1de23d426 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 13 Nov 2024 09:26:55 +0100 Subject: [PATCH 137/989] Android: Hide JLSSettings in cpp and provide a setup function Change-Id: I21e07ea1d606f238ef1ca3db8d6f170d6a194b73 Reviewed-by: hjk --- src/plugins/android/androidplugin.cpp | 7 +---- src/plugins/android/javalanguageserver.cpp | 30 +++++++++++++++++++++- src/plugins/android/javalanguageserver.h | 23 +---------------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index f3500c9d8c6..32a68aeac8d 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -33,8 +33,6 @@ #include -#include - #include #include #include @@ -111,10 +109,7 @@ class AndroidPlugin final : public ExtensionSystem::IPlugin connect(KitManager::instance(), &KitManager::kitsLoaded, this, &AndroidPlugin::kitsRestored, Qt::SingleShotConnection); - LanguageClient::LanguageClientSettings::registerClientType( - {Android::Constants::JLS_SETTINGS_ID, - Tr::tr("Java Language Server"), - [] { return new JLSSettings; }}); + setupJavaLanguageServer(); #ifdef WITH_TESTS addTestCreator(createAndroidSdkManagerTest); diff --git a/src/plugins/android/javalanguageserver.cpp b/src/plugins/android/javalanguageserver.cpp index ff4886dcbdb..b039d9ece59 100644 --- a/src/plugins/android/javalanguageserver.cpp +++ b/src/plugins/android/javalanguageserver.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -35,6 +36,26 @@ constexpr char languageServerKey[] = "languageServer"; namespace Android::Internal { +class JLSSettings final : public LanguageClient::StdIOSettings +{ +public: + JLSSettings(); + + bool applyFromSettingsWidget(QWidget *widget) final; + QWidget *createSettingsWidget(QWidget *parent) const final; + bool isValid() const final; + void toMap(Store &map) const final; + void fromMap(const Store &map) final; + LanguageClient::BaseSettings *copy() const final; + LanguageClient::Client *createClient(LanguageClient::BaseClientInterface *interface) const final; + LanguageClient::BaseClientInterface *createInterface(Project *project) const final; + + FilePath m_languageServer; + +private: + JLSSettings(const JLSSettings &other) = default; +}; + class JLSSettingsWidget : public QWidget { public: @@ -164,7 +185,7 @@ private: TemporaryDirectory m_workspaceDir = TemporaryDirectory("QtCreator-jls-XXXXXX"); }; -LanguageClient::BaseClientInterface *JLSSettings::createInterface(ProjectExplorer::Project *) const +LanguageClient::BaseClientInterface *JLSSettings::createInterface(Project *) const { auto interface = new JLSInterface(); CommandLine cmd{m_executable, arguments(), CommandLine::Raw}; @@ -337,4 +358,11 @@ LanguageClient::Client *JLSSettings::createClient(LanguageClient::BaseClientInte return new JLSClient(interface); } +void setupJavaLanguageServer() +{ + LanguageClient::LanguageClientSettings::registerClientType( + {Android::Constants::JLS_SETTINGS_ID, Tr::tr("Java Language Server"), + [] { return new JLSSettings; }}); +} + } // namespace Android::Internal diff --git a/src/plugins/android/javalanguageserver.h b/src/plugins/android/javalanguageserver.h index b3fc8f0e282..0225077cf29 100644 --- a/src/plugins/android/javalanguageserver.h +++ b/src/plugins/android/javalanguageserver.h @@ -3,29 +3,8 @@ #pragma once -#include - namespace Android::Internal { -class JLSSettings final : public LanguageClient::StdIOSettings -{ -public: - JLSSettings(); - - bool applyFromSettingsWidget(QWidget *widget) final; - QWidget *createSettingsWidget(QWidget *parent) const final; - bool isValid() const final; - void toMap(Utils::Store &map) const final; - void fromMap(const Utils::Store &map) final; - LanguageClient::BaseSettings *copy() const final; - LanguageClient::Client *createClient(LanguageClient::BaseClientInterface *interface) const final; - LanguageClient::BaseClientInterface *createInterface( - ProjectExplorer::Project *project) const final; - - Utils::FilePath m_languageServer; - -private: - JLSSettings(const JLSSettings &other) = default; -}; +void setupJavaLanguageServer(); } // namespace Android::Internal From efecb51f37713b85a3fb01712aa208958544a2c5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 13 Nov 2024 09:30:16 +0100 Subject: [PATCH 138/989] Android: Use LanguageClient namespace in javalanguageserver.cpp Change-Id: I8d6325b2a5c1b3696683d32c64aa8df9dc7a3b81 Reviewed-by: hjk --- src/plugins/android/javalanguageserver.cpp | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/plugins/android/javalanguageserver.cpp b/src/plugins/android/javalanguageserver.cpp index b039d9ece59..fbeebd8418d 100644 --- a/src/plugins/android/javalanguageserver.cpp +++ b/src/plugins/android/javalanguageserver.cpp @@ -29,6 +29,7 @@ #include #include +using namespace LanguageClient; using namespace ProjectExplorer; using namespace Utils; @@ -36,7 +37,7 @@ constexpr char languageServerKey[] = "languageServer"; namespace Android::Internal { -class JLSSettings final : public LanguageClient::StdIOSettings +class JLSSettings final : public StdIOSettings { public: JLSSettings(); @@ -46,9 +47,9 @@ public: bool isValid() const final; void toMap(Store &map) const final; void fromMap(const Store &map) final; - LanguageClient::BaseSettings *copy() const final; - LanguageClient::Client *createClient(LanguageClient::BaseClientInterface *interface) const final; - LanguageClient::BaseClientInterface *createInterface(Project *project) const final; + BaseSettings *copy() const final; + Client *createClient(BaseClientInterface *interface) const final; + BaseClientInterface *createInterface(Project *project) const final; FilePath m_languageServer; @@ -169,23 +170,21 @@ void JLSSettings::fromMap(const Store &map) m_languageServer = FilePath::fromSettings(map[languageServerKey]); } -LanguageClient::BaseSettings *JLSSettings::copy() const +BaseSettings *JLSSettings::copy() const { return new JLSSettings(*this); } -class JLSInterface : public LanguageClient::StdIOClientInterface +class JLSInterface : public StdIOClientInterface { public: - JLSInterface() = default; - QString workspaceDir() const { return m_workspaceDir.path().path(); } private: TemporaryDirectory m_workspaceDir = TemporaryDirectory("QtCreator-jls-XXXXXX"); }; -LanguageClient::BaseClientInterface *JLSSettings::createInterface(Project *) const +BaseClientInterface *JLSSettings::createInterface(Project *) const { auto interface = new JLSInterface(); CommandLine cmd{m_executable, arguments(), CommandLine::Raw}; @@ -194,7 +193,7 @@ LanguageClient::BaseClientInterface *JLSSettings::createInterface(Project *) con return interface; } -class JLSClient : public LanguageClient::Client +class JLSClient : public Client { public: using Client::Client; @@ -353,14 +352,14 @@ void JLSClient::updateTarget(Target *target) updateProjectFiles(); } -LanguageClient::Client *JLSSettings::createClient(LanguageClient::BaseClientInterface *interface) const +Client *JLSSettings::createClient(BaseClientInterface *interface) const { return new JLSClient(interface); } void setupJavaLanguageServer() { - LanguageClient::LanguageClientSettings::registerClientType( + LanguageClientSettings::registerClientType( {Android::Constants::JLS_SETTINGS_ID, Tr::tr("Java Language Server"), [] { return new JLSSettings; }}); } From a10258d9aa474bd94fa0bad084cc3a14a67db587 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 13 Nov 2024 09:43:02 +0100 Subject: [PATCH 139/989] Android: Remove dead include We no longer have the HAVE_QBS, and the androidqbspropertyprovider.h file doesn't exist anymore. Change-Id: Ib4f2e11f1b13c27942286df3a5aac6f6e2adf3a4 Reviewed-by: hjk --- src/plugins/android/androidplugin.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 32a68aeac8d..50217a6f8c0 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -25,10 +25,6 @@ #include "javaeditor.h" #include "javalanguageserver.h" -#ifdef HAVE_QBS -# include "androidqbspropertyprovider.h" -#endif - #include #include From 3ec3af549839fb32c403d35422fb635521ec0109 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 13 Nov 2024 09:19:23 +0100 Subject: [PATCH 140/989] RemoteLinux: Introduce an indirection in the device Plan is to handle the "disconnected" state as a separate type of access which wouldn't have the shell thread. Changing states would happen by destructing an existing access object (consisting of a file access object and surrounding helpers/mutex/...) and creating a new one, so it makes sense to have any state-internal data/objects part of the access object, so they can be constructed/destructed as a unit. Change-Id: I3fdb40b560e5902a40c96703afb8678c2f60c80d Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/linuxdevice.cpp | 133 ++++++++++++++---------- src/plugins/remotelinux/linuxdevice.h | 6 +- 2 files changed, 81 insertions(+), 58 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index e8d9a1b80f8..77dc20b6834 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -286,13 +286,13 @@ private: // LinuxDevicePrivate class ShellThreadHandler; -class LinuxDevicePrivate; +class LinuxDeviceAccess; class LinuxDeviceFileAccess : public UnixDeviceFileAccess { public: - LinuxDeviceFileAccess(LinuxDevicePrivate *dev) - : m_dev(dev) + LinuxDeviceFileAccess(LinuxDeviceAccess *access) + : m_access(access) {} RunResult runInShell(const CommandLine &cmdLine, @@ -302,20 +302,20 @@ public: bool disconnected() const override; - LinuxDevicePrivate *m_dev; + LinuxDeviceAccess *m_access; }; -class LinuxDevicePrivate +class LinuxDeviceAccess { public: - explicit LinuxDevicePrivate(LinuxDevice *parent); - ~LinuxDevicePrivate(); + LinuxDeviceAccess(LinuxDevice *device, LinuxDevicePrivate *devicePrivate); + ~LinuxDeviceAccess(); Result setupShell(const SshParameters &sshParameters, bool announce); RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); void announceConnectionAttempt(); void unannounceConnectionAttempt(); - Id announceId() const { return q->id().withPrefix("announce_"); } + Id announceId() const { return m_device->id().withPrefix("announce_"); } void attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters); @@ -329,7 +329,8 @@ public: void setDisconnected(bool disconnected); bool checkDisconnectedWithWarning(); - LinuxDevice *q = nullptr; + LinuxDevice *m_device = nullptr; + LinuxDevicePrivate *m_devicePrivate = nullptr; QThread m_shellThread; ShellThreadHandler *m_handler = nullptr; mutable QRecursiveMutex m_shellMutex; @@ -339,13 +340,48 @@ public: std::optional m_environmentCache; }; -void LinuxDevicePrivate::invalidateEnvironmentCache() +class LinuxDevicePrivate +{ +public: + explicit LinuxDevicePrivate(LinuxDevice *parent) + : q(parent) + { + m_disconnected.setSettingsKey("Disconnected"); + parent->registerAspect(&m_disconnected); + + setupScriptAccess(); + } + + void setOsType(OsType osType) + { + qCDebug(linuxDeviceLog) << "Setting OS type to" << osType << "for" << q->displayName(); + q->setOsType(osType); + } + + void setupScriptAccess() + { + m_access.reset(new LinuxDeviceAccess(q, this)); + q->setFileAccess(&m_access->m_fileAccess); + } + + bool tryToConnect(const SshParameters &sshParameters) + { + QMutexLocker locker(&m_access->m_shellMutex); + return m_access->setupShell(sshParameters, false); + } + + LinuxDevice *q = nullptr; + std::unique_ptr m_access; + BoolAspect m_disconnected; +}; + +void LinuxDeviceAccess::invalidateEnvironmentCache() { QWriteLocker locker(&m_environmentCacheLock); m_environmentCache.reset(); } -Environment LinuxDevicePrivate::getEnvironment() +Environment LinuxDeviceAccess::getEnvironment() { QReadLocker locker(&m_environmentCacheLock); if (m_environmentCache.has_value()) @@ -356,16 +392,16 @@ Environment LinuxDevicePrivate::getEnvironment() if (m_environmentCache.has_value()) return m_environmentCache.value(); - if (q->disconnected()) + if (m_devicePrivate->m_disconnected()) return {}; Process getEnvProc; - getEnvProc.setCommand(CommandLine{q->filePath("env")}); + getEnvProc.setCommand(CommandLine{m_device->filePath("env")}); using namespace std::chrono; getEnvProc.runBlocking(5s); const QString remoteOutput = getEnvProc.cleanedStdOut(); - m_environmentCache = Environment(remoteOutput.split('\n', Qt::SkipEmptyParts), q->osType()); + m_environmentCache = Environment(remoteOutput.split('\n', Qt::SkipEmptyParts), m_device->osType()); return m_environmentCache.value(); } @@ -374,7 +410,7 @@ RunResult LinuxDeviceFileAccess::runInShell(const CommandLine &cmdLine, { if (disconnected()) return {-1, {}, Tr::tr("Device is disconnected.").toUtf8()}; - return m_dev->runInShell(cmdLine, stdInData); + return m_access->runInShell(cmdLine, stdInData); } Environment LinuxDeviceFileAccess::deviceEnvironment() const @@ -382,12 +418,12 @@ Environment LinuxDeviceFileAccess::deviceEnvironment() const if (disconnected()) return {}; - return m_dev->getEnvironment(); + return m_access->getEnvironment(); } bool LinuxDeviceFileAccess::disconnected() const { - return m_dev->checkDisconnectedWithWarning(); + return m_access->checkDisconnectedWithWarning(); } // SshProcessImpl @@ -1009,7 +1045,6 @@ private: LinuxDevice::LinuxDevice() : d(new LinuxDevicePrivate(this)) { - setFileAccess(&d->m_fileAccess); setDisplayType(Tr::tr("Remote Linux")); setOsType(OsTypeLinux); setDefaultDisplayName(Tr::tr("Remote Linux Device")); @@ -1022,8 +1057,6 @@ LinuxDevice::LinuxDevice() sshParams.timeout = 10; setSshParameters(sshParams); - disconnected.setSettingsKey("Disconnected"); - addDeviceAction({Tr::tr("Deploy Public Key..."), [](const IDevice::Ptr &device, QWidget *parent) { if (auto d = Internal::PublicKeyDeploymentDialog::createDialog(device, parent)) { d->exec(); @@ -1066,11 +1099,7 @@ LinuxDevice::LinuxDevice() }}); } -void LinuxDevice::_setOsType(Utils::OsType osType) -{ - qCDebug(linuxDeviceLog) << "Setting OS type to" << osType << "for" << displayName(); - IDevice::setOsType(osType); -} + LinuxDevice::~LinuxDevice() { @@ -1126,8 +1155,8 @@ ProcessInterface *LinuxDevice::createProcessInterface() const return new SshProcessInterface(shared_from_this()); } -LinuxDevicePrivate::LinuxDevicePrivate(LinuxDevice *parent) - : q(parent) +LinuxDeviceAccess::LinuxDeviceAccess(LinuxDevice *device, LinuxDevicePrivate *devicePrivate) + : m_device(device), m_devicePrivate(devicePrivate) { m_shellThread.setObjectName("LinuxDeviceShell"); m_handler = new ShellThreadHandler(); @@ -1136,7 +1165,7 @@ LinuxDevicePrivate::LinuxDevicePrivate(LinuxDevice *parent) m_shellThread.start(); } -LinuxDevicePrivate::~LinuxDevicePrivate() +LinuxDeviceAccess::~LinuxDeviceAccess() { QMutexLocker locker(&m_shellMutex); auto closeShell = [this] { @@ -1149,37 +1178,36 @@ LinuxDevicePrivate::~LinuxDevicePrivate() QMetaObject::invokeMethod(&m_shellThread, closeShell, Qt::BlockingQueuedConnection); } -void LinuxDevicePrivate::queryOsType(std::function runInShell) +void LinuxDeviceAccess::queryOsType(std::function runInShell) { const RunResult result = runInShell({"uname", {"-s"}, OsType::OsTypeLinux}); if (result.exitCode != 0) - q->_setOsType(OsTypeOtherUnix); + m_devicePrivate->setOsType(OsTypeOtherUnix); const QString osName = QString::fromUtf8(result.stdOut).trimmed(); if (osName == "Darwin") - q->_setOsType(OsTypeMac); + m_devicePrivate->setOsType(OsTypeMac); if (osName == "Linux") - q->_setOsType(OsTypeLinux); + m_devicePrivate->setOsType(OsTypeLinux); } -void LinuxDevicePrivate::setDisconnected(bool disconnected) +void LinuxDeviceAccess::setDisconnected(bool disconnected) { - if (disconnected == q->disconnected()) + if (disconnected == m_devicePrivate->m_disconnected()) return; - q->disconnected.setValue(disconnected); + m_devicePrivate->m_disconnected.setValue(disconnected); if (disconnected) m_handler->closeShell(); - } -void LinuxDevicePrivate::checkOsType() +void LinuxDeviceAccess::checkOsType() { queryOsType([this](const CommandLine &cmd) { return runInShell(cmd); }); } // Call me with shell mutex locked -Result LinuxDevicePrivate::setupShell(const SshParameters &sshParameters, bool announce) +Result LinuxDeviceAccess::setupShell(const SshParameters &sshParameters, bool announce) { if (m_handler->isRunning(sshParameters)) { setDisconnected(false); @@ -1209,23 +1237,23 @@ Result LinuxDevicePrivate::setupShell(const SshParameters &sshParameters, bool a return result; } -RunResult LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &data) +RunResult LinuxDeviceAccess::runInShell(const CommandLine &cmd, const QByteArray &data) { QMutexLocker locker(&m_shellMutex); DEBUG(cmd.toUserOutput()); if (checkDisconnectedWithWarning()) return {}; - const bool isSetup = setupShell(q->sshParameters(), true); + const bool isSetup = setupShell(m_device->sshParameters(), true); if (checkDisconnectedWithWarning()) return {}; QTC_ASSERT(isSetup, return {}); return m_handler->runInShell(cmd, data); } -void LinuxDevicePrivate::announceConnectionAttempt() +void LinuxDeviceAccess::announceConnectionAttempt() { const QString message = Tr::tr("Establishing initial connection to device \"%1\". " - "This might take a moment.").arg(q->displayName()); + "This might take a moment.").arg(m_device->displayName()); qCDebug(linuxDeviceLog) << message; if (isMainThread()) { Core::ICore::infoBar()->addInfo(InfoBarEntry(announceId(), message)); @@ -1234,18 +1262,18 @@ void LinuxDevicePrivate::announceConnectionAttempt() } } -void LinuxDevicePrivate::unannounceConnectionAttempt() +void LinuxDeviceAccess::unannounceConnectionAttempt() { if (isMainThread()) Core::ICore::infoBar()->removeInfo(announceId()); } -bool LinuxDevicePrivate::checkDisconnectedWithWarning() +bool LinuxDeviceAccess::checkDisconnectedWithWarning() { - if (!q->disconnected()) + if (!m_devicePrivate->m_disconnected()) return false; - QMetaObject::invokeMethod(Core::ICore::infoBar(), [id = q->id(), name = q->displayName()] { + QMetaObject::invokeMethod(Core::ICore::infoBar(), [id = m_device->id(), name = m_device->displayName()] { const Id errorId = id.withPrefix("error_"); if (!Core::ICore::infoBar()->canInfoBeAdded(errorId)) return; @@ -1269,7 +1297,7 @@ bool LinuxDevicePrivate::checkDisconnectedWithWarning() return true; } -void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectionHandle, +void LinuxDeviceAccess::attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters) { QString socketFilePath; @@ -1678,14 +1706,14 @@ FileTransferInterface *LinuxDevice::createFileTransferInterface( return {}; } -LinuxDevicePrivate *LinuxDevice::connectionAccess() const +LinuxDeviceAccess *LinuxDevice::connectionAccess() const { - return d; + return d->m_access.get(); } void LinuxDevice::checkOsType() { - d->checkOsType(); + d->m_access->checkOsType(); } IDevice::DeviceState LinuxDevice::deviceState() const @@ -1704,13 +1732,12 @@ QString LinuxDevice::deviceStateToString() const bool LinuxDevice::isDisconnected() const { - return disconnected(); + return d->m_disconnected(); } bool LinuxDevice::tryToConnect() { - QMutexLocker locker(&d->m_shellMutex); - return d->setupShell(sshParameters(), false); + return d->tryToConnect(sshParameters()); } namespace Internal { diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index 22221d4f3cc..dd84a77ff95 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -39,7 +39,7 @@ public: ProjectExplorer::FileTransferInterface *createFileTransferInterface( const ProjectExplorer::FileTransferSetupData &setup) const override; - class LinuxDevicePrivate *connectionAccess() const; + class LinuxDeviceAccess *connectionAccess() const; void checkOsType() override; DeviceState deviceState() const override; @@ -51,10 +51,6 @@ public: protected: LinuxDevice(); - Utils::BoolAspect disconnected{this}; - - void _setOsType(Utils::OsType osType); - class LinuxDevicePrivate *d; friend class LinuxDevicePrivate; }; From d4209b10874b212b7fc87fc0541d49f260058853 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 13 Nov 2024 10:01:47 +0100 Subject: [PATCH 141/989] Android: Move JavaIndenter into javaeditor.cpp Remove createJavaIndenter() indirection. Change-Id: I872a61aff98c863547d112d47dda48fcb8b69889 Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 1 - src/plugins/android/android.qbs | 2 - src/plugins/android/javaeditor.cpp | 59 +++++++++++++++++++++- src/plugins/android/javaindenter.cpp | 74 ---------------------------- src/plugins/android/javaindenter.h | 12 ----- 5 files changed, 57 insertions(+), 91 deletions(-) delete mode 100644 src/plugins/android/javaindenter.cpp delete mode 100644 src/plugins/android/javaindenter.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 443b0c58f66..745b53f6db5 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -32,7 +32,6 @@ add_qtc_plugin(Android avddialog.cpp avddialog.h avdmanageroutputparser.cpp avdmanageroutputparser.h javaeditor.cpp javaeditor.h - javaindenter.cpp javaindenter.h javalanguageserver.cpp javalanguageserver.h javaparser.cpp javaparser.h keystorecertificatedialog.cpp keystorecertificatedialog.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 9c85bcf68b8..05e34e31d75 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -67,8 +67,6 @@ QtcPlugin { "avdmanageroutputparser.h", "javaeditor.cpp", "javaeditor.h", - "javaindenter.cpp", - "javaindenter.h", "javalanguageserver.cpp", "javalanguageserver.h", "javaparser.cpp", diff --git a/src/plugins/android/javaeditor.cpp b/src/plugins/android/javaeditor.cpp index 8fa69e6e8b2..1023331c0c1 100644 --- a/src/plugins/android/javaeditor.cpp +++ b/src/plugins/android/javaeditor.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "javaeditor.h" -#include "javaindenter.h" #include "androidconstants.h" #include @@ -12,18 +11,74 @@ #include #include #include +#include #include #include namespace Android::Internal { +class JavaIndenter final : public TextEditor::TextIndenter +{ +public: + explicit JavaIndenter(QTextDocument *doc) : TextEditor::TextIndenter(doc) {} + + bool isElectricCharacter(const QChar &ch) const final + { + return ch == QLatin1Char('{') || ch == QLatin1Char('}'); + } + + void indentBlock(const QTextBlock &block, + const QChar &typedChar, + const TextEditor::TabSettings &tabSettings, + int cursorPositionInEditor = -1) final; + + int indentFor(const QTextBlock &block, + const TextEditor::TabSettings &tabSettings, + int cursorPositionInEditor = -1) final; +}; + +void JavaIndenter::indentBlock(const QTextBlock &block, + const QChar &typedChar, + const TextEditor::TabSettings &tabSettings, + int /*cursorPositionInEditor*/) +{ + int indent = indentFor(block, tabSettings); + if (typedChar == QLatin1Char('}')) + indent -= tabSettings.m_indentSize; + tabSettings.indentLine(block, qMax(0, indent)); +} + +int JavaIndenter::indentFor(const QTextBlock &block, + const TextEditor::TabSettings &tabSettings, + int /*cursorPositionInEditor*/) +{ + QTextBlock previous = block.previous(); + if (!previous.isValid()) + return 0; + + QString previousText = previous.text(); + while (previousText.trimmed().isEmpty()) { + previous = previous.previous(); + if (!previous.isValid()) + return 0; + previousText = previous.text(); + } + + int indent = tabSettings.indentationColumn(previousText); + + int adjust = previousText.count(QLatin1Char('{')) - previousText.count(QLatin1Char('}')); + adjust *= tabSettings.m_indentSize; + + return qMax(0, indent + adjust); +} + static TextEditor::TextDocument *createJavaDocument() { auto doc = new TextEditor::TextDocument; doc->setId(Constants::JAVA_EDITOR_ID); doc->setMimeType(Utils::Constants::JAVA_MIMETYPE); - doc->setIndenter(createJavaIndenter(doc->document())); + doc->setIndenter(new JavaIndenter(doc->document())); return doc; } diff --git a/src/plugins/android/javaindenter.cpp b/src/plugins/android/javaindenter.cpp deleted file mode 100644 index ca131f584a3..00000000000 --- a/src/plugins/android/javaindenter.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "javaindenter.h" - -#include - -#include - -namespace Android::Internal { - -class JavaIndenter final : public TextEditor::TextIndenter -{ -public: - explicit JavaIndenter(QTextDocument *doc) - : TextEditor::TextIndenter(doc) - {} - - bool isElectricCharacter(const QChar &ch) const final - { - return ch == QLatin1Char('{') || ch == QLatin1Char('}'); - } - - void indentBlock(const QTextBlock &block, - const QChar &typedChar, - const TextEditor::TabSettings &tabSettings, - int cursorPositionInEditor = -1) final; - - int indentFor(const QTextBlock &block, - const TextEditor::TabSettings &tabSettings, - int cursorPositionInEditor = -1) final; -}; - -void JavaIndenter::indentBlock(const QTextBlock &block, - const QChar &typedChar, - const TextEditor::TabSettings &tabSettings, - int /*cursorPositionInEditor*/) -{ - int indent = indentFor(block, tabSettings); - if (typedChar == QLatin1Char('}')) - indent -= tabSettings.m_indentSize; - tabSettings.indentLine(block, qMax(0, indent)); -} - -int JavaIndenter::indentFor(const QTextBlock &block, - const TextEditor::TabSettings &tabSettings, - int /*cursorPositionInEditor*/) -{ - QTextBlock previous = block.previous(); - if (!previous.isValid()) - return 0; - - QString previousText = previous.text(); - while (previousText.trimmed().isEmpty()) { - previous = previous.previous(); - if (!previous.isValid()) - return 0; - previousText = previous.text(); - } - - int indent = tabSettings.indentationColumn(previousText); - - int adjust = previousText.count(QLatin1Char('{')) - previousText.count(QLatin1Char('}')); - adjust *= tabSettings.m_indentSize; - - return qMax(0, indent + adjust); -} - -TextEditor::TextIndenter *createJavaIndenter(QTextDocument *doc) -{ - return new JavaIndenter(doc); -} - -} // Android::Internal diff --git a/src/plugins/android/javaindenter.h b/src/plugins/android/javaindenter.h deleted file mode 100644 index f57da987e9c..00000000000 --- a/src/plugins/android/javaindenter.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Android::Internal { - -TextEditor::TextIndenter *createJavaIndenter(QTextDocument *doc); - -} // Android::Internal From f8abb04b77d1d6201959589d99cb935f3ed8778a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 13 Nov 2024 11:56:47 +0100 Subject: [PATCH 142/989] Android: Cut the convoluted indirection Get rid of a call to BuildStepList::firstOfType() from the packagePath() function, as the found step is the same as the only one caller has in hand. Hide packagePath() inside the androidbuildapkstep.cpp. Change-Id: Ifbf1557a0bac9a67a4bf256aaf9fa4d94c7372ad Reviewed-by: hjk --- src/plugins/android/androidbuildapkstep.cpp | 29 ++++++++++++++++- src/plugins/android/androidutils.cpp | 36 --------------------- src/plugins/android/androidutils.h | 1 - 3 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 4c99a617e23..18acd4f26a8 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -668,6 +668,33 @@ AndroidBuildApkStep::AndroidBuildApkStep(BuildStepList *parent, Utils::Id id) }); } +enum PackageFormat { Apk, Aab }; + +static QString packageSubPath(PackageFormat format, BuildConfiguration::BuildType buildType, + bool sig) +{ + const bool deb = (buildType == BuildConfiguration::Debug); + + if (format == Apk) { + if (deb) { + return sig ? packageSubPath(Apk, BuildConfiguration::Release, true) // Intentional + : "apk/debug/android-build-debug.apk"; + } + return QLatin1String(sig ? "apk/release/android-build-release-signed.apk" + : "apk/release/android-build-release-unsigned.apk"); + } + return QLatin1String(deb ? "bundle/debug/android-build-debug.aab" + : "bundle/release/android-build-release.aab"); +} + +static FilePath packagePath(const AndroidBuildApkStep *buildApkStep) +{ + const QString subPath = packageSubPath(buildApkStep->buildAAB() ? Aab : Apk, + buildApkStep->buildConfiguration()->buildType(), + buildApkStep->signPackage()); + return androidBuildDirectory(buildApkStep->target()) / "build/outputs" / subPath; +} + bool AndroidBuildApkStep::init() { if (!AbstractProcessStep::init()) { @@ -708,7 +735,7 @@ bool AndroidBuildApkStep::init() m_openPackageLocationForRun = openPackageLocation(); const FilePath outputDir = androidBuildDirectory(target()); - m_packagePath = packagePath(target()); + m_packagePath = packagePath(this); qCDebug(buildapkstepLog).noquote() << "APK or AAB path:" << m_packagePath.toUserOutput(); diff --git a/src/plugins/android/androidutils.cpp b/src/plugins/android/androidutils.cpp index 7bd230fb9ed..33d723b042e 100644 --- a/src/plugins/android/androidutils.cpp +++ b/src/plugins/android/androidutils.cpp @@ -346,42 +346,6 @@ FilePath buildDirectory(const Target *target) return {}; } -enum PackageFormat { Apk, Aab }; - -static QString packageSubPath(PackageFormat format, BuildConfiguration::BuildType buildType, - bool sig) -{ - const bool deb = (buildType == BuildConfiguration::Debug); - - if (format == Apk) { - if (deb) { - return sig ? packageSubPath(Apk, BuildConfiguration::Release, true) // Intentional - : QLatin1String("apk/debug/android-build-debug.apk"); - } - return QLatin1String(sig ? "apk/release/android-build-release-signed.apk" - : "apk/release/android-build-release-unsigned.apk"); - } - return QLatin1String(deb ? "bundle/debug/android-build-debug.aab" - : "bundle/release/android-build-release.aab"); -} - -FilePath packagePath(const Target *target) -{ - QTC_ASSERT(target, return {}); - - auto bc = target->activeBuildConfiguration(); - if (!bc) - return {}; - auto buildApkStep = bc->buildSteps()->firstOfType(); - if (!buildApkStep) - return {}; - - const QString subPath = packageSubPath(buildApkStep->buildAAB() ? Aab : Apk, - bc->buildType(), buildApkStep->signPackage()); - - return androidBuildDirectory(target) / "build/outputs" / subPath; -} - Abi androidAbi2Abi(const QString &androidAbi) { if (androidAbi == ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A) { diff --git a/src/plugins/android/androidutils.h b/src/plugins/android/androidutils.h index 5768ec3dc45..09b1c854891 100644 --- a/src/plugins/android/androidutils.h +++ b/src/plugins/android/androidutils.h @@ -49,7 +49,6 @@ Utils::FilePath androidAppProcessDir(const ProjectExplorer::Target *target); Utils::FilePath buildDirectory(const ProjectExplorer::Target *target); Utils::FilePath manifestPath(const ProjectExplorer::Target *target); void setManifestPath(ProjectExplorer::Target *target, const Utils::FilePath &path); -Utils::FilePath packagePath(const ProjectExplorer::Target *target); ProjectExplorer::Abi androidAbi2Abi(const QString &androidAbi); bool skipInstallationAndPackageSteps(const ProjectExplorer::Target *target); From d9ee476eb724cd8c16cbb7e58080d3d6800131fb Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 13 Nov 2024 11:43:12 +0100 Subject: [PATCH 143/989] RemoteLinux: Remove some unused variable and function Change-Id: Ia5415f39b09b0e3561b57037108e6fe6878ff4ff Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/linuxdevice.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 77dc20b6834..2ef15453f9d 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -443,7 +443,6 @@ public: void handleReadyReadStandardOutput(); void handleReadyReadStandardError(); - void clearForStart(); void doStart(); CommandLine fullLocalCommandLine() const; @@ -462,8 +461,6 @@ public: bool m_connecting = false; bool m_killed = false; - ProcessResultData m_result; - QByteArray m_output; QByteArray m_error; bool m_pidParsed = false; @@ -673,7 +670,6 @@ SshProcessInterfacePrivate::SshProcessInterfacePrivate(SshProcessInterface *sshI void SshProcessInterfacePrivate::start() { - clearForStart(); m_sshParameters = m_device->sshParameters(); const Id linkDeviceId = Id::fromSetting(m_device->extraData(Constants::LinkDevice)); @@ -771,11 +767,6 @@ void SshProcessInterfacePrivate::handleDisconnected(const ProcessResultData &res emit q->done(resultData); // TODO: don't emit done() on process finished afterwards } -void SshProcessInterfacePrivate::clearForStart() -{ - m_result = {}; -} - void SshProcessInterfacePrivate::doStart() { m_process.setProcessMode(q->m_setup.m_processMode); From 98510fa58b7456a38422f7c5913dd6669e012ad3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 13 Nov 2024 12:30:09 +0100 Subject: [PATCH 144/989] Android: Simplify packageSubPath() Drop recursive call to packageSubPath() when Apk && deb && sig is true -> in this case the recursive call returned "apk/release/android-build-release-signed.apk". Remove unneeded PackageFormat enum. Pass AndroidBuildApkStep directly into the packageSubPath(). Drop buildType and sig arguments. Change-Id: Iea48c2b125d2a6121555999c1f0f239283eeb722 Reviewed-by: Assam Boudjelthia --- src/plugins/android/androidbuildapkstep.cpp | 28 ++++++++------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 18acd4f26a8..b6563eb870f 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -668,31 +668,23 @@ AndroidBuildApkStep::AndroidBuildApkStep(BuildStepList *parent, Utils::Id id) }); } -enum PackageFormat { Apk, Aab }; - -static QString packageSubPath(PackageFormat format, BuildConfiguration::BuildType buildType, - bool sig) +static QString packageSubPath(const AndroidBuildApkStep *step) { - const bool deb = (buildType == BuildConfiguration::Debug); - - if (format == Apk) { - if (deb) { - return sig ? packageSubPath(Apk, BuildConfiguration::Release, true) // Intentional - : "apk/debug/android-build-debug.apk"; - } - return QLatin1String(sig ? "apk/release/android-build-release-signed.apk" - : "apk/release/android-build-release-unsigned.apk"); + const bool deb = (step->buildConfiguration()->buildType() == BuildConfiguration::Debug); + const bool sign = step->signPackage(); + if (!step->buildAAB()) { // APK build + if (deb && !sign) + return "apk/debug/android-build-debug.apk"; + return QLatin1String(sign ? "apk/release/android-build-release-signed.apk" + : "apk/release/android-build-release-unsigned.apk"); } return QLatin1String(deb ? "bundle/debug/android-build-debug.aab" : "bundle/release/android-build-release.aab"); } -static FilePath packagePath(const AndroidBuildApkStep *buildApkStep) +static FilePath packagePath(const AndroidBuildApkStep *step) { - const QString subPath = packageSubPath(buildApkStep->buildAAB() ? Aab : Apk, - buildApkStep->buildConfiguration()->buildType(), - buildApkStep->signPackage()); - return androidBuildDirectory(buildApkStep->target()) / "build/outputs" / subPath; + return androidBuildDirectory(step->target()) / "build/outputs" / packageSubPath(step); } bool AndroidBuildApkStep::init() From 3abc7ecf6634c614f81e3ef64258751692a9e3c1 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 13 Nov 2024 17:02:04 +0100 Subject: [PATCH 145/989] Utils: Fix return value of UnavailableDeviceFileAccess::fileSize() Change-Id: I153d5e906ff7e4000e98208af84116dd79524ebe Reviewed-by: Christian Kandeler --- src/libs/utils/devicefileaccess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 445aae81e7d..f86ccf122e5 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -591,7 +591,7 @@ bool UnavailableDeviceFileAccess::setPermissions(const FilePath &filePath, QFile qint64 UnavailableDeviceFileAccess::fileSize(const FilePath &filePath) const { Q_UNUSED(filePath) - return false; + return -1; } qint64 UnavailableDeviceFileAccess::bytesAvailable(const FilePath &filePath) const From 406d1c57a4a6cf916bc48cf40ac95e25b637fbee Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 5 Nov 2024 12:48:47 +0100 Subject: [PATCH 146/989] Android: Print messages if clearing/compiling app profiles are successful Errors are ignored, but it is good to see if it succeeded or failed (or was done at all). Change-Id: I1035e70f79226da1a0b222127764ff3296a0b37c Reviewed-by: Jarek Kobus --- src/plugins/android/androidrunnerworker.cpp | 28 ++++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index fd6b363c542..a7693f229df 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -841,13 +841,27 @@ static ExecutableItem pidRecipe(const Storage &storage) }; const auto onArtSetup = [storage](Process &process) { - process.setCommand(storage->adbCommand({"shell", "pm", "art", "clear-app-profiles", - storage->m_packageName})); + process.setCommand(storage->adbCommand( + {"shell", "pm", "art", "clear-app-profiles", storage->m_packageName})); + }; + const auto onArtDone = [storage](const Process &process) { + if (process.result() == ProcessResult::FinishedWithSuccess) + emit storage->m_glue->stdOut(Tr::tr("Art: Cleared App Profiles.")); + else + emit storage->m_glue->stdOut(Tr::tr("Art: Clearing App Profiles failed.")); + return DoneResult::Success; }; const auto onCompileSetup = [storage](Process &process) { - process.setCommand(storage->adbCommand({"shell", "pm", "compile", "-m", "verify", "-f", - storage->m_packageName})); + process.setCommand(storage->adbCommand( + {"shell", "pm", "compile", "-m", "verify", "-f", storage->m_packageName})); + }; + const auto onCompileDone = [storage](const Process &process) { + if (process.result() == ProcessResult::FinishedWithSuccess) + emit storage->m_glue->stdOut(Tr::tr("Art: Compiled App Profiles.")); + else + emit storage->m_glue->stdOut(Tr::tr("Art: Compiling App Profiles failed.")); + return DoneResult::Success; }; const auto onIsAliveSetup = [storage](Process &process) { @@ -855,6 +869,7 @@ static ExecutableItem pidRecipe(const Storage &storage) process.setCommand(storage->adbCommand({"shell", pidPollingScript.arg(storage->m_processPID)})); }; + // clang-format off return Group { Forever { stopOnSuccess, @@ -863,14 +878,15 @@ static ExecutableItem pidRecipe(const Storage &storage) DoneResult::Error) }.withTimeout(45s), ProcessTask(onUserSetup, onUserDone, CallDoneIf::Success), - ProcessTask(onArtSetup, DoneResult::Success), - ProcessTask(onCompileSetup, DoneResult::Success), + ProcessTask(onArtSetup, onArtDone), + ProcessTask(onCompileSetup, onCompileDone), Group { parallel, startNativeDebuggingRecipe(storage), ProcessTask(onIsAliveSetup) } }; + // clang-format on } void RunnerInterface::cancel() From 0aae5ac6491597323640b5dfcdb5dd62063d408e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 12 Nov 2024 16:52:51 +0100 Subject: [PATCH 147/989] ClangCodeModel: Get name of containing function from clangd No need to look it up in the AST anymore, as clangd >= 16 gives it to us for free. Change-Id: I7fe66be5b9e860bf85ff7a2a18e6854e776c5b83 Reviewed-by: hjk --- src/plugins/clangcodemodel/clangdclient.cpp | 8 +++++ .../clangcodemodel/clangdfindreferences.cpp | 36 ++++++++++++------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index ada183d4d74..2184ecbcf8a 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -453,6 +453,14 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir, c = textCaps->completion(); if (completionCaps) clangdTextCaps.setCompletion(ClangdCompletionCapabilities(*completionCaps)); + + // https://clangd.llvm.org/extensions#reference-container + if (const auto references = textCaps->references()) { + QJsonObject obj = *references; + obj.insert("container", true); + clangdTextCaps.setReferences(DynamicRegistrationCapabilities(obj)); + } + caps.setTextDocument(clangdTextCaps); } caps.clearExperimental(); diff --git a/src/plugins/clangcodemodel/clangdfindreferences.cpp b/src/plugins/clangcodemodel/clangdfindreferences.cpp index 4d6e7da9238..028fc295c88 100644 --- a/src/plugins/clangcodemodel/clangdfindreferences.cpp +++ b/src/plugins/clangcodemodel/clangdfindreferences.cpp @@ -47,7 +47,15 @@ namespace ClangCodeModel::Internal { class ReferencesFileData { public: - QList> rangesAndLineText; + struct ItemData { + ItemData(const Range &r, const QString &c, const QString &l) + : range(r), container(c), lineText(l) {} + Range range; + QString container; + QString lineText; + }; + + QList itemData; QString fileContent; ClangdAstNode ast; }; @@ -290,8 +298,10 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList finishSearch(); }); - for (const Location &loc : locations) - fileData[loc.uri()].rangesAndLineText.push_back({loc.range(), {}}); + for (const Location &loc : locations) { + fileData[loc.uri()].itemData.emplaceBack( + loc.range(), QJsonObject(loc).value("containerName").toString(), QString()); + } QSet canonicalFilePaths; for (auto it = fileData.begin(); it != fileData.end();) { const Utils::FilePath filePath = client()->serverUriToHostPath(it.key()); @@ -305,10 +315,10 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList } const QStringList lines = SymbolSupport::getFileContents(filePath); it->fileContent = lines.join('\n'); - for (auto &rangeWithText : it.value().rangesAndLineText) { - const int lineNo = rangeWithText.first.start().line(); + for (ReferencesFileData::ItemData &itemData : it.value().itemData) { + const int lineNo = itemData.range.start().line(); if (lineNo >= 0 && lineNo < lines.size()) - rangeWithText.second = lines.at(lineNo); + itemData.lineText = lines.at(lineNo); } ++it; } @@ -406,8 +416,8 @@ void ClangdFindReferences::Private::addSearchResultsForFile(const FilePath &file return {"Function", "CXXMethod"}; return {}; }(); - for (const auto &rangeWithText : fileData.rangesAndLineText) { - const Range &range = rangeWithText.first; + for (const ReferencesFileData::ItemData &itemData : fileData.itemData) { + const Range &range = itemData.range; const ClangdAstPath astPath = getAstPath(fileData.ast, range); const Usage::Tags usageType = fileData.ast.isValid() ? getUsageType(astPath, searchTerm, expectedDeclTypes) @@ -433,7 +443,7 @@ void ClangdFindReferences::Private::addSearchResultsForFile(const FilePath &file isProperUsage = !isRecursiveCall; } if (isProperUsage) { - qCDebug(clangdLog) << "proper usage at" << rangeWithText.second; + qCDebug(clangdLog) << "proper usage at" << itemData.lineText; canceled = true; finishSearch(); return; @@ -445,19 +455,19 @@ void ClangdFindReferences::Private::addSearchResultsForFile(const FilePath &file item.setFilePath(file); item.setMainRange(SymbolSupport::convertRange(range)); item.setUseTextEditorFont(true); - item.setLineText(rangeWithText.second); + item.setLineText(itemData.lineText); if (checkUnusedData) { - if (rangeWithText.second.contains("template<>")) { + if (itemData.lineText.contains("template<>")) { // Hack: Function specializations are not detectable in the AST. canceled = true; finishSearch(); return; } - qCDebug(clangdLog) << "collecting decl/def" << rangeWithText.second; + qCDebug(clangdLog) << "collecting decl/def" << itemData.lineText; checkUnusedData->declDefItems << item; continue; } - item.setContainingFunctionName(getContainingFunction(astPath, range).detail()); + item.setContainingFunctionName(itemData.container); if (search->supportsReplace()) { const Node * const node = ProjectTree::nodeForFile(file); From 73bcda2bbe53bb52866f129268181d29dc37ed02 Mon Sep 17 00:00:00 2001 From: Morteza Jamshidi Date: Thu, 14 Nov 2024 09:22:00 +0100 Subject: [PATCH 148/989] Add default download location for Windows App SDK Set the default download location of Windows App SDK to be the Download folder and also fixed NuGet spelling. Task-number: QTBUG-124800 Change-Id: I5ae6314cbea1d9cbb63a4e36f39ce9ba1db0079c Reviewed-by: hjk --- .../projectexplorer/windowsappsdksettings.cpp | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/plugins/projectexplorer/windowsappsdksettings.cpp b/src/plugins/projectexplorer/windowsappsdksettings.cpp index d14180f9855..8c67a6cbea1 100644 --- a/src/plugins/projectexplorer/windowsappsdksettings.cpp +++ b/src/plugins/projectexplorer/windowsappsdksettings.cpp @@ -68,6 +68,13 @@ WindowsAppSdkSettings::WindowsAppSdkSettings() AspectContainer::readSettings(); + if (downloadLocation().isEmpty()) { + QString path = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + + QStringLiteral("/WindowsAppSDK"); + QDir().mkpath(path); + downloadLocation.setValue(path); + } + if (windowsAppSdkLocation().isEmpty()) { windowsAppSdkLocation.setValue(FilePath::fromUserInput( Environment::systemEnvironment().value(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY))); @@ -238,34 +245,34 @@ WindowsSettingsWidget::WindowsSettingsWidget() auto winAppSdkDetailsWidget = new DetailsWidget; m_downloadPathChooser = new PathChooser; - m_downloadPathChooser->setToolTip(Tr::tr("Select the path of downloads.")); + m_downloadPathChooser->setToolTip(Tr::tr("Select the download path of NuGet and Windows App SDK.")); m_downloadPathChooser->setPromptDialogTitle(Tr::tr("Select download path")); m_downloadPathChooser->setExpectedKind(PathChooser::ExistingDirectory); m_downloadPathChooser->setFilePath(windowsAppSdkSettings().downloadLocation()); m_nugetPathChooser = new PathChooser; - m_nugetPathChooser->setToolTip(Tr::tr("Select the path of the Nuget.")); + m_nugetPathChooser->setToolTip(Tr::tr("Select the path of the NuGet.")); m_nugetPathChooser->setPromptDialogTitle(Tr::tr("Select nuget.exe file")); m_nugetPathChooser->setExpectedKind(PathChooser::Any); m_nugetPathChooser->setFilePath(windowsAppSdkSettings().nugetLocation()); - auto downloadNuget = new QPushButton(Tr::tr("Download Nuget")); + auto downloadNuget = new QPushButton(Tr::tr("Download NuGet")); downloadNuget->setToolTip( - Tr::tr("Automatically download Nuget.\n\n" - "Nuget is needed for downloading Windows App SDK.")); + Tr::tr("Automatically download NuGet.\n\n" + "NuGet is needed for downloading Windows App SDK.")); m_winAppSdkPathChooser = new PathChooser; m_winAppSdkPathChooser->setToolTip(Tr::tr("Select the path of the Windows App SDK.")); auto downloadWindowsAppSdk = new QPushButton(Tr::tr("Download WindowsAppSDK")); downloadWindowsAppSdk->setToolTip( - Tr::tr("Automatically download Windows App Sdk with Nuget.\n\n" + Tr::tr("Automatically download Windows App Sdk with NuGet.\n\n" "If the automatic download fails, Qt Creator proposes to open the download URL\n" "in the system's browser for manual download.")); const QMap winAppSdkValidationPoints = { { DownloadPathExistsRow, Tr::tr("Download path exists.") }, - { NugetPathExistsRow, Tr::tr("Nuget path exists.") }, + { NugetPathExistsRow, Tr::tr("NuGet path exists.") }, { WindowsAppSdkPathExists, Tr::tr("WindowsAppSDK path exists.") } }; m_winAppSdkSummary = new SummaryWidget(winAppSdkValidationPoints, @@ -293,9 +300,9 @@ WindowsSettingsWidget::WindowsSettingsWidget() } }, Layouting::Group { - title(Tr::tr("Nuget")), + title(Tr::tr("NuGet")), Grid { - Tr::tr("Nuget location:"), + Tr::tr("NuGet location:"), m_nugetPathChooser, downloadNuget, br, @@ -391,10 +398,10 @@ GroupItem WindowsSettingsWidget::downloadNugetRecipe() const auto failDialog = [=](const QString &msgSuffix = {}) { QStringList sl; - sl << Tr::tr("Nuget downloading failed."); + sl << Tr::tr("NuGet downloading failed."); if (!msgSuffix.isEmpty()) sl << msgSuffix; - sl << Tr::tr("Opening Nuget URL for manual download."); + sl << Tr::tr("Opening NuGet URL for manual download."); QMessageBox msgBox; msgBox.setText(sl.join(" ")); msgBox.addButton(Tr::tr("Cancel"), QMessageBox::RejectRole); @@ -410,7 +417,7 @@ GroupItem WindowsSettingsWidget::downloadNugetRecipe() struct StorageStruct { StorageStruct() { - progressDialog.reset(new QProgressDialog(Tr::tr("Downloading Nuget..."), + progressDialog.reset(new QProgressDialog(Tr::tr("Downloading NuGet..."), Tr::tr("Cancel"), 0, 100, Core::ICore::dialogParent())); progressDialog->setWindowModality(Qt::ApplicationModal); @@ -464,7 +471,7 @@ GroupItem WindowsSettingsWidget::downloadNugetRecipe() QTC_ASSERT(reply, return); const QUrl url = reply->url(); if (result != DoneWith::Success) { - failDialog(Tr::tr("Downloading Nuget from URL %1 has failed: %2.") + failDialog(Tr::tr("Downloading NuGet from URL %1 has failed: %2.") .arg(url.toString(), reply->errorString())); return; } @@ -506,7 +513,7 @@ void WindowsSettingsWidget::downloadNuget() this, nugetDownloadingTitle, Tr::tr( - "The selected download path (%1) for Nuget already exists.\n" + "The selected download path (%1) for NuGet already exists.\n" "Select a different path.") .arg(nugetPath.toUserOutput())); return; From 8eb1d52e1c2b92ba5f68d3ae5685370dfcd5eeba Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 14 Nov 2024 15:57:46 +0100 Subject: [PATCH 149/989] ProjectExplorer: Make run device kit aspect appear again ... in the mini target selector. Change-Id: Ia312b2fba8c11b96065584805c5fe3c11b00e6ba Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 5d914d82f41..6912dfb3962 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -188,7 +188,7 @@ private: void addToInnerLayout(Layouting::Layout &parentItem) override { - Layouting::Layout layout = parentItem; + Layouting::Layout &layout = parentItem; if (const QList embedded = aspectsToEmbed(); !embedded.isEmpty()) { layout = Layouting::Layout(new QHBoxLayout); parentItem.addItem(layout); From 9787ece8a5b42cc642264021b284f717e4278a88 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 14 Nov 2024 13:43:34 +0100 Subject: [PATCH 150/989] ProjectExplorer: Guard an TreeItem::parent() access Change-Id: Ia0b565ecdc5980420977e88e18ed7769e21950bf Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/targetsettingspanel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp index d6ad9e34cea..1daf0b95b12 100644 --- a/src/plugins/projectexplorer/targetsettingspanel.cpp +++ b/src/plugins/projectexplorer/targetsettingspanel.cpp @@ -735,6 +735,7 @@ bool TargetGroupItem::setData(int column, const QVariant &data, int role) Q_UNUSED(data) if (role == ItemActivatedFromBelowRole || role == ItemUpdatedFromBelowRole) { // Bubble up to trigger setting the active project. + QTC_ASSERT(parent(), return false); parent()->setData(column, QVariant::fromValue(static_cast(this)), role); return true; } From e13adc92b2fd495c8151e5502f011fded36a5ff5 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 14 Nov 2024 15:14:24 +0100 Subject: [PATCH 151/989] ProjectExplorer: Improve run device kit aspect appearance Give the trailing combo box a stretch factor. Change-Id: I1e11bb5ad78fa59304eaf315e0e188066826b277 Reviewed-by: hjk --- .../projectexplorer/devicesupport/devicekitaspects.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 6912dfb3962..22f1e918928 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -196,7 +196,9 @@ private: embedded.first()->addToInnerLayout(layout); layout.addItem(Tr::tr("Device:")); KitAspect::addToInnerLayout(layout); - layout.addItem(Layouting::Stretch(1)); + QSizePolicy p = comboBoxes().first()->sizePolicy(); + p.setHorizontalStretch(1); + comboBoxes().first()->setSizePolicy(p); } else { KitAspect::addToInnerLayout(layout); } From 295e5bb46e1d77e40182864465221942c9b4e6e6 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 14 Nov 2024 16:21:56 +0100 Subject: [PATCH 152/989] ProjectExplorer: Fix RunDeviceKitAspect layout again Commit 8eb1d52e1c2b92ba5f68d3ae5685370dfcd5eeba fixed the target selector, but broke the kit settings page. Change-Id: I6364f4ac3b3a201df1e376d863bcd16340e2b14e Reviewed-by: hjk --- .../projectexplorer/devicesupport/devicekitaspects.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 22f1e918928..1cfc074cfb5 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -188,10 +188,8 @@ private: void addToInnerLayout(Layouting::Layout &parentItem) override { - Layouting::Layout &layout = parentItem; if (const QList embedded = aspectsToEmbed(); !embedded.isEmpty()) { - layout = Layouting::Layout(new QHBoxLayout); - parentItem.addItem(layout); + Layouting::Layout layout(new QHBoxLayout); layout.addItem(Tr::tr("Type:")); embedded.first()->addToInnerLayout(layout); layout.addItem(Tr::tr("Device:")); @@ -199,8 +197,9 @@ private: QSizePolicy p = comboBoxes().first()->sizePolicy(); p.setHorizontalStretch(1); comboBoxes().first()->setSizePolicy(p); + parentItem.addItem(layout); } else { - KitAspect::addToInnerLayout(layout); + KitAspect::addToInnerLayout(parentItem); } } }; From 8f3bc91732d77aef80507770269a942e1db9e321 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 06:54:04 +0100 Subject: [PATCH 153/989] Android: Hide AvdDialog in cpp Rename it to avdcreatordialog.h. Provide executeAvdCreatorDialog() global function. Change-Id: Ib633dc75e94dcef8a8348d37fb2456661d9ade66 Reviewed-by: hjk --- src/plugins/android/CMakeLists.txt | 2 +- src/plugins/android/android.qbs | 4 +- src/plugins/android/androiddevice.cpp | 8 +- .../{avddialog.cpp => avdcreatordialog.cpp} | 162 +++++++++++------- src/plugins/android/avdcreatordialog.h | 14 ++ src/plugins/android/avddialog.h | 79 --------- 6 files changed, 117 insertions(+), 152 deletions(-) rename src/plugins/android/{avddialog.cpp => avdcreatordialog.cpp} (80%) create mode 100644 src/plugins/android/avdcreatordialog.h delete mode 100644 src/plugins/android/avddialog.h diff --git a/src/plugins/android/CMakeLists.txt b/src/plugins/android/CMakeLists.txt index 745b53f6db5..4849ee4e445 100644 --- a/src/plugins/android/CMakeLists.txt +++ b/src/plugins/android/CMakeLists.txt @@ -29,7 +29,7 @@ add_qtc_plugin(Android androidsignaloperation.cpp androidsignaloperation.h androidtoolchain.cpp androidtoolchain.h androidutils.cpp androidutils.h - avddialog.cpp avddialog.h + avdcreatordialog.cpp avdcreatordialog.h avdmanageroutputparser.cpp avdmanageroutputparser.h javaeditor.cpp javaeditor.h javalanguageserver.cpp javalanguageserver.h diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 05e34e31d75..c68f6280736 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -61,8 +61,8 @@ QtcPlugin { "androidtoolchain.h", "androidutils.cpp", "androidutils.h", - "avddialog.cpp", - "avddialog.h", + "avdcreatordialog.cpp", + "avdcreatordialog.h", "avdmanageroutputparser.cpp", "avdmanageroutputparser.h", "javaeditor.cpp", diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 84977d53962..316e2470396 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -9,7 +9,7 @@ #include "androidsignaloperation.h" #include "androidtr.h" #include "androidutils.h" -#include "avddialog.h" +#include "avdcreatordialog.h" #include "avdmanageroutputparser.h" #include @@ -1053,11 +1053,11 @@ public: return IDevice::Ptr(); } - AvdDialog dialog = AvdDialog(Core::ICore::dialogParent()); - if (dialog.exec() != QDialog::Accepted) + const auto info = executeAvdCreatorDialog(); + if (!info) return IDevice::Ptr(); - const IDevice::Ptr dev = createDeviceFromInfo(dialog.avdInfo()); + const IDevice::Ptr dev = createDeviceFromInfo(*info); if (const auto androidDev = static_cast(dev.get())) { qCDebug(androidDeviceLog, "Created new Android AVD id \"%s\".", qPrintable(androidDev->avdName())); diff --git a/src/plugins/android/avddialog.cpp b/src/plugins/android/avdcreatordialog.cpp similarity index 80% rename from src/plugins/android/avddialog.cpp rename to src/plugins/android/avdcreatordialog.cpp index 39a0780b2de..fad76a6c0ad 100644 --- a/src/plugins/android/avddialog.cpp +++ b/src/plugins/android/avdcreatordialog.cpp @@ -1,17 +1,19 @@ // Copyright (C) 2016 BogDan Vatra // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "avddialog.h" -#include "androidtr.h" +#include "avdcreatordialog.h" + #include "androidconfigurations.h" #include "androiddevice.h" #include "androidsdkmanager.h" +#include "androidtr.h" #include #include #include +#include #include #include @@ -23,6 +25,7 @@ #include #include +#include #include #include #include @@ -30,9 +33,11 @@ #include #include #include +#include #include -#include #include +#include +#include using namespace ProjectExplorer; using namespace SpinnerSolution; @@ -43,8 +48,71 @@ namespace Android::Internal { static Q_LOGGING_CATEGORY(avdDialogLog, "qtc.android.avdDialog", QtWarningMsg) -AvdDialog::AvdDialog(QWidget *parent) - : QDialog(parent) +enum class DeviceType { Phone, Tablet, Automotive, TV, Wear, Desktop, PhoneOrTablet }; + +static DeviceType tagToDeviceType(const QString &type_tag) +{ + if (type_tag.contains("android-wear")) + return DeviceType::Wear; + else if (type_tag.contains("android-tv")) + return DeviceType::TV; + else if (type_tag.contains("android-automotive")) + return DeviceType::Automotive; + else if (type_tag.contains("android-desktop")) + return DeviceType::Desktop; + return DeviceType::PhoneOrTablet; +} + +class AvdDialog : public QDialog +{ +public: + explicit AvdDialog(); + CreateAvdInfo avdInfo() const { return m_createdAvdInfo; } + +private: + const SystemImage *systemImage() const + { return m_targetApiComboBox->currentData().value(); } + QString name() const { return m_nameLineEdit->text(); } + QString abi() const { return m_abiComboBox->currentText(); } + QString deviceDefinition() const { return m_deviceDefinitionComboBox->currentText(); } + int sdcardSize() const { return m_sdcardSizeSpinBox->value(); } + bool isValid() const + { return !name().isEmpty() && systemImage() && systemImage()->isValid() && !abi().isEmpty(); } + + bool eventFilter(QObject *obj, QEvent *event) override; + void updateDeviceDefinitionComboBox(); + void updateApiLevelComboBox(); + void collectInitialData(); + void createAvd(); + + struct DeviceDefinitionStruct + { + QString name_id; + QString type_str; + DeviceType deviceType; + }; + + CreateAvdInfo m_createdAvdInfo; + QTimer m_hideTipTimer; + QRegularExpression m_allowedNameChars; + QList m_deviceDefinitionsList; + QMap m_deviceTypeToStringMap; + + QWidget *m_gui; + QComboBox *m_abiComboBox; + QSpinBox *m_sdcardSizeSpinBox; + QLineEdit *m_nameLineEdit; + QComboBox *m_targetApiComboBox; + QComboBox *m_deviceDefinitionComboBox; + Utils::InfoLabel *m_warningText; + QComboBox *m_deviceDefinitionTypeComboBox; + QCheckBox *m_overwriteCheckBox; + QDialogButtonBox *m_buttonBox; + Tasking::TaskTreeRunner m_taskTreeRunner; +}; + +AvdDialog::AvdDialog() + : QDialog(Core::ICore::dialogParent()) , m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")) { resize(800, 0); @@ -125,39 +193,16 @@ AvdDialog::AvdDialog(QWidget *parent) connect(m_buttonBox, &QDialogButtonBox::accepted, this, &AvdDialog::createAvd); connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - m_deviceTypeToStringMap.insert(AvdDialog::Phone, "Phone"); - m_deviceTypeToStringMap.insert(AvdDialog::Tablet, "Tablet"); - m_deviceTypeToStringMap.insert(AvdDialog::Automotive, "Automotive"); - m_deviceTypeToStringMap.insert(AvdDialog::TV, "TV"); - m_deviceTypeToStringMap.insert(AvdDialog::Wear, "Wear"); - m_deviceTypeToStringMap.insert(AvdDialog::Desktop, "Desktop"); + m_deviceTypeToStringMap.insert(DeviceType::Phone, "Phone"); + m_deviceTypeToStringMap.insert(DeviceType::Tablet, "Tablet"); + m_deviceTypeToStringMap.insert(DeviceType::Automotive, "Automotive"); + m_deviceTypeToStringMap.insert(DeviceType::TV, "TV"); + m_deviceTypeToStringMap.insert(DeviceType::Wear, "Wear"); + m_deviceTypeToStringMap.insert(DeviceType::Desktop, "Desktop"); collectInitialData(); } -bool AvdDialog::isValid() const -{ - return !name().isEmpty() && systemImage() && systemImage()->isValid() && !abi().isEmpty(); -} - -CreateAvdInfo AvdDialog::avdInfo() const -{ - return m_createdAvdInfo; -} - -AvdDialog::DeviceType AvdDialog::tagToDeviceType(const QString &type_tag) -{ - if (type_tag.contains("android-wear")) - return AvdDialog::Wear; - else if (type_tag.contains("android-tv")) - return AvdDialog::TV; - else if (type_tag.contains("android-automotive")) - return AvdDialog::Automotive; - else if (type_tag.contains("android-desktop")) - return AvdDialog::Desktop; - return AvdDialog::PhoneOrTablet; -} - void AvdDialog::collectInitialData() { const auto onProcessSetup = [this](Process &process) { @@ -218,11 +263,11 @@ id: 3 or "desktop_large" } DeviceType deviceType = tagToDeviceType(deviceDefinition.type_str); - if (deviceType == PhoneOrTablet) { + if (deviceType == DeviceType::PhoneOrTablet) { if (deviceDefinition.name_id.contains("Tablet")) - deviceType = Tablet; + deviceType = DeviceType::Tablet; else - deviceType = Phone; + deviceType = DeviceType::Phone; } deviceDefinition.deviceType = deviceType; m_deviceDefinitionsList.append(deviceDefinition); @@ -330,31 +375,6 @@ void AvdDialog::updateDeviceDefinitionComboBox() updateApiLevelComboBox(); } -const SystemImage* AvdDialog::systemImage() const -{ - return m_targetApiComboBox->currentData().value(); -} - -QString AvdDialog::name() const -{ - return m_nameLineEdit->text(); -} - -QString AvdDialog::abi() const -{ - return m_abiComboBox->currentText(); -} - -QString AvdDialog::deviceDefinition() const -{ - return m_deviceDefinitionComboBox->currentText(); -} - -int AvdDialog::sdcardSize() const -{ - return m_sdcardSizeSpinBox->value(); -} - void AvdDialog::updateApiLevelComboBox() { const SystemImageList installedSystemImages = sdkManager().installedSystemImages(); @@ -366,11 +386,13 @@ void AvdDialog::updateApiLevelComboBox() return image && image->isValid() && (image->abiName() == selectedAbi); }; - SystemImageList filteredList; - filteredList = Utils::filtered(installedSystemImages, [hasAbi, &curDeviceType](const SystemImage *image) { + const SystemImageList filteredList = Utils::filtered( + installedSystemImages, [hasAbi, &curDeviceType](const SystemImage *image) { DeviceType deviceType = tagToDeviceType(image->sdkStylePath().split(';').at(2)); - if (deviceType == PhoneOrTablet && (curDeviceType == Phone || curDeviceType == Tablet)) - curDeviceType = PhoneOrTablet; + if (deviceType == DeviceType::PhoneOrTablet + && (curDeviceType == DeviceType::Phone || curDeviceType == DeviceType::Tablet)) { + curDeviceType = DeviceType::PhoneOrTablet; + } return image && deviceType == curDeviceType && hasAbi(image); }); @@ -426,4 +448,12 @@ bool AvdDialog::eventFilter(QObject *obj, QEvent *event) return QDialog::eventFilter(obj, event); } +std::optional executeAvdCreatorDialog() +{ + AvdDialog dialog; + if (dialog.exec() != QDialog::Accepted) + return {}; + return dialog.avdInfo(); +} + } // Android::Internal diff --git a/src/plugins/android/avdcreatordialog.h b/src/plugins/android/avdcreatordialog.h new file mode 100644 index 00000000000..051b0403c46 --- /dev/null +++ b/src/plugins/android/avdcreatordialog.h @@ -0,0 +1,14 @@ +// Copyright (C) 2016 BogDan Vatra +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Android::Internal { + +class CreateAvdInfo; + +std::optional executeAvdCreatorDialog(); + +} // Android::Internal diff --git a/src/plugins/android/avddialog.h b/src/plugins/android/avddialog.h deleted file mode 100644 index 3cb3a3c62d4..00000000000 --- a/src/plugins/android/avddialog.h +++ /dev/null @@ -1,79 +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 - -#include "androidconfigurations.h" - -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QComboBox; -class QCheckBox; -class QDialogButtonBox; -class QLineEdit; -class QSpinBox; -QT_END_NAMESPACE - -namespace Utils { class InfoLabel; } - -namespace Android::Internal { - -class SdkPlatform; - -class AvdDialog : public QDialog -{ -public: - explicit AvdDialog(QWidget *parent = nullptr); - CreateAvdInfo avdInfo() const; - -private: - enum DeviceType { Phone, Tablet, Automotive, TV, Wear, Desktop, PhoneOrTablet }; - - const SystemImage *systemImage() const; - QString name() const; - QString abi() const; - QString deviceDefinition() const; - int sdcardSize() const; - bool isValid() const; - - void updateDeviceDefinitionComboBox(); - void updateApiLevelComboBox(); - bool eventFilter(QObject *obj, QEvent *event) override; - - static AvdDialog::DeviceType tagToDeviceType(const QString &type_tag); - - void collectInitialData(); - void createAvd(); - - struct DeviceDefinitionStruct - { - QString name_id; - QString type_str; - DeviceType deviceType; - }; - - CreateAvdInfo m_createdAvdInfo; - QTimer m_hideTipTimer; - QRegularExpression m_allowedNameChars; - QList m_deviceDefinitionsList; - QMap m_deviceTypeToStringMap; - - QWidget *m_gui; - QComboBox *m_abiComboBox; - QSpinBox *m_sdcardSizeSpinBox; - QLineEdit *m_nameLineEdit; - QComboBox *m_targetApiComboBox; - QComboBox *m_deviceDefinitionComboBox; - Utils::InfoLabel *m_warningText; - QComboBox *m_deviceDefinitionTypeComboBox; - QCheckBox *m_overwriteCheckBox; - QDialogButtonBox *m_buttonBox; - Tasking::TaskTreeRunner m_taskTreeRunner; -}; - -} // Android::Internal From 301f0c0c373fb49afda6197dfaea16e875733ea4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 07:25:42 +0100 Subject: [PATCH 154/989] Android: More forward declarations in androidutils.h Change-Id: I1b3155f553c6795c46f9f93cd81b198d8a298af8 Reviewed-by: hjk --- src/plugins/android/androidutils.cpp | 2 ++ src/plugins/android/androidutils.h | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/plugins/android/androidutils.cpp b/src/plugins/android/androidutils.cpp index 33d723b042e..d01a941d090 100644 --- a/src/plugins/android/androidutils.cpp +++ b/src/plugins/android/androidutils.cpp @@ -16,12 +16,14 @@ #include #include +#include #include #include #include #include #include +#include #include #include diff --git a/src/plugins/android/androidutils.h b/src/plugins/android/androidutils.h index 09b1c854891..ba26d196b00 100644 --- a/src/plugins/android/androidutils.h +++ b/src/plugins/android/androidutils.h @@ -3,22 +3,31 @@ #pragma once -#include - -#include - -#include +#include namespace ProjectExplorer { +class Abi; class Kit; class Target; } +namespace QtSupport { class QtVersion; } + +namespace Tasking { +class ExecutableItem; +template +class Storage; +} + namespace Utils { class FilePath; class Process; } +QT_BEGIN_NAMESPACE +class QJsonObject; +QT_END_NAMESPACE + namespace Android::Internal { QString packageName(const ProjectExplorer::Target *target); From 2e736b7946f9b1807d0351086f8d228d4f7dc653 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 07:57:10 +0100 Subject: [PATCH 155/989] Android: Move #include into cpp It's used only there. Change-Id: I40879516f9560019778891956180a909223c8fd5 Reviewed-by: hjk --- src/plugins/android/androidqtversion.cpp | 2 ++ src/plugins/android/androidqtversion.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index bda3c7e8a0e..411a640fd87 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -27,6 +27,8 @@ #include +#include + #include #include #include diff --git a/src/plugins/android/androidqtversion.h b/src/plugins/android/androidqtversion.h index d01197ecab3..14ec91d3fca 100644 --- a/src/plugins/android/androidqtversion.h +++ b/src/plugins/android/androidqtversion.h @@ -4,7 +4,6 @@ #pragma once #include -#include namespace Android::Internal { From 533b7ab6eea9e1fbe48f4dd07e9b8c10582ade00 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 07:42:53 +0100 Subject: [PATCH 156/989] Android: Drop parent from executeAndroidSdkManagerDialog() Use common Core::ICore::dialogParent() instead. Change-Id: Ifcdf9370b03706b7451ad47d88381f67ff59003f Reviewed-by: hjk --- src/plugins/android/androidsdkmanagerdialog.cpp | 13 +++++++------ src/plugins/android/androidsdkmanagerdialog.h | 4 +--- src/plugins/android/androidsettingswidget.cpp | 4 +--- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/plugins/android/androidsdkmanagerdialog.cpp b/src/plugins/android/androidsdkmanagerdialog.cpp index 4b5deacabc9..4de5df631bf 100644 --- a/src/plugins/android/androidsdkmanagerdialog.cpp +++ b/src/plugins/android/androidsdkmanagerdialog.cpp @@ -7,6 +7,8 @@ #include "androidtr.h" #include "androidutils.h" +#include + #include #include #include @@ -406,14 +408,14 @@ private: class AndroidSdkManagerDialog : public QDialog { public: - AndroidSdkManagerDialog(QWidget *parent); + AndroidSdkManagerDialog(); private: AndroidSdkModel *m_sdkModel = nullptr; }; -AndroidSdkManagerDialog::AndroidSdkManagerDialog(QWidget *parent) - : QDialog(parent) +AndroidSdkManagerDialog::AndroidSdkManagerDialog() + : QDialog(Core::ICore::dialogParent()) , m_sdkModel(new AndroidSdkModel(this)) { setWindowTitle(Tr::tr("Android SDK Manager")); @@ -631,10 +633,9 @@ bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour return showTopLevel || ((packageState(srcIndex) & m_packageState) && packageFound(srcIndex)); } -void executeAndroidSdkManagerDialog(QWidget *parent) +void executeAndroidSdkManagerDialog() { - AndroidSdkManagerDialog dialog(parent); - dialog.exec(); + AndroidSdkManagerDialog().exec(); } } // Android::Internal diff --git a/src/plugins/android/androidsdkmanagerdialog.h b/src/plugins/android/androidsdkmanagerdialog.h index 24e4698fc07..606f1030e42 100644 --- a/src/plugins/android/androidsdkmanagerdialog.h +++ b/src/plugins/android/androidsdkmanagerdialog.h @@ -2,10 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -#include - namespace Android::Internal { -void executeAndroidSdkManagerDialog(QWidget *parent); +void executeAndroidSdkManagerDialog(); } // Android::Internal diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 8224b18e644..fc44ad5f6c3 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -476,9 +476,7 @@ AndroidSettingsWidget::AndroidSettingsWidget() this, &AndroidSettingsWidget::downloadOpenSslRepo); connect(downloadOpenJdkToolButton, &QAbstractButton::clicked, this, &AndroidSettingsWidget::openOpenJDKDownloadUrl); - connect(sdkManagerToolButton, &QAbstractButton::clicked, this, [this] { - executeAndroidSdkManagerDialog(this); - }); + connect(sdkManagerToolButton, &QAbstractButton::clicked, this, &executeAndroidSdkManagerDialog); connect(sdkToolsAutoDownloadButton, &QAbstractButton::clicked, this, &AndroidSettingsWidget::downloadSdk); connect(&m_sdkDownloader, &Tasking::TaskTreeRunner::done, this, [this](Tasking::DoneWith result) { From d53d92b2f742962612a8a3ad01e4579af8c828ad Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 14 Nov 2024 16:25:34 +0100 Subject: [PATCH 157/989] Doc: Add screenshot of Preferences > SDKs > Android - Replaces the old screenshot - Added SDK and NDK topics to the How To - Develop for Devices - SDKs category Task-number: QTCREATORBUG-32016 Change-Id: I6b2af44152079d29f51c1ef34606ee522b80f378 Reviewed-by: Assam Boudjelthia --- .../images/qtcreator-preferences-android.webp | Bin 17192 -> 13222 bytes doc/qtcreator/src/android/androiddev.qdoc | 2 ++ 2 files changed, 2 insertions(+) diff --git a/doc/qtcreator/images/qtcreator-preferences-android.webp b/doc/qtcreator/images/qtcreator-preferences-android.webp index 3c6e909df2e38f29ea77b342349553124ae59dab..f5017be66b0e57d392a8c9db1b2bd5501689e3e1 100644 GIT binary patch literal 13222 zcmWIYbaR_$%)k)t>J$(bVBs^#n1MmR&8djtYu917NlMGL|8Hn~ypg%1gL8$3?avFV z@BMVW@zF41Zphb#Tb(xk`nPgn?9T%G$@fDZHt?Ej#cQ3meeQpyF=O^IWjjBqobamK zj8lb|S3aw+PTvx@LTAI(cdy*bGc_+b@;y5H#gzhVx@H3 zsJD+5W>^~}oe!LF_+G=|$xrljoQ@as{CdrPT`uohV|&w<6DKK z%^Xr^s(xDVe?v*ma;Xigk3^c7NG&gOnRx8d(T5?26udM4rTo14e|hegmxetBm2Xz9 zNMW4za-#P_*LTYn80NJb%`SPMQ{eMy@)Bm5`+t>BZu_<^H?Hbtlcd82si(Y4jD#xh zypF0icNEaOqOtkNT^9a1cE#J(|88gX+%|zDY~$-{tLEFawlM-9&wM>Gef#(S;@dC& zdmpD`Y+O8JW~QXx+eY!3An@^0Veq#d+!ey#{?^so&7b+P!Y)}}49S${>(%lzTdNhxoPY@(1M)A6I;)x$#rUxntT- zPQ@SK>!|cn^LxxQC-_3h^LVqI716)$eRkz_XW!`GI60!y_UM!a3m-ab%iamNE3xt6 z^X?eFyJuQ6vVL7C-moz5gM=wcb?|iy0re>YGQRbAu zTgUj8F$KT9#y;il`?ls)Q2|MN0%~}+G0!dAD}CwGePgK*GVRnY4wOZld$F+Y`&YXR>GFZ=kUQMmajgsd-^If|atc$U;{d?f{ z!~?q~vj_-xMPKfl^UY3SfBK0tf$wWYr`~r?*O`3TRr0rf)$iuDMN;O)W_q3lvu;Q` zCnb0{tnZt6H~9G6rI(+6%1SUiXr=D$QL?7*;W3@ORbkAtoBU)2@=w z#EK6Gv$XYiSy%H--fcduYVo;$-Ej_~v9FfOPTa65%yfZ-sE+FXdp^(8lir7kDi`MQ zEIa+~f&TA<-uy>;7o5;Po8!6TT#20H!K#|CrT;w~o-esGIe%*Y)&j$-^bhRsqrKi} z>BQ`>xf}k~_T(P-)w2%DM;$xT+WUy-XXZ}cxo?A>JM;n|53^((3#BsrvgB>t)Yt_pVxhxT$Sj)T?<{CVkxX;=*m^!;@VlUq`Cn z)-yCtF*Xc(AnLg8ME?m<-L{V}KWnD-<`wOXse2~Z77!Guq)@{sB^@VMchJ{1`c2T0pBXv#Kka*)_o}>0%8qMevFOU; zlU1#MxI5-cdpz6YT;|nsdC7mDHcz$ATXXxWvhB`45@9d9s-1n+g2j5{JO2FXC*GP( z+3c}KqSTMAn|aO8HVzsUw4X`5CVlel#@6*)O}ly5{Cx9?OL30K@*AIT3aT`A zeqX%wnA}1wJ5y<{d)wFUeD`GDyL$|!bNM*J!Qh4N<1UaQI?Vqb0D zx`2=4#=ZHkD)-y(cv(4L%Q7j|pT(oKRZOP$)S_-Lhh7!yc+s3j$B->oZY-TC=Xh)y zlYF(EHS3@5z?zB;b>G?CW~g45JrV7H{dSJ;-c4+mI{en&TJWTC($uY5zcxrH#4d_B zzG4eUl>gP%pp6!}ley$-wRoLX7bGPGNT$77=&9luy0AX+e7gIAKZ!bb_UvD?$gTX^ zrMJJnd9fN@zEqMdG|6Y9(V`~{mz@>-u|YB*qdn5))=Le?s0OE%32&1)Ggq@*SrMkc zhjHfgr3Y?Edq>XZ<*JqWbaQ8ti%y#HngtvDmcMZiWcVb~eOdWKqVa+NzUs(~?APC1 z16Ou%U0Lyf_e4qZq~}iZ?KNe8xRPVT9!gDXnD+I))$6&|K5<%~4zQaZP~h`TGge#S ze%oQCLAVm5=xXgfj5Eb=m@2YyRf)))=ezj#lgCDjx10NBt0r!J_tjYHe%$vrH&3Su zl|DGKT{3Fk$%k+Mu3)yyVVe?C!V$)wKV864TeQq|<$*H6l@A?yPbp+N1bXi|(0A*Q zyg29Ump{su?3Ot3wewF|pqpAJAOEAn2OZvR{&Z`BMRK8(83TyBZnH)0POF#yrGwRX zRwb|6^{IX8RxQ!R{o0#3wI2$cZ*aeon5bQS#7N^|yVd#@)-OK~4#zmDJUiKl+uyve!$p z;8tI)Ja_X&>wfD~?^Z8Ny!p(%`=@B?eK*m{yB1rY72ajbR!;qXRryGy$UY`n$+#yk zL@&8z?NKACa#KVN0<`XX*-`2~UtI=>qiXlM2Y&YXSft)JY| zx(j!Erq!x{EGU++{rXtu_*8~VCboZ`O?YWpp|^d7%~CDDQ-POeJiU6%sYYHlWcvrR zUv_u&S_kFV(!@g}X?|-&MF69$d`R9_ zV09hG-nEToH{ADY1a4DLo2tEdcGb0W9=mg{o;$y5qvaI&%mbe%90*XB)6XV2|8QdtUUK=&v6DX&_m}<4{o1xAY4caPmfwo29rO0<{}K$* zk8_Y(b%k-4|&bO`6b7_Z8Q-oxYF~w0?r1Z0nC2*#B*e3_GjJ+ZCa)7d56xkdGRz`Jf36EviV`&wu=S3Z!%^$U1gZK z$-;J#PMUGq%c^T>r*EEl8zonld*S7jy{|SF&7QmdVXep~-gPO@FK177k3Z_SHp1Q} z;AiT>*wgLoPr6)e;}o5R7j=njyvOr8jWc%Brn|4qQ@_fv?LFA=F~ok|hFHl}M-z)z zgm%r{=dx?pqCZ-lT#;$BrkOUB9lN#Ey2PQ?_}hP}t$yrNOnZ%-uIBKCGHX}{#;p)| zF=g|FvQv@=)~wZ0H29XY)9qE#1@B7J_$SFcvBxjCTmI2XD>M$0x-fakCfmrX&byr^ zx%}1ESoZvHNAHVvO)r)WX}lVR+zIg=@9h6Bbp5_M;J~lH3-;eU^0#r>{$sT>|K6(H zb+t<1W$j}AO94xxOizbC4fq)<^gH&4=*5zh!))sWBX-BkuFtaEw7A9eSIe!+Zk~{% z7vJ6u^<5#=aEj4l{}Psa$G3F0%&)Pu%UIS}xHj$c>Gy6--5weLG&Zbb-TvOvV-Np^ z@4Nzr`*KqrZe5n^^-@0TU+#hGo6eQb_DQ|iZGNH9&3@%_+lg<#b$TWhYh-`_vCKmH zKwI`%OPB9g8(!YKaZO=ffR|Z{^`Z@rlteOT#LR9NzxzpWQ&nEh*W&rAyMn$)oZ7Hy zUgFNROZ9c;7F(GYaC=!8UcbEh*Rwy9ie&p1uJ~@damt+7$sZJ-``8?g-6#`2&qDNg zz?JRaGE+o<-0||yKOQ0$#5rr--|Ukga(_+UX!yZah@RcB|f=3b+De5G%G?1f(ozOv3LzGK{ZvhUOKvwNj-kJ5f=bfWA6f_vpkxb~dY z)!j0$k3UjLQ8ScfRJ(UWJM6^Y$PHb>n%kM2-7*y>yB+3Ig_wJBTBVMk%1UN$?q@v0 z$C9TUSMIlX%w=&7WN7x^KtS=a7?|08fLf!MM%CiS)?-S>gp5fzM|9Hke zb%S)li6&5W96aRSe%wqM~)SWBM zzj9Ba&eYbBsakwXb2i>doUz3F?&JpVxhgu%Q(_k^IKO$)$~S2Vav_evH}Gmd8GcL?>K5`~GnHt#Bl~ydyzi1rHN&N=TUY&9D6~AXZg=U{ z!iHO)tyRR5PN|4}mJmulXX7@p#Y<}PmhJnT zQ#@>bPn)DIJ}2&);ndmL+)*-%(_JE<38TmU^Nho;@|T+gGsFzuTyN9xvF>r1Ywfe= z#-ujK_)|jD7BWSL8BMy{t!B2lYNLw8?Mq2hCDsaW-&HBMX@zH&n&E8e={O#M{U}UEJ=}@ z-Dt;`*1TNcQ_7-jmXh?}D%=t|>YMf?N(I^b6}R)g^*nseJmQei(uOqE;Fo(Ia9usV zS0jSSM0Z+@8qTVUXoL>4pdEHL` zq%)}k_uh9->#%q$>6@=tK4bQuxt=*{OBeJLBKwiwvlE58-T>dBkQ9bfP;vD2I6V{}-QkhTt;DjrJ?NbvxUUVGxGE^z)@jWlKlu6W` zy;;TANOs4IIKRcxuR=B1P2JgdUp?W(RUR(1SVq*Hee#+UW&iR$tVbIw-Y{}Ak{o2F7}FVn!`VOe%y`Njs$(+cw=JKF_r9&|bBAKg4V@(iD4 zs$Phb;pEji2j0C{?7D@`c)EDVvyJyQTq)itsbo0k)Kk{T?K+kZbwcNFN|F05F{OxO zrbM3M?2R999f-5gTE5DEY7@sq3BS@EE1e&%coRBbi}zz-!Fj$mE>N7TzWhmk#&3Q5 zXJN^ry2>pb4K=C1Yvb}Jwxk*yTQ-Srqn|z38e8ACs?bBsL0Z%LEJSaY=s&DyeZc&w zn*D~GOxPsFh01)|N1=i9s^hSie!kD#H#U0ycS+Feoh!a@CJj(Bsd)XP)*C$;% zR-b%tcSm!>23|(>JU+9eNM9L|4}xsRPb)Ck$7$PbI^zD|k$Xq8=YM6zw&a6H>{pz7 z@Lfhhy6wUe*$zGftJaIW$DXBEGW%CL%&YnN@8q*}-G36AzW>`et+eFnI|&xs6-yS2 zv#;f^>ug&2KDxwiPTe=V1@$f`54-vH8{GA4TDE8X%byMwr|Qnse2A0j;91Am!uDfd zkkR|vvrc)>LVa%i$Y1baU(;cMf+-R~otd9CvlczRKH=w&IlRkk?p%HLU9N14O%H#0 zsl|ylMIWJV+na{F%adh}OT2CL<#=%Lhvf65nzplzMP+Ze+6=Z^Y!#Sh_cckq=iKIl zTk4N&(PHK?l3|gYsKoNT`P{>kYCCou=+9C(yex5*TZpW8{|%``HFM)m)vQ0}HGhPr zDLx3e_SNHHlEZ|_2^PPfG{>gz*bv6ryq0y_#bqDA-4tuKXt>DAGCSb>KL=Nr_0L#b zR2y&b@q(?Zj64{V(%{&-dx80J?_Vi)SF^KO6%H?Yc;m;K2=!IZ&N|&){nV~g>VGfa zn{5XtB{pmd@?5-s)4WrhqU{oD&pxJ|P&;%uHg{LXf9=Z~ZB8CAR$X6zhv&`)g)YHE z9gZ>wBxGK?O_;!8W$m{yFURIhNAbR6?^gDE-<|S3_NLK`CMHhv-XCANcg$`2wM27G zoZREN-%SI4M0A(M&w9quA^OydM`~wKu$$I_joPt>D@v?69^F=bDX9HOd3!mMX+S;A| zI!$oR$GS_emTJ##S@gm1v*H11Z&QKpZ2>$lT3j<8Dld4tRX#*we^S8fGQpC-u=iPZ zyf5bnURiMSjdbS%6&}%;wxar3fxD9A*GK)~d^^eHpLA=^wzzds?G4Tij3-uT2O60z zd%-1_5xHLQ+`Pkjr+({w%dTH8JuN*~R-)nN@#G&Ne;L*Zzmb!1NR;J#c%fM?#O%in z+r$lLs^uRrhAhZ^eQZY50W-y4GJ9mQSMx=NWN!58xwLZIuFgG$Ojm27ws$Y+-gMz% z4a=sjO$EFH?>@%{2yySe&p-cURN3ppPbMz;cwZo8@zp{O3-4Wh@w4~I8kRRjol=w8SO3^-f5C#|(rnw)A@uDTn`*x$jYn7mR3r9q+)#M6 z@~o?X_fZ4oyWL)LEvqs^F0aeXPi@%S+C4ET&(NGFGxwDlzS*)Nu&1|``RoA)J9(Z-jk#|fHu2|){kPaw5nwC)dcmO^eQ^;vR?o8) zdsM$%oqd*Xc1+pL6MQbeVl0~$oO}J^IGdpKt9pYAE>n2^h|k;Xys2qlQOjz^#P&tp zl^a!buAyZL}yBWpTu^~NJt0>Y0} zz504%V{)V52M(3biZf?s%33+-TJWu`IBn^Eqpm*q+3os!XIF%z`iFdfV)AZRhjFKG z&tUjGVPKzvgRLoSgY(_L3ltp8a`F3BTQc@bYgg+3meDtiDvRFhPd> z!N<%#JG!R4|C9n!J#H*kW$|^>^oL3r{w^lvsw0e6tUjNz0mmX6# zUXZQ7%W}Y3CFghAv!ag2%3KrpTkWm9)LEMyJdpaN%+ zTIl5VmYN5#H5I4)vSc>QzHYb3Vf#Zb`Bph*#rR}7_7`WnW-;1JefoJtVbX5rMPlBw z4|-xb zw6MZx<`ETnm+bb7W?RHqk1V+MR%yk0aVz2LA~(V|oZJ3Vnth@(=l5qiD|FX%_!Skp zb~9y)Og2(rdfF6WJ;Uda@AH>$4k{dd5GC@$%tWuLKushudGo>Nmv0G#LbNOiQ;7brt+7!h{{=HP#9yBs5TV5z zusUk1!0wx(x?CdD_q$|hO!YciwDaCQ2D{)U$4M!x)aR>rf4hC`+MlSfeLZn!*GRr#+3xY#fYbR$=8=MRN1v>$vXM&{-W(WoQ8H6?sq$ZC z>#Jo=+TJr<1a=(rU{RiDqB>=_=gU)p^KbbTq;jes^muqAuET-lsDWn0uA(dHY*q(# zuRJ{DG&4b*fvHx%ZWQ5 zAM(j8fA;iM@x(}wJDx^-ja|^>WNCPKx1mVHo*hXJkJtY)%R2XZv3Re>BEHaxt1c~+ zd%d+|$K&Mb``_%F_5Hr=yG4gnL4nd2djIkv4Y2?vl{S`$lz^{$cjk9GzsTkNanP!W zCt!QyDv!{Y9ddT_g=IyQwp>`FWj(uR_p!U;i?#{JSccX5Yj?RYbxxdWG1R7MRS>2#AaCED}QytkxyRPYR>q`H- zH6P!0LSeyt~8to~7UEoik=j*DDr0`oBLr@8`Nm zp}u{ae!aT?x4!24Znw+R>-W~OhFUI!JD-JRk~0&_;`P7S%4N!2#XMbfH3efcADgw@ zOY@x?v-?T<-H*k0%OW?YOl8h)>=jUq@_GDw{;u-cx9{uju8I47`oDR7op8w24gQMr zZxvgsA7Ax8(=TO$(#DnvF$}If`(8=kIa$YD_4!$V{N3Dzja5HtCT?8zFZb2?oo#=z z;uo_l?p#si^mgam$;nr@ckHXQVAMM!%Kmu$uVZ=B!zcOil()N0W!q94|MKBy%ZsO! z7H*FUR(*c>qi*@0)w}g}3HqE+e;>d9!^Hah`2U-K@A+^n{?m`?|K+9iJG7Rcd>;%+ zca|we6_qnM<@Vb2?0+S_F=SHS<;jb8SBAcH=uh4EA|mAbJ}dci(ehJk&TAddv{aui z-ZNqUZW6O&M(?WkMcmsLXs6e>-Q!$W zwu%U!0Phf6A}mX|E{P z(jznaCUvEKIl2Ut5#o4eO?=?{;zUBqTu`>+o%U^poYi#U%%mW5H|5jUR=#DqKKtOg zQajn5d2?U=UHmlStL)N)tt;Q0^la{Yko$`*>g!s2AvrdqHNTz-JT+vT@R$FGMBUZx z&U@$mezGHP(nRUa1&)Fj?J$H6|Z2;@-3%$>knA*?u=}+MOCxHqR7Vn!mFRwZM-m}kvcfJ%WpW689 z_ODmIftu^yoc!%xd;9g*nA-;y?+&$2aLbDc3ShpPytCl^z8Oy=zOGGJm7AU>GCkzU z|Hb<@#+{e3S+u(>&R&N1&HTV-SN`L+zmujVUo~%h$6##yFg)UBu!YRmx6^73y|*n% z5=!V3Te#@JnO3Kbb#<*QP07z&f^G$BTsyyBAwk{WV5-FP{Z9n^q{L=SUG&0P?SzP5 zZR7!NcX^>>ONHNjykE_%*4D9uF>U$ApAX&BmK}X}+UnWA(hYKTWmEOVg}x{zsx%f~ zem^}e>w)=!HFMlni3?6hKV_5Q%2`|aNaAA$-wWptMiU)gJe=*r%UH;K=9{9@rT#N- z6uLM9qx!^Hl;wW%`E+S$Pi|hsHsfkL|Fx~3l;?-e2sxPV@#LZI|KrAw-6zyv-OkIy z?Wrg+X~nO!#}bO}wb_gb$uErLS8b9p%yUj;KGS=5*7negzkjH2-xhw*|KR>f^;fqG zhcR_B?q+6O8B+V6`}&K(`_tC@w#xiIYucc-XlLU76P;2CVLytGE@ZppW6x~-d(N3A ze*bW{uz#WV%?xx-CmopJan)S%ILDV;J`TlU()VSGc>k=p^KY&$y9=*@_Me@PE-+`R z&2N;_I>@HAEnwraPrB2!f-$YtK3t|s;p`h@gT*#0 z4?g&!$Edd8Rdk?;NlzEZj=tn0vNp$NXE_9Hjxvn!i0xU#HpB72jO=%l9WMTk2>d(i zjj_Sz{$n=%HGMA6&iq)qDQ&?kYaOALzm665>}Wn-5zO21wBut6|BdrJA+_zUQla;y zzRwO+y3P>MC*f~~r1-<(T*j+;H>6^ib!4U~ADe8O=VBc2RaWw+{qt=zX1v{fA%E2} zZUZsitl&mD!+9SHm1i}s%5Rxsp>)Q*w!_e4;j7&jWX%`VZE@_%6}|j^cY@UU`SV{M z=(j#FL!c<}PDdKEy?|4aPFz3ptzO>O$L~-0&G9=j$xFk{u4GwGiMsltU;`ij>ytl+ z1sVORxOTo{fk6Ju$^Smz`Cs$u_u+8gr4^5kwyQ^3o0UysS^B@rYH7{WViBLen&O6L zu@gT9d{Sk2FaI{8WaH#tKUObTRC%RlRmXycr1T?M0Z9{8bB%;HPVHEuSFQi(;$08( zMje>m-&`UKM!=@;%Pe6aHGx5HQ0 zi}A(wK0dyDPSFv)W3C+A+_wB@tLWT2(c$sKBNo-x(=7#kx^KM|=C{$$?)g=E3rs`!gzfS28^qX_|+_m3aN0&)%xqD1qgE3A$ z|H}T33VH{Evo@Tz`uObJ(_g!ncLW>qZE!m%7N|6T#oIe&hcXO~y!G6+H7bFX8#K}+v#!s{I%Z;lC-84B!-_bKDTlrw^-$A<&q_3 zx)KXdEoGT^&nDvE+pkyoO9E`CaByClxM_9j%BQ(Uwna?+$nUq(E${@F^kU&%fg(rb zPZ!T#{^(oDvPILhudJB&zox)z8pmG8!=?w0MRR#gX|JjN{3_&>oFI>)ORMO4GocN) zWwvkhVDIo_o)91C_?X#7H2J{Zt_?-&@2q?LmSKAPtpx4jJF~{@A9`{%2 z2J=2xwrEO%@so=;Pb@zFsJrFDDlYBC)!*5w=13e-+g877`S#DJRO~h9#Je1Mr`wll z*(n<$cZ+3Bc%JyFJ2NMLbvgNALYL?N%3o6_B~H8P`M>g;baK;slh{Ma5g%&5?`@pp ze9YU!H2x{$o5XvSf3FI~?TQbQK9^x=6#Ha0;~rVL605@6x3}MYi(y^ACbXO5+*9Y8 z*4Z1{k3Ro;-Ez*GSxE;pHg^U- zMV$#cUU}o&x$_??^_rRA$A3C{XP@`=ho?EOvHrcQ9CEb()V<}hr>`&d-S3#2GCi&8 z%E73$i&SDo9_%)sagXms0JqQjwK9vE`!u|#MhnPR?rhv@Y;Z8;WmyB8kM)wJQ^XBo zH(d7nbyWFV^Ah>ZjQ=YCiiXVh;`(*l+Gc`d_`25{Tr;QT2Skg14zK-rQ6qEZ^rqgg zQ(mN6C1hUAx^^{f`O#dd%AJk5yJqU#;%jH$^6`ZD-n)8F^!1+9E|K5er~f%{oARU2 zzg`D<#;!f~^!2588JY#U2H%baT}%74KgDEK)}AdZroUv^)Um}`CM@W{Gqb)T=3rZ& zeR=Hd$1cZdWh&M`^|JG`n!E0}8_V;r<|-dbGjBU+t`ONSuUk+U)&6N_s~O`ehBplQ z<^_uyrY&lC$@DKgPibzQxI0JFC|VOhjJ zz1&~CS=uM|xlU2>N_cxettyaxlSOUC?m15F0jvqE#nSFO8$GiNe=d=&cpP}3#IfFe z`-1J}f{K6KmL7E03X7AT!o+V7J!fBxuB6;^iH(R_FDSl#;t&|=u zEbhFed*z0c^VVE*;<#$cze241$h6b-g;gzzZ-4A>XaAFv{U~YC;yFgyf)^w6#mkR; z7X6nPvM6NgHu?WW4VU&@37&bEGm7oiZP2>6`GNIU?`v+jdFAFm-}zbFpOx5|eY6)> zIQgl|KIz0${)5Z*DXLFeQDGZ8>!D5dqx9(D<(C&4T?^hBu>E$wq@O^j+&YO^_IUBI+|9zbW)bg8q0Yc-f!~7XUL1x zyUaR0|K1t@jjE^TPdbo(Y8e>t{Pu9ZB$ zSv>I*>aVZH!Jp3D<2X1<}=4xYo6c?-9;%gz>!wmU$4osYQ>Z*i>wCSi>?4>lUw^?NYuVsek_MtY^oSF1szM z)7F~ek-fEDbWZ$}y$`)qw`ne_oEf4u)0aSu86~{p5Qzi)q&4EkP%%iVR+?U_I^iW{rg31MNBeUi=x(K9(s{4=i=NI_sZl z^Pb=Pd$nG*iEQeS`eG_OXTp zw&YUwf=SVL*HjcI1*KkE!J3qp7PI%yw(q(+E=4Um`|nCcJbgT~R8=Wp;#-;BN}u)8 zi+wmdzjK9tJj^(+ELOPah}GpWoi9U#Z>LPSyyi8gzCso+LkR8$-HyI zjg!@`%dX}v3gB;$iau@H?qz&s!xl^Fqps&?e`x!$>z47t-P;nx+HOZm%ree;_$_pA z1<&H6dh+MiXmdViUD`1}IsCv<*-4E-e`=mSlbTl+9;G)29JH>rg28-|A{thA+UE7{ z3fEfM*1v6Mvrz2h6J=InpW-KGPMzJ6#nR2|7~OZ}-n6jCWiK2gz2uzNuK8%PX4(5w zDnvN|knlT4`Tg6z@Zn4O1Gv`9)&g*MGmF_>1#PmqzUeDpw3}YFvB`p$FW_?n( zIVVVn{#<`z%L_HRb!S)Kx~;X~&$bWM?;_+1P9>QoPhXdwyKTe&L z|1DQcUKw$`zaP5PFRbVz%f6(~mBmHUdqh93HkVjg`RwZKnuwHJFP3LS>D|04=QnNk zm#1MWrfTy9W;m?+9c9fw`@m9dp{j{*7AdQrKD*b4y|p^wvBIh#b@9yh5S2YIP8{*| z^A+dL{gixhV(09bNAEszK0V96?Bfz;_m^ssOa1g--J3BBnzdtpU!Rn?t>bx7+NJ+W z|NI`sABm3&k56ClY0?s}sWCp2w0>GQ1|1OjIQ{C?>tE${*6M3+&=;S)#Ot5m5)nPu zKTo#?mvV)ye5XE>-%;}9sweMTydDM}iO*KeJipTG&$=rc8usoASstv+G;!h_uYZ0U zM08yLY`uC_{MGL+)3>3lZ(1+?+QjsGQr?y2oU5L!PtgqN`jNf!fYq*L)42X7W!7dk z*5+$(e17Rk$fxj4A}X$bN^d!tDCLO$N_7p1ZA(+QT%_ta_0QDT1&KjN;;Un8m%9l~ zhUnaQU?0nbiCet>`OVoZ3bFKi`UiQ7!oIanA~S2XQ}m}znz+L2pWgxzC)Yo%2|gjJ t_1*Wx1wX5Ny&tFlcES>`f75vQS5`<(_56P_Wlx*?%(-9Yr%$}d2mpqg=jngdRsYT9MH>7Q4+(y+ zIWAc9`M5`SQ-xJ(lcZXP?SUI9`AsS>G+r!p%vI9zVdB$*YrM*9cpo&% zKR$TiS!~wrZEJI9uYP;tm&pbbz3qn#-^V}ef1_<2Y%ww9*|o@f8=op0?-5UpynWB* z+~+@YXE+)2EpU4~M^{Ac{JDK6cCxldf7Eg+_ufBeuQEq^bcp1tU;f;i-fqY(UYFrL zf#*KEUBiM&jxUeJ@3{BBTy6W=)t)=KChoph9qf5t^{(&o@2i9w7$>g2cW1_`9Uo_D zX8#hknBl#@XAi6G^Y6dseztjj#>Ti`^xUab)wj#Cjz9Ruy4S@-PdfFwL}h|ta)7~$ zUEjRq%$p=H3HLa!|CX_JiMmRd2-~`p+pDHb6}FZ9K2v>q_>RNRg@Tv-Y1nf3jQ#4TmHmj(&ChaD&7m}^Cm1?l|AcE+>`4rsinT% zEU|@MdsQ}ttj!1x{d(o1`0Mx0-ffvbe*c=iYMIjc?h@J9g<_$R(fwtXnk7@C)hiSi zZMtaSGQC}P;@$fum4Pb3(^t;w+9y!&TbCAi_3P%2$xh)rOY7p#yM~%cwY~VXLHX6( zWtE;Kjpss4OBH@)3kA$~IO4f*^&PAI?j3RgH!~y_oj%;heDVJEJx|uGTX!z2dGoGk zrDgvkr}nlf?uvP1vHSmgrNq$9tMty--#K!xF5`T(<(X?i_n(JJ>+PKE#8oSA7_4D< zxjm?x#pzD${SzBs)#=LSg_~+Gzw|QUImZ`G2RGAYHR~(fH>W)Gemkx8SKr!Qdv>*M zb5L8cw56!UNhqrL-924Z0VT$>a}L#>M z&a!?CM>qV?KFWP(T^GY!K2gKjmQ}y3WL=8YUh}3d5#sn3Yqhk2C6)D`UH|=eE{lxK zjkp(W+0*)K!c36`OMLInjhuJymGRzHca}R(3#nffFFc{G^#EJjy@_Xq%nPj4^L(Us z@%Y*E)l2mDO_}`d@Q;8v%O^26K6>PYhdx+$$DeoaS4mElTQk?kluB+0PqX_xp|Y@? zv+-9pT`Ant6%umlCuB&vHkfUi=+-*TDX#@(IG|j;H~iVwP$u|SIqo*>hSMY4~6=d z5 z5Z>|Pj$rMtmy?%1TPA+O+IWhg&<5%0ZiP#zgn%~u)gJ`ZFW(WH~JUX{)!81J?!+v&vo{6QQn%nF0L1a9;vffKXg9A@6D)q zvH0wggLg~$nx82EEaj8`DIydlbgN473CJkdq;gA?l@R6MO8jPF>T(% zonP(?*GqhPbbU*w*Xk>qe~Z5F_uHM4vLo&5{eQvV z=U+Dt+&I7biO2VS_rvmc+)$e;@+)xN%t>>dI67zCJF$UN`w54|3)#lNRt+QJ2~Jmf z9XzWJ7akJgw!HTK?DgqqH=M8BVsXsScCuw5=cK%6FC@15YOx!ps{DQJ+4@1!&4H`q z>(YN0m+WtPsW>-MK=mqb2}cUs#3@xZZH;I4etx#}>{f~Rw7Tm_H8Tr44Q9V6*&MBO zPBdDjqs3C8DnUdCQbllb$v<%pVy!Px# z=CmxY^O<6G(oau_H>l5cT644M;Nk=gMM&&6!Au0Ymnfo7Z>+>d+FD;R8jmdSf*|62$ z>)EbOi*mmB_cC$zxm=Zc8VAKr2MDg*%3)V9h> zv_j;xOR6mb@6XQ8k9d-`%&6Am-nxtY2@~BGUsS5Gce#Fw-B7AG?&AR=7iH5K8h(8q zrj8%id};9fw(HLGeGNTxm(&>lKCn-1rqT7%6NQ&JR@3yYEo7sjx z@^RNab@(^i>V$V{Tw5ISb_$#G;`WU*U(GqBxl?Fr;IgSDnbYI*7XM^#{c^l~=G4Hg zB}>CTc;1lSTQFl{bNJ$F`^Hy}2S4cfZaLjG-`@PB=S_W^&#D`ZuJbm`-I_D=?b&ae z($mlOJ>_-S8?-pTtGDj8V_LPFzsHk|wo@91Pt6U_3)~sil_6FqT`RYPzt3?^+=3f@ z``s&bzL<*(ChYiR<|e;i;xS9h@!&24kDZ)*-cL;5@7;H)f9c#W&;M`93*TT=9|VaRc*^Hm-y4V2ZgmU!K3&!yCi!^D*_@dk)8Cy6yYII6_|ioe{W(?Hqj;7% zMeRJ{+4{#nFmYqi^QqGBcir7-n;+?0woGX5QnUOZm)3~zdsY5^jWgbzX8z8+sxLA* zrNsK zaNYXux&3c4%g$c@Ru(jCneQ{5Wbs9EN5dD$Jw6>gJ;_Bh_2A???5jmS?5cV=S3QOy z(0uhbyYM~hugR~`Xts9rT6ceP-*F3RzFxs~62XqMG*)Ow|1fRloic+hd1l&cjW26g zr?;P7_BrddyC=KC#}i-9Z1}c8Jp_g}kL6|M4i?^vc&T(W!4mJ$Kq znQxkEkCvvX#lHX5*L}LF7~{VQuQmIFRxm;AYwD?v%@K+MJIkw_xpCVNmJz{ zQ`g~RzDtx2y?5Fyn7BFR;2ROs4{d*LEUI|^-b{Mgx(RIS_Rct?*}Fma%Ze{&zO{HI zZ`PF9;_z*f%OR1CZBPHU>IT0o`cbufxu9sC$b5~dGgKVARS!Mdsi!74)30bx!H&80 zH!pwWWS=7HTeFDiW2u_DyOU=~yZ2MJcZ?tB=N{PofO*o=-10-MLOqMMf1REdz%;M9 zl6{IGN7HG4N5kxs?)zS97wXjfKA$T*H%60-X^n!-hHlGm^VTtmOznt}wcMe2&-(b{ zsTCy-S_j$=zh2%e;h&gx^!wns0X{&ahoufLGA zZSYBs=g;(~+Nl*SSXQD|@g(W5n}3&c8vmPLC+iP3hjw#0y>?ruxz*{pHCOUk{smS% zroE?*oU19iu-hy7wM^)ewOfBiT0j23T(g(`+-H+$@s~NF3!WT#dP{05v*{A<_#HB4 z`d7u>HldTc*! z@pHQeX>z{}H%Iinc=PDhN2WuYlF!{<&wlCN^mP|sD9FpU-Cg7LFq^q4CU;}z(HDJD z>N^#=zdsdWkv<(5{pVP=TFa60$f-per+)e_Z@&JA&1#DcKly|ECvBRO`$qkHTu;oO z<3(TYu;1}Xwoj8fZ78dtbGUuE+Rki~T`75eEX#at?0vkiUlhCYYR%+5v&!f3w14V) znz5a&$Kva}!o!?hS6ZajJnEV9eR|Peo3j&DtG_>NQ~I>{qx|WM#qtHly?KwoF zW=-me&5Hk|dcU3F)%#Rdb}dLb_hiRh(}y-Pd{0GBUpzSLcHHdsd^K)r_8LLLSsOZ( zHT5O7dR?|z{B6VUhrGFY=NJ2!{7bg1ddIx(|Be208)Za|ZY}D3wBvn3-y`F+V@v1X zFYny$rrhQdvi{0Zrz|FCrv{gR3s)}6Yj&wf`7^4#-6j)adu*QS1(o)OH%$_kIvY!M zKFa+K3fn02_L@VD?RxQ>Td#yJ77#DU`LO5r`+d4P<&T6_`o7jYdh^Zpol(&79h*~5 zxj^{vXjd?{~v%%Wui6BKnvla|OT8vK3LQcy2v;x93f^lne`FuakX@jD{CX zrFwO@J?Po6JgiYMuu=Ed;*NzHOdeJ@k~p8-NZqK?R{BVtP4@joeNa%JoptVoZ_e~T z?=uY6yIfy=P(tlUV;}!H1N+^#f2S;h#+&W&Iv?@VAAi}#+@9O(EZ7=&H2uhdvW~iK z8DGjI7QKnlzI)ao)yK9~%l0H$T19UHS+hH2gs2IrTah1DY_fXS?^v$gSjcSo= zA{^$j`$;cr`Bt*WeLsur>5Gzge#MxnHa*#NA)no6=EwZ%M+wh9^lcDuKi0HIe@;!* zBl~HK@7q0K6ZmcDs^k9aR)kCR5>~bQi*0jZErMBPuzwINZ{b{9d z(-^%?m0h=mTzitDgfg zWb^XOw4%PJGuE1Z-lJc-ck8_jrCG+Iha#=@LLMofd@3WVAD#WI>i?RpaoI| zN*hzB6p+{jj)|_hXJ+sE&2sCto4CZnZ@VsjbzQMHucTHmYrS-Ae9O((Zs8J*-*#PO zbz87EucT2hW4&~2#*)tSKRzC77m&}lpK_xzre8)N^O5ns`+Ego?8?iJ<;*H=Q-!|A3Y0H*842=p1br~_05aF?axfy`!|3i z!u-=_L%Tx#j)n#O`}24F)|D_4Qu4a@ns>(q55f5tH7s}Dtv>0Pep2gu+?z-L%+)U{ z$>(k8SXo{FfA7zq+Y{cncf>`l_!u)$$xb9UNq57xy^qz$U$`|6y#S&U> zy*~D+JD~b*L`CJ6{dJ1dl5M@Xp87AeTimPF);(>$`&aJX+h2AjJ^Fb3{Jh$2CCjc> zEt~N_Vu7GXx8@nGM}>zoa&t2zZmqwWeN<=Pin-bo*zWXi;8tDT8FJXt_Ge$NeaauB zs`p$gwVZ@qjk`73YMbFL+f-<97Sx+L*z+8eF21%69EII(7-ZpWx~AHm1?!L0yaLUnZ%;-(%Z~U(Jr)zH9gN zHSsl?b514v{CQVbJ}p$>_NOz4jATp8qwD_dc=fvV=}kf9(63*2y?7$F*N^c{(*0-y zIlulnyMB1Ms^8!B>Tu4l2N#!JpXT)@yw+DoOnbc;*W#k>5-dA!JzDT}c|Y6#AHV;U zb)UO^ecsWeP@S41a(P!)+s(^Ycbq&!%fBH?tbsRlqaBC!%WvHG%gXN;-Y`41;gB)+ z|NNPK8?>Js$=t)dzh(FT5W}s-td}PI7TmU_wovV8f#1dBdiN$J{`oY?@la~}-}k~_ ztn6|_%{ez;zgzbx`b1m7S%vP{Nbc~hiWOT5WjWlRJvq$GcO1dWi1Wwaxd@) zZNL9ZOzEMu&z3!kiL>WFKH~Z3$>~ki-={xeTU55rL8`$1kPCaPPAunS9iI!$@#}0Q zo_(3^>#rlKocyMm`%y!JMDM5553fHqzi`leZdoBqgv;Xi%B>k6wV6~6+5K*;oVYE; z<#wIK!sY8um3M9X%Tn$*zw$2UueA&Mmu!oPidd#Rum8Ht_4|6FdUrMkRNVc4!$`I; zCiZoy(EBUyjc@Cl96+&qrLLvWa)!r-5>=m~O~#Y|9#W2&BkdVICsfDN;(@b)HNytw zf>&3T)yG#Zj+ei_pgUD!>O%)N>FpafwJhxYd-n4l-|WkWg=M7zb9aAN@SD5s|7IU| zou1qNd*a^i-xD=q7Q-FS?MIVl$3-79adqeOkxLb-UdY67Z1Jjp%4N~-Buwo-G^z$v zxQFd9-adQDOva6FmYoM1O@4SP1b2iq^D$1!V|R?Pi;;Mp-?4C>`Le~|B9weRCA}{( z?mnb9_qULGVgC1nd&L*Ox~;l*Qhn1~cZvGYLhoajwk3xj`cb9#t36e2Y4w^tQ6Ca4 z8-06zDn2|RwL#(-~k_M&zpD7CqbN*HC8}&*G-e@S6m+UuA9R#^PluJ-@QMK z^J6DfC+^l&_wl{1vFGuITK}X=LLIJ~19(1lR>ka?eakwub973aG!c z=4gvbva;RK;H0(phUm97QsG9S8$a=P^}aD8drIxna~2$}I_hwjX}@>lGBb8XJ3n6wqi-*w^iLH(VOX;3;IEu* zDNL64o6oss-Y8nqcYAuFV2YU+dvBVMR@M~0;O+I_co^q}syqnQ*!CeKZs*FlqaWG3 z3g!e>E#*lQTkrIXE#33w*3TPw?j{?4Nqv*UIiD?e_Aak`m$MqH3`%%6MF@V5FqDtd z6TWvh_LNuU;lxws^XH$Jlz*(SiDRR~e}><=`#(*b6)?}NW%uzHHmueRD>=f9+>AFI z7x|U5O<+;l$1*W(u?^>MUyo~-d-eS0;rE7TjQN^;It5gYZDQDP?9krYw>>iqOBKR0 zEZI^nhW2OMfP_jJ~%dAdD60CllU{= z=fd8ZJlgHI=RH2`5wpUs@xp9Kg0~71z{-W>*#l z&)DSelH%!t=qo&D*L>N4`;6E&98Yo`&eV4*o=ULZKs`u z3y=K_GhgU){Qlg-d*h4O>RflbQ*rI?xy?Vr9^7uo7oWi-eQ`}uo|%*E$&#;)kDnCA zB)qh0eC{%j`={Qbjw9a!woQLp(I{Nvbl~eQy9aF@THOxH6Q1$tU*JEHc7x^parxCf zl1~ki!vrEPw#vS_dGYPFzNt%v-+XuX>shgh!;~p=--REl6>InT$>)YhDxXYsd$2fd z(<-qrp@@~&qZ8EG%eX=!TcjFI;wzq{8T_cKZE^l~_|m~IZ$kOp#AZaMJafoP?L1|s zBYV2Exd|@dzhV_Bl5VX@z7?bGjeNQ{4WnoG3C6w!NOer@FmHbAgLO!;;liuvL4s1 zFLRGtd|_70wX4$G7aZdCJ}%+0OP1y1Qq74U9;Dgr6_vkXs(Dd4_xk&nTCLXE)((rW zuW9;dpd;(?F2?oUDd(k^Uuzx?di&+K@)EwS=SqH6M?Gv?n#_}Om#=9B-=Z14f7Jq% z$^r$hCT&>4JDVXkNm=7`sFvE7BKsc_)6PAZY|=N0O(#={UyQp_$$u)NMx)W(mCON9 zBlMbPE$cDbvvwi>>xVm6`0AheR>98Au4t5AANCf7zkZsOgwli$1GW4 z?PM{JsCS=Y;siwVBdn~md%736?LR4z$nF<;B|iAT>KcjFxf58PSI4Y7!z{8jt72<^ z;>#TSyB{V9A9|*;u39%wV5drMrh~&;ayR4_)_MVAc?Sj z$DhdkHxmqFxs>0UKXp}K;K}oIxMx}NhxFUqWxrb&JH55o!Ghu8k9Zq_iVJ62S3UFi zWZrQ>X@Xs3X^&Uku|tR3({-3G_N30(DR3n3?C-8;yayb2D6TTv$J8p;SQ1j&ZIz_AV?nmf^$G_I6Zwu;Jr|TF^nu**e?o_0 zt?0Q0);)HzU5kF+`SL3)L(s!L^!U_!e-zz$ik=&l&1iZZwa`^TcB$;t8ou8Fdvv|N zY?GL=Y<t)5;f(Q#Mm+8EZxAM(YzWQtBMR%y${O*LpeI@EEzA^UyDsPso zUi9gA0Ea)BCd1bc(KqnLk&O_=1?V_R?GqHxxr@^?XuftAC~D0|ai8gExTDZbJE zs5+!&`^(H4_NK;pCm7|q?)b$p1@1cg?Lk+^Et5I#IYXcQnY(kHxlEE}luuXs@t-FT z?oRRGlDiizcgebbo`}Aa;ldevRX?8Cr^+AS@nKR*gr&;E52sQ#Xh?9zZ>oqh*c~y6 zCvHP)%+4c4GO+LnO%3JU8T{Mv>-!Fw4+{luN6yuBXuH<1JaLlHo(VmSfi~O^H|XA+ z{OaHT6Ek1+86Nafi#To>{C6wAh<@K$;WLwSr|EdIy*bsnW$~o*iSk^m7oy+V$5}pb zZd`iAYw>lKEo`6GGN_iETVgJwG+~x+SG#jr(TRELM?W8&qp_^(x!CK6hqqlk;L{+O z<#wa(W`hs7Fp%8za7^c z_K7YyV$Qcw##haCb8=Ww$9joLq9+B;&r)~o-m57%d%@Ea9i<*(>i-S>Z%jS3RmMGY z{gzd2dYYetc-%8e-otaE-IH=AGw{}tRHP@8li(LGlH~Hs;C-z_B ze;rQyYp*wJcY1&67x@_ro}TfT$eyNoxBJh_pWkO#KUtN#-&WcUlwNk*iI^t#%6fkN zUv!{-(Z%JzglezMem#rnNCxkNXvJ?vapv5*OfNwR!xd(3s`C}kF5|v>cH$FI9trC6+UM}-wZayT zCH%`|r`GKIEIVmu=X0gHzL2+bwl4m#U*hZ854=GUf*$+jY(ZwV^6X!E`N`>LLfcPI zzq$DD?4|7PjCbW~R?IC6`P9nuSoZqSx7H6gKb36UvSF#w?*I|TkTm(O0~_{M?d_cN zb>WG=Q}3M{&pKHA43PPg{kZH@a?`EO3A!#J9!1yMm3Ftwd{}rOO(CX6<4ak|w!=T? z1$5hqOq~eUSo2|Fgyqf`kDM27Z!R{i?&NO`=zcyc)UD`7yOQ*$gYAnh=0|0I(YdYo z!g=8-|HbnyQ*Vi1l=-%>V*Ad{-1BwpHOs%;NPbmsa+qP($||`Z0cVcY1vftp$xlyF z*KB_4vLMQTN@l!E@s0LFRrYU7u50h(XEkR|OiuUBKOSt+kiNJ%Du2pza3+K(C_d26 zlYxT|to_xN6zx8X~t(WVbH}JEXF)uvtwq3utmakT$C+ge66Z1aF zfJ>N~I$YT{7Pu z9=9&F7Gc-X*Z=lxb@QKg?uhm5>0g~@RnJ(w>iL?vuk&OCAZn(t>73WPSF?NP%aS#l zJYJ};=HKTnWWH55-?~3!?#G%$`MN!OZ!au5@QH6xi@>F#UB3?ew42FzCR%_ z`Pv27`&SOX*&fg8*CfIa+Rop)@3YiDv)czk-rDT=wxIM->5q@e618hBG7o$zV)-;J z@RYw!ZAg#TzE>X>PALB~d&lGIQl*&c(w7#0eoVS5Q8lwre);N@&Rq_zQjL40mhM@) zc=~z4<*WJRyWUSb;#>P|wrhgZQs)JhZ3|^SEL>oxW4d;-f7|VcGiSdDZG7IBWh+-G zSNG@iz0EGiZn3)XMAW@yTIo{xY*OpK-*Z}59cp(fK2&6X{_e76pqzDdBY$g9yL!Y5 zKK--b0-CQq?%kYw{o!%{cuzftO!Y&o_n-JRtrk47y7A=xGaSFvyu#Z)zj?XpaC_6W zh<7XISzc7z<@>aOzxBmop|`(w&ey77+qK)Cb;TJbOTYFBzm=j&e*~P^KX=0Xzq4Mj zJ!#-){gUX}`0Z5CLcjCwyixva{8>IKj^AHxdi7!9hgV(O)Xue?X#b`V_G}lER)O=U z*$VvJ8V?p6T%_L2YWi=^f|XV^8flzCGdi~~Tt8PjHH+b_sZGGoT8$S^W5h1xGui5F z&}x?2GVe^-|1J}rJ^G76+xS^s(`NfReEqbIz34=H)1E31nY`t;nqSHyZI;^nQi@9b z5fG5Ft$xGA9p`_uCA^6-LOb7`SMiF_BTbGM}HjBSRnd4)b3kkmZAO|{jEI!+6Yih}|PpwY(C*~=({J69-e#(Y-=eIB2|39YuSAX}Vwf6m)9MgZNZ?pUT zi~sz`+@BKjkI!-IyK&TlW1-TNw|{4yT&3UBZqQLBk&l6) z#`}B^ztcZdRbLOa*xF9vg2d* zO55`?RA;8sv|Inn)lOdesF`S?#uc6OpsI;`he(^RUrck=xwM>*)`}WSY6Vs?ot+?7 z$x_o?y>72*M|-Kp!7YcTw0^pMDf{Ak&$PYe4@9jkZ}UI6c~&g_PwGdrKIn5} z;obgui$Za5`45lzdrZ@r-o+#deXikhkQU=TF-JMrBPOhTeO|=oZ)w^G^|GrBSMqav zUo2q1GFfJ3oUMqVDc8YeQ+TW+w)>Jx3#+DnX47rx`sg`%w+{D&z-O^{+I)@ow=TCI~C* zELNExH`gZRrozM1yB8&;$pwUNKWgH)ciV7B<-!{*1~MyjdrX|2c2Y#l7Ot&E5}! zf>%nuePfq=9(Y4@Tf**aWyRHv@pm>A81&xj*9g?far^9Ruy{Y8p}gRs4JWxWb1oit zOTMY1dE^q~Di6*J@Pbz%=^6|EtT)n44YTs^QGv&Ix8nRsK)xTo#pqS28zx`{S?ks+3 z)i$g2%YnI4sX|`YBRB4Lxsq(ym!rewA?SNu^U9j&I{%r?#zIqrA`%;uO=5d{ilS8} zDb0F!!1PLv5XZ(RDX+BVN<<69bhh%a3Dkf4wTjc^cO=ie>RTL}T`z8Rz2W*gBCVi&cxmJCzsXPnLRe#=AavSx^d#Vyet29xL#J3aX!1Q-+6^~U?HQTgw(`G=cn1_ zKVPO0lf=FB#EK|B!7|REG?B9Yh2n0Ei{DMW>ZHql<1ojbt@eHwOC*m6Z0;1=Y%Hc& zcy+UdMV`4|(1(~KLax`vR!>Pt?VR!7>dA6Xm1yO@fGk5XE!Lg7B4RJ%MZX1XZn^o= z*(0X6qy2aR&#gw)u64?5a;iQ)PcA-l*RJTz=g-goP6d^<0TZIOOmn&=#^hhvv268= zccw8;XVs>%O>S0HS;yODf0|pSxh$b`(QBc^>8ee3o8NVqmVG z2q@3gnqD96`)2*KwKN^FyF z2zjxTC2yW_z^-7|gWiG&zANj0C>@ITwf9(?(=p}2vsrA_NmKXdu1mjE<;C*y*s`gY z)PoXdOz^k!Zf)5wwe}p7_;r)00FLX%={I_P6FxQyw{iY-Nqo58?1kHnp0<4tx+Z7O z;$9ZCMA7?#!o!ctF4z?uGEj_HO*VYEzHR=cZ&D^-Si|SUTwXKb^~^X0keXv^6Jcrs zt9{&B~_CthuT7L~#6Qg13Jv*}y3 z_r;Wui7(ctZRHiU)E8;{m!-Er>3M6@#dzNJ9*0aFwk>?NBXZ)4^=1Z-?k9_AyS}^f z_j~y2>F?LOrMpCkmh1B6IGQJi-T1NkWcK%DOK%t9GW{Q4 zwF#!bR9ZY)eL_JH_a@2BNz3Ycni~teynPp(ogu3KH(BJyoJ&i}v_V#{_|hM^c-IMy zt=0k+#%ZPh|6YCd;P>jv58mE44Q{1*CmLU_YieWvzqRRL{MqLCS;dDlBI8$IczHDN z+dPM(&HJV1{#)uf)%G&)5uJ^uo1?c+wPkJIKZ||8NjSUtwz8^HA+O+DulMl0XPfzZ zy(rJWEV)0If-H7iWZj(0Yqay+>1Rpn)86e5Gx)JO_09BY#}4)yzMky8b?!ea{n_;= z?$obM_z-^jhQ999W@$&$pI@$5-n2=9Dt|wH+M$EI;j{C7`*xo1yj^=kt@ zgrB~puN!(eBSNuheUI^ubEngc<^N^7UNN-fzb`Bv?mnq`-?lSz!|whsJJ-j5``pYI z;X?Cx&t#om6u3EQ`P|J<)y=1rwVJs_RygkXDq{C`&Q#r_e%9%+1xFU}th+MJb#WT2 zuXXw%We>%xAkI-=>+}W1QdG+M7Q_BK3H!YiM{I%h4=oXzRAQ>O) z^c61O!zW&4yR{-Ru-a#x#L{>6&5s*@tzMg6kk;5-9LY6Tljp~4L_;10DIj+6W z*Q+ruXaAtWTyAuw@mhil2MOO+vncBH7RP+)vaFg z|MFt*tonTDg**$NQFZ~Z(AsMs!hlU7Nzu2{ z3ntF4w{p`wd3iz0-fI`6^8aO;*)L(~_L46v$z76P;LCe^4co`?WEX)6XDu|-H-;o; zJ~>mxDL(UKvPNZYfYXEpJ%29;B?iu1DZ6g<=Inyp4U+2FeD$UiKOd?7|4ih3(n?lu z<@9UbJ2J#7`bs`VX@6phdVJKrccaD5$dIZH%zLIP91)qc@1W`H4QI2s>rEN0+8ggj zm_KS)-^lQGR-~Ip+WwaA*N=ZNW>uBG7hDW>qyE24wwJc<8B-;1EACe}V_lxSPuK7M zgIT3F(o7#2?$r6j?;^L_W&6|fKe=3ktS{fp4q2moavk@waNpb|D{Qluzq2p>zw-C_ z`X@_Q{GD69>i7AN9vTzuS=ZI93)W-Xx$8yKQ?uGLrryi`>56docm3V7C}VDCZqU}- zuXyK|yk8u@+~@hE6D~i+#2!Vw$k#ixL%rQZVCrOv^3QWv79ZUzeg69S!}kwFPjNor z_?|=K#F|;D3%FEH=_t+lRDAN)v^QQ;y=Tf~o>dD7ipn~|zWRul%8A5^+M7JTvuwrQ z8d-9&h@EgS*s-4JA5Yv$nM-G7WEV5C8@2{%z1)6v^8^98FSA9Xg6NYufCa~KVucE*RBm;jC?rjKMQq!E1wrob$dbcsq42` zB0I#k^lp;eBk!MLux|Hq@ynxI4v%VX}WG}xVTkF zTlHI>h3FsQ&Zo%}m`{67o7oZ=61+lk+1!&8l4XK*52bIpprd|mR^CsGr9T3@k7vZ2 zNb;-3M$Be37E5c1TguEOzB+P&*5;$PB)yB)_(~k^UE%$_M`K}r=IkRkO0*-DWPO-k z9Z`-x@FJ>n`iteN&+3~0nbt_gsn|UDVgF{~f`!3cf$eXWd-h$5>R@5LX*5C9Dd^SW zy2PAUXX_n>-q$71aoFp{ZqPO}lbhSxxZ!Nn^d}F>6<7LqZhRT`$x>EEs6Y4RnJWR@ z>#wbM(h-YpaAdMu#a-yJUh$0QuE>6w8(d{w&-aOKvAE_~R+r>-AuqnGnD50C4lWN( zPKj7++ox-Vx@%?p0#DfNco}9~ow7xxg1>HIapJR_$*W@DF>Z1?@ZPv%7DHC}qbYnM zrG;)6+mg~YhpDrRCPhv76(c^+ZsC(+s|X=~Cb#PWvn&5grDaSwzJUMfn)W|NyQP|c z)My>7?E9SkvCHP+9+5?of0ykMvUvY;kxD?(CgH~|m%6Pcywpx!xPRx4PBFb1cP$pK zxq9;8F@2ZMA`AUH8D}bO-BL4=&+4N}LW%BIr~F{uf1aNn#3)u@gYW zJi9FA%+^F}#&<1&^C}m7HPd#Lw)US_u%*Yx{wLq!>$h&4_uc!?_t@GSH{`c144mM1 zq}Jf|t1}PFm@*ErJ@w29oA>67LD^}GcYD{q6uFwgU%lv`@3OTwBEqF-y0t7ltNQ1Y zqsbM8u4I);%?7hFf!(QLCCT<*zw_HgZEVb942w?NpgCLesP1{uAD0-nPu`+`R^?O7 z28ohPw(oEFroC)k?jIrbd*#jW>dd3d_6lq)y|i?##Pbd34$j(mG;nL|oQLoGR%Xua zPP4Ufjn2^>FNX} z|G1(glg7yC>d)Ch3)oGT9#=Zot!9#)UHDAeL{)C>RxeXaR-<@RRr#aaSBGUT6H|{@ zH(4q>MOJvL*Z-LA$;%^GY1)cEbO~O)Wwzx!r3vaxcbYmTPkR${#eZM2b#R#1_m6FJ z)lc&7|9eTH%+n`q!igG{(?Pph1Rm|JT+HghB7Z)a_eX_h{r|$xvz$&>e=l0v7a81n zl0W@HS*MSGigaVlW5beW*PZUO&ZdbToa!?*aJ}{ZJ8qx(xnB0aH_~35^^)r;SKor| z7w46G={D(<>%PA^+xyL~MKjNteVfedS~8hC^V5m94|(&BU$UQRdDBf{edLLYJW~VP zrdqGRv#4mR$igQtoNv_Lb5v~ATO78~b;8p%s)uhL%iFXrM{ZT)pL_HHTf_E%|`bGg8Wn zZ+G&WzboCxs=+AJ`2Ew%w{elbzu*7+drI=3+Q&T{K_$zVNSMDfRXW9WaMkxqd>yYh zE&i_i{eEq9#5)zPiy_mZPfg```1V~LcN944xEr^-yaPB@edDPWiJo@$-Y!-7Y>MUuJc(d|u)r+{M^3YwhBxpKE;sLN;GiKHFQj zhnh?LO9 zI_8H9Hm6i|KHg|hAHIm&Cv|7%Jd0BOoaci6f+qqOTzqJj!hWT8lkwpfiR@bf7bWu) zZA~z$=uuUA@;l}4xxjPfzBe0Xt1}JmlsjztFVAJz5Rx2s^38|j`KIR&`|Y2e9&vSz zkx}&T;?=z;=86Qp_#NPD4cbeoqnmFn>r%XI@7yWNGACP}ma(m!d(lwQN>TSsWp>!n zO#kdxu<#8o)O>H^;k50f^$KSvufF5!@r()^d>f5 zOWSuVn59T0!^1FzT_(3#Si#VC!vFR1dk=Ga`lfJb&2rgnDc$~I&!40tON@-bI~DJw zl&#*fr*T%1+Ec#ZWSh8)&#w1>c@i?cPrx_w*^4sE%$EwYj2?g7v^OS(-PrV^)Y6^@ z96e>b|G4yDoT8KHE^un%yvOac>l)WO-6(t_v7M1~>J8ItwTVpIy;Bx!otghkooOeJ zN}l{C=KUuBJinawcwD8y|IY9PD{tU&fvEx^8%<484{uYrlJoV&RFkte`kgG} zEay!QQ_0QQetF8}IUF)if~ST2WP3VkSN5&>U(0>?jLVkVt4(*TJfRtO+UDw%UCOt* z(&l|%x^DY5>2%lG%P+ik+5G=pd01xivM+Nxwk?|Z`tRmzRd3g1eEzlY+hQ^M?DST? zOs{C=IT=|~k7XAe+gv(v-t`HSgdh9$s2OBu=f|zm?@2jb6rnil;?DQ`8RC|m1C_AZ z1^wTqpQ>VEY#%ApA#j+0WqagD#IbI|~*qS^B3s zIiOh4_)dlQ%7960{_J`1zfnHsc^;cu!_mq%$$}>PuO{_bhW8Y_pT6&Pjj=OFFI#E^t>-IUuXl*mF@N?ADACyNWbCaFS%mYY5zG6 zlJguctd=(O{$IX6@HFFZ+cS0BR&IJ2)4u(F%k@R~CuLacTb#Yib6(KqU3n&3nvSq3 zv+$qJ%YQVx^iDd|K5M*odl}D`)n)fA43$)_q-D;Lxl+^d#@&)Uw2D`(C+*tKcaV@Z*$+VGpQS1WY-41VwQnaW%1 zvuN$Vpr+m${Rdb0Zf0-KVoS^U`sD1iS^tAk)x>*?3y#tb?5Yj%5B5nb7l5(>;T&HKQ->3d^Y( zSv$@K{al?LxO$_V-AcRco9dU-g8zS2Un0<-SCZT_ISK63#cDq`tL~F@kzA60;o#S- zL-`qXDL;0n7#=rP35o71UAXtJV_3K1vWh92=I5@;(YQYKq~Xp5Wm`}C=ZP@6Ptw+( iyVp(8Q_R>j7*uVCyT1DO*+wHPdCK*_&n?bKFaQAPM`J<& diff --git a/doc/qtcreator/src/android/androiddev.qdoc b/doc/qtcreator/src/android/androiddev.qdoc index 9be6e430eaf..930abd1d675 100644 --- a/doc/qtcreator/src/android/androiddev.qdoc +++ b/doc/qtcreator/src/android/androiddev.qdoc @@ -157,6 +157,7 @@ \previouspage creator-how-tos.html \ingroup creator-how-to-android + \ingroup creator-how-to-sdks \title Manage Android NDK packages @@ -195,6 +196,7 @@ \previouspage creator-how-tos.html \ingroup creator-how-to-android + \ingroup creator-how-to-sdks \title Manage Android SDK packages From 67c1c2e67dbb1f231f5ac61e672155f3c444f144 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 14 Nov 2024 12:50:16 +0100 Subject: [PATCH 158/989] Utils: Make FileUtils::copyIfDifferent return Result instead of bool Change-Id: I84191384fcc792030a1c70dea22fd760ae121561 Reviewed-by: Marcus Tillmanns Reviewed-by: Cristian Adam --- src/libs/utils/fileutils.cpp | 21 ++++++++++--------- src/libs/utils/fileutils.h | 2 +- .../cmakeprojectmanager/fileapireader.cpp | 10 +++++---- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index d011cd5a4d8..ce012f81fa1 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -717,10 +717,13 @@ bool FileUtils::copyRecursively(const FilePath &srcFilePath, Returns whether the operation succeeded. */ -bool FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath) +Result copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath) { - QTC_ASSERT(srcFilePath.exists(), qDebug() << srcFilePath.toUserOutput(); return false); - QTC_ASSERT(srcFilePath.isSameDevice(tgtFilePath), return false); + if (!srcFilePath.exists()) + return Result::Error(Tr::tr("File %1 does not exist.").arg(srcFilePath.toUserOutput())); + + if (srcFilePath.needsDevice() || tgtFilePath.needsDevice()) + return srcFilePath.copyFile(tgtFilePath); if (tgtFilePath.exists()) { const QDateTime srcModified = srcFilePath.lastModified(); @@ -730,16 +733,14 @@ bool FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgt const expected_str srcContents = srcFilePath.fileContents(); const expected_str tgtContents = srcFilePath.fileContents(); if (srcContents && srcContents == tgtContents) - return true; + return Result::Ok; } - tgtFilePath.removeFile(); + + if (Result res = tgtFilePath.removeFile(); !res) + return res; } - 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); - return true; + return srcFilePath.copyFile(tgtFilePath); } QString FileUtils::fileSystemFriendlyName(const QString &name) diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 0b3ec7ae448..d78dbb03ffa 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -62,7 +62,7 @@ public: QString *error, CopyHelper helper); - static bool copyIfDifferent(const FilePath &srcFilePath, + static Result copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath); static QString fileSystemFriendlyName(const QString &name); static int indexOfQmakeUnfriendly(const QString &name, int startpos = 0); diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index 4409eb73892..bcfb12e13c4 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -323,11 +323,13 @@ void FileApiReader::makeBackupConfiguration(bool store) if (!store) std::swap(cmakeCacheTxt, cmakeCacheTxtPrev); - if (cmakeCacheTxt.exists()) - if (!FileUtils::copyIfDifferent(cmakeCacheTxt, cmakeCacheTxtPrev)) + if (cmakeCacheTxt.exists()) { + if (Result res = FileUtils::copyIfDifferent(cmakeCacheTxt, cmakeCacheTxtPrev); !res) { Core::MessageManager::writeFlashing(addCMakePrefix( - Tr::tr("Failed to copy \"%1\" to \"%2\".") - .arg(cmakeCacheTxt.toUserOutput(), cmakeCacheTxtPrev.toUserOutput()))); + Tr::tr("Failed to copy \"%1\" to \"%2\": %3") + .arg(cmakeCacheTxt.toUserOutput(), cmakeCacheTxtPrev.toUserOutput(), res.error()))); + } + } } void FileApiReader::writeConfigurationIntoBuildDirectory(const QStringList &configurationArguments) From 9d8a3357632f7f035e4f9dd5530dca3f8ab9cbf5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 4 Nov 2024 15:23:37 +0100 Subject: [PATCH 159/989] RemoteLinux: Use "UnavailableDevice" for disconnected devices Idea is that we will have one more file access implementation using the GoCmdBridge, making handling the different code paths with 'if's uncomfortable. Instead, switch between complete accessor objects when the connected/unconnected state of the device changes Change-Id: I75621a13b69838cb819d8a0ada2788a0e148e721 Reviewed-by: Christian Kandeler --- src/libs/utils/devicefileaccess.cpp | 102 +------------ src/libs/utils/devicefileaccess.h | 2 - src/plugins/remotelinux/linuxdevice.cpp | 187 +++++++++++------------- 3 files changed, 86 insertions(+), 205 deletions(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 08eb2b956cf..24d69f728b7 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -1288,23 +1288,11 @@ 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(disconnectedMessage()); -} - UnixDeviceFileAccess::~UnixDeviceFileAccess() = default; Result UnixDeviceFileAccess::runInShellSuccess(const CommandLine &cmdLine, const QByteArray &stdInData) const { - if (disconnected()) - return Result::Error("disconnected"); const int retval = runInShell(cmdLine, stdInData).exitCode; if (retval != 0) return Result::Error(QString("return value %1").arg(retval)); @@ -1313,56 +1301,42 @@ Result UnixDeviceFileAccess::runInShellSuccess(const CommandLine &cmdLine, bool UnixDeviceFileAccess::isExecutableFile(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-x", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isReadableFile(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-r", path, "-a", "-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isWritableFile(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-w", path, "-a", "-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isReadableDirectory(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-r", path, "-a", "-d", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isWritableDirectory(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-w", path, "-a", "-d", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isFile(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isDirectory(const FilePath &filePath) const { - if (disconnected()) - return false; if (filePath.isRootPath()) return true; @@ -1372,16 +1346,12 @@ bool UnixDeviceFileAccess::isDirectory(const FilePath &filePath) const bool UnixDeviceFileAccess::isSymLink(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-h", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::hasHardLinks(const FilePath &filePath) const { - if (disconnected()) - return false; const QStringList args = statArgs(filePath, "%h", "%l"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); return result.stdOut.toLongLong() > 1; @@ -1389,32 +1359,24 @@ bool UnixDeviceFileAccess::hasHardLinks(const FilePath &filePath) const bool UnixDeviceFileAccess::ensureExistingFile(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"touch", {path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::createDirectory(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"mkdir", {"-p", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::exists(const FilePath &filePath) const { - if (disconnected()) - return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-e", path}, OsType::OsTypeLinux}); } Result UnixDeviceFileAccess::removeFile(const FilePath &filePath) const { - if (disconnected()) - return Result::Error(disconnectedMessage()); RunResult result = runInShell({"rm", {filePath.path()}, OsType::OsTypeLinux}); if (result.exitCode != 0) return Result::Error(QString::fromUtf8(result.stdErr)); @@ -1423,9 +1385,6 @@ Result UnixDeviceFileAccess::removeFile(const FilePath &filePath) const 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(); @@ -1445,8 +1404,6 @@ bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString * Result UnixDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const { - if (disconnected()) - return Result::Error(disconnectedMessage()); const RunResult result = runInShell( {"cp", {filePath.path(), target.path()}, OsType::OsTypeLinux}); @@ -1461,9 +1418,6 @@ Result UnixDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath & Result UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const { - if (disconnected()) - return Result::Error(disconnectedMessage()); - RunResult result = runInShell({"mv", {filePath.path(), target.path()}, OsType::OsTypeLinux}); if (result.exitCode != 0) { return Result::Error(Tr::tr("Failed to rename file \"%1\" to \"%2\": %3") @@ -1476,9 +1430,6 @@ Result UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath FilePath UnixDeviceFileAccess::symLinkTarget(const FilePath &filePath) const { - if (disconnected()) - return {}; - const RunResult result = runInShell( {"readlink", {"-n", "-e", filePath.path()}, OsType::OsTypeLinux}); const QString out = QString::fromUtf8(result.stdOut); @@ -1489,9 +1440,6 @@ expected_str UnixDeviceFileAccess::fileContents(const FilePath &file qint64 limit, qint64 offset) const { - if (disconnected()) - return make_unexpected_disconnected(); - expected_str localSource = filePath.localSource(); if (localSource && *localSource != filePath) return localSource->fileContents(limit, offset); @@ -1522,9 +1470,6 @@ expected_str UnixDeviceFileAccess::fileContents(const FilePath &file expected_str UnixDeviceFileAccess::writeFileContents(const FilePath &filePath, const QByteArray &data) const { - if (disconnected()) - return make_unexpected_disconnected(); - expected_str localSource = filePath.localSource(); if (localSource && *localSource != filePath) return localSource->writeFileContents(data); @@ -1541,9 +1486,6 @@ expected_str UnixDeviceFileAccess::writeFileContents(const FilePath &fil expected_str UnixDeviceFileAccess::createTempFile(const FilePath &filePath) { - if (disconnected()) - return make_unexpected_disconnected(); - if (!m_hasMkTemp.has_value()) m_hasMkTemp = runInShellSuccess({"which", {"mktemp"}, OsType::OsTypeLinux}); @@ -1603,9 +1545,6 @@ expected_str UnixDeviceFileAccess::createTempFile(const FilePath &file QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const { - if (disconnected()) - return {}; - const RunResult result = runInShell( {"stat", {"-L", "-c", "%Y", filePath.path()}, OsType::OsTypeLinux}); qint64 secs = result.stdOut.toLongLong(); @@ -1617,9 +1556,6 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, const QString &linuxFormat, const QString &macFormat) const { - if (disconnected()) - return {}; - return (filePath.osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat}) << "-L" << filePath.path(); @@ -1627,9 +1563,6 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) const { - if (disconnected()) - return {}; - QStringList args = statArgs(filePath, "%a", "%p"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); @@ -1682,9 +1615,6 @@ constexpr int toUnixChmod(QFileDevice::Permissions permissions) bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permissions perms) const { - if (disconnected()) - return false; - const int flags = toUnixChmod(perms); return runInShellSuccess( {"chmod", {"0" + QString::number(flags, 8), filePath.path()}, OsType::OsTypeLinux}); @@ -1692,9 +1622,6 @@ bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permi qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const { - if (disconnected()) - return -1; - const QStringList args = statArgs(filePath, "%s", "%z"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); return result.stdOut.toLongLong(); @@ -1702,18 +1629,12 @@ qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const qint64 UnixDeviceFileAccess::bytesAvailable(const FilePath &filePath) const { - if (disconnected()) - return -1; - const RunResult result = runInShell({"df", {"-k", filePath.path()}, OsType::OsTypeLinux}); return FileUtils::bytesAvailableFromDFOutput(result.stdOut); } QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const { - if (disconnected()) - return {}; - const QStringList args = statArgs(filePath, "%D:%i", "%d:%i"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); @@ -1725,11 +1646,7 @@ QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const { - if (disconnected()) - return {}; - - if (filePath.path() == "/") // TODO: Add FilePath::isRoot() - { + if (filePath.path() == "/") { // TODO: Add FilePath::isRoot() const FilePathInfo r{4096, FilePathInfo::FileFlags( FilePathInfo::ReadOwnerPerm | FilePathInfo::WriteOwnerPerm @@ -1754,9 +1671,6 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, const FileFilter &filter, const FilePath::IterateDirCallback &callBack) const { - if (disconnected()) - return false; - QTC_CHECK(filePath.isAbsolutePath()); CommandLine cmdLine{"find", filter.asFindArguments(filePath.path()), OsType::OsTypeLinux}; @@ -1829,9 +1743,6 @@ void UnixDeviceFileAccess::findUsingLs(const QString ¤t, QStringList *found, const QString &start) const { - if (disconnected()) - return; - const RunResult result = runInShell( {"ls", {"-1", "-a", "-p", "--", current}, OsType::OsTypeLinux}); const QStringList entries = QString::fromUtf8(result.stdOut).split('\n', Qt::SkipEmptyParts); @@ -1891,9 +1802,6 @@ void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath, const FilePath::IterateDirCallback &callBack, const FileFilter &filter) const { - if (disconnected()) - return; - // We try to use 'find' first, because that can filter better directly. // Unfortunately, it's not installed on all devices by default. if (m_tryUseFind) { @@ -1911,17 +1819,9 @@ void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath, Environment UnixDeviceFileAccess::deviceEnvironment() const { - if (disconnected()) - return {}; - const RunResult result = runInShell({"env", {}, OsType::OsTypeLinux}); const QString out = QString::fromUtf8(result.stdOut); return Environment(out.split('\n', Qt::SkipEmptyParts), OsTypeLinux); } -bool UnixDeviceFileAccess::disconnected() const -{ - return false; -} - } // namespace Utils diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index b1836f3bff3..04931046472 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -251,8 +251,6 @@ protected: QStringList *found, const QString &start) const; - virtual bool disconnected() const; - private: bool iterateWithFind(const FilePath &filePath, const FileFilter &filter, diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 2ef15453f9d..193112c9113 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -286,70 +286,42 @@ private: // LinuxDevicePrivate class ShellThreadHandler; -class LinuxDeviceAccess; -class LinuxDeviceFileAccess : public UnixDeviceFileAccess +class LinuxDeviceAccess : public UnixDeviceFileAccess { public: - LinuxDeviceFileAccess(LinuxDeviceAccess *access) - : m_access(access) - {} + explicit LinuxDeviceAccess(LinuxDevicePrivate *devicePrivate); + ~LinuxDeviceAccess(); RunResult runInShell(const CommandLine &cmdLine, const QByteArray &stdInData) const override; Environment deviceEnvironment() const override; - bool disconnected() const override; - - LinuxDeviceAccess *m_access; -}; - -class LinuxDeviceAccess -{ -public: - LinuxDeviceAccess(LinuxDevice *device, LinuxDevicePrivate *devicePrivate); - ~LinuxDeviceAccess(); - - Result setupShell(const SshParameters &sshParameters, bool announce); - RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); - void announceConnectionAttempt(); - void unannounceConnectionAttempt(); - Id announceId() const { return m_device->id().withPrefix("announce_"); } - void attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters); - Environment getEnvironment(); - void invalidateEnvironmentCache(); - - void checkOsType(); - void queryOsType(std::function run); - - void setDisconnected(bool disconnected); - bool checkDisconnectedWithWarning(); - - LinuxDevice *m_device = nullptr; LinuxDevicePrivate *m_devicePrivate = nullptr; QThread m_shellThread; ShellThreadHandler *m_handler = nullptr; mutable QRecursiveMutex m_shellMutex; - LinuxDeviceFileAccess m_fileAccess{this}; - - QReadWriteLock m_environmentCacheLock; - std::optional m_environmentCache; }; class LinuxDevicePrivate { public: explicit LinuxDevicePrivate(LinuxDevice *parent) - : q(parent) + : q(parent), m_scriptAccess(this) { m_disconnected.setSettingsKey("Disconnected"); parent->registerAspect(&m_disconnected); - setupScriptAccess(); + q->readSettings(); + + if (m_disconnected()) + setupDisconnectedAccess(); + else + setupConnectedAccess(); } void setOsType(OsType osType) @@ -358,30 +330,52 @@ public: q->setOsType(osType); } - void setupScriptAccess() + void setupConnectedAccess() { - m_access.reset(new LinuxDeviceAccess(q, this)); - q->setFileAccess(&m_access->m_fileAccess); + m_disconnected.setValue(false); + q->setFileAccess(&m_scriptAccess); } + void setupDisconnectedAccess(); + + Result setupShell(const SshParameters &sshParameters, bool announce); + + RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); + bool tryToConnect(const SshParameters &sshParameters) { - QMutexLocker locker(&m_access->m_shellMutex); - return m_access->setupShell(sshParameters, false); + QMutexLocker locker(&m_scriptAccess.m_shellMutex); + return setupShell(sshParameters, false); } + bool checkDisconnectedWithWarning(); + + void announceConnectionAttempt(); + void unannounceConnectionAttempt(); + Id announceId() const { return q->id().withPrefix("announce_"); } + + void checkOsType(); + void queryOsType(std::function run); + + Environment getEnvironment(); + void invalidateEnvironmentCache(); + LinuxDevice *q = nullptr; - std::unique_ptr m_access; + LinuxDeviceAccess m_scriptAccess; + UnavailableDeviceFileAccess m_disconnectedAccess; BoolAspect m_disconnected; + + QReadWriteLock m_environmentCacheLock; + std::optional m_environmentCache; }; -void LinuxDeviceAccess::invalidateEnvironmentCache() +void LinuxDevicePrivate::invalidateEnvironmentCache() { QWriteLocker locker(&m_environmentCacheLock); m_environmentCache.reset(); } -Environment LinuxDeviceAccess::getEnvironment() +Environment LinuxDevicePrivate::getEnvironment() { QReadLocker locker(&m_environmentCacheLock); if (m_environmentCache.has_value()) @@ -392,38 +386,33 @@ Environment LinuxDeviceAccess::getEnvironment() if (m_environmentCache.has_value()) return m_environmentCache.value(); - if (m_devicePrivate->m_disconnected()) + if (m_disconnected()) return {}; Process getEnvProc; - getEnvProc.setCommand(CommandLine{m_device->filePath("env")}); + getEnvProc.setCommand(CommandLine{q->filePath("env")}); using namespace std::chrono; getEnvProc.runBlocking(5s); const QString remoteOutput = getEnvProc.cleanedStdOut(); - m_environmentCache = Environment(remoteOutput.split('\n', Qt::SkipEmptyParts), m_device->osType()); + m_environmentCache = Environment(remoteOutput.split('\n', Qt::SkipEmptyParts), q->osType()); return m_environmentCache.value(); } -RunResult LinuxDeviceFileAccess::runInShell(const CommandLine &cmdLine, - const QByteArray &stdInData) const +RunResult LinuxDeviceAccess::runInShell(const CommandLine &cmdLine, + const QByteArray &stdInData) const { - if (disconnected()) + if (m_devicePrivate->checkDisconnectedWithWarning()) return {-1, {}, Tr::tr("Device is disconnected.").toUtf8()}; - return m_access->runInShell(cmdLine, stdInData); + return m_devicePrivate->runInShell(cmdLine, stdInData); } -Environment LinuxDeviceFileAccess::deviceEnvironment() const +Environment LinuxDeviceAccess::deviceEnvironment() const { - if (disconnected()) + if (m_devicePrivate->checkDisconnectedWithWarning()) return {}; - return m_access->getEnvironment(); -} - -bool LinuxDeviceFileAccess::disconnected() const -{ - return m_access->checkDisconnectedWithWarning(); + return m_devicePrivate->getEnvironment(); } // SshProcessImpl @@ -1090,8 +1079,6 @@ LinuxDevice::LinuxDevice() }}); } - - LinuxDevice::~LinuxDevice() { delete d; @@ -1146,8 +1133,8 @@ ProcessInterface *LinuxDevice::createProcessInterface() const return new SshProcessInterface(shared_from_this()); } -LinuxDeviceAccess::LinuxDeviceAccess(LinuxDevice *device, LinuxDevicePrivate *devicePrivate) - : m_device(device), m_devicePrivate(devicePrivate) +LinuxDeviceAccess::LinuxDeviceAccess(LinuxDevicePrivate *devicePrivate) + : m_devicePrivate(devicePrivate) { m_shellThread.setObjectName("LinuxDeviceShell"); m_handler = new ShellThreadHandler(); @@ -1169,39 +1156,35 @@ LinuxDeviceAccess::~LinuxDeviceAccess() QMetaObject::invokeMethod(&m_shellThread, closeShell, Qt::BlockingQueuedConnection); } -void LinuxDeviceAccess::queryOsType(std::function runInShell) +void LinuxDevicePrivate::queryOsType(std::function runInShell) { const RunResult result = runInShell({"uname", {"-s"}, OsType::OsTypeLinux}); if (result.exitCode != 0) - m_devicePrivate->setOsType(OsTypeOtherUnix); + setOsType(OsTypeOtherUnix); const QString osName = QString::fromUtf8(result.stdOut).trimmed(); if (osName == "Darwin") - m_devicePrivate->setOsType(OsTypeMac); + setOsType(OsTypeMac); if (osName == "Linux") - m_devicePrivate->setOsType(OsTypeLinux); + setOsType(OsTypeLinux); } -void LinuxDeviceAccess::setDisconnected(bool disconnected) -{ - if (disconnected == m_devicePrivate->m_disconnected()) - return; - - m_devicePrivate->m_disconnected.setValue(disconnected); - - if (disconnected) - m_handler->closeShell(); -} - -void LinuxDeviceAccess::checkOsType() +void LinuxDevicePrivate::checkOsType() { queryOsType([this](const CommandLine &cmd) { return runInShell(cmd); }); } -// Call me with shell mutex locked -Result LinuxDeviceAccess::setupShell(const SshParameters &sshParameters, bool announce) +void LinuxDevicePrivate::setupDisconnectedAccess() { - if (m_handler->isRunning(sshParameters)) { - setDisconnected(false); + m_disconnected.setValue(true); + q->setFileAccess(&m_disconnectedAccess); + m_scriptAccess.m_handler->closeShell(); +} + +// Call me with shell mutex locked +Result LinuxDevicePrivate::setupShell(const SshParameters &sshParameters, bool announce) +{ + if (m_scriptAccess.m_handler->isRunning(sshParameters)) { + setupConnectedAccess(); return Result::Ok; } @@ -1211,40 +1194,40 @@ Result LinuxDeviceAccess::setupShell(const SshParameters &sshParameters, bool an announceConnectionAttempt(); Result result = Result::Error("setupShell failed"); - QMetaObject::invokeMethod(m_handler, [this, sshParameters] { - return m_handler->start(sshParameters); + QMetaObject::invokeMethod(m_scriptAccess.m_handler, [this, sshParameters] { + return m_scriptAccess.m_handler->start(sshParameters); }, Qt::BlockingQueuedConnection, &result); if (announce) unannounceConnectionAttempt(); if (result) { - setDisconnected(false); - queryOsType([this](const CommandLine &cmd) { return m_handler->runInShell(cmd); }); + setupConnectedAccess(); + queryOsType([this](const CommandLine &cmd) { return m_scriptAccess.m_handler->runInShell(cmd); }); } else { - setDisconnected(true); + setupDisconnectedAccess(); } return result; } -RunResult LinuxDeviceAccess::runInShell(const CommandLine &cmd, const QByteArray &data) +RunResult LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &data) { - QMutexLocker locker(&m_shellMutex); + QMutexLocker locker(&m_scriptAccess.m_shellMutex); DEBUG(cmd.toUserOutput()); if (checkDisconnectedWithWarning()) return {}; - const bool isSetup = setupShell(m_device->sshParameters(), true); + const bool isSetup = setupShell(q->sshParameters(), true); if (checkDisconnectedWithWarning()) return {}; QTC_ASSERT(isSetup, return {}); - return m_handler->runInShell(cmd, data); + return m_scriptAccess.m_handler->runInShell(cmd, data); } -void LinuxDeviceAccess::announceConnectionAttempt() +void LinuxDevicePrivate::announceConnectionAttempt() { const QString message = Tr::tr("Establishing initial connection to device \"%1\". " - "This might take a moment.").arg(m_device->displayName()); + "This might take a moment.").arg(q->displayName()); qCDebug(linuxDeviceLog) << message; if (isMainThread()) { Core::ICore::infoBar()->addInfo(InfoBarEntry(announceId(), message)); @@ -1253,18 +1236,18 @@ void LinuxDeviceAccess::announceConnectionAttempt() } } -void LinuxDeviceAccess::unannounceConnectionAttempt() +void LinuxDevicePrivate::unannounceConnectionAttempt() { if (isMainThread()) Core::ICore::infoBar()->removeInfo(announceId()); } -bool LinuxDeviceAccess::checkDisconnectedWithWarning() +bool LinuxDevicePrivate::checkDisconnectedWithWarning() { - if (!m_devicePrivate->m_disconnected()) + if (!m_disconnected()) return false; - QMetaObject::invokeMethod(Core::ICore::infoBar(), [id = m_device->id(), name = m_device->displayName()] { + QMetaObject::invokeMethod(Core::ICore::infoBar(), [id = q->id(), name = q->displayName()] { const Id errorId = id.withPrefix("error_"); if (!Core::ICore::infoBar()->canInfoBeAdded(errorId)) return; @@ -1699,12 +1682,12 @@ FileTransferInterface *LinuxDevice::createFileTransferInterface( LinuxDeviceAccess *LinuxDevice::connectionAccess() const { - return d->m_access.get(); + return &d->m_scriptAccess; } void LinuxDevice::checkOsType() { - d->m_access->checkOsType(); + d->checkOsType(); } IDevice::DeviceState LinuxDevice::deviceState() const From 819ffe761159afbc1bc2d08c243c5348372a4dfb Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 15 Nov 2024 12:56:57 +0100 Subject: [PATCH 160/989] Core: Use dialogParent directly in a few places Change-Id: I608cf3a3d06635a4aea68779128bf946cb64bbcc Reviewed-by: Eike Ziller --- src/plugins/coreplugin/session.cpp | 2 +- src/plugins/coreplugin/sessiondialog.cpp | 8 +++++--- src/plugins/coreplugin/sessiondialog.h | 8 ++------ src/plugins/coreplugin/sessionmodel.cpp | 12 ++++++------ src/plugins/coreplugin/sessionmodel.h | 6 +++--- src/plugins/coreplugin/sessionview.cpp | 6 +++--- src/plugins/projectexplorer/projectwelcomepage.cpp | 4 ++-- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/plugins/coreplugin/session.cpp b/src/plugins/coreplugin/session.cpp index e1e0aea47fe..d5c33d15b23 100644 --- a/src/plugins/coreplugin/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -315,7 +315,7 @@ bool SessionManager::renameSession(const QString &original, const QString &newNa void SessionManager::showSessionManager() { saveSession(); - Internal::SessionDialog sessionDialog(ICore::dialogParent()); + Internal::SessionDialog sessionDialog; sessionDialog.setAutoLoadSession(d->isAutoRestoreLastSession()); sessionDialog.exec(); d->setAutoRestoreLastSession(sessionDialog.autoLoadSession()); diff --git a/src/plugins/coreplugin/sessiondialog.cpp b/src/plugins/coreplugin/sessiondialog.cpp index 5ab1343a963..3fc53738506 100644 --- a/src/plugins/coreplugin/sessiondialog.cpp +++ b/src/plugins/coreplugin/sessiondialog.cpp @@ -3,6 +3,7 @@ #include "sessiondialog.h" +#include "icore.h" #include "session.h" #include "sessionview.h" @@ -69,8 +70,8 @@ void SessionValidator::fixup(QString &input) const input = copy; } -SessionNameInputDialog::SessionNameInputDialog(QWidget *parent) - : QDialog(parent) +SessionNameInputDialog::SessionNameInputDialog() + : QDialog(ICore::dialogParent()) { m_newSessionLineEdit = new QLineEdit(this); m_newSessionLineEdit->setValidator(new SessionValidator(this, SessionManager::sessions())); @@ -125,7 +126,8 @@ bool SessionNameInputDialog::isSwitchToRequested() const return m_usedSwitchTo; } -SessionDialog::SessionDialog(QWidget *parent) : QDialog(parent) +SessionDialog::SessionDialog() + : QDialog(ICore::dialogParent()) { setObjectName("ProjectExplorer.SessionDialog"); resize(550, 400); diff --git a/src/plugins/coreplugin/sessiondialog.h b/src/plugins/coreplugin/sessiondialog.h index b6512feab6c..46e4fe60ddf 100644 --- a/src/plugins/coreplugin/sessiondialog.h +++ b/src/plugins/coreplugin/sessiondialog.h @@ -16,10 +16,8 @@ namespace Core::Internal { class SessionDialog : public QDialog { - Q_OBJECT - public: - explicit SessionDialog(QWidget *parent = nullptr); + SessionDialog(); void setAutoLoadSession(bool); bool autoLoadSession() const; @@ -36,10 +34,8 @@ private: class SessionNameInputDialog : public QDialog { - Q_OBJECT - public: - explicit SessionNameInputDialog(QWidget *parent); + SessionNameInputDialog(); void setActionText(const QString &actionText, const QString &openActionText); void setValue(const QString &value); diff --git a/src/plugins/coreplugin/sessionmodel.cpp b/src/plugins/coreplugin/sessionmodel.cpp index 1d97762eb0f..d4f49874ac9 100644 --- a/src/plugins/coreplugin/sessionmodel.cpp +++ b/src/plugins/coreplugin/sessionmodel.cpp @@ -183,9 +183,9 @@ void SessionModel::resetSessions() endResetModel(); } -void SessionModel::newSession(QWidget *parent) +void SessionModel::newSession() { - SessionNameInputDialog sessionInputDialog(parent); + SessionNameInputDialog sessionInputDialog; sessionInputDialog.setWindowTitle(PE::Tr::tr("New Session Name")); sessionInputDialog.setActionText(PE::Tr::tr("&Create"), PE::Tr::tr("Create and &Open")); @@ -194,9 +194,9 @@ void SessionModel::newSession(QWidget *parent) }); } -void SessionModel::cloneSession(QWidget *parent, const QString &session) +void SessionModel::cloneSession(const QString &session) { - SessionNameInputDialog sessionInputDialog(parent); + SessionNameInputDialog sessionInputDialog; sessionInputDialog.setWindowTitle(PE::Tr::tr("New Session Name")); sessionInputDialog.setActionText(PE::Tr::tr("&Clone"), PE::Tr::tr("Clone and &Open")); sessionInputDialog.setValue(session + " (2)"); @@ -217,9 +217,9 @@ void SessionModel::deleteSessions(const QStringList &sessions) endResetModel(); } -void SessionModel::renameSession(QWidget *parent, const QString &session) +void SessionModel::renameSession(const QString &session) { - SessionNameInputDialog sessionInputDialog(parent); + SessionNameInputDialog sessionInputDialog; sessionInputDialog.setWindowTitle(PE::Tr::tr("Rename Session")); sessionInputDialog.setActionText(PE::Tr::tr("&Rename"), PE::Tr::tr("Rename and &Open")); sessionInputDialog.setValue(session); diff --git a/src/plugins/coreplugin/sessionmodel.h b/src/plugins/coreplugin/sessionmodel.h index 79abd7ae3f1..23da9459ca1 100644 --- a/src/plugins/coreplugin/sessionmodel.h +++ b/src/plugins/coreplugin/sessionmodel.h @@ -48,10 +48,10 @@ signals: public slots: void resetSessions(); - void newSession(QWidget *parent); - void cloneSession(QWidget *parent, const QString &session); + void newSession(); + void cloneSession(const QString &session); void deleteSessions(const QStringList &sessions); - void renameSession(QWidget *parent, const QString &session); + void renameSession(const QString &session); void switchToSession(const QString &session); private: diff --git a/src/plugins/coreplugin/sessionview.cpp b/src/plugins/coreplugin/sessionview.cpp index 589d725156b..fff2dfa7cde 100644 --- a/src/plugins/coreplugin/sessionview.cpp +++ b/src/plugins/coreplugin/sessionview.cpp @@ -72,7 +72,7 @@ SessionView::SessionView(QWidget *parent) void SessionView::createNewSession() { - m_sessionModel.newSession(this); + m_sessionModel.newSession(); } void SessionView::deleteSelectedSessions() @@ -87,12 +87,12 @@ void SessionView::deleteSessions(const QStringList &sessions) void SessionView::cloneCurrentSession() { - m_sessionModel.cloneSession(this, currentSession()); + m_sessionModel.cloneSession(currentSession()); } void SessionView::renameCurrentSession() { - m_sessionModel.renameSession(this, currentSession()); + m_sessionModel.renameSession(currentSession()); } void SessionView::switchToCurrentSession() diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index d5871d1a135..50a98a364a6 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -607,9 +607,9 @@ public: if (m_activeSwitchToRect.contains(pos)) sessionModel->switchToSession(sessionName); else if (m_activeActionRects[0].contains(pos)) - sessionModel->cloneSession(ICore::dialogParent(), sessionName); + sessionModel->cloneSession(sessionName); else if (m_activeActionRects[1].contains(pos)) - sessionModel->renameSession(ICore::dialogParent(), sessionName); + sessionModel->renameSession(sessionName); else if (m_activeActionRects[2].contains(pos)) sessionModel->deleteSessions(QStringList(sessionName)); return true; From e7eefd3e35718ba0d8900f455d7ef4b4955d9f9b Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 15 Nov 2024 13:30:00 +0100 Subject: [PATCH 161/989] LinuxDevice: Simplify uname calling code paths Change-Id: If56d2327f83ac53bca370d86e2b62b9e3b31510b Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/linuxdevice.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 193112c9113..bf5f86c2f96 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -354,8 +354,8 @@ public: void unannounceConnectionAttempt(); Id announceId() const { return q->id().withPrefix("announce_"); } - void checkOsType(); - void queryOsType(std::function run); + CommandLine unameCommand() const { return {"uname", {"-s"}, OsType::OsTypeLinux}; } + void setOsTypeFromUnameResult(const RunResult &result); Environment getEnvironment(); void invalidateEnvironmentCache(); @@ -1156,9 +1156,8 @@ LinuxDeviceAccess::~LinuxDeviceAccess() QMetaObject::invokeMethod(&m_shellThread, closeShell, Qt::BlockingQueuedConnection); } -void LinuxDevicePrivate::queryOsType(std::function runInShell) +void LinuxDevicePrivate::setOsTypeFromUnameResult(const RunResult &result) { - const RunResult result = runInShell({"uname", {"-s"}, OsType::OsTypeLinux}); if (result.exitCode != 0) setOsType(OsTypeOtherUnix); const QString osName = QString::fromUtf8(result.stdOut).trimmed(); @@ -1168,11 +1167,6 @@ void LinuxDevicePrivate::queryOsType(std::functionrunInShell(cmd); }); + setOsTypeFromUnameResult(m_scriptAccess.m_handler->runInShell(unameCommand())); } else { setupDisconnectedAccess(); } @@ -1687,7 +1681,7 @@ LinuxDeviceAccess *LinuxDevice::connectionAccess() const void LinuxDevice::checkOsType() { - d->checkOsType(); + d->setOsTypeFromUnameResult(d->runInShell(d->unameCommand())); } IDevice::DeviceState LinuxDevice::deviceState() const From ba5e4b7eff81bf84eb359df3bf5730d7a2a04588 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 8 Nov 2024 13:56:24 +0100 Subject: [PATCH 162/989] Core: Provide settings categories centrally It was conceptually wrong that an options page was supposed to set its category's display name and icon. Instead, categories are now explicitly registered with name and icon. Change-Id: Ic10b3791c8068176f55470e6845ab4832160b8e7 Reviewed-by: Eike Ziller --- src/plugins/android/androidsettingswidget.cpp | 2 -- src/plugins/autotest/autotestplugin.cpp | 6 ++++ src/plugins/autotest/testsettingspage.cpp | 2 -- src/plugins/axivion/axivionplugin.cpp | 4 +++ src/plugins/axivion/axivionsettings.cpp | 2 -- src/plugins/beautifier/beautifierplugin.cpp | 5 +++ src/plugins/beautifier/generalsettings.cpp | 2 -- src/plugins/clangtools/settingswidget.cpp | 5 --- .../cmakeprojectmanager/cmakeformatter.cpp | 1 - .../cmakeprojectplugin.cpp | 4 +++ .../cmakeprojectmanager/cmakesettingspage.cpp | 1 - .../cmakespecificsettings.cpp | 2 -- src/plugins/coco/cocoplugin.cpp | 5 +++ src/plugins/coco/globalsettingspage.cpp | 2 -- src/plugins/copilot/copilotplugin.cpp | 5 +++ src/plugins/copilot/copilotsettings.cpp | 2 -- src/plugins/coreplugin/coreplugin.cpp | 5 +++ .../coreplugin/dialogs/ioptionspage.cpp | 34 ++++++++----------- src/plugins/coreplugin/dialogs/ioptionspage.h | 4 +-- src/plugins/coreplugin/generalsettings.cpp | 2 -- src/plugins/cpaster/cpasterplugin.cpp | 7 ++++ src/plugins/cpaster/settings.cpp | 2 -- src/plugins/cppcheck/cppchecksettings.cpp | 6 ---- .../cppeditor/cppcodemodelsettings.cpp | 2 -- src/plugins/debugger/commonoptionspage.cpp | 2 -- src/plugins/debugger/debuggerplugin.cpp | 8 +++++ .../extensionmanagerplugin.cpp | 6 ++++ .../extensionmanagersettings.cpp | 2 -- src/plugins/fakevim/fakevimactions.cpp | 2 -- src/plugins/fakevim/fakevimplugin.cpp | 3 ++ src/plugins/haskell/haskellplugin.cpp | 5 +++ src/plugins/haskell/haskellsettings.cpp | 2 -- src/plugins/help/generalsettingspage.cpp | 2 -- src/plugins/help/helpplugin.cpp | 3 ++ .../languageclient/languageclientplugin.cpp | 5 +++ .../languageclient/languageclientsettings.cpp | 2 -- src/plugins/lua/bindings/fetch.cpp | 2 -- src/plugins/lua/bindings/settings.cpp | 13 ++++--- src/plugins/lua/luaplugin.cpp | 4 +++ .../mcusupport/mcusupportoptionspage.cpp | 2 -- .../mesonprojectplugin.cpp | 6 ++++ src/plugins/mesonprojectmanager/settings.cpp | 2 -- src/plugins/nim/nimplugin.cpp | 11 ++++++ .../nim/settings/nimcodestylesettingspage.cpp | 2 -- src/plugins/nim/settings/nimsettings.cpp | 2 -- src/plugins/perfprofiler/perfsettings.cpp | 5 --- .../devicesupport/devicesettingspage.cpp | 2 -- .../devicesupport/sshsettingspage.cpp | 2 -- .../projectexplorer/kitoptionspage.cpp | 2 -- .../projectexplorer/projectexplorer.cpp | 23 +++++++++++++ .../projectexplorersettings.cpp | 2 -- .../projectexplorer/windowsappsdksettings.cpp | 2 -- src/plugins/python/pythonplugin.cpp | 5 +++ src/plugins/python/pythonsettings.cpp | 2 -- .../qbsprojectmanagerplugin.cpp | 5 +++ src/plugins/qbsprojectmanager/qbssettings.cpp | 2 -- .../qmljstools/qmljscodestylesettingspage.cpp | 2 -- src/plugins/qmljstools/qmljstoolsplugin.cpp | 7 ++++ .../qmlprofiler/qmlprofilersettings.cpp | 2 -- src/plugins/qnx/qnxsettingspage.cpp | 2 -- src/plugins/qtsupport/codegensettings.cpp | 5 --- src/plugins/squish/squishplugin.cpp | 6 ++++ src/plugins/squish/squishsettings.cpp | 2 -- src/plugins/terminal/terminalplugin.cpp | 5 +++ src/plugins/terminal/terminalsettings.cpp | 2 -- .../texteditor/behaviorsettingspage.cpp | 2 -- src/plugins/texteditor/commentssettings.cpp | 2 -- .../texteditor/completionsettingspage.cpp | 2 -- .../texteditor/displaysettingspage.cpp | 2 -- src/plugins/texteditor/fontsettingspage.cpp | 2 -- .../texteditor/highlightersettingspage.cpp | 2 -- .../snippets/snippetssettingspage.cpp | 4 +-- src/plugins/texteditor/texteditorplugin.cpp | 4 +++ src/plugins/todo/settings.cpp | 2 -- src/plugins/todo/todoplugin.cpp | 5 +++ src/plugins/valgrind/valgrindsettings.cpp | 5 --- src/plugins/vcsbase/commonvcssettings.cpp | 3 -- src/plugins/vcsbase/vcsplugin.cpp | 6 ++++ .../webassembly/webassemblysettings.cpp | 2 -- 79 files changed, 182 insertions(+), 144 deletions(-) diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index fc44ad5f6c3..5684e2b0922 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -842,8 +842,6 @@ public: setId(Constants::ANDROID_SETTINGS_ID); setDisplayName(Tr::tr("Android")); setCategory(ProjectExplorer::Constants::SDK_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("SDKs")); - setCategoryIconPath(":/projectexplorer/images/sdk.png"); setWidgetCreator([] { return new AndroidSettingsWidget; }); } }; diff --git a/src/plugins/autotest/autotestplugin.cpp b/src/plugins/autotest/autotestplugin.cpp index c9ae7a7e052..ff2afa7ee83 100644 --- a/src/plugins/autotest/autotestplugin.cpp +++ b/src/plugins/autotest/autotestplugin.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -519,6 +520,11 @@ public: void initialize() final { + IOptionsPage::registerCategory( + Constants::AUTOTEST_SETTINGS_CATEGORY, + Tr::tr("Testing"), + ":/autotest/images/settingscategory_autotest.png"); + setupTestSettingsPage(); dd = new AutotestPluginPrivate; diff --git a/src/plugins/autotest/testsettingspage.cpp b/src/plugins/autotest/testsettingspage.cpp index 1b2c7cbd6e0..e707470c221 100644 --- a/src/plugins/autotest/testsettingspage.cpp +++ b/src/plugins/autotest/testsettingspage.cpp @@ -263,8 +263,6 @@ public: setId(Constants::AUTOTEST_SETTINGS_ID); setDisplayName(Tr::tr("General")); setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Testing")); - setCategoryIconPath(":/autotest/images/settingscategory_autotest.png"); setWidgetCreator([] { return new TestSettingsWidget; }); } }; diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 27991963f35..d8f5044ad36 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -10,6 +10,7 @@ #include "dashboard/error.h" #include +#include #include #include #include @@ -1054,6 +1055,9 @@ class AxivionPlugin final : public ExtensionSystem::IPlugin void initialize() final { + IOptionsPage::registerCategory( + "XY.Axivion", Tr::tr("Axivion"), ":/axivion/images/axivion.png"); + setupAxivionPerspective(); dd = new AxivionPluginPrivate; diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 508f4e47225..951488df134 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -784,8 +784,6 @@ public: setId("Axivion.Settings.General"); setDisplayName(Tr::tr("General")); setCategory("XY.Axivion"); - setDisplayCategory(Tr::tr("Axivion")); - setCategoryIconPath(":/axivion/images/axivion.png"); setWidgetCreator([] { return new AxivionSettingsWidget; }); } }; diff --git a/src/plugins/beautifier/beautifierplugin.cpp b/src/plugins/beautifier/beautifierplugin.cpp index 555ab6e1a42..14b405d4c7a 100644 --- a/src/plugins/beautifier/beautifierplugin.cpp +++ b/src/plugins/beautifier/beautifierplugin.cpp @@ -62,6 +62,11 @@ class BeautifierPlugin final : public ExtensionSystem::IPlugin void initialize() final { + IOptionsPage::registerCategory( + Constants::OPTION_CATEGORY, + Tr::tr("Beautifier"), + ":/beautifier/images/settingscategory_beautifier.png"); + MenuBuilder(Constants::MENU_ID) .setTitle(Tr::tr("Bea&utifier")) .setOnAllDisabledBehavior(ActionContainer::Show) diff --git a/src/plugins/beautifier/generalsettings.cpp b/src/plugins/beautifier/generalsettings.cpp index 413e80698fb..0b4830c5086 100644 --- a/src/plugins/beautifier/generalsettings.cpp +++ b/src/plugins/beautifier/generalsettings.cpp @@ -85,8 +85,6 @@ public: setId(Constants::OPTION_GENERAL_ID); setDisplayName(Tr::tr("General")); setCategory(Constants::OPTION_CATEGORY); - setDisplayCategory(Tr::tr("Beautifier")); - setCategoryIconPath(":/beautifier/images/settingscategory_beautifier.png"); setSettingsProvider([] { return &generalSettings(); }); } }; diff --git a/src/plugins/clangtools/settingswidget.cpp b/src/plugins/clangtools/settingswidget.cpp index 4b686e61ac9..21d386b4cdb 100644 --- a/src/plugins/clangtools/settingswidget.cpp +++ b/src/plugins/clangtools/settingswidget.cpp @@ -11,9 +11,6 @@ #include #include -#include -#include - #include #include @@ -114,8 +111,6 @@ ClangToolsOptionsPage::ClangToolsOptionsPage() setId(Constants::SETTINGS_PAGE_ID); setDisplayName(Tr::tr("Clang Tools")); setCategory("T.Analyzer"); - setDisplayCategory(::Debugger::Tr::tr("Analyzer")); - setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); setWidgetCreator([] { return new SettingsWidget; }); } diff --git a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp index 4db53a64d3d..6adf5306e3f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp @@ -264,7 +264,6 @@ public: { setId(Constants::Settings::FORMATTER_ID); setDisplayName(Tr::tr("Formatter")); - setDisplayCategory("CMake"); setCategory(Constants::Settings::CATEGORY); setSettingsProvider([] { return &formatterSettings(); }); } diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp index 179a9962cce..e9a8bb40c91 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp @@ -22,6 +22,7 @@ #include #include +#include #include @@ -54,6 +55,9 @@ class CMakeProjectPlugin final : public ExtensionSystem::IPlugin void initialize() final { + IOptionsPage::registerCategory( + Constants::Settings::CATEGORY, Tr::tr("CMake"), Constants::Icons::SETTINGS_CATEGORY); + setupCMakeToolManager(this); setupCMakeSettingsPage(); diff --git a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp index a2ed1ae8bd7..5dc29c3df8a 100644 --- a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp @@ -663,7 +663,6 @@ public: { setId(Constants::Settings::TOOLS_ID); setDisplayName(Tr::tr("Tools")); - setDisplayCategory("CMake"); setCategory(Constants::Settings::CATEGORY); setWidgetCreator([] { return new CMakeToolConfigWidget; }); } diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index a56a66c533b..d670fe938a8 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -181,9 +181,7 @@ public: { setId(Constants::Settings::GENERAL_ID); setDisplayName(::CMakeProjectManager::Tr::tr("General")); - setDisplayCategory("CMake"); setCategory(Constants::Settings::CATEGORY); - setCategoryIconPath(Constants::Icons::SETTINGS_CATEGORY); setSettingsProvider([] { return &settings(nullptr); }); } }; diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index a87e163ee59..6a1ceff67eb 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -135,6 +135,11 @@ bool CocoPlugin::initialize(const QStringList &arguments, QString *errorString) Q_UNUSED(arguments) Q_UNUSED(errorString) + IOptionsPage::registerCategory( + "I.Coco", + QCoreApplication::translate("Coco", "Coco"), + ":/cocoplugin/images/SquishCoco_48x48.png"); + GlobalSettings::read(); GlobalSettingsPage::instance().widget(); addEntryToProjectSettings(); diff --git a/src/plugins/coco/globalsettingspage.cpp b/src/plugins/coco/globalsettingspage.cpp index b4eda76d0ba..c76e424e040 100644 --- a/src/plugins/coco/globalsettingspage.cpp +++ b/src/plugins/coco/globalsettingspage.cpp @@ -84,8 +84,6 @@ GlobalSettingsPage::GlobalSettingsPage() setId(Constants::COCO_SETTINGS_PAGE_ID); setDisplayName(QCoreApplication::translate("Coco", "Coco")); setCategory("I.Coco"); // Category I contains also the C++ settings. - setDisplayCategory(QCoreApplication::translate("Coco", "Coco")); - setCategoryIconPath(":/cocoplugin/images/SquishCoco_48x48.png"); } GlobalSettingsPage &GlobalSettingsPage::instance() diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index 670fa9d435d..077331655f8 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -58,6 +58,11 @@ class CopilotPlugin final : public ExtensionSystem::IPlugin public: void initialize() final { + IOptionsPage::registerCategory( + Constants::COPILOT_GENERAL_OPTIONS_CATEGORY, + Constants::COPILOT_GENERAL_OPTIONS_DISPLAY_CATEGORY, + ":/copilot/images/settingscategory_copilot.png"); + ActionBuilder requestAction(this, Constants::COPILOT_REQUEST_SUGGESTION); requestAction.setText(Tr::tr("Request Copilot Suggestion")); requestAction.setToolTip(Tr::tr( diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp index fc1c48ea419..e4f98dccb2f 100644 --- a/src/plugins/copilot/copilotsettings.cpp +++ b/src/plugins/copilot/copilotsettings.cpp @@ -286,8 +286,6 @@ public: setId(Constants::COPILOT_GENERAL_OPTIONS_ID); setDisplayName("Copilot"); setCategory(Constants::COPILOT_GENERAL_OPTIONS_CATEGORY); - setDisplayCategory(Constants::COPILOT_GENERAL_OPTIONS_DISPLAY_CATEGORY); - setCategoryIconPath(":/copilot/images/settingscategory_copilot.png"); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 08e249403fb..36cd4463d0d 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -273,6 +273,11 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) ModeManager::activateMode(m_editMode->id()); m_folderNavigationWidgetFactory = new FolderNavigationWidgetFactory; + IOptionsPage::registerCategory( + Constants::SETTINGS_CATEGORY_CORE, + Tr::tr("Environment"), + ":/core/images/settingscategory_core.png"); + IWizardFactory::initialize(); // Make sure we respect the process's umask when creating new files diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index a34bf3552f1..8b2213d7afd 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -19,10 +19,13 @@ #include #include +#include + using namespace Utils; -namespace Core { +static QHash> g_categories; +namespace Core { namespace Internal { class IOptionsPageWidgetPrivate @@ -39,8 +42,6 @@ public: Id m_id; Id m_category; QString m_displayName; - QString m_displayCategory; - FilePath m_categoryIconPath; IOptionsPage::WidgetCreator m_widgetCreator; QPointer m_widget; // Used in conjunction with m_widgetCreator @@ -150,7 +151,7 @@ void IOptionsPageWidget::finish() */ FilePath IOptionsPage::categoryIconPath() const { - return d->m_categoryIconPath; + return g_categories.value(category()).second; } std::optional IOptionsPage::aspects() const @@ -210,11 +211,6 @@ void IOptionsPage::setCategory(Id category) d->m_category = category; } -void IOptionsPage::setDisplayCategory(const QString &displayCategory) -{ - d->m_displayCategory = displayCategory; -} - /*! Returns the widget to show in the \uicontrol Options dialog. You should create a widget lazily here, and delete it again in the finish() method. This method can be called multiple times, so you @@ -312,15 +308,6 @@ void IOptionsPage::finish() delete d->m_widget; } -/*! - Sets \a categoryIconPath as the path to the category icon of the options - page. -*/ -void IOptionsPage::setCategoryIconPath(const FilePath &categoryIconPath) -{ - d->m_categoryIconPath = categoryIconPath; -} - void IOptionsPage::setSettingsProvider(const std::function &provider) { d->m_settingsProvider = provider; @@ -351,6 +338,15 @@ IOptionsPage::~IOptionsPage() optionsPages().removeOne(this); } +/*! + Registers a category with user-visible name and icon. + */ +void IOptionsPage::registerCategory( + Utils::Id id, const QString &displayName, const Utils::FilePath &iconPath) +{ + g_categories.insert(id, std::make_pair(displayName, iconPath)); +} + /*! Returns a list of all options pages. */ @@ -390,7 +386,7 @@ Id IOptionsPage::category() const */ QString IOptionsPage::displayCategory() const { - return d->m_displayCategory; + return g_categories.value(category()).first; } /*! diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index 224a536331e..b053f93409e 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -48,6 +48,8 @@ public: explicit IOptionsPage(bool registerGlobally = true); virtual ~IOptionsPage(); + static void registerCategory( + Utils::Id id, const QString &displayName, const Utils::FilePath &iconPath); static const QList allOptionsPages(); Utils::Id id() const; @@ -73,8 +75,6 @@ protected: void setId(Utils::Id id); void setDisplayName(const QString &displayName); void setCategory(Utils::Id category); - void setDisplayCategory(const QString &displayCategory); - void setCategoryIconPath(const Utils::FilePath &categoryIconPath); void setSettingsProvider(const std::function &provider); private: diff --git a/src/plugins/coreplugin/generalsettings.cpp b/src/plugins/coreplugin/generalsettings.cpp index 586d6a07bb6..3938bd9861a 100644 --- a/src/plugins/coreplugin/generalsettings.cpp +++ b/src/plugins/coreplugin/generalsettings.cpp @@ -430,8 +430,6 @@ public: setId(Constants::SETTINGS_ID_INTERFACE); setDisplayName(Tr::tr("Interface")); setCategory(Constants::SETTINGS_CATEGORY_CORE); - setDisplayCategory(Tr::tr("Environment")); - setCategoryIconPath(":/core/images/settingscategory_core.png"); setWidgetCreator([] { return new GeneralSettingsWidget; }); } }; diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp index 9920ed4535d..299bbba23d1 100644 --- a/src/plugins/cpaster/cpasterplugin.cpp +++ b/src/plugins/cpaster/cpasterplugin.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "codepasterservice.h" +#include "cpasterconstants.h" #include "cpastertr.h" #include "dpastedotcomprotocol.h" #include "fileshareprotocol.h" @@ -16,6 +17,7 @@ #include #include #include +#include #include #include @@ -394,6 +396,11 @@ public: private: void initialize() final { + IOptionsPage::registerCategory( + CodePaster::Constants::CPASTER_SETTINGS_CATEGORY, + Tr::tr("Code Pasting"), + ":/cpaster/images/settingscategory_cpaster.png"); + d = new CodePasterPluginPrivate; } diff --git a/src/plugins/cpaster/settings.cpp b/src/plugins/cpaster/settings.cpp index 597b3080f9b..d6549242d33 100644 --- a/src/plugins/cpaster/settings.cpp +++ b/src/plugins/cpaster/settings.cpp @@ -75,8 +75,6 @@ public: setId("A.CodePaster.General"); setDisplayName(Tr::tr("General")); setCategory(Constants::CPASTER_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Code Pasting")); - setCategoryIconPath(":/cpaster/images/settingscategory_cpaster.png"); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/cppcheck/cppchecksettings.cpp b/src/plugins/cppcheck/cppchecksettings.cpp index 144ed112f36..a8c771efb8d 100644 --- a/src/plugins/cppcheck/cppchecksettings.cpp +++ b/src/plugins/cppcheck/cppchecksettings.cpp @@ -6,7 +6,6 @@ #include "cppcheckconstants.h" #include "cppchecktool.h" #include "cppchecktr.h" -#include "cppchecktrigger.h" #include #include @@ -19,9 +18,6 @@ #include #include -#include -#include - using namespace Utils; namespace Cppcheck::Internal { @@ -147,8 +143,6 @@ public: setId(Constants::OPTIONS_PAGE_ID); setDisplayName(Tr::tr("Cppcheck")); setCategory("T.Analyzer"); - setDisplayCategory(::Debugger::Tr::tr("Analyzer")); - setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 5dde29a49cf..67c42e5d0e2 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -398,8 +398,6 @@ public: setId(Constants::CPP_CODE_MODEL_SETTINGS_ID); setDisplayName(Tr::tr("Code Model")); setCategory(Constants::CPP_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("C++")); - setCategoryIconPath(":/projectexplorer/images/settingscategory_cpp.png"); setWidgetCreator( [] { return new CppCodeModelSettingsWidget(CppCodeModelSettings::global()); }); } diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index 1ec14dc3475..f81eac7cad5 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -225,8 +225,6 @@ public: setId(DEBUGGER_COMMON_SETTINGS_ID); setDisplayName(Tr::tr("General")); setCategory(DEBUGGER_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Debugger")); - setCategoryIconPath(":/debugger/images/settingscategory_debugger.png"); setSettingsProvider([] { return &commonSettings(); }); } }; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 793411a35b6..03f3cb3f096 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "analyzer/analyzericons.h" #include "debuggeractions.h" #include "debuggerinternalconstants.h" #include "debuggercore.h" @@ -2363,6 +2364,13 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess { Q_UNUSED(errorMessage) + IOptionsPage::registerCategory( + DEBUGGER_SETTINGS_CATEGORY, + Tr::tr("Debugger"), + ":/debugger/images/settingscategory_debugger.png"); + IOptionsPage::registerCategory( + "T.Analyzer", Tr::tr("Analyzer"), Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); + // Needed for call from AppOutputPane::attachToRunControl() and GammarayIntegration. ExtensionSystem::PluginManager::addObject(this); diff --git a/src/plugins/extensionmanager/extensionmanagerplugin.cpp b/src/plugins/extensionmanager/extensionmanagerplugin.cpp index 0b20803b7a5..ecf5848b581 100644 --- a/src/plugins/extensionmanager/extensionmanagerplugin.cpp +++ b/src/plugins/extensionmanager/extensionmanagerplugin.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,11 @@ public: { m_mode = new ExtensionManagerMode; + IOptionsPage::registerCategory( + Constants::EXTENSIONMANAGER_SETTINGSPAGE_CATEGORY, + Tr::tr("Extensions"), + ":/extensionmanager/images/settingscategory_extensionmanager.png"); + #ifdef WITH_TESTS addTestCreator(createExtensionsModelTest); #endif // WITH_TESTS diff --git a/src/plugins/extensionmanager/extensionmanagersettings.cpp b/src/plugins/extensionmanager/extensionmanagersettings.cpp index 1986199f100..8a96020a2d9 100644 --- a/src/plugins/extensionmanager/extensionmanagersettings.cpp +++ b/src/plugins/extensionmanager/extensionmanagersettings.cpp @@ -88,8 +88,6 @@ public: setId(Constants::EXTENSIONMANAGER_SETTINGSPAGE_ID); setDisplayName(Tr::tr("Browser")); setCategory(Constants::EXTENSIONMANAGER_SETTINGSPAGE_CATEGORY); - setDisplayCategory(Tr::tr("Extensions")); - setCategoryIconPath(":/extensionmanager/images/settingscategory_extensionmanager.png"); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp index 1146ac894b4..d04ee8bf0d6 100644 --- a/src/plugins/fakevim/fakevimactions.cpp +++ b/src/plugins/fakevim/fakevimactions.cpp @@ -305,8 +305,6 @@ public: setId(SETTINGS_ID); setDisplayName(Tr::tr("General")); setCategory(SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("FakeVim")); - setCategoryIconPath(":/fakevim/images/settingscategory_fakevim.png"); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 40de3337706..cf91672d749 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1073,6 +1073,9 @@ FakeVimPlugin::FakeVimPlugin() void FakeVimPlugin::initialize() { + IOptionsPage::registerCategory( + "D.FakeVim", Tr::tr("FakeVim"), ":/fakevim/images/settingscategory_fakevim.png"); + /* // Set completion settings and keep them up to date. TextEditorSettings *textEditorSettings = TextEditorSettings::instance(); diff --git a/src/plugins/haskell/haskellplugin.cpp b/src/plugins/haskell/haskellplugin.cpp index 1041bf4695e..5ef2b623343 100644 --- a/src/plugins/haskell/haskellplugin.cpp +++ b/src/plugins/haskell/haskellplugin.cpp @@ -12,6 +12,8 @@ #include +#include + #include #include @@ -26,6 +28,9 @@ class HaskellPlugin final : public ExtensionSystem::IPlugin public: void initialize() final { + Core::IOptionsPage::registerCategory( + "J.Z.Haskell", Tr::tr("Haskell"), ":/haskell/images/settingscategory_haskell.png"); + setupHaskellStackBuildStep(); setupHaskellBuildConfiguration(); diff --git a/src/plugins/haskell/haskellsettings.cpp b/src/plugins/haskell/haskellsettings.cpp index ffc6fa066dc..7658664f613 100644 --- a/src/plugins/haskell/haskellsettings.cpp +++ b/src/plugins/haskell/haskellsettings.cpp @@ -60,8 +60,6 @@ public: setId(Constants::OPTIONS_GENERAL); setDisplayName(Tr::tr("General")); setCategory("J.Z.Haskell"); - setDisplayCategory(Tr::tr("Haskell")); - setCategoryIconPath(":/haskell/images/settingscategory_haskell.png"); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/help/generalsettingspage.cpp b/src/plugins/help/generalsettingspage.cpp index a87633a8408..4188bbcdb31 100644 --- a/src/plugins/help/generalsettingspage.cpp +++ b/src/plugins/help/generalsettingspage.cpp @@ -501,8 +501,6 @@ GeneralSettingsPage::GeneralSettingsPage() setId("A.General settings"); setDisplayName(Tr::tr("General")); setCategory(Help::Constants::HELP_CATEGORY); - setDisplayCategory(Tr::tr("Help")); - setCategoryIconPath(":/help/images/settingscategory_help.png"); setWidgetCreator([] { return new GeneralSettingsPageWidget; }); } diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 1b70196a20a..92540a02f93 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -651,6 +651,9 @@ private: void initialize() final { dd = new HelpPluginPrivate; + + IOptionsPage::registerCategory( + Constants::HELP_CATEGORY, Tr::tr("Help"), ":/help/images/settingscategory_help.png"); } void extensionsInitialized() final diff --git a/src/plugins/languageclient/languageclientplugin.cpp b/src/plugins/languageclient/languageclientplugin.cpp index a466a5b300a..8422635fb33 100644 --- a/src/plugins/languageclient/languageclientplugin.cpp +++ b/src/plugins/languageclient/languageclientplugin.cpp @@ -44,6 +44,11 @@ void LanguageClientPlugin::initialize() { using namespace Core; + IOptionsPage::registerCategory( + Constants::LANGUAGECLIENT_SETTINGS_CATEGORY, + Constants::LANGUAGECLIENT_SETTINGS_TR, + ":/languageclient/images/settingscategory_languageclient.png"); + setupCallHierarchyFactory(); setupTypeHierarchyFactory(); setupLanguageClientProjectPanel(); diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 361da8cd86e..5a8a0965ddd 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -345,8 +345,6 @@ LanguageClientSettingsPage::LanguageClientSettingsPage() setId(Constants::LANGUAGECLIENT_SETTINGS_PAGE); setDisplayName(Tr::tr("General")); setCategory(Constants::LANGUAGECLIENT_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr(Constants::LANGUAGECLIENT_SETTINGS_TR)); - setCategoryIconPath(":/languageclient/images/settingscategory_languageclient.png"); setWidgetCreator([this] { return new LanguageClientSettingsPageWidget(m_model, m_changedSettings); }); QObject::connect(&m_model, &LanguageClientSettingsModel::dataChanged, [this](const QModelIndex &index) { if (BaseSettings *setting = m_model.settingForIndex(index)) diff --git a/src/plugins/lua/bindings/fetch.cpp b/src/plugins/lua/bindings/fetch.cpp index dd165cf72f8..e2685afb4f0 100644 --- a/src/plugins/lua/bindings/fetch.cpp +++ b/src/plugins/lua/bindings/fetch.cpp @@ -63,8 +63,6 @@ void setupFetchModule() setId("BB.Lua.Fetch"); setDisplayName(Tr::tr("Network Access")); setCategory("ZY.Lua"); - setDisplayCategory("Lua"); - setCategoryIconPath(":/lua/images/settingscategory_lua.png"); setSettingsProvider( [module] { return static_cast(module); }); } diff --git a/src/plugins/lua/bindings/settings.cpp b/src/plugins/lua/bindings/settings.cpp index 47f34f71da9..1d6448e33fd 100644 --- a/src/plugins/lua/bindings/settings.cpp +++ b/src/plugins/lua/bindings/settings.cpp @@ -657,19 +657,18 @@ void setupSettingsModule() public: OptionsPage(const ScriptPluginSpec *spec, const sol::table &options) { - setId( - Id::fromString(QString("%1.%2").arg(spec->id).arg(options.get("id")))); setCategory(Id::fromString( QString("%1.%2").arg(spec->id).arg(options.get("categoryId")))); - - setDisplayName(options.get("displayName")); - setDisplayCategory(options.get("displayCategory")); - + const QString catName = options.get("displayCategory"); const FilePath catIcon = options.get>("categoryIconPath") .value_or(FilePath::fromUserInput( options.get_or("categoryIconPath", {}))); + if (!catName.isEmpty() || !catIcon.isEmpty()) + IOptionsPage::registerCategory(category(), catName, catIcon); - setCategoryIconPath(catIcon); + setId( + Id::fromString(QString("%1.%2").arg(spec->id).arg(options.get("id")))); + setDisplayName(options.get("displayName")); AspectContainer *container = options.get("aspectContainer"); if (container->isAutoApply()) diff --git a/src/plugins/lua/luaplugin.cpp b/src/plugins/lua/luaplugin.cpp index 07661245121..a137ede7e56 100644 --- a/src/plugins/lua/luaplugin.cpp +++ b/src/plugins/lua/luaplugin.cpp @@ -6,6 +6,7 @@ #include "luatr.h" #include +#include #include #include #include @@ -290,6 +291,9 @@ public: void initialize() final { + IOptionsPage::registerCategory( + "ZY.Lua", Tr::tr("Lua"), ":/lua/images/settingscategory_lua.png"); + setupLuaEngine(this); registerProvider("async", ":/lua/scripts/async.lua"); diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index 6e595d62ff2..94a869ee593 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -372,8 +372,6 @@ McuSupportOptionsPage::McuSupportOptionsPage(McuSupportOptions &options, setId(Utils::Id(Constants::SETTINGS_ID)); setDisplayName(Tr::tr("MCU")); setCategory(ProjectExplorer::Constants::SDK_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("SDKs")); - setCategoryIconPath(":/projectexplorer/images/sdk.png"); setWidgetCreator([&options, &settingsHandler] { return new McuSupportOptionsWidget(options, settingsHandler); }); diff --git a/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp b/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp index 316aa271d53..ab011a39fde 100644 --- a/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp +++ b/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp @@ -6,11 +6,14 @@ #include "mesonbuildsystem.h" #include "mesonpluginconstants.h" #include "mesonproject.h" +#include "mesonprojectmanagertr.h" #include "mesonrunconfiguration.h" #include "ninjabuildstep.h" #include "toolssettingsaccessor.h" #include "toolssettingspage.h" +#include + #include #include @@ -27,6 +30,9 @@ class MesonProjectPlugin final : public ExtensionSystem::IPlugin void initialize() final { + Core::IOptionsPage::registerCategory( + Constants::SettingsPage::CATEGORY, Tr::tr("Meson"), Constants::Icons::MESON_BW); + setupToolsSettingsPage(); setupToolsSettingsAccessor(); diff --git a/src/plugins/mesonprojectmanager/settings.cpp b/src/plugins/mesonprojectmanager/settings.cpp index b233ae3c48b..d46939be8b4 100644 --- a/src/plugins/mesonprojectmanager/settings.cpp +++ b/src/plugins/mesonprojectmanager/settings.cpp @@ -50,9 +50,7 @@ public: { setId("A.MesonProjectManager.SettingsPage.General"); setDisplayName(Tr::tr("General")); - setDisplayCategory("Meson"); setCategory(Constants::SettingsPage::CATEGORY); - setCategoryIconPath(Constants::Icons::MESON_BW); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/nim/nimplugin.cpp b/src/plugins/nim/nimplugin.cpp index 10ac5567bdb..577f464a958 100644 --- a/src/plugins/nim/nimplugin.cpp +++ b/src/plugins/nim/nimplugin.cpp @@ -77,6 +77,17 @@ class NimPlugin final : public ExtensionSystem::IPlugin { d = new NimPluginPrivate; + Core::IOptionsPage::registerCategory( + Constants::C_NIMTOOLSSETTINGSPAGE_CATEGORY, + Tr::tr("Nim"), + ":/nim/images/settingscategory_nim.png"); + + // ??? + Core::IOptionsPage::registerCategory( + Constants::C_NIMCODESTYLESETTINGSPAGE_CATEGORY, + Tr::tr("Nim"), + ":/nim/images/settingscategory_nim.png"); + setupNimProject(); setupNimbleProject(); diff --git a/src/plugins/nim/settings/nimcodestylesettingspage.cpp b/src/plugins/nim/settings/nimcodestylesettingspage.cpp index 270097508f8..42e4f7832b1 100644 --- a/src/plugins/nim/settings/nimcodestylesettingspage.cpp +++ b/src/plugins/nim/settings/nimcodestylesettingspage.cpp @@ -125,8 +125,6 @@ NimCodeStyleSettingsPage::NimCodeStyleSettingsPage() setId(Nim::Constants::C_NIMCODESTYLESETTINGSPAGE_ID); setDisplayName(Tr::tr("Code Style")); setCategory(Nim::Constants::C_NIMCODESTYLESETTINGSPAGE_CATEGORY); - setDisplayCategory(Tr::tr("Nim")); - setCategoryIconPath(":/nim/images/settingscategory_nim.png"); setWidgetCreator([] { return new NimCodeStyleSettingsWidget; }); createGlobalCodeStyle(); diff --git a/src/plugins/nim/settings/nimsettings.cpp b/src/plugins/nim/settings/nimsettings.cpp index ce5f406f5be..c140f72c95d 100644 --- a/src/plugins/nim/settings/nimsettings.cpp +++ b/src/plugins/nim/settings/nimsettings.cpp @@ -54,8 +54,6 @@ public: setId(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_ID); setDisplayName(Tr::tr("Tools")); setCategory(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_CATEGORY); - setDisplayCategory(Tr::tr("Nim")); - setCategoryIconPath(":/nim/images/settingscategory_nim.png"); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp index d48a43805f7..2cf1f9e14d9 100644 --- a/src/plugins/perfprofiler/perfsettings.cpp +++ b/src/plugins/perfprofiler/perfsettings.cpp @@ -11,9 +11,6 @@ #include #include -#include -#include - #include #include #include @@ -495,8 +492,6 @@ public: setId(Constants::PerfSettingsId); setDisplayName(Tr::tr("CPU Usage")); setCategory("T.Analyzer"); - setDisplayCategory(::Debugger::Tr::tr("Analyzer")); - setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); setSettingsProvider([] { return &globalSettings(); }); } }; diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp index 5fc55dff9a0..29edb86b2eb 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp @@ -413,8 +413,6 @@ DeviceSettingsPage::DeviceSettingsPage() setId(Constants::DEVICE_SETTINGS_PAGE_ID); setDisplayName(Tr::tr("Devices")); setCategory(Constants::DEVICE_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Devices")); - setCategoryIconPath(":/projectexplorer/images/settingscategory_devices.png"); setWidgetCreator([] { return new DeviceSettingsWidget; }); } diff --git a/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp b/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp index 1948bd3ebbb..339e80f6863 100644 --- a/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshsettingspage.cpp @@ -57,8 +57,6 @@ SshSettingsPage::SshSettingsPage() setId(Constants::SSH_SETTINGS_PAGE_ID); setDisplayName(Tr::tr("SSH")); setCategory(Constants::DEVICE_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("SSH")); - setCategoryIconPath(":/projectexplorer/images/settingscategory_devices.png"); setWidgetCreator([] { return new SshSettingsWidget; }); } diff --git a/src/plugins/projectexplorer/kitoptionspage.cpp b/src/plugins/projectexplorer/kitoptionspage.cpp index 4c0c4d49d2f..2cdc1451757 100644 --- a/src/plugins/projectexplorer/kitoptionspage.cpp +++ b/src/plugins/projectexplorer/kitoptionspage.cpp @@ -728,8 +728,6 @@ public: setId(Constants::KITS_SETTINGS_PAGE_ID); setDisplayName(Tr::tr("Kits")); setCategory(Constants::KITS_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Kits")); - setCategoryIconPath(":/projectexplorer/images/settingscategory_kits.png"); setWidgetCreator([] { return new Internal::KitOptionsPageWidget; }); } }; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index a9f26c695a5..bc0e95c2a18 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -119,6 +119,8 @@ #include #include +#include + #include #include @@ -807,6 +809,27 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er { Q_UNUSED(error) + IOptionsPage::registerCategory( + Constants::KITS_SETTINGS_CATEGORY, + Tr::tr("Kits"), + ":/projectexplorer/images/settingscategory_kits.png"); + IOptionsPage::registerCategory( + Constants::DEVICE_SETTINGS_CATEGORY, + Tr::tr("Devices"), + ":/projectexplorer/images/settingscategory_devices.png"); + IOptionsPage::registerCategory( + Constants::BUILD_AND_RUN_SETTINGS_CATEGORY, + Tr::tr("Build & Run"), + ":/projectexplorer/images/settingscategory_buildrun.png"); + IOptionsPage::registerCategory( + Constants::SDK_SETTINGS_CATEGORY, Tr::tr("SDKs"), ":/projectexplorer/images/sdk.png"); + + // QtSupport piggybacks on C++ settings, but has no dependency on CppEditor. + IOptionsPage::registerCategory( + CppEditor::Constants::CPP_SETTINGS_CATEGORY, + Tr::tr("C++"), + ":/projectexplorer/images/settingscategory_cpp.png"); + #ifdef WITH_TESTS addTest(); addTestCreator(createOutputParserTest); diff --git a/src/plugins/projectexplorer/projectexplorersettings.cpp b/src/plugins/projectexplorer/projectexplorersettings.cpp index a45872eeff3..5d023a711f9 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.cpp +++ b/src/plugins/projectexplorer/projectexplorersettings.cpp @@ -547,8 +547,6 @@ public: setId(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_PAGE_ID); setDisplayName(Tr::tr("General")); setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Build & Run")); - setCategoryIconPath(":/projectexplorer/images/settingscategory_buildrun.png"); setWidgetCreator([] { return new ProjectExplorerSettingsWidget; }); } }; diff --git a/src/plugins/projectexplorer/windowsappsdksettings.cpp b/src/plugins/projectexplorer/windowsappsdksettings.cpp index 8c67a6cbea1..556a30a2c4c 100644 --- a/src/plugins/projectexplorer/windowsappsdksettings.cpp +++ b/src/plugins/projectexplorer/windowsappsdksettings.cpp @@ -640,9 +640,7 @@ public: setId(Constants::WINDOWS_SETTINGS_ID); setDisplayName(Tr::tr("Windows App SDK")); setCategory(Constants::SDK_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("SDKs")); setWidgetCreator([] { return new WindowsSettingsWidget; }); - setCategoryIconPath(":/projectexplorer/images/sdk.png"); } }; diff --git a/src/plugins/python/pythonplugin.cpp b/src/plugins/python/pythonplugin.cpp index 65c3ef7b887..a26ced0381c 100644 --- a/src/plugins/python/pythonplugin.cpp +++ b/src/plugins/python/pythonplugin.cpp @@ -75,6 +75,11 @@ class PythonPlugin final : public ExtensionSystem::IPlugin void initialize() final { + Core::IOptionsPage::registerCategory( + Constants::C_PYTHON_SETTINGS_CATEGORY, + Tr::tr("Python"), + ":/python/images/settingscategory_python.png"); + setupPythonEditorFactory(this); setupPySideBuildStep(); diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index fa978b17857..49091b886c9 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -316,8 +316,6 @@ public: setId(Constants::C_PYTHONOPTIONS_PAGE_ID); setDisplayName(Tr::tr("Interpreters")); setCategory(Constants::C_PYTHON_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Python")); - setCategoryIconPath(":/python/images/settingscategory_python.png"); setWidgetCreator([] { return new InterpreterOptionsWidget(); }); } diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index 67cbaf0ecf3..1290d0162f3 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -143,6 +143,11 @@ void QbsProjectManagerPlugin::initialize() { d = new QbsProjectManagerPluginPrivate; + Core::IOptionsPage::registerCategory( + Constants::QBS_SETTINGS_CATEGORY, + Tr::tr(Constants::QBS_SETTINGS_TR_CATEGORY), + ":/qbsprojectmanager/images/settingscategory_qbsprojectmanager.png"); + const Core::Context projectContext(::QbsProjectManager::Constants::PROJECT_ID); Utils::FileIconProvider::registerIconOverlayForSuffix(ProjectExplorer::Constants::FILEOVERLAY_QT, "qbs"); diff --git a/src/plugins/qbsprojectmanager/qbssettings.cpp b/src/plugins/qbsprojectmanager/qbssettings.cpp index 00426e001fd..b550a7b0168 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.cpp +++ b/src/plugins/qbsprojectmanager/qbssettings.cpp @@ -224,8 +224,6 @@ QbsSettingsPage::QbsSettingsPage() setId("A.QbsProjectManager.QbsSettings"); setDisplayName(Tr::tr("General")); setCategory(Constants::QBS_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr(Constants::QBS_SETTINGS_TR_CATEGORY)); - setCategoryIconPath(":/qbsprojectmanager/images/settingscategory_qbsprojectmanager.png"); setWidgetCreator([] { return new QbsSettingsPageWidget; }); } diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp index f332f1ad0dc..70420def1c4 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp @@ -169,8 +169,6 @@ QmlJSCodeStyleSettingsPage::QmlJSCodeStyleSettingsPage() setId(Constants::QML_JS_CODE_STYLE_SETTINGS_ID); setDisplayName(Tr::tr(Constants::QML_JS_CODE_STYLE_SETTINGS_NAME)); setCategory(QmlJSEditor::Constants::SETTINGS_CATEGORY_QML); - setDisplayCategory(Tr::tr("Qt Quick")); - setCategoryIconPath(":/qmljstools/images/settingscategory_qml.png"); setWidgetCreator([] { return new QmlJSCodeStyleSettingsPageWidget; }); } diff --git a/src/plugins/qmljstools/qmljstoolsplugin.cpp b/src/plugins/qmljstools/qmljstoolsplugin.cpp index 156b57a7838..3138b35ccdf 100644 --- a/src/plugins/qmljstools/qmljstoolsplugin.cpp +++ b/src/plugins/qmljstools/qmljstoolsplugin.cpp @@ -20,6 +20,8 @@ #include +#include + #include using namespace Core; @@ -96,6 +98,11 @@ public: private: void initialize() final { + IOptionsPage::registerCategory( + QmlJSEditor::Constants::SETTINGS_CATEGORY_QML, + Tr::tr("Qt Quick"), + ":/qmljstools/images/settingscategory_qml.png"); + #ifdef WITH_TESTS addTestCreator(createQmlJSToolsTest); #endif diff --git a/src/plugins/qmlprofiler/qmlprofilersettings.cpp b/src/plugins/qmlprofiler/qmlprofilersettings.cpp index 32063ec947b..596ba54b9b1 100644 --- a/src/plugins/qmlprofiler/qmlprofilersettings.cpp +++ b/src/plugins/qmlprofiler/qmlprofilersettings.cpp @@ -76,8 +76,6 @@ public: setId(Constants::SETTINGS); setDisplayName(Tr::tr("QML Profiler")); setCategory("T.Analyzer"); - setDisplayCategory(::Debugger::Tr::tr("Analyzer")); - setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); setSettingsProvider([] { return &globalSettings(); }); } }; diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 18ef409d222..6d46b6c2c01 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -745,8 +745,6 @@ QnxSettingsPage::QnxSettingsPage(QObject *guard) setId("DD.Qnx Configuration"); setDisplayName(Tr::tr("QNX")); setCategory(ProjectExplorer::Constants::SDK_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("SDKs")); - setCategoryIconPath(":/projectexplorer/images/sdk.png"); setWidgetCreator([] { return new QnxSettingsWidget; }); connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, diff --git a/src/plugins/qtsupport/codegensettings.cpp b/src/plugins/qtsupport/codegensettings.cpp index 9100e5ab189..950592d5d88 100644 --- a/src/plugins/qtsupport/codegensettings.cpp +++ b/src/plugins/qtsupport/codegensettings.cpp @@ -7,10 +7,7 @@ #include "qtsupporttr.h" #include - #include -#include - #include using namespace Utils; @@ -77,8 +74,6 @@ public: setId(Constants::CODEGEN_SETTINGS_PAGE_ID); setDisplayName(Tr::tr("Qt Class Generation")); setCategory(CppEditor::Constants::CPP_SETTINGS_CATEGORY); - setDisplayCategory(::CppEditor::Tr::tr(CppEditor::Constants::CPP_SETTINGS_NAME)); - setCategoryIconPath(":/projectexplorer/images/settingscategory_cpp.png"); setSettingsProvider([] { return &codeGenSettings(); }); } }; diff --git a/src/plugins/squish/squishplugin.cpp b/src/plugins/squish/squishplugin.cpp index 4cc72fde73b..ca24ec78da4 100644 --- a/src/plugins/squish/squishplugin.cpp +++ b/src/plugins/squish/squishplugin.cpp @@ -14,6 +14,7 @@ #include "squishwizardpages.h" #include +#include #include #include @@ -39,6 +40,11 @@ class SquishPlugin final : public ExtensionSystem::IPlugin private: void initialize() final { + IOptionsPage::registerCategory( + Constants::SQUISH_SETTINGS_CATEGORY, + Tr::tr("Squish"), + ":/squish/images/settingscategory_squish.png"); + setupObjectsMapEditor(); setupSquishOutputPane(this); diff --git a/src/plugins/squish/squishsettings.cpp b/src/plugins/squish/squishsettings.cpp index 1b8c799eda1..de4bf4744b2 100644 --- a/src/plugins/squish/squishsettings.cpp +++ b/src/plugins/squish/squishsettings.cpp @@ -133,8 +133,6 @@ public: setId("A.Squish.General"); setDisplayName(Tr::tr("General")); setCategory(Constants::SQUISH_SETTINGS_CATEGORY); - setDisplayCategory("Squish"); - setCategoryIconPath(":/squish/images/settingscategory_squish.png"); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/terminal/terminalplugin.cpp b/src/plugins/terminal/terminalplugin.cpp index ad2b03e241d..358513ddff6 100644 --- a/src/plugins/terminal/terminalplugin.cpp +++ b/src/plugins/terminal/terminalplugin.cpp @@ -4,11 +4,13 @@ #include "terminalpane.h" #include "terminalprocessimpl.h" #include "terminalsettings.h" +#include "terminaltr.h" #include "terminalwidget.h" #include #include #include +#include #include #include #include @@ -36,6 +38,9 @@ public: { m_terminalPane = new TerminalPane(this); + Core::IOptionsPage::registerCategory( + "ZY.Terminal", Tr::tr("Terminal"), ":/terminal/images/settingscategory_terminal.png"); + TerminalWidget::initActions(this); auto enable = [this] { diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index 4e754dc7dd1..f14766918da 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -703,8 +703,6 @@ public: setId("Terminal.General"); setDisplayName("Terminal"); setCategory("ZY.Terminal"); - setDisplayCategory("Terminal"); - setCategoryIconPath(":/terminal/images/settingscategory_terminal.png"); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/plugins/texteditor/behaviorsettingspage.cpp b/src/plugins/texteditor/behaviorsettingspage.cpp index c92e1b44c53..eb2917aaccd 100644 --- a/src/plugins/texteditor/behaviorsettingspage.cpp +++ b/src/plugins/texteditor/behaviorsettingspage.cpp @@ -118,8 +118,6 @@ BehaviorSettingsPage::BehaviorSettingsPage() setDisplayName(Tr::tr("Behavior")); setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Text Editor")); - setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); setWidgetCreator([this] { return new BehaviorSettingsWidgetImpl(d); }); } diff --git a/src/plugins/texteditor/commentssettings.cpp b/src/plugins/texteditor/commentssettings.cpp index d3171a94d68..f4ada82353a 100644 --- a/src/plugins/texteditor/commentssettings.cpp +++ b/src/plugins/texteditor/commentssettings.cpp @@ -169,8 +169,6 @@ CommentsSettingsPage::CommentsSettingsPage() setId(Constants::TEXT_EDITOR_COMMENTS_SETTINGS); setDisplayName(Tr::tr("Documentation Comments")); setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Text Editor")); - setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); setWidgetCreator([] { return new CommentsSettingsWidget(CommentsSettings::data()); }); } diff --git a/src/plugins/texteditor/completionsettingspage.cpp b/src/plugins/texteditor/completionsettingspage.cpp index 03f45404c6b..271eac8129b 100644 --- a/src/plugins/texteditor/completionsettingspage.cpp +++ b/src/plugins/texteditor/completionsettingspage.cpp @@ -309,8 +309,6 @@ CompletionSettingsPage::CompletionSettingsPage() setId("P.Completion"); setDisplayName(Tr::tr("Completion")); setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Text Editor")); - setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); setWidgetCreator([this] { return new CompletionSettingsPageWidget(this); }); QtcSettings *s = Core::ICore::settings(); diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index fe914b27ce9..84b73f3a625 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -326,8 +326,6 @@ DisplaySettingsPage::DisplaySettingsPage() setId(Constants::TEXT_EDITOR_DISPLAY_SETTINGS); setDisplayName(Tr::tr("Display")); setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Text Editor")); - setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); setWidgetCreator([this] { return new DisplaySettingsWidget(d); }); } diff --git a/src/plugins/texteditor/fontsettingspage.cpp b/src/plugins/texteditor/fontsettingspage.cpp index f528496dcf0..5f38e583a12 100644 --- a/src/plugins/texteditor/fontsettingspage.cpp +++ b/src/plugins/texteditor/fontsettingspage.cpp @@ -775,8 +775,6 @@ FontSettingsPage::FontSettingsPage(FontSettings *fontSettings, const FormatDescr setId(Constants::TEXT_EDITOR_FONT_SETTINGS); setDisplayName(Tr::tr("Font && Colors")); setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Text Editor")); - setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); setWidgetCreator([this, fontSettings, fd] { return new FontSettingsPageWidget(this, fd, fontSettings); }); } diff --git a/src/plugins/texteditor/highlightersettingspage.cpp b/src/plugins/texteditor/highlightersettingspage.cpp index 81eacbe7e06..0e395fbd33d 100644 --- a/src/plugins/texteditor/highlightersettingspage.cpp +++ b/src/plugins/texteditor/highlightersettingspage.cpp @@ -154,8 +154,6 @@ HighlighterSettingsPage::HighlighterSettingsPage() setId(Constants::TEXT_EDITOR_HIGHLIGHTER_SETTINGS); setDisplayName(Tr::tr("Generic Highlighter")); setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Text Editor")); - setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); setWidgetCreator([this] { return new HighlighterSettingsPageWidget(d); }); } diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.cpp b/src/plugins/texteditor/snippets/snippetssettingspage.cpp index 546d532bbf3..9ce588ec39f 100644 --- a/src/plugins/texteditor/snippets/snippetssettingspage.cpp +++ b/src/plugins/texteditor/snippets/snippetssettingspage.cpp @@ -538,9 +538,7 @@ SnippetsSettingsPage::SnippetsSettingsPage() { setId(Constants::TEXT_EDITOR_SNIPPETS_SETTINGS); setDisplayName(Tr::tr("Snippets")); - setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Text Editor")); - setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); + setCategory(Constants::TEXT_EDITOR_SETTINGS_CATEGORY); setWidgetCreator([] { return new SnippetsSettingsWidget; }); } diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp index c530524a38a..384c2603f3b 100644 --- a/src/plugins/texteditor/texteditorplugin.cpp +++ b/src/plugins/texteditor/texteditorplugin.cpp @@ -99,6 +99,10 @@ void TextEditorPlugin::initialize() addTestCreator(createSnippetParserTest); #endif + IOptionsPage::registerCategory( + Constants::TEXT_EDITOR_SETTINGS_CATEGORY, + Tr::tr("Text Editor"), + Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); setupBehaviorSettings(); setupExtraEncodingSettings(); setupStorageSettings(); diff --git a/src/plugins/todo/settings.cpp b/src/plugins/todo/settings.cpp index dc534f98c88..edb81a30677 100644 --- a/src/plugins/todo/settings.cpp +++ b/src/plugins/todo/settings.cpp @@ -377,8 +377,6 @@ public: setId(Constants::TODO_SETTINGS); setDisplayName(Tr::tr("To-Do")); setCategory("To-Do"); - setDisplayCategory(Tr::tr("To-Do")); - setCategoryIconPath(":/todoplugin/images/settingscategory_todo.png"); setWidgetCreator([] { return new OptionsDialog; }); } }; diff --git a/src/plugins/todo/todoplugin.cpp b/src/plugins/todo/todoplugin.cpp index 8ba19b2e448..99bc6afacdc 100644 --- a/src/plugins/todo/todoplugin.cpp +++ b/src/plugins/todo/todoplugin.cpp @@ -5,7 +5,9 @@ #include "todooutputpane.h" #include "todoitemsprovider.h" #include "todoprojectpanel.h" +#include "todotr.h" +#include #include namespace Todo::Internal { @@ -23,6 +25,9 @@ public: void initialize() final { + Core::IOptionsPage::registerCategory( + "To-Do", Tr::tr("To-Do"), ":/todoplugin/images/settingscategory_todo.png"); + todoSettings().load(); setupTodoItemsProvider(this); diff --git a/src/plugins/valgrind/valgrindsettings.cpp b/src/plugins/valgrind/valgrindsettings.cpp index 2291c9aa76a..386020c7a80 100644 --- a/src/plugins/valgrind/valgrindsettings.cpp +++ b/src/plugins/valgrind/valgrindsettings.cpp @@ -9,9 +9,6 @@ #include -#include -#include - #include #include #include @@ -424,8 +421,6 @@ public: setId(ANALYZER_VALGRIND_SETTINGS); setDisplayName(Tr::tr("Valgrind")); setCategory("T.Analyzer"); - setDisplayCategory(::Debugger::Tr::tr("Analyzer")); - setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); setSettingsProvider([] { return &globalSettings(); }); } }; diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index 9bc924c1d4c..5f009487108 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -122,9 +122,6 @@ public: setId(Constants::VCS_COMMON_SETTINGS_ID); setDisplayName(Tr::tr("General")); setCategory(Constants::VCS_SETTINGS_CATEGORY); - // The following act as blueprint for other pages in the same category: - setDisplayCategory(Tr::tr("Version Control")); - setCategoryIconPath(":/vcsbase/images/settingscategory_vcs.png"); setSettingsProvider([] { return &commonSettings(); }); } }; diff --git a/src/plugins/vcsbase/vcsplugin.cpp b/src/plugins/vcsbase/vcsplugin.cpp index 553bfc61a69..c06c3116b6d 100644 --- a/src/plugins/vcsbase/vcsplugin.cpp +++ b/src/plugins/vcsbase/vcsplugin.cpp @@ -13,6 +13,7 @@ #include "wizard/vcsconfigurationpage.h" #include "wizard/vcsjsextension.h" +#include #include #include #include @@ -96,6 +97,11 @@ void VcsPlugin::initialize() { d = new VcsPluginPrivate(this); + IOptionsPage::registerCategory( + Constants::VCS_SETTINGS_CATEGORY, + Tr::tr("Version Control"), + ":/vcsbase/images/settingscategory_vcs.png"); + JsExpander::registerGlobalObject("Vcs"); MacroExpander *expander = globalMacroExpander(); diff --git a/src/plugins/webassembly/webassemblysettings.cpp b/src/plugins/webassembly/webassemblysettings.cpp index aa2554bc9c1..4c90c6e1f60 100644 --- a/src/plugins/webassembly/webassemblysettings.cpp +++ b/src/plugins/webassembly/webassemblysettings.cpp @@ -208,8 +208,6 @@ public: setId(Id(Constants::SETTINGS_ID)); setDisplayName(Tr::tr("WebAssembly")); setCategory(ProjectExplorer::Constants::SDK_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("SDKs")); - setCategoryIconPath(":/projectexplorer/images/sdk.png"); setSettingsProvider([] { return &settings(); }); } }; From d78c2ad6de1cec9e96822548d3f17072b334637f Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 15 Nov 2024 11:40:21 +0100 Subject: [PATCH 163/989] Fix Windows build Change-Id: Idac06dcb2d12ed959c9a39e663c1fa71a69dbe8e Reviewed-by: hjk --- src/libs/utils/fileutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index ce012f81fa1..ef87925be0e 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -717,7 +717,7 @@ bool FileUtils::copyRecursively(const FilePath &srcFilePath, Returns whether the operation succeeded. */ -Result copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath) +Result FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath) { if (!srcFilePath.exists()) return Result::Error(Tr::tr("File %1 does not exist.").arg(srcFilePath.toUserOutput())); From 05c7c6384b7e863997a3962878fe8ea624cd643b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 14:41:59 +0100 Subject: [PATCH 164/989] Android: Expose serialNumberRecipe It's going to be reused in ports gathering recipe. Change-Id: I2d9652ac4aad8c211f542874eb47c3e49e78eca4 Reviewed-by: hjk --- src/plugins/android/androidutils.cpp | 2 +- src/plugins/android/androidutils.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/androidutils.cpp b/src/plugins/android/androidutils.cpp index d01a941d090..4fac7c363c1 100644 --- a/src/plugins/android/androidutils.cpp +++ b/src/plugins/android/androidutils.cpp @@ -636,7 +636,7 @@ static ExecutableItem startAvdAsyncRecipe(const QString &avdName) }; } -static ExecutableItem serialNumberRecipe(const QString &avdName, const Storage &serialNumberStorage) +ExecutableItem serialNumberRecipe(const QString &avdName, const Storage &serialNumberStorage) { const Storage outputStorage; const Storage currentSerialNumberStorage; diff --git a/src/plugins/android/androidutils.h b/src/plugins/android/androidutils.h index ba26d196b00..ccd3bbe08de 100644 --- a/src/plugins/android/androidutils.h +++ b/src/plugins/android/androidutils.h @@ -68,6 +68,8 @@ bool isQtCreatorGenerated(const Utils::FilePath &deploymentFile); QStringList adbSelector(const QString &serialNumber); +Tasking::ExecutableItem serialNumberRecipe(const QString &avdName, + const Tasking::Storage &serialNumberStorage); Tasking::ExecutableItem startAvdRecipe( const QString &avdName, const Tasking::Storage &serialNumberStorage); From b5f1373c018ec7858ad2294ee79fb25890765619 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 15:28:07 +0100 Subject: [PATCH 165/989] RunControl: Remove unused method Change-Id: I6b34e86589f4623a8420968688db9d19d4bd716a Reviewed-by: hjk --- src/plugins/projectexplorer/runcontrol.cpp | 10 ---------- src/plugins/projectexplorer/runcontrol.h | 1 - 2 files changed, 11 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index a7bc7a147a2..fb0609af6ec 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -648,16 +648,6 @@ QUrl RunControlPrivate::getNextChannel() return result; } -QUrl RunControl::findEndPoint() -{ - QTC_ASSERT(d->portsGatherer, return {}); - QUrl result; - result.setScheme(urlTcpScheme()); - result.setHost(device()->sshParameters().host()); - result.setPort(d->portList.getNextFreePort(d->portsGatherer->usedPorts()).number()); - return result; -} - void RunControl::requestDebugChannel() { d->enablePortsGatherer(); diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 6967ef35d09..311a39f3440 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -244,7 +244,6 @@ public: void postMessage(const QString &msg, Utils::OutputFormat format, bool appendNewLine = true); void enablePortsGatherer(); - QUrl findEndPoint(); void requestDebugChannel(); bool usesDebugChannel() const; From 27bddc436c71efdc05e49ec7620390e3f2bc89a5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 14:39:57 +0100 Subject: [PATCH 166/989] Utils: Add portsFromProcessRecipe() It's going to be used instead of DeviceUsedPortsGatherer. Change-Id: Ie9871e0b6b9267c1511a7248a5dfffbc503956f9 Reviewed-by: hjk --- src/libs/utils/portlist.cpp | 34 ++++++++++++++++++++++++++++++++++ src/libs/utils/portlist.h | 20 ++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/libs/utils/portlist.cpp b/src/libs/utils/portlist.cpp index 5fcd5070670..a89f4426a92 100644 --- a/src/libs/utils/portlist.cpp +++ b/src/libs/utils/portlist.cpp @@ -3,11 +3,19 @@ #include "portlist.h" +#include "qtcprocess.h" +#include "stringutils.h" +#include "utilstr.h" + +#include + #include #include #include +using namespace Tasking; + namespace Utils { namespace Internal { namespace { @@ -199,4 +207,30 @@ QString PortList::regularExpression() return QString::fromLatin1("((%1)(,%1)*)?").arg(listElemExpr); } +ExecutableItem portsFromProcessRecipe(const Storage &input, + const Storage &output) +{ + const auto onSetup = [input](Process &process) { + process.setCommand(input->commandLine); + }; + const auto onDone = [input, output](const Process &process, DoneWith result) { + if (result == DoneWith::Success) { + QList portList; + const QList usedPorts = input->portsParser(process.rawStdOut()); + for (const Port port : usedPorts) { + if (input->freePorts.contains(port)) + portList.append(port); + } + *output = portList; + } else { + const QString errorString = process.errorString(); + const QString stdErr = process.stdErr(); + const QString outputString + = stdErr.isEmpty() ? stdErr : Tr::tr("Remote error output was: %1").arg(stdErr); + *output = make_unexpected(Utils::joinStrings({errorString, outputString}, '\n')); + } + }; + return ProcessTask(onSetup, onDone); +} + } // namespace Utils diff --git a/src/libs/utils/portlist.h b/src/libs/utils/portlist.h index 9207ab90966..4badbbc5497 100644 --- a/src/libs/utils/portlist.h +++ b/src/libs/utils/portlist.h @@ -5,8 +5,15 @@ #include "utils_global.h" +#include "commandline.h" #include "port.h" +namespace Tasking { +class ExecutableItem; +template +class Storage; +} + QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE @@ -38,4 +45,17 @@ private: Internal::PortListPrivate * const d; }; +class QTCREATOR_UTILS_EXPORT PortsInputData +{ +public: + PortList freePorts; + CommandLine commandLine; + std::function(const QByteArray &)> portsParser = &Port::parseFromCommandOutput; +}; + +using PortsOutputData = expected_str>; + +QTCREATOR_UTILS_EXPORT Tasking::ExecutableItem portsFromProcessRecipe( + const Tasking::Storage &input, const Tasking::Storage &output); + } // namespace Utils From 94c1428a2ada739f0a2061267a48c5c5524969a7 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Mon, 15 Apr 2019 09:03:16 +0200 Subject: [PATCH 167/989] Git: Create new branch from a change in Log or Reflog Change-Id: I109e66e1b4e7ea0ab927179dd291e4070a5ff51e Reviewed-by: Orgad Shaneh --- src/plugins/git/gitclient.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index ea60ac555a2..0b35a79e310 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -3750,6 +3750,31 @@ void GitClient::addChangeActions(QMenu *menu, const FilePath &source, const QStr menu->addAction(Tr::tr("C&heckout %1").arg(change), [workingDir, change] { gitClient().checkout(workingDir, change); }); + menu->addAction(tr("Create &Branch from %1...").arg(change), [workingDir, change] { + const QStringList localBranches = + gitClient().synchronousRepositoryBranches(workingDir.toFSPathString()); + BranchAddDialog dialog(localBranches, BranchAddDialog::Type::AddBranch, + Core::ICore::dialogParent()); + dialog.setBranchName(suggestedLocalBranchName(workingDir, localBranches, change, + BranchTargetType::Commit)); + dialog.setCheckoutVisible(true); + if (dialog.exec() != QDialog::Accepted) + return; + + const QString newBranch = dialog.branchName(); + QString output; + QString errorMessage; + if (!gitClient().synchronousBranchCmd(workingDir, + {"--no-track", newBranch, change}, + &output, &errorMessage)) { + VcsOutputWindow::appendError(errorMessage); + return; + } + + if (dialog.checkout()) + gitClient().checkout(workingDir, newBranch); + }); + connect(menu->addAction(Tr::tr("&Interactive Rebase from %1...").arg(change)), &QAction::triggered, [workingDir, change] { startRebaseFromCommit(workingDir, change); From 11d8912bf470b3015ccda1e4d4268c9234984fae Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 31 Oct 2024 11:04:47 +0100 Subject: [PATCH 168/989] Core: Merge messageoutputwindow.* into messagemanager.cpp Barely 70 lines and re-used nowhere else. Change-Id: Ic112d828abd12e078a4b18bb706ae04dab7d09f2 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/CMakeLists.txt | 2 - src/plugins/coreplugin/coreplugin.qbs | 2 - src/plugins/coreplugin/messagemanager.cpp | 73 ++++++++++- .../coreplugin/messageoutputwindow.cpp | 115 ------------------ src/plugins/coreplugin/messageoutputwindow.h | 45 ------- 5 files changed, 72 insertions(+), 165 deletions(-) delete mode 100644 src/plugins/coreplugin/messageoutputwindow.cpp delete mode 100644 src/plugins/coreplugin/messageoutputwindow.h diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index 544dd1e6cbe..7ae5182cd6c 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -211,8 +211,6 @@ add_qtc_plugin(Core messagebox.h messagemanager.cpp messagemanager.h - messageoutputwindow.cpp - messageoutputwindow.h mimetypemagicdialog.cpp mimetypemagicdialog.h mimetypesettings.cpp diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index b5d15242351..767ca65efe7 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -113,8 +113,6 @@ QtcPlugin { "messagebox.h", "messagemanager.cpp", "messagemanager.h", - "messageoutputwindow.cpp", - "messageoutputwindow.h", "mimetypemagicdialog.cpp", "mimetypemagicdialog.h", "mimetypesettings.cpp", diff --git a/src/plugins/coreplugin/messagemanager.cpp b/src/plugins/coreplugin/messagemanager.cpp index 68efe3020c6..e72400bc99d 100644 --- a/src/plugins/coreplugin/messagemanager.cpp +++ b/src/plugins/coreplugin/messagemanager.cpp @@ -3,11 +3,16 @@ #include "messagemanager.h" -#include "messageoutputwindow.h" +#include "coreconstants.h" +#include "coreplugintr.h" +#include "icontext.h" +#include "ioutputpane.h" +#include "outputwindow.h" #include #include +#include #include #include @@ -26,6 +31,72 @@ using namespace Core::Internal; namespace Core::MessageManager { +const char zoomSettingsKey[] = "Core/MessageOutput/Zoom"; + +class MessageOutputWindow final : public IOutputPane +{ +public: + explicit MessageOutputWindow(QObject *parent) + : IOutputPane(parent) + { + setId("GeneralMessages"); + setDisplayName(Tr::tr("General Messages")); + setPriorityInStatusBar(-100); + + m_widget = new OutputWindow(Context(Constants::C_GENERAL_OUTPUT_PANE), zoomSettingsKey); + m_widget->setReadOnly(true); + + connect(this, &IOutputPane::zoomInRequested, m_widget, &Core::OutputWindow::zoomIn); + connect(this, &IOutputPane::zoomOutRequested, m_widget, &Core::OutputWindow::zoomOut); + connect(this, &IOutputPane::resetZoomRequested, m_widget, &Core::OutputWindow::resetZoom); + connect(this, &IOutputPane::fontChanged, m_widget, &OutputWindow::setBaseFont); + connect(this, &IOutputPane::wheelZoomEnabledChanged, m_widget, &OutputWindow::setWheelZoomEnabled); + + setupFilterUi("MessageOutputPane.Filter"); + setFilteringEnabled(true); + setupContext(Constants::C_GENERAL_OUTPUT_PANE, m_widget); + } + + ~MessageOutputWindow() final + { + delete m_widget; + } + + void append(const QString &text) + { + m_widget->appendMessage(text, Utils::GeneralMessageFormat); + } + +private: + QWidget *outputWidget(QWidget *parent) final + { + m_widget->setParent(parent); + return m_widget; + } + + void clearContents() final { m_widget->clear(); } + + bool canFocus() const final { return true; } + bool hasFocus() const final { return m_widget->window()->focusWidget() == m_widget; } + void setFocus() final { m_widget->setFocus(); } + + bool canNext() const final { return false; } + bool canPrevious() const final { return false; } + void goToNext() final {} + void goToPrev() final {} + bool canNavigate() const final { return false; } + + bool hasFilterContext() const final { return true; } + + void updateFilter() final + { + m_widget->updateFilterProperties(filterText(), filterCaseSensitivity(), filterUsesRegexp(), + filterIsInverted(), beforeContext(), afterContext()); + } + + OutputWindow *m_widget = nullptr; +}; + static MessageOutputWindow *messageOutputWindow() { static QPointer theMessageOutputWindow diff --git a/src/plugins/coreplugin/messageoutputwindow.cpp b/src/plugins/coreplugin/messageoutputwindow.cpp deleted file mode 100644 index 75dca7e66ad..00000000000 --- a/src/plugins/coreplugin/messageoutputwindow.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "messageoutputwindow.h" - -#include "coreconstants.h" -#include "coreplugintr.h" -#include "icontext.h" -#include "outputwindow.h" - -#include - -#include -#include - -namespace Core { -namespace Internal { - -const char zoomSettingsKey[] = "Core/MessageOutput/Zoom"; - -MessageOutputWindow::MessageOutputWindow(QObject *parent) - : IOutputPane(parent) -{ - setId("GeneralMessages"); - setDisplayName(Tr::tr("General Messages")); - setPriorityInStatusBar(-100); - - m_widget = new OutputWindow(Context(Constants::C_GENERAL_OUTPUT_PANE), zoomSettingsKey); - m_widget->setReadOnly(true); - - connect(this, &IOutputPane::zoomInRequested, m_widget, &Core::OutputWindow::zoomIn); - connect(this, &IOutputPane::zoomOutRequested, m_widget, &Core::OutputWindow::zoomOut); - connect(this, &IOutputPane::resetZoomRequested, m_widget, &Core::OutputWindow::resetZoom); - connect(this, &IOutputPane::fontChanged, m_widget, &OutputWindow::setBaseFont); - connect(this, &IOutputPane::wheelZoomEnabledChanged, m_widget, &OutputWindow::setWheelZoomEnabled); - - setupFilterUi("MessageOutputPane.Filter"); - setFilteringEnabled(true); - setupContext(Constants::C_GENERAL_OUTPUT_PANE, m_widget); -} - -MessageOutputWindow::~MessageOutputWindow() -{ - delete m_widget; -} - -bool MessageOutputWindow::hasFocus() const -{ - return m_widget->window()->focusWidget() == m_widget; -} - -bool MessageOutputWindow::canFocus() const -{ - return true; -} - -void MessageOutputWindow::setFocus() -{ - m_widget->setFocus(); -} - -void MessageOutputWindow::clearContents() -{ - m_widget->clear(); -} - -QWidget *MessageOutputWindow::outputWidget(QWidget *parent) -{ - m_widget->setParent(parent); - return m_widget; -} - -void MessageOutputWindow::append(const QString &text) -{ - m_widget->appendMessage(text, Utils::GeneralMessageFormat); -} - -bool MessageOutputWindow::canNext() const -{ - return false; -} - -bool MessageOutputWindow::canPrevious() const -{ - return false; -} - -void MessageOutputWindow::goToNext() -{ - -} - -void MessageOutputWindow::goToPrev() -{ - -} - -bool MessageOutputWindow::canNavigate() const -{ - return false; -} - -bool MessageOutputWindow::hasFilterContext() const -{ - return true; -} - -void MessageOutputWindow::updateFilter() -{ - m_widget->updateFilterProperties(filterText(), filterCaseSensitivity(), filterUsesRegexp(), - filterIsInverted(), beforeContext(), afterContext()); -} - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/messageoutputwindow.h b/src/plugins/coreplugin/messageoutputwindow.h deleted file mode 100644 index f8bf96bff53..00000000000 --- a/src/plugins/coreplugin/messageoutputwindow.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "ioutputpane.h" - -namespace Core { -class OutputWindow; - -namespace Internal { - -class MessageOutputWindow : public IOutputPane -{ - Q_OBJECT - -public: - explicit MessageOutputWindow(QObject *parent); - ~MessageOutputWindow() override; - - QWidget *outputWidget(QWidget *parent) override; - - void clearContents() override; - - void append(const QString &text); - bool canFocus() const override; - bool hasFocus() const override; - void setFocus() override; - - bool canNext() const override; - bool canPrevious() const override; - void goToNext() override; - void goToPrev() override; - bool canNavigate() const override; - - bool hasFilterContext() const override; - -private: - void updateFilter() override; - - OutputWindow *m_widget; -}; - -} // namespace Internal -} // namespace Core From 725c2a474be374763d0bc2e9bc25eeb74a840cd7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 15 Nov 2024 15:19:19 +0100 Subject: [PATCH 169/989] Help: Move settings category registration + resources to Core This category is also used by the unrelated ScreenRecorder plugin. Change-Id: I3eb976e1b3b42feae74b6f96116e2096591782dc Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/core.qrc | 2 ++ src/plugins/coreplugin/coreconstants.h | 2 ++ src/plugins/coreplugin/coreplugin.cpp | 4 ++++ .../images/settingscategory_help.png | Bin .../images/settingscategory_help@2x.png | Bin src/plugins/help/docsettingspage.cpp | 4 ++-- src/plugins/help/filtersettingspage.cpp | 4 ++-- src/plugins/help/generalsettingspage.cpp | 2 +- src/plugins/help/help.qrc | 2 -- src/plugins/help/helpconstants.h | 1 - src/plugins/help/helpplugin.cpp | 3 --- .../screenrecorder/screenrecordersettings.cpp | 5 ++--- src/tools/icons/qtcreatoricons.svg | 2 +- 13 files changed, 16 insertions(+), 15 deletions(-) rename src/plugins/{help => coreplugin}/images/settingscategory_help.png (100%) rename src/plugins/{help => coreplugin}/images/settingscategory_help@2x.png (100%) diff --git a/src/plugins/coreplugin/core.qrc b/src/plugins/coreplugin/core.qrc index 239bd946121..1a991bd7e00 100644 --- a/src/plugins/coreplugin/core.qrc +++ b/src/plugins/coreplugin/core.qrc @@ -10,5 +10,7 @@ images/settingscategory_design@2x.png images/qtlogo.png images/qtlogo@2x.png + images/settingscategory_help.png + images/settingscategory_help@2x.png diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index b1512082844..d381b3ce1f2 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -230,5 +230,7 @@ const int DEFAULT_MAX_CHAR_COUNT = 10000000; const char SETTINGS_MENU_HIDE_TOOLS[] = "Menu/HideTools"; +const char HELP_CATEGORY[] = "H.Help"; + } // namespace Constants } // namespace Core diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 36cd4463d0d..73c2079161f 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -278,6 +278,10 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) Tr::tr("Environment"), ":/core/images/settingscategory_core.png"); + // Shared by Help and ScreenRecorder + IOptionsPage::registerCategory( + Constants::HELP_CATEGORY, Tr::tr("Help"), ":/core/images/settingscategory_help.png"); + IWizardFactory::initialize(); // Make sure we respect the process's umask when creating new files diff --git a/src/plugins/help/images/settingscategory_help.png b/src/plugins/coreplugin/images/settingscategory_help.png similarity index 100% rename from src/plugins/help/images/settingscategory_help.png rename to src/plugins/coreplugin/images/settingscategory_help.png diff --git a/src/plugins/help/images/settingscategory_help@2x.png b/src/plugins/coreplugin/images/settingscategory_help@2x.png similarity index 100% rename from src/plugins/help/images/settingscategory_help@2x.png rename to src/plugins/coreplugin/images/settingscategory_help@2x.png diff --git a/src/plugins/help/docsettingspage.cpp b/src/plugins/help/docsettingspage.cpp index 6408166958f..8663e6e93cd 100644 --- a/src/plugins/help/docsettingspage.cpp +++ b/src/plugins/help/docsettingspage.cpp @@ -3,10 +3,10 @@ #include "docsettingspage.h" -#include "helpconstants.h" #include "helpmanager.h" #include "helptr.h" +#include #include #include #include @@ -356,7 +356,7 @@ DocSettingsPage::DocSettingsPage() { setId("B.Documentation"); setDisplayName(Tr::tr("Documentation")); - setCategory(Help::Constants::HELP_CATEGORY); + setCategory(Core::Constants::HELP_CATEGORY); setWidgetCreator([] { return new DocSettingsPageWidget; }); } diff --git a/src/plugins/help/filtersettingspage.cpp b/src/plugins/help/filtersettingspage.cpp index e227b025ef0..db7360f1e6b 100644 --- a/src/plugins/help/filtersettingspage.cpp +++ b/src/plugins/help/filtersettingspage.cpp @@ -3,10 +3,10 @@ #include "filtersettingspage.h" -#include "helpconstants.h" #include "helptr.h" #include "localhelpmanager.h" +#include #include #include @@ -55,7 +55,7 @@ FilterSettingsPage::FilterSettingsPage(const std::function &onChanged) { setId("D.Filters"); setDisplayName(Tr::tr("Filters")); - setCategory(Help::Constants::HELP_CATEGORY); + setCategory(Core::Constants::HELP_CATEGORY); setWidgetCreator([onChanged] { return new FilterSettingsPageWidget(onChanged); }); } diff --git a/src/plugins/help/generalsettingspage.cpp b/src/plugins/help/generalsettingspage.cpp index 4188bbcdb31..384752d4c19 100644 --- a/src/plugins/help/generalsettingspage.cpp +++ b/src/plugins/help/generalsettingspage.cpp @@ -500,7 +500,7 @@ GeneralSettingsPage::GeneralSettingsPage() { setId("A.General settings"); setDisplayName(Tr::tr("General")); - setCategory(Help::Constants::HELP_CATEGORY); + setCategory(Core::Constants::HELP_CATEGORY); setWidgetCreator([] { return new GeneralSettingsPageWidget; }); } diff --git a/src/plugins/help/help.qrc b/src/plugins/help/help.qrc index 84b6776caaa..7510e65e7a9 100644 --- a/src/plugins/help/help.qrc +++ b/src/plugins/help/help.qrc @@ -1,7 +1,5 @@ - images/settingscategory_help.png - images/settingscategory_help@2x.png images/mode_help.png images/mode_help@2x.png images/mode_help_mask.png diff --git a/src/plugins/help/helpconstants.h b/src/plugins/help/helpconstants.h index 5acb6281056..2cf94222361 100644 --- a/src/plugins/help/helpconstants.h +++ b/src/plugins/help/helpconstants.h @@ -13,7 +13,6 @@ const QLatin1String AboutBlank("about:blank"); const int P_MODE_HELP = 70; const char ID_MODE_HELP [] = "Help"; -const char HELP_CATEGORY[] = "H.Help"; const char C_MODE_HELP [] = "Help Mode"; const char C_HELP_SIDEBAR[] = "Help Sidebar"; diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 92540a02f93..1b70196a20a 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -651,9 +651,6 @@ private: void initialize() final { dd = new HelpPluginPrivate; - - IOptionsPage::registerCategory( - Constants::HELP_CATEGORY, Tr::tr("Help"), ":/help/images/settingscategory_help.png"); } void extensionsInitialized() final diff --git a/src/plugins/screenrecorder/screenrecordersettings.cpp b/src/plugins/screenrecorder/screenrecordersettings.cpp index 35ba138faad..94436646367 100644 --- a/src/plugins/screenrecorder/screenrecordersettings.cpp +++ b/src/plugins/screenrecorder/screenrecordersettings.cpp @@ -6,11 +6,10 @@ #include "screenrecorderconstants.h" #include "screenrecordertr.h" +#include #include #include -#include - #include #include #include @@ -263,7 +262,7 @@ public: { setId(Constants::TOOLSSETTINGSPAGE_ID); setDisplayName(Tr::tr("Screen Recording")); - setCategory(Help::Constants::HELP_CATEGORY); + setCategory(Core::Constants::HELP_CATEGORY); setSettingsProvider([] { return &settings(); }); } }; diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index b98508da4d3..d299279052b 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -2668,7 +2668,7 @@ inkscape:connector-curvature="0" /> Date: Thu, 14 Nov 2024 15:10:08 +0100 Subject: [PATCH 170/989] LanguageClient: stabilize Manager Api Opening a temporary document in a language client results in asserts instead of crashes now. Task-number: QTCREATORBUG-32011 Change-Id: I775db51171b707ab3dd644dbf965182b8c831fe7 Reviewed-by: Christian Stenger --- src/plugins/languageclient/client.cpp | 6 ++++++ src/plugins/languageclient/client.h | 1 + src/plugins/languageclient/languageclientmanager.cpp | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 02bb7ca9a1b..ce6dcb75fc7 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -1622,6 +1622,12 @@ bool Client::hasDiagnostics(const TextEditor::TextDocument *document) const return false; } +void Client::hideDiagnostics(const Utils::FilePath &documentPath) +{ + if (d->m_diagnosticManager) + d->m_diagnosticManager->hideDiagnostics(documentPath); +} + DiagnosticManager *Client::createDiagnosticManager() { return new DiagnosticManager(this); diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 57b49463915..079d3eb9677 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -171,6 +171,7 @@ public: bool hasDiagnostic(const Utils::FilePath &filePath, const LanguageServerProtocol::Diagnostic &diag) const; bool hasDiagnostics(const TextEditor::TextDocument *document) const; + void hideDiagnostics(const Utils::FilePath &documentPath); void setSemanticTokensHandler(const SemanticTokensHandler &handler); void setSnippetsGroup(const QString &group); void setCompletionAssistProvider(LanguageClientCompletionAssistProvider *provider); diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index f0bf50c270f..857162903bf 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -462,7 +462,14 @@ void LanguageClientManager::openDocumentWithClient(TextEditor::TextDocument *doc Client *currentClient = clientForDocument(document); if (client == currentClient) return; - managerInstance->m_clientForDocument.remove(document); + const bool firstOpen = !managerInstance->m_clientForDocument.remove(document); + if (firstOpen) { + connect( + document, &QObject::destroyed, managerInstance, [document, path = document->filePath()] { + const QPointer client = managerInstance->m_clientForDocument.take(document); + QTC_ASSERT(!client, client->hideDiagnostics(path)); + }); + } if (currentClient) currentClient->deactivateDocument(document); managerInstance->m_clientForDocument[document] = client; From ba8cef149f7730d8a6299557dd5e761c9700a65f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 12 Nov 2024 14:55:24 +0100 Subject: [PATCH 171/989] ProjectExplorer: Add BuildDeviceTypeKitAspect For symmetry between build and run devices. Change-Id: I2cb7bdbe0264e42b3e4e7c2fad88cdc34ba43fde Reviewed-by: hjk --- src/plugins/docker/dockerdevice.cpp | 5 - src/plugins/docker/dockerdevice.h | 1 - .../devicesupport/desktopdevice.cpp | 5 - .../devicesupport/desktopdevice.h | 1 - .../devicesupport/devicekitaspects.cpp | 284 +++++++++--------- .../devicesupport/devicekitaspects.h | 8 + .../projectexplorer/devicesupport/idevice.h | 2 - src/plugins/remotelinux/linuxdevice.cpp | 5 - src/plugins/remotelinux/linuxdevice.h | 1 - 9 files changed, 156 insertions(+), 156 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 4882325cb1b..ffe0cb84e33 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -1071,11 +1071,6 @@ DeviceTester *DockerDevice::createDeviceTester() return nullptr; } -bool DockerDevice::usableAsBuildDevice() const -{ - return true; -} - FilePath DockerDevice::filePath(const QString &pathOnDevice) const { return FilePath::fromParts(Constants::DOCKER_DEVICE_SCHEME, diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index 0754819af43..b738ac41b05 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -35,7 +35,6 @@ public: bool canCreateProcessModel() const override { return true; } bool hasDeviceTester() const override { return false; } ProjectExplorer::DeviceTester *createDeviceTester() override; - bool usableAsBuildDevice() const override; Utils::FilePath rootPath() const override; Utils::FilePath filePath(const QString &pathOnDevice) const override; diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 548e20625e6..b055cb399a4 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -103,11 +103,6 @@ QUrl DesktopDevice::toolControlChannel(const ControlChannelHint &) const return url; } -bool DesktopDevice::usableAsBuildDevice() const -{ - return true; -} - bool DesktopDevice::handlesFile(const FilePath &filePath) const { return !filePath.needsDevice(); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h index 437a4f8c074..4d03ed472e3 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h @@ -28,7 +28,6 @@ public: bool canCreateProcessModel() const override; DeviceProcessSignalOperation::Ptr signalOperation() const override; QUrl toolControlChannel(const ControlChannelHint &) const override; - bool usableAsBuildDevice() const override; bool handlesFile(const Utils::FilePath &filePath) const override; Utils::expected_str systemEnvironmentWithError() const override; diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 1cfc074cfb5..e3c6d03d910 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -29,15 +29,12 @@ using namespace Utils; namespace ProjectExplorer { - -// -------------------------------------------------------------------------- -// RunDeviceTypeKitAspect: -// -------------------------------------------------------------------------- namespace Internal { -class RunDeviceTypeKitAspectImpl final : public KitAspect + +template class DeviceTypeKitAspectImpl final : public KitAspect { public: - RunDeviceTypeKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) + DeviceTypeKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) : KitAspect(workingCopy, factory) { using ItemData = std::tuple; @@ -53,9 +50,9 @@ public: return std::get<2>(d); return {}; }); - auto getter = [](const Kit &k) { return RunDeviceTypeKitAspect::deviceTypeId(&k).toSetting(); }; + auto getter = [](const Kit &k) { return Aspect::deviceTypeId(&k).toSetting(); }; auto setter = [](Kit &k, const QVariant &type) { - RunDeviceTypeKitAspect::setDeviceTypeId(&k, Id::fromSetting(type)); + Aspect::setDeviceTypeId(&k, Id::fromSetting(type)); }; auto resetModel = [model] { model->clear(); @@ -69,73 +66,118 @@ public: } }; -class RunDeviceTypeKitAspectFactory : public KitAspectFactory +template +class DeviceKitAspectImpl final : public KitAspect { public: - RunDeviceTypeKitAspectFactory(); + DeviceKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) + : KitAspect(workingCopy, factory) + { + setManagingPage(Constants::DEVICE_SETTINGS_PAGE_ID); - void setup(Kit *k) override; - Tasks validate(const Kit *k) const override; - KitAspect *createKitAspect(Kit *k) const override; - ItemList toUserOutput(const Kit *k) const override; + const auto model = new DeviceManagerModel(DeviceManager::instance(), this); + auto getter = [](const Kit &k) { + auto device = DeviceAspect::device(&k); + return device ? device->id().toSetting() : QVariant{}; + }; + auto setter = [](Kit &k, const QVariant &id) { + DeviceAspect::setDeviceId(&k, Id::fromSetting(id)); + }; + auto resetModel = [this, model] { + model->setTypeFilter(TypeAspect::deviceTypeId(kit())); + }; + addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); - QSet supportedPlatforms(const Kit *k) const override; - QSet availableFeatures(const Kit *k) const override; + connect(DeviceManager::instance(), &DeviceManager::updated, + this, &DeviceKitAspectImpl::refresh); + } + +private: + Id settingsPageItemToPreselect() const override { return DeviceAspect::deviceId(kit()); } + + void addToInnerLayout(Layouting::Layout &parentItem) override + { + if (const QList embedded = aspectsToEmbed(); !embedded.isEmpty()) { + Layouting::Layout layout(new QHBoxLayout); + layout.addItem(Tr::tr("Type:")); + embedded.first()->addToInnerLayout(layout); + layout.addItem(Tr::tr("Device:")); + KitAspect::addToInnerLayout(layout); + QSizePolicy p = comboBoxes().first()->sizePolicy(); + p.setHorizontalStretch(1); + comboBoxes().first()->setSizePolicy(p); + parentItem.addItem(layout); + } else { + KitAspect::addToInnerLayout(parentItem); + } + } }; -RunDeviceTypeKitAspectFactory::RunDeviceTypeKitAspectFactory() +template +class DeviceTypeKitAspectFactory : public KitAspectFactory { - setId(RunDeviceTypeKitAspect::id()); - setDisplayName(Tr::tr("Run device type")); - setDescription(Tr::tr("The type of device to run applications on.")); - setPriority(33000); - makeEssential(); -} - -void RunDeviceTypeKitAspectFactory::setup(Kit *k) -{ - if (k && !k->hasValue(id())) - k->setValue(id(), QByteArray(Constants::DESKTOP_DEVICE_TYPE)); -} - -Tasks RunDeviceTypeKitAspectFactory::validate(const Kit *k) const -{ - Q_UNUSED(k) - return {}; -} - -KitAspect *RunDeviceTypeKitAspectFactory::createKitAspect(Kit *k) const -{ - QTC_ASSERT(k, return nullptr); - return new Internal::RunDeviceTypeKitAspectImpl(k, this); -} - -KitAspectFactory::ItemList RunDeviceTypeKitAspectFactory::toUserOutput(const Kit *k) const -{ - QTC_ASSERT(k, return {}); - Id type = RunDeviceTypeKitAspect::deviceTypeId(k); - QString typeDisplayName = Tr::tr("Unknown device type"); - if (type.isValid()) { - if (IDeviceFactory *factory = IDeviceFactory::find(type)) - typeDisplayName = factory->displayName(); +public: + DeviceTypeKitAspectFactory() + { + setId(DeviceTypeKitAspect::id()); + makeEssential(); } - return {{Tr::tr("Device type"), typeDisplayName}}; -} -QSet RunDeviceTypeKitAspectFactory::supportedPlatforms(const Kit *k) const + void setup(Kit *k) override + { + if (k && !k->hasValue(id())) + k->setValue(id(), QByteArray(Constants::DESKTOP_DEVICE_TYPE)); + } + + KitAspect *createKitAspect(Kit *k) const override + { + QTC_ASSERT(k, return nullptr); + return new DeviceTypeKitAspectImpl(k, this); + } + + ItemList toUserOutput(const Kit *k) const override + { + QTC_ASSERT(k, return {}); + const Id type = DeviceTypeKitAspect::deviceTypeId(k); + QString typeDisplayName = Tr::tr("Unknown device type"); + if (type.isValid()) { + if (IDeviceFactory *factory = IDeviceFactory::find(type)) + typeDisplayName = factory->displayName(); + } + return {{Tr::tr("Device type"), typeDisplayName}}; + } + + QSet availableFeatures(const Kit *k) const override + { + if (const Id id = DeviceTypeKitAspect::deviceTypeId(k); id.isValid()) + return {id.withPrefix("DeviceType.")}; + return {}; + } + + QSet supportedPlatforms(const Kit *k) const override + { + return {DeviceTypeKitAspect::deviceTypeId(k)}; + } + + Tasks validate(const Kit *) const override { return {}; } +}; + +// -------------------------------------------------------------------------- +// RunDeviceTypeKitAspect: +// -------------------------------------------------------------------------- +class RunDeviceTypeKitAspectFactory : public DeviceTypeKitAspectFactory { - return {RunDeviceTypeKitAspect::deviceTypeId(k)}; -} +public: + RunDeviceTypeKitAspectFactory() + { + setPriority(33000); + setDisplayName(Tr::tr("Run device type")); + setDescription(Tr::tr("The type of device to run applications on.")); + } +}; -QSet RunDeviceTypeKitAspectFactory::availableFeatures(const Kit *k) const -{ - Id id = RunDeviceTypeKitAspect::deviceTypeId(k); - if (id.isValid()) - return {id.withPrefix("DeviceType.")}; - return {}; -} +const RunDeviceTypeKitAspectFactory theRunDeviceTypeKitAspectFactory; -const RunDeviceTypeKitAspectFactory theDeviceTypeKitAspectFactory; } // namespace Internal const Id RunDeviceTypeKitAspect::id() @@ -158,51 +200,6 @@ void RunDeviceTypeKitAspect::setDeviceTypeId(Kit *k, Id type) // RunDeviceKitAspect: // -------------------------------------------------------------------------- namespace Internal { -class RunDeviceKitAspectImpl final : public KitAspect -{ -public: - RunDeviceKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) - : KitAspect(workingCopy, factory) - { - setManagingPage(Constants::DEVICE_SETTINGS_PAGE_ID); - - const auto model = new DeviceManagerModel(DeviceManager::instance(), this); - auto getter = [](const Kit &k) { - auto device = RunDeviceKitAspect::device(&k); - return device ? device->id().toSetting() : QVariant{}; - }; - auto setter = [](Kit &k, const QVariant &id) { - RunDeviceKitAspect::setDeviceId(&k, Id::fromSetting(id)); - }; - auto resetModel = [this, model] { - model->setTypeFilter(RunDeviceTypeKitAspect::deviceTypeId(kit())); - }; - addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); - - connect(DeviceManager::instance(), &DeviceManager::updated, - this, &RunDeviceKitAspectImpl::refresh); - } - -private: - Id settingsPageItemToPreselect() const override { return RunDeviceKitAspect::deviceId(kit()); } - - void addToInnerLayout(Layouting::Layout &parentItem) override - { - if (const QList embedded = aspectsToEmbed(); !embedded.isEmpty()) { - Layouting::Layout layout(new QHBoxLayout); - layout.addItem(Tr::tr("Type:")); - embedded.first()->addToInnerLayout(layout); - layout.addItem(Tr::tr("Device:")); - KitAspect::addToInnerLayout(layout); - QSizePolicy p = comboBoxes().first()->sizePolicy(); - p.setHorizontalStretch(1); - comboBoxes().first()->setSizePolicy(p); - parentItem.addItem(layout); - } else { - KitAspect::addToInnerLayout(parentItem); - } - } -}; class RunDeviceKitAspectFactory : public KitAspectFactory { @@ -294,7 +291,7 @@ void RunDeviceKitAspectFactory::setup(Kit *k) KitAspect *RunDeviceKitAspectFactory::createKitAspect(Kit *k) const { QTC_ASSERT(k, return nullptr); - return new Internal::RunDeviceKitAspectImpl(k, this); + return new Internal::DeviceKitAspectImpl(k, this); } QString RunDeviceKitAspectFactory::displayNamePostfix(const Kit *k) const @@ -414,41 +411,55 @@ FilePath RunDeviceKitAspect::deviceFilePath(const Kit *k, const QString &pathOnD } // -------------------------------------------------------------------------- -// BuildDeviceKitAspect: +// BuildDeviceTypeKitAspect: // -------------------------------------------------------------------------- namespace Internal { -class BuildDeviceKitAspectImpl final : public KitAspect + +class BuildDeviceTypeKitAspectFactory : public DeviceTypeKitAspectFactory { public: - BuildDeviceKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) - : KitAspect(workingCopy, factory) + BuildDeviceTypeKitAspectFactory() { - setManagingPage(Constants::DEVICE_SETTINGS_PAGE_ID); + setDisplayName(Tr::tr("Build device type")); + setDescription(Tr::tr("The type of device to build on.")); + setPriority(31899); + } - const auto model = new DeviceManagerModel(DeviceManager::instance(), this); - auto getter = [](const Kit &k) { - return BuildDeviceKitAspect::device(&k)->id().toSetting(); - }; - auto setter = [](Kit &k, const QVariant &id) { - BuildDeviceKitAspect::setDeviceId(&k, Id::fromSetting(id)); - }; - auto resetModel = [model] { - QList blackList; - const DeviceManager *dm = DeviceManager::instance(); - for (int i = 0; i < dm->deviceCount(); ++i) { - IDevice::ConstPtr device = dm->deviceAt(i); - if (!device->usableAsBuildDevice()) - blackList.append(device->id()); - } - model->setFilter(blackList); - }; - addListAspectSpec({model, std::move(getter), std::move(setter), std::move(resetModel)}); - - connect(DeviceManager::instance(), &DeviceManager::updated, - this, &BuildDeviceKitAspectImpl::refresh); +private: + // QtC < 16 did not have a build device type, but the user might have set the build device. + void upgrade(Kit *k) + { + if (!BuildDeviceTypeKitAspect::deviceTypeId(k).isValid()) { + if (const IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k)) + BuildDeviceTypeKitAspect::setDeviceTypeId(k, dev->type()); + } } }; +const BuildDeviceTypeKitAspectFactory theBuildDeviceTypeKitAspectFactory; + +} // namespace Internal + +Id BuildDeviceTypeKitAspect::id() +{ + return "PE.Profile.BuildDeviceType"; +} + +Id BuildDeviceTypeKitAspect::deviceTypeId(const Kit *k) +{ + return k ? Id::fromSetting(k->value(BuildDeviceTypeKitAspect::id())) : Id(); +} + +void BuildDeviceTypeKitAspect::setDeviceTypeId(Kit *k, Utils::Id type) +{ + QTC_ASSERT(k, return); + k->setValue(BuildDeviceTypeKitAspect::id(), type.toSetting()); +} + +// -------------------------------------------------------------------------- +// BuildDeviceKitAspect: +// -------------------------------------------------------------------------- +namespace Internal { class BuildDeviceKitAspectFactory : public KitAspectFactory { public: @@ -479,6 +490,7 @@ BuildDeviceKitAspectFactory::BuildDeviceKitAspectFactory() setDisplayName(Tr::tr("Build device")); setDescription(Tr::tr("The device used to build applications on.")); setPriority(31900); + setEmbeddableAspects({BuildDeviceTypeKitAspect::id()}); } static IDeviceConstPtr defaultDevice() @@ -510,7 +522,7 @@ Tasks BuildDeviceKitAspectFactory::validate(const Kit *k) const KitAspect *BuildDeviceKitAspectFactory::createKitAspect(Kit *k) const { QTC_ASSERT(k, return nullptr); - return new Internal::BuildDeviceKitAspectImpl(k, this); + return new Internal::DeviceKitAspectImpl(k, this); } QString BuildDeviceKitAspectFactory::displayNamePostfix(const Kit *k) const diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.h b/src/plugins/projectexplorer/devicesupport/devicekitaspects.h index 1f57aaeac92..e99bb14010a 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.h +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.h @@ -32,6 +32,14 @@ public: static Utils::FilePath deviceFilePath(const Kit *k, const QString &pathOnDevice); }; +class PROJECTEXPLORER_EXPORT BuildDeviceTypeKitAspect +{ +public: + static Utils::Id id(); + static Utils::Id deviceTypeId(const Kit *k); + static void setDeviceTypeId(Kit *k, Utils::Id type); +}; + class PROJECTEXPLORER_EXPORT BuildDeviceKitAspect { public: diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 048a87fbf70..fb1fd2b1196 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -128,8 +128,6 @@ public: virtual bool isCompatibleWith(const Kit *k) const; virtual QList validate() const; - virtual bool usableAsBuildDevice() const { return false; } - QString displayType() const; Utils::OsType osType() const; diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index bf5f86c2f96..82821747682 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1099,11 +1099,6 @@ DeviceProcessSignalOperation::Ptr LinuxDevice::signalOperation() const return DeviceProcessSignalOperation::Ptr(new RemoteLinuxSignalOperation(shared_from_this())); } -bool LinuxDevice::usableAsBuildDevice() const -{ - return true; -} - QString LinuxDevice::userAtHost() const { return sshParameters().userAtHost(); diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index dd84a77ff95..d2a67c03c64 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -26,7 +26,6 @@ public: bool hasDeviceTester() const override { return true; } ProjectExplorer::DeviceTester *createDeviceTester() override; ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; - bool usableAsBuildDevice() const override; QString userAtHost() const; QString userAtHostAndPort() const; From 85748cd42bb33796cebc9d48b439ae11600cd7a4 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 4 Nov 2024 19:00:20 +0100 Subject: [PATCH 172/989] Debugger: Don't tweak LLDB python environment twice If it was already tweaked by DebuggerItem::addAndroidLldbPythonEnv, it is ready to run. No need to tweak it a second time. Change-Id: I6ab86739b4c6cb6379017a046f92296416bb8276 Reviewed-by: hjk --- src/plugins/debugger/lldb/lldbengine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 0fc4eea265b..45cb3f829ba 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -184,9 +184,9 @@ void LldbEngine::setupEngine() Environment environment = runParameters().debugger.environment; environment.set("QT_CREATOR_LLDB_PROCESS", "1"); environment.set("PYTHONUNBUFFERED", "1"); // avoid flushing problem on macOS - DebuggerItem::addAndroidLldbPythonEnv(lldbCmd, environment); + const bool ndkPythonEnvTweaked = DebuggerItem::addAndroidLldbPythonEnv(lldbCmd, environment); - if (lldbCmd.osType() == OsTypeLinux) { + if (!ndkPythonEnvTweaked && lldbCmd.osType() == OsTypeLinux) { // LLDB 14 installation on Ubuntu 22.04 is broken: // https://bugs.launchpad.net/ubuntu/+source/llvm-defaults/+bug/1972855 // Brush over it: From 26c352ae81e53db3cdb63b67326c545f25a97b0c Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 31 Oct 2024 16:04:14 +0100 Subject: [PATCH 173/989] Core: Move outputpane.cpp contents to outputpanemanager.cpp That's the smaller diff then the otherway round. Plan is to consolidate everything here and then move back. Change-Id: I54ed0f40c52d35cc13b43225d93da4513d4ccc60 Reviewed-by: Christian Stenger --- src/plugins/coreplugin/outputpane.cpp | 218 ------------------- src/plugins/coreplugin/outputpanemanager.cpp | 203 ++++++++++++++++- 2 files changed, 200 insertions(+), 221 deletions(-) diff --git a/src/plugins/coreplugin/outputpane.cpp b/src/plugins/coreplugin/outputpane.cpp index d4011370c92..e69de29bb2d 100644 --- a/src/plugins/coreplugin/outputpane.cpp +++ b/src/plugins/coreplugin/outputpane.cpp @@ -1,218 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "modemanager.h" -#include "outputpane.h" -#include "outputpanemanager.h" - -#include - -#include -#include -#include - -using namespace Utils; - -Q_GLOBAL_STATIC(QList, sPlaceholders) - -namespace Core { - -class OutputPanePlaceHolderPrivate { -public: - explicit OutputPanePlaceHolderPrivate(Id mode, QSplitter *parent); - - Id m_mode; - QSplitter *m_splitter; - int m_nonMaximizedSize = 0; - bool m_isMaximized = false; - bool m_initialized = false; - static OutputPanePlaceHolder* m_current; -}; - -OutputPanePlaceHolderPrivate::OutputPanePlaceHolderPrivate(Id mode, QSplitter *parent) : - m_mode(mode), m_splitter(parent) -{ -} - -OutputPanePlaceHolder *OutputPanePlaceHolderPrivate::m_current = nullptr; - -OutputPanePlaceHolder::OutputPanePlaceHolder(Id mode, QSplitter *parent) - : QWidget(parent), d(new OutputPanePlaceHolderPrivate(mode, parent)) -{ - sPlaceholders->append(this); - setVisible(false); - setLayout(new QVBoxLayout); - QSizePolicy sp; - sp.setHorizontalPolicy(QSizePolicy::Preferred); - sp.setVerticalPolicy(QSizePolicy::Preferred); - sp.setHorizontalStretch(0); - setSizePolicy(sp); - layout()->setContentsMargins(0, 0, 0, 0); - connect(ModeManager::instance(), &ModeManager::currentModeChanged, - this, &OutputPanePlaceHolder::currentModeChanged); - // if this is part of a lazily created mode widget, - // we need to check if this is the current placeholder - currentModeChanged(ModeManager::currentModeId()); -} - -OutputPanePlaceHolder::~OutputPanePlaceHolder() -{ - if (OutputPanePlaceHolderPrivate::m_current == this) { - if (Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance()) { - om->setParent(nullptr); - om->hide(); - } - OutputPanePlaceHolderPrivate::m_current = nullptr; - } - delete d; -} - -void OutputPanePlaceHolder::currentModeChanged(Id mode) -{ - if (OutputPanePlaceHolderPrivate::m_current == this) { - OutputPanePlaceHolderPrivate::m_current = nullptr; - if (d->m_initialized) - Internal::OutputPaneManager::setOutputPaneHeightSetting(d->m_nonMaximizedSize); - Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); - om->hide(); - om->setParent(nullptr); - om->updateStatusButtons(false); - } - if (d->m_mode == mode) { - if (OutputPanePlaceHolderPrivate::m_current && OutputPanePlaceHolderPrivate::m_current->d->m_initialized) - Internal::OutputPaneManager::setOutputPaneHeightSetting(OutputPanePlaceHolderPrivate::m_current->d->m_nonMaximizedSize); - Core::OutputPanePlaceHolderPrivate::m_current = this; - Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); - layout()->addWidget(om); - om->show(); - om->updateStatusButtons(isVisible()); - Internal::OutputPaneManager::updateMaximizeButton(d->m_isMaximized); - } -} - -void OutputPanePlaceHolder::setMaximized(bool maximize) -{ - if (d->m_isMaximized == maximize) - return; - if (!d->m_splitter) - return; - int idx = d->m_splitter->indexOf(this); - if (idx < 0) - return; - - d->m_isMaximized = maximize; - if (OutputPanePlaceHolderPrivate::m_current == this) - Internal::OutputPaneManager::updateMaximizeButton(d->m_isMaximized); - QList sizes = d->m_splitter->sizes(); - - if (maximize) { - d->m_nonMaximizedSize = sizes[idx]; - int sum = 0; - for (const int s : std::as_const(sizes)) - sum += s; - for (int i = 0; i < sizes.count(); ++i) { - sizes[i] = 32; - } - sizes[idx] = sum - (sizes.count()-1) * 32; - } else { - int target = d->m_nonMaximizedSize > 0 ? d->m_nonMaximizedSize : sizeHint().height(); - int space = sizes[idx] - target; - if (space > 0) { - for (int i = 0; i < sizes.count(); ++i) { - sizes[i] += space / (sizes.count()-1); - } - sizes[idx] = target; - } - } - - d->m_splitter->setSizes(sizes); -} - -bool OutputPanePlaceHolder::isMaximized() const -{ - return d->m_isMaximized; -} - -void OutputPanePlaceHolder::setHeight(int height) -{ - if (height == 0) - return; - if (!d->m_splitter) - return; - const int idx = d->m_splitter->indexOf(this); - if (idx < 0) - return; - - d->m_splitter->refresh(); - QList sizes = d->m_splitter->sizes(); - const int difference = height - sizes.at(idx); - if (difference == 0) - return; - const int adaption = difference / (sizes.count()-1); - for (int i = 0; i < sizes.count(); ++i) { - sizes[i] -= adaption; - } - sizes[idx] = height; - d->m_splitter->setSizes(sizes); -} - -void OutputPanePlaceHolder::ensureSizeHintAsMinimum() -{ - if (!d->m_splitter) - return; - Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); - int minimum = (d->m_splitter->orientation() == Qt::Vertical - ? om->sizeHint().height() : om->sizeHint().width()); - if (nonMaximizedSize() < minimum && !d->m_isMaximized) - setHeight(minimum); -} - -int OutputPanePlaceHolder::nonMaximizedSize() const -{ - if (!d->m_initialized) - return Internal::OutputPaneManager::outputPaneHeightSetting(); - return d->m_nonMaximizedSize; -} - -Id OutputPanePlaceHolder::mode() const -{ - return d->m_mode; -} - -void OutputPanePlaceHolder::resizeEvent(QResizeEvent *event) -{ - if (d->m_isMaximized || event->size().height() == 0) - return; - d->m_nonMaximizedSize = event->size().height(); -} - -void OutputPanePlaceHolder::showEvent(QShowEvent *) -{ - if (!d->m_initialized) { - d->m_initialized = true; - setHeight(Internal::OutputPaneManager::outputPaneHeightSetting()); - } - if (OutputPanePlaceHolderPrivate::m_current == this) { - Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); - om->updateStatusButtons(true); - } -} - -OutputPanePlaceHolder *OutputPanePlaceHolder::getCurrent() -{ - return OutputPanePlaceHolderPrivate::m_current; -} - -bool OutputPanePlaceHolder::isCurrentVisible() -{ - return OutputPanePlaceHolderPrivate::m_current && OutputPanePlaceHolderPrivate::m_current->isVisible(); -} - -bool OutputPanePlaceHolder::modeHasOutputPanePlaceholder(Utils::Id mode) -{ - return Utils::anyOf(*sPlaceholders, Utils::equal(&OutputPanePlaceHolder::mode, mode)); -} - -} // namespace Core - - diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 23bb37d98ff..ec30f0701a0 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,205 @@ using namespace Utils; using namespace Core::Internal; namespace Core { -namespace Internal { + +Q_GLOBAL_STATIC(QList, sPlaceholders) + +class OutputPanePlaceHolderPrivate { +public: + explicit OutputPanePlaceHolderPrivate(Id mode, QSplitter *parent); + + Id m_mode; + QSplitter *m_splitter; + int m_nonMaximizedSize = 0; + bool m_isMaximized = false; + bool m_initialized = false; + static OutputPanePlaceHolder* m_current; +}; + +OutputPanePlaceHolderPrivate::OutputPanePlaceHolderPrivate(Id mode, QSplitter *parent) : + m_mode(mode), m_splitter(parent) +{ +} + +OutputPanePlaceHolder *OutputPanePlaceHolderPrivate::m_current = nullptr; + + +OutputPanePlaceHolder::OutputPanePlaceHolder(Id mode, QSplitter *parent) + : QWidget(parent), d(new OutputPanePlaceHolderPrivate(mode, parent)) +{ + sPlaceholders->append(this); + setVisible(false); + setLayout(new QVBoxLayout); + QSizePolicy sp; + sp.setHorizontalPolicy(QSizePolicy::Preferred); + sp.setVerticalPolicy(QSizePolicy::Preferred); + sp.setHorizontalStretch(0); + setSizePolicy(sp); + layout()->setContentsMargins(0, 0, 0, 0); + connect(ModeManager::instance(), &ModeManager::currentModeChanged, + this, &OutputPanePlaceHolder::currentModeChanged); + // if this is part of a lazily created mode widget, + // we need to check if this is the current placeholder + currentModeChanged(ModeManager::currentModeId()); +} + +OutputPanePlaceHolder::~OutputPanePlaceHolder() +{ + if (OutputPanePlaceHolderPrivate::m_current == this) { + if (Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance()) { + om->setParent(nullptr); + om->hide(); + } + OutputPanePlaceHolderPrivate::m_current = nullptr; + } + delete d; +} + +void OutputPanePlaceHolder::currentModeChanged(Id mode) +{ + if (OutputPanePlaceHolderPrivate::m_current == this) { + OutputPanePlaceHolderPrivate::m_current = nullptr; + if (d->m_initialized) + Internal::OutputPaneManager::setOutputPaneHeightSetting(d->m_nonMaximizedSize); + Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); + om->hide(); + om->setParent(nullptr); + om->updateStatusButtons(false); + } + if (d->m_mode == mode) { + if (OutputPanePlaceHolderPrivate::m_current && OutputPanePlaceHolderPrivate::m_current->d->m_initialized) + Internal::OutputPaneManager::setOutputPaneHeightSetting(OutputPanePlaceHolderPrivate::m_current->d->m_nonMaximizedSize); + Core::OutputPanePlaceHolderPrivate::m_current = this; + Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); + layout()->addWidget(om); + om->show(); + om->updateStatusButtons(isVisible()); + Internal::OutputPaneManager::updateMaximizeButton(d->m_isMaximized); + } +} + +void OutputPanePlaceHolder::setMaximized(bool maximize) +{ + if (d->m_isMaximized == maximize) + return; + if (!d->m_splitter) + return; + int idx = d->m_splitter->indexOf(this); + if (idx < 0) + return; + + d->m_isMaximized = maximize; + if (OutputPanePlaceHolderPrivate::m_current == this) + Internal::OutputPaneManager::updateMaximizeButton(d->m_isMaximized); + QList sizes = d->m_splitter->sizes(); + + if (maximize) { + d->m_nonMaximizedSize = sizes[idx]; + int sum = 0; + for (const int s : std::as_const(sizes)) + sum += s; + for (int i = 0; i < sizes.count(); ++i) { + sizes[i] = 32; + } + sizes[idx] = sum - (sizes.count()-1) * 32; + } else { + int target = d->m_nonMaximizedSize > 0 ? d->m_nonMaximizedSize : sizeHint().height(); + int space = sizes[idx] - target; + if (space > 0) { + for (int i = 0; i < sizes.count(); ++i) { + sizes[i] += space / (sizes.count()-1); + } + sizes[idx] = target; + } + } + + d->m_splitter->setSizes(sizes); +} + +bool OutputPanePlaceHolder::isMaximized() const +{ + return d->m_isMaximized; +} + +void OutputPanePlaceHolder::setHeight(int height) +{ + if (height == 0) + return; + if (!d->m_splitter) + return; + const int idx = d->m_splitter->indexOf(this); + if (idx < 0) + return; + + d->m_splitter->refresh(); + QList sizes = d->m_splitter->sizes(); + const int difference = height - sizes.at(idx); + if (difference == 0) + return; + const int adaption = difference / (sizes.count()-1); + for (int i = 0; i < sizes.count(); ++i) { + sizes[i] -= adaption; + } + sizes[idx] = height; + d->m_splitter->setSizes(sizes); +} + +void OutputPanePlaceHolder::ensureSizeHintAsMinimum() +{ + if (!d->m_splitter) + return; + Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); + int minimum = (d->m_splitter->orientation() == Qt::Vertical + ? om->sizeHint().height() : om->sizeHint().width()); + if (nonMaximizedSize() < minimum && !d->m_isMaximized) + setHeight(minimum); +} + +int OutputPanePlaceHolder::nonMaximizedSize() const +{ + if (!d->m_initialized) + return Internal::OutputPaneManager::outputPaneHeightSetting(); + return d->m_nonMaximizedSize; +} + +Id OutputPanePlaceHolder::mode() const +{ + return d->m_mode; +} + +void OutputPanePlaceHolder::resizeEvent(QResizeEvent *event) +{ + if (d->m_isMaximized || event->size().height() == 0) + return; + d->m_nonMaximizedSize = event->size().height(); +} + +void OutputPanePlaceHolder::showEvent(QShowEvent *) +{ + if (!d->m_initialized) { + d->m_initialized = true; + setHeight(Internal::OutputPaneManager::outputPaneHeightSetting()); + } + if (OutputPanePlaceHolderPrivate::m_current == this) { + Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); + om->updateStatusButtons(true); + } +} + +OutputPanePlaceHolder *OutputPanePlaceHolder::getCurrent() +{ + return OutputPanePlaceHolderPrivate::m_current; +} + +bool OutputPanePlaceHolder::isCurrentVisible() +{ + return OutputPanePlaceHolderPrivate::m_current && OutputPanePlaceHolderPrivate::m_current->isVisible(); +} + +bool OutputPanePlaceHolder::modeHasOutputPanePlaceholder(Utils::Id mode) +{ + return Utils::anyOf(*sPlaceholders, Utils::equal(&OutputPanePlaceHolder::mode, mode)); +} class OutputPaneData { @@ -61,8 +260,6 @@ public: static QVector g_outputPanes; static bool g_managerConstructed = false; // For debugging reasons. -} // Internal - // OutputPane IOutputPane::IOutputPane(QObject *parent) From b62bd26bd969e8c357ff97f43b3b11375e4c024c Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 18 Nov 2024 13:59:05 +0100 Subject: [PATCH 174/989] Bump version to 16.0.0-beta1 Change-Id: I8732f51ed886160fc8bafb20416753b7f552180c Reviewed-by: Eike Ziller --- cmake/QtCreatorIDEBranding.cmake | 6 +++--- qbs/modules/qtc/qtc.qbs | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index 616559f60c5..d4a65cc6061 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,6 +1,6 @@ -set(IDE_VERSION "14.0.84") # The IDE version. -set(IDE_VERSION_COMPAT "14.0.84") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "15.0.0-rc1") # The IDE display version. +set(IDE_VERSION "15.0.82") # The IDE version. +set(IDE_VERSION_COMPAT "15.0.82") # The IDE Compatibility version. +set(IDE_VERSION_DISPLAY "16.0.0-beta1") # The IDE display version. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. set(IDE_DISPLAY_NAME "Qt Creator") # The IDE display name. diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 95ee4e504be..eb40ad30e2a 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -4,16 +4,16 @@ import qbs.FileInfo import qbs.Utilities Module { - property string qtcreator_display_version: '15.0.0-rc1' - property string ide_version_major: '14' + property string qtcreator_display_version: '16.0.0-beta1' + property string ide_version_major: '15' property string ide_version_minor: '0' - property string ide_version_release: '84' + property string ide_version_release: '82' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release - property string ide_compat_version_major: '14' + property string ide_compat_version_major: '15' property string ide_compat_version_minor: '0' - property string ide_compat_version_release: '84' + property string ide_compat_version_release: '82' property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release From 10685ae91155011116db5bc3a04efaa848fa3928 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 18 Nov 2024 13:46:27 +0100 Subject: [PATCH 175/989] Debugger: Move StartApplicationDialog implementation to .cpp Change-Id: I70422f55f0189da0ee5a369b31688a87bd4b595e Reviewed-by: Jarek Kobus --- src/plugins/debugger/debuggerdialogs.cpp | 324 +++++++++++------------ src/plugins/debugger/debuggerdialogs.h | 23 +- src/plugins/debugger/debuggerplugin.cpp | 4 +- 3 files changed, 166 insertions(+), 185 deletions(-) diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 3409109d157..3ced7bd8d3b 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -44,38 +44,6 @@ using namespace Utils; namespace Debugger::Internal { -/////////////////////////////////////////////////////////////////////// -// -// StartApplicationDialogPrivate -// -/////////////////////////////////////////////////////////////////////// - -class StartApplicationDialogPrivate -{ -public: - KitChooser *kitChooser; - QLabel *serverPortLabel; - QLabel *channelOverrideHintLabel; - QLabel *channelOverrideLabel; - QLineEdit *channelOverrideEdit; - QSpinBox *serverPortSpinBox; - PathChooser *localExecutablePathChooser; - FancyLineEdit *arguments; - PathChooser *workingDirectory; - QCheckBox *breakAtMainCheckBox; - QCheckBox *runInTerminalCheckBox; - QCheckBox *useTargetExtendedRemoteCheckBox; - PathChooser *debuginfoPathChooser; - QLabel *sysRootLabel; - PathChooser *sysRootPathChooser; - QLabel *serverInitCommandsLabel; - QPlainTextEdit *serverInitCommandsTextEdit; - QLabel *serverResetCommandsLabel; - QPlainTextEdit *serverResetCommandsTextEdit; - QComboBox *historyComboBox; - QDialogButtonBox *buttonBox; -}; - /////////////////////////////////////////////////////////////////////// // // StartApplicationParameters @@ -181,166 +149,198 @@ void StartApplicationParameters::fromSettings(const QtcSettings *settings) // /////////////////////////////////////////////////////////////////////// -StartApplicationDialog::StartApplicationDialog(QWidget *parent) - : QDialog(parent), d(new StartApplicationDialogPrivate) +class StartApplicationDialog final : public QDialog +{ +public: + StartApplicationDialog(); + + static void run(bool); + +private: + void historyIndexChanged(int); + void updateState(); + StartApplicationParameters parameters() const; + void setParameters(const StartApplicationParameters &p); + void setHistory(const QList &l); + void onChannelOverrideChanged(const QString &channel); + + KitChooser *kitChooser; + QLabel *serverPortLabel; + QLabel *channelOverrideHintLabel; + QLabel *channelOverrideLabel; + QLineEdit *channelOverrideEdit; + QSpinBox *serverPortSpinBox; + PathChooser *localExecutablePathChooser; + FancyLineEdit *arguments; + PathChooser *workingDirectory; + QCheckBox *breakAtMainCheckBox; + QCheckBox *runInTerminalCheckBox; + QCheckBox *useTargetExtendedRemoteCheckBox; + PathChooser *debuginfoPathChooser; + QLabel *sysRootLabel; + PathChooser *sysRootPathChooser; + QLabel *serverInitCommandsLabel; + QPlainTextEdit *serverInitCommandsTextEdit; + QLabel *serverResetCommandsLabel; + QPlainTextEdit *serverResetCommandsTextEdit; + QComboBox *historyComboBox; + QDialogButtonBox *buttonBox; +}; + +StartApplicationDialog::StartApplicationDialog() + : QDialog(ICore::dialogParent()) { setWindowTitle(Tr::tr("Start Debugger")); - d->kitChooser = new KitChooser(this); - d->kitChooser->setShowIcons(true); - d->kitChooser->populate(); + kitChooser = new KitChooser(this); + kitChooser->setShowIcons(true); + kitChooser->populate(); - d->serverPortLabel = new QLabel(Tr::tr("Server port:"), this); - d->serverPortSpinBox = new QSpinBox(this); - d->serverPortSpinBox->setRange(1, 65535); + serverPortLabel = new QLabel(Tr::tr("Server port:"), this); + serverPortSpinBox = new QSpinBox(this); + serverPortSpinBox->setRange(1, 65535); - d->channelOverrideHintLabel = + channelOverrideHintLabel = new QLabel(Tr::tr("Normally, the running server is identified by the IP of the " "device in the kit and the server port selected above.\n" "You can choose another communication channel here, such as " "a serial line or custom ip:port.")); - d->channelOverrideLabel = new QLabel(Tr::tr("Override server channel:"), this); - d->channelOverrideEdit = new QLineEdit(this); + channelOverrideLabel = new QLabel(Tr::tr("Override server channel:"), this); + channelOverrideEdit = new QLineEdit(this); //: "For example, /dev/ttyS0, COM1, 127.0.0.1:1234" - d->channelOverrideEdit->setPlaceholderText( + channelOverrideEdit->setPlaceholderText( Tr::tr("For example, %1").arg("/dev/ttyS0, COM1, 127.0.0.1:1234")); - d->localExecutablePathChooser = new PathChooser(this); - d->localExecutablePathChooser->setExpectedKind(PathChooser::File); - d->localExecutablePathChooser->setPromptDialogTitle(Tr::tr("Select Executable")); - d->localExecutablePathChooser->setHistoryCompleter("LocalExecutable"); + localExecutablePathChooser = new PathChooser(this); + localExecutablePathChooser->setExpectedKind(PathChooser::File); + localExecutablePathChooser->setPromptDialogTitle(Tr::tr("Select Executable")); + localExecutablePathChooser->setHistoryCompleter("LocalExecutable"); - d->arguments = new FancyLineEdit(this); - d->arguments->setClearButtonEnabled(true); - d->arguments->setHistoryCompleter("CommandlineArguments"); + arguments = new FancyLineEdit(this); + arguments->setClearButtonEnabled(true); + arguments->setHistoryCompleter("CommandlineArguments"); - d->workingDirectory = new PathChooser(this); - d->workingDirectory->setExpectedKind(PathChooser::ExistingDirectory); - d->workingDirectory->setPromptDialogTitle(Tr::tr("Select Working Directory")); - d->workingDirectory->setHistoryCompleter("WorkingDirectory"); + workingDirectory = new PathChooser(this); + workingDirectory->setExpectedKind(PathChooser::ExistingDirectory); + workingDirectory->setPromptDialogTitle(Tr::tr("Select Working Directory")); + workingDirectory->setHistoryCompleter("WorkingDirectory"); - d->runInTerminalCheckBox = new QCheckBox(this); + runInTerminalCheckBox = new QCheckBox(this); - d->breakAtMainCheckBox = new QCheckBox(this); - d->breakAtMainCheckBox->setText(QString()); + breakAtMainCheckBox = new QCheckBox(this); + breakAtMainCheckBox->setText(QString()); - d->useTargetExtendedRemoteCheckBox = new QCheckBox(this); + useTargetExtendedRemoteCheckBox = new QCheckBox(this); - d->sysRootPathChooser = new PathChooser(this); - d->sysRootPathChooser->setExpectedKind(PathChooser::Directory); - d->sysRootPathChooser->setHistoryCompleter("Debugger.SysRoot.History"); - d->sysRootPathChooser->setPromptDialogTitle(Tr::tr("Select SysRoot Directory")); - d->sysRootPathChooser->setToolTip(Tr::tr( + sysRootPathChooser = new PathChooser(this); + sysRootPathChooser->setExpectedKind(PathChooser::Directory); + sysRootPathChooser->setHistoryCompleter("Debugger.SysRoot.History"); + sysRootPathChooser->setPromptDialogTitle(Tr::tr("Select SysRoot Directory")); + sysRootPathChooser->setToolTip(Tr::tr( "This option can be used to override the kit's SysRoot setting.")); - d->sysRootLabel = new QLabel(Tr::tr("Override S&ysRoot:"), this); - d->sysRootLabel->setBuddy(d->sysRootPathChooser); - d->sysRootLabel->setToolTip(d->sysRootPathChooser->toolTip()); + sysRootLabel = new QLabel(Tr::tr("Override S&ysRoot:"), this); + sysRootLabel->setBuddy(sysRootPathChooser); + sysRootLabel->setToolTip(sysRootPathChooser->toolTip()); - d->serverInitCommandsTextEdit = new QPlainTextEdit(this); - d->serverInitCommandsTextEdit->setToolTip(Tr::tr( + serverInitCommandsTextEdit = new QPlainTextEdit(this); + serverInitCommandsTextEdit->setToolTip(Tr::tr( "This option can be used to send the target init commands.")); - d->serverInitCommandsLabel = new QLabel(Tr::tr("&Init commands:"), this); - d->serverInitCommandsLabel->setBuddy(d->serverInitCommandsTextEdit); - d->serverInitCommandsLabel->setToolTip(d->serverInitCommandsTextEdit->toolTip()); + serverInitCommandsLabel = new QLabel(Tr::tr("&Init commands:"), this); + serverInitCommandsLabel->setBuddy(serverInitCommandsTextEdit); + serverInitCommandsLabel->setToolTip(serverInitCommandsTextEdit->toolTip()); - d->serverResetCommandsTextEdit = new QPlainTextEdit(this); - d->serverResetCommandsTextEdit->setToolTip(Tr::tr( + serverResetCommandsTextEdit = new QPlainTextEdit(this); + serverResetCommandsTextEdit->setToolTip(Tr::tr( "This option can be used to send the target reset commands.")); - d->serverResetCommandsLabel = new QLabel(Tr::tr("&Reset commands:"), this); - d->serverResetCommandsLabel->setBuddy(d->serverResetCommandsTextEdit); - d->serverResetCommandsLabel->setToolTip(d->serverResetCommandsTextEdit->toolTip()); + serverResetCommandsLabel = new QLabel(Tr::tr("&Reset commands:"), this); + serverResetCommandsLabel->setBuddy(serverResetCommandsTextEdit); + serverResetCommandsLabel->setToolTip(serverResetCommandsTextEdit->toolTip()); - d->debuginfoPathChooser = new PathChooser(this); - d->debuginfoPathChooser->setPromptDialogTitle(Tr::tr("Select Location of Debugging Information")); - d->debuginfoPathChooser->setToolTip(Tr::tr( + debuginfoPathChooser = new PathChooser(this); + debuginfoPathChooser->setPromptDialogTitle(Tr::tr("Select Location of Debugging Information")); + debuginfoPathChooser->setToolTip(Tr::tr( "Base path for external debug information and debug sources. " "If empty, $SYSROOT/usr/lib/debug will be chosen.")); - d->debuginfoPathChooser->setHistoryCompleter("Debugger.DebugLocation.History"); + debuginfoPathChooser->setHistoryCompleter("Debugger.DebugLocation.History"); - d->historyComboBox = new QComboBox(this); + historyComboBox = new QComboBox(this); - d->buttonBox = new QDialogButtonBox(this); - d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - d->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); + buttonBox = new QDialogButtonBox(this); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); auto formLayout = new QFormLayout(); formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); - formLayout->addRow(Tr::tr("&Kit:"), d->kitChooser); - formLayout->addRow(d->serverPortLabel, d->serverPortSpinBox); - formLayout->addRow(Tr::tr("Local &executable:"), d->localExecutablePathChooser); - formLayout->addRow(Tr::tr("Command line &arguments:"), d->arguments); - formLayout->addRow(Tr::tr("&Working directory:"), d->workingDirectory); - formLayout->addRow(Tr::tr("Run in &terminal:"), d->runInTerminalCheckBox); - formLayout->addRow(Tr::tr("Break at \"&main\":"), d->breakAtMainCheckBox); - formLayout->addRow(Tr::tr("Use target extended-remote to connect:"), d->useTargetExtendedRemoteCheckBox); - formLayout->addRow(d->sysRootLabel, d->sysRootPathChooser); - formLayout->addRow(d->serverInitCommandsLabel, d->serverInitCommandsTextEdit); - formLayout->addRow(d->serverResetCommandsLabel, d->serverResetCommandsTextEdit); - formLayout->addRow(Tr::tr("Debug &information:"), d->debuginfoPathChooser); - formLayout->addRow(d->channelOverrideHintLabel); - formLayout->addRow(d->channelOverrideLabel, d->channelOverrideEdit); + formLayout->addRow(Tr::tr("&Kit:"), kitChooser); + formLayout->addRow(serverPortLabel, serverPortSpinBox); + formLayout->addRow(Tr::tr("Local &executable:"), localExecutablePathChooser); + formLayout->addRow(Tr::tr("Command line &arguments:"), arguments); + formLayout->addRow(Tr::tr("&Working directory:"), workingDirectory); + formLayout->addRow(Tr::tr("Run in &terminal:"), runInTerminalCheckBox); + formLayout->addRow(Tr::tr("Break at \"&main\":"), breakAtMainCheckBox); + formLayout->addRow(Tr::tr("Use target extended-remote to connect:"), useTargetExtendedRemoteCheckBox); + formLayout->addRow(sysRootLabel, sysRootPathChooser); + formLayout->addRow(serverInitCommandsLabel, serverInitCommandsTextEdit); + formLayout->addRow(serverResetCommandsLabel, serverResetCommandsTextEdit); + formLayout->addRow(Tr::tr("Debug &information:"), debuginfoPathChooser); + formLayout->addRow(channelOverrideHintLabel); + formLayout->addRow(channelOverrideLabel, channelOverrideEdit); formLayout->addRow(Layouting::createHr()); - formLayout->addRow(Tr::tr("&Recent:"), d->historyComboBox); + formLayout->addRow(Tr::tr("&Recent:"), historyComboBox); auto verticalLayout = new QVBoxLayout(this); verticalLayout->addLayout(formLayout); verticalLayout->addStretch(); verticalLayout->addWidget(Layouting::createHr()); - verticalLayout->addWidget(d->buttonBox); + verticalLayout->addWidget(buttonBox); - connect(d->localExecutablePathChooser, - &PathChooser::validChanged, - this, - &StartApplicationDialog::updateState); + connect(localExecutablePathChooser, &PathChooser::validChanged, + this, &StartApplicationDialog::updateState); - connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(d->historyComboBox, &QComboBox::currentIndexChanged, + connect(historyComboBox, &QComboBox::currentIndexChanged, this, &StartApplicationDialog::historyIndexChanged); - connect(d->channelOverrideEdit, &QLineEdit::textChanged, + connect(channelOverrideEdit, &QLineEdit::textChanged, this, &StartApplicationDialog::onChannelOverrideChanged); updateState(); -} -StartApplicationDialog::~StartApplicationDialog() -{ - delete d; + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } void StartApplicationDialog::setHistory(const QList &l) { - d->historyComboBox->clear(); + historyComboBox->clear(); for (int i = l.size(); --i >= 0; ) { const StartApplicationParameters &p = l.at(i); if (!p.runnable.command.isEmpty()) - d->historyComboBox->addItem(p.displayName(), QVariant::fromValue(p)); + historyComboBox->addItem(p.displayName(), QVariant::fromValue(p)); } } void StartApplicationDialog::onChannelOverrideChanged(const QString &channel) { - d->serverPortSpinBox->setEnabled(channel.isEmpty()); - d->serverPortLabel->setEnabled(channel.isEmpty()); + serverPortSpinBox->setEnabled(channel.isEmpty()); + serverPortLabel->setEnabled(channel.isEmpty()); } void StartApplicationDialog::historyIndexChanged(int index) { if (index < 0) return; - const QVariant v = d->historyComboBox->itemData(index); + const QVariant v = historyComboBox->itemData(index); QTC_ASSERT(v.canConvert(), return); setParameters(v.value()); } void StartApplicationDialog::updateState() { - bool okEnabled = d->localExecutablePathChooser->isValid(); - d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(okEnabled); + bool okEnabled = localExecutablePathChooser->isValid(); + buttonBox->button(QDialogButtonBox::Ok)->setEnabled(okEnabled); } void StartApplicationDialog::run(bool attachRemote) @@ -364,24 +364,24 @@ void StartApplicationDialog::run(bool attachRemote) settings->endArray(); settings->endGroup(); - StartApplicationDialog dialog(ICore::dialogParent()); + StartApplicationDialog dialog; dialog.setHistory(history); dialog.setParameters(history.back()); if (!attachRemote) { - dialog.d->serverInitCommandsTextEdit->setVisible(false); - dialog.d->serverInitCommandsLabel->setVisible(false); - dialog.d->serverResetCommandsTextEdit->setVisible(false); - dialog.d->serverResetCommandsLabel->setVisible(false); - dialog.d->serverPortSpinBox->setVisible(false); - dialog.d->serverPortLabel->setVisible(false); - dialog.d->channelOverrideHintLabel->setVisible(false); - dialog.d->channelOverrideLabel->setVisible(false); - dialog.d->channelOverrideEdit->setVisible(false); + dialog.serverInitCommandsTextEdit->setVisible(false); + dialog.serverInitCommandsLabel->setVisible(false); + dialog.serverResetCommandsTextEdit->setVisible(false); + dialog.serverResetCommandsLabel->setVisible(false); + dialog.serverPortSpinBox->setVisible(false); + dialog.serverPortLabel->setVisible(false); + dialog.channelOverrideHintLabel->setVisible(false); + dialog.channelOverrideLabel->setVisible(false); + dialog.channelOverrideEdit->setVisible(false); } if (dialog.exec() != QDialog::Accepted) return; - Kit *k = dialog.d->kitChooser->currentKit(); + Kit *k = dialog.kitChooser->currentKit(); auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); runControl->setKit(k); @@ -409,7 +409,7 @@ void StartApplicationDialog::run(bool attachRemote) return; } ProcessRunData inferior = newParameters.runnable; - const QString inputAddress = dialog.d->channelOverrideEdit->text(); + const QString inputAddress = dialog.channelOverrideEdit->text(); if (!inputAddress.isEmpty()) debugger->setRemoteChannel(inputAddress); else @@ -441,50 +441,50 @@ void StartApplicationDialog::run(bool attachRemote) debugger->startRunControl(); } -void StartApplicationDialog::attachToRemoteServer() +void runAttachToRemoteServerDialog() { - run(true); + StartApplicationDialog::run(true); } -void StartApplicationDialog::startAndDebugApplication() +void runStartAndDebugApplicationDialog() { - run(false); + StartApplicationDialog::run(false); } StartApplicationParameters StartApplicationDialog::parameters() const { StartApplicationParameters result; - result.serverPort = d->serverPortSpinBox->value(); - result.serverAddress = d->channelOverrideEdit->text(); - result.runnable.command.setExecutable(d->localExecutablePathChooser->filePath()); - result.sysRoot = d->sysRootPathChooser->filePath(); - result.serverInitCommands = d->serverInitCommandsTextEdit->toPlainText(); - result.serverResetCommands = d->serverResetCommandsTextEdit->toPlainText(); - result.kitId = d->kitChooser->currentKitId(); - result.debugInfoLocation = d->debuginfoPathChooser->filePath(); - result.runnable.command.setArguments(d->arguments->text()); - result.runnable.workingDirectory = d->workingDirectory->filePath(); - result.breakAtMain = d->breakAtMainCheckBox->isChecked(); - result.runInTerminal = d->runInTerminalCheckBox->isChecked(); - result.useTargetExtendedRemote = d->useTargetExtendedRemoteCheckBox->isChecked(); + result.serverPort = serverPortSpinBox->value(); + result.serverAddress = channelOverrideEdit->text(); + result.runnable.command.setExecutable(localExecutablePathChooser->filePath()); + result.sysRoot = sysRootPathChooser->filePath(); + result.serverInitCommands = serverInitCommandsTextEdit->toPlainText(); + result.serverResetCommands = serverResetCommandsTextEdit->toPlainText(); + result.kitId = kitChooser->currentKitId(); + result.debugInfoLocation = debuginfoPathChooser->filePath(); + result.runnable.command.setArguments(arguments->text()); + result.runnable.workingDirectory = workingDirectory->filePath(); + result.breakAtMain = breakAtMainCheckBox->isChecked(); + result.runInTerminal = runInTerminalCheckBox->isChecked(); + result.useTargetExtendedRemote = useTargetExtendedRemoteCheckBox->isChecked(); return result; } void StartApplicationDialog::setParameters(const StartApplicationParameters &p) { - d->kitChooser->setCurrentKitId(p.kitId); - d->serverPortSpinBox->setValue(p.serverPort); - d->channelOverrideEdit->setText(p.serverAddress); - d->localExecutablePathChooser->setFilePath(p.runnable.command.executable()); - d->sysRootPathChooser->setFilePath(p.sysRoot); - d->serverInitCommandsTextEdit->setPlainText(p.serverInitCommands); - d->serverResetCommandsTextEdit->setPlainText(p.serverResetCommands); - d->debuginfoPathChooser->setFilePath(p.debugInfoLocation); - d->arguments->setText(p.runnable.command.arguments()); - d->workingDirectory->setFilePath(p.runnable.workingDirectory); - d->breakAtMainCheckBox->setChecked(p.breakAtMain); - d->runInTerminalCheckBox->setChecked(p.runInTerminal); - d->useTargetExtendedRemoteCheckBox->setChecked(p.useTargetExtendedRemote); + kitChooser->setCurrentKitId(p.kitId); + serverPortSpinBox->setValue(p.serverPort); + channelOverrideEdit->setText(p.serverAddress); + localExecutablePathChooser->setFilePath(p.runnable.command.executable()); + sysRootPathChooser->setFilePath(p.sysRoot); + serverInitCommandsTextEdit->setPlainText(p.serverInitCommands); + serverResetCommandsTextEdit->setPlainText(p.serverResetCommands); + debuginfoPathChooser->setFilePath(p.debugInfoLocation); + arguments->setText(p.runnable.command.arguments()); + workingDirectory->setFilePath(p.runnable.workingDirectory); + breakAtMainCheckBox->setChecked(p.breakAtMain); + runInTerminalCheckBox->setChecked(p.runInTerminal); + useTargetExtendedRemoteCheckBox->setChecked(p.useTargetExtendedRemote); updateState(); } diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h index f1fa045da86..7d01d3c836b 100644 --- a/src/plugins/debugger/debuggerdialogs.h +++ b/src/plugins/debugger/debuggerdialogs.h @@ -21,29 +21,10 @@ namespace Debugger::Internal { class AttachToQmlPortDialogPrivate; class DebuggerRunParameters; class StartApplicationParameters; -class StartApplicationDialogPrivate; class StartRemoteEngineDialogPrivate; -class StartApplicationDialog : public QDialog -{ -public: - explicit StartApplicationDialog(QWidget *parent); - ~StartApplicationDialog() override; - - static void attachToRemoteServer(); - static void startAndDebugApplication(); - -private: - void historyIndexChanged(int); - void updateState(); - StartApplicationParameters parameters() const; - void setParameters(const StartApplicationParameters &p); - void setHistory(const QList &l); - void onChannelOverrideChanged(const QString &channel); - static void run(bool); - - StartApplicationDialogPrivate *d; -}; +void runAttachToRemoteServerDialog(); +void runStartAndDebugApplicationDialog(); class AttachToQmlPortDialog : public QDialog { diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 03f3cb3f096..8d0d4320ff7 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -872,7 +872,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) }); connect(&m_startAndDebugApplicationAction, &QAction::triggered, - this, &StartApplicationDialog::startAndDebugApplication); + this, [] { runStartAndDebugApplicationDialog(); }); connect(&m_attachToCoreAction, &QAction::triggered, this, &DebuggerPluginPrivate::attachCore); @@ -881,7 +881,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) this, &DebuggerPluginPrivate::attachToLastCore); connect(&m_attachToRemoteServerAction, &QAction::triggered, - this, &StartApplicationDialog::attachToRemoteServer); + this, [] { runAttachToRemoteServerDialog(); }); connect(&m_attachToRunningApplication, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRunningApplication); From 9dac95882f21afb77f4019fb1a7ec54e66a880bd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 18 Nov 2024 13:47:39 +0100 Subject: [PATCH 176/989] QmlProfiler: Remove unused method Task-number: QTCREATORBUG-29168 Change-Id: I4ab8b33fefcfd55cf4e56118311e9cac0d274862 Reviewed-by: Ulf Hermann --- .../qmlprofiler/qmlprofilerruncontrol.cpp | 18 ------------------ .../qmlprofiler/qmlprofilerruncontrol.h | 2 -- 2 files changed, 20 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index 9d17fb49797..2f7bfb488ff 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -96,24 +96,6 @@ void QmlProfilerRunner::stop() } } -void QmlProfilerRunner::notifyRemoteFinished() -{ - QTC_ASSERT(d->m_profilerState, return); - - switch (d->m_profilerState->currentState()) { - case QmlProfilerStateManager::AppRunning: - d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppDying); - break; - case QmlProfilerStateManager::Idle: - break; - default: - const QString message = QString::fromLatin1("Process died unexpectedly from state %1 in %2:%3") - .arg(d->m_profilerState->currentStateAsString(), QString::fromLatin1(__FILE__), QString::number(__LINE__)); - qWarning("%s", qPrintable(message)); - break; - } -} - void QmlProfilerRunner::cancelProcess() { QTC_ASSERT(d->m_profilerState, return); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h index 8864885ee2f..424d8e1afc4 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h @@ -25,9 +25,7 @@ public: ~QmlProfilerRunner() override; void registerProfilerStateManager( QmlProfilerStateManager *profilerState ); - void cancelProcess(); - void notifyRemoteFinished(); private: void start() override; From 5c35645eba059cf739437220accf3c035461b931 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 18 Nov 2024 14:00:10 +0100 Subject: [PATCH 177/989] QmlPreview: Hide serverUrl() in private section Task-number: QTCREATORBUG-29168 Change-Id: Ia99ac83666654ae8ca997e642ed17ac2034584dd Reviewed-by: hjk --- src/plugins/qmlpreview/qmlpreviewruncontrol.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp index d0baa3173ee..a82ad47e777 100644 --- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp +++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp @@ -70,7 +70,6 @@ public: const QmlPreviewRunnerSetting &settings); void setServerUrl(const QUrl &serverUrl); - QUrl serverUrl() const; signals: void loadFile(const QString &previewedFile, const QString &changedFile, @@ -79,9 +78,11 @@ signals: void zoom(float zoomFactor); void rerun(); void ready(); + private: void start() override; void stop() override; + QUrl serverUrl() const; QmlPreviewConnectionManager m_connectionManager; }; From bf111451cd6bdf344d98e64adf7c38a32e46c278 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 1 Nov 2024 14:16:05 +0100 Subject: [PATCH 178/989] QtSupport: collect all documentationFiles in parallel Change-Id: Ica6e2021f2bd0c2f8a68e370f79ee4438e478b4a Reviewed-by: Jarek Kobus Reviewed-by: hjk --- src/plugins/qtsupport/qtversionmanager.cpp | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index e4f592306fd..987b647d871 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #include @@ -33,6 +33,7 @@ #include #include #include +#include using namespace ProjectExplorer; using namespace Utils; @@ -514,11 +515,10 @@ using DocumentationFile = std::pair; using DocumentationFiles = QList; using AllDocumentationFiles = QHash; -static DocumentationFiles allDocumentationFiles(QtVersion *v) +static DocumentationFiles allDocumentationFiles(const QString &docsPath) { DocumentationFiles files; - const QStringList docPaths = QStringList( - {v->docsPath().toString() + QChar('/'), v->docsPath().toString() + "/qch/"}); + const QStringList docPaths{docsPath + QChar('/'), docsPath + "/qch/"}; for (const QString &docPath : docPaths) { const QDir versionHelpDir(docPath); for (const QString &helpFile : versionHelpDir.entryList(QStringList("q*.qch"), QDir::Files)) @@ -529,10 +529,18 @@ static DocumentationFiles allDocumentationFiles(QtVersion *v) static AllDocumentationFiles allDocumentationFiles(const QtVersions &versions) { - AllDocumentationFiles result; - for (QtVersion *v : versions) - result.insert(v, allDocumentationFiles(v)); - return result; + QList> versionsWithDocPath; + for (QtVersion *v : versions) { + if (v->hasDocs() && !v->docsPath().needsDevice()) + versionsWithDocPath << qMakePair(v, v->docsPath().path()); + } + QFuture> future = QtConcurrent::mapped( + versionsWithDocPath, [](const QPair &versionWithDoc) { + return qMakePair(versionWithDoc.first, allDocumentationFiles(versionWithDoc.second)); + }); + future.waitForFinished(); + return Utils::transform( + future.results(), [](const QPair &r) { return r; }); } static QStringList documentationFiles(const QtVersions &vs, From 4bddce64f5880c8e26d1e9fc2cfe444b1d1358d5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 18 Nov 2024 14:15:50 +0100 Subject: [PATCH 179/989] Qnx: Remove unused commandFound() method Task-number: QTCREATORBUG-29168 Change-Id: Ifad415adfcfa06f6152d39112e576bdc18487a6b Reviewed-by: hjk --- src/plugins/qnx/slog2inforunner.cpp | 12 +----------- src/plugins/qnx/slog2inforunner.h | 5 ----- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index b7ed28ffd21..2c7bf6716c8 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -38,10 +38,6 @@ void Slog2InfoRunner::start() process.setCommand(CommandLine{device()->filePath("slog2info")}); }; const auto onTestDone = [this](DoneWith result) { - if (result == DoneWith::Success) { - m_found = true; - return; - } appendMessage(Tr::tr("Warning: \"slog2info\" is not found on the device, " "debug output not available."), ErrorMessageFormat); }; @@ -51,7 +47,6 @@ void Slog2InfoRunner::start() }; const auto onLaunchTimeDone = [this](const Process &process) { QTC_CHECK(!m_applicationId.isEmpty()); - QTC_CHECK(m_found); m_launchDateTime = QDateTime::fromString(process.cleanedStdOut().trimmed(), "dd HH:mm:ss"); }; @@ -70,7 +65,7 @@ void Slog2InfoRunner::start() }; const Group root { - ProcessTask(onTestSetup, onTestDone), + ProcessTask(onTestSetup, onTestDone, CallDoneIf::Error), ProcessTask(onLaunchTimeSetup, onLaunchTimeDone, CallDoneIf::Success), ProcessTask(onLogSetup, onLogError, CallDoneIf::Error) }; @@ -86,11 +81,6 @@ void Slog2InfoRunner::stop() reportStopped(); } -bool Slog2InfoRunner::commandFound() const -{ - return m_found; -} - void Slog2InfoRunner::processRemainingLogData() { if (!m_remainingData.isEmpty()) diff --git a/src/plugins/qnx/slog2inforunner.h b/src/plugins/qnx/slog2inforunner.h index 663be2ce69e..e77fa661079 100644 --- a/src/plugins/qnx/slog2inforunner.h +++ b/src/plugins/qnx/slog2inforunner.h @@ -19,20 +19,15 @@ public: void start() override; void stop() override; - bool commandFound() const; - private: void processRemainingLogData(); void processLogInput(const QString &input); void processLogLine(const QString &line); QString m_applicationId; - QDateTime m_launchDateTime; - bool m_found = false; bool m_currentLogs = false; QString m_remainingData; - Tasking::TaskTreeRunner m_taskTreeRunner; }; From 96bb9964fb457844bf5d9526fd7a335bd174c65b Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 18 Nov 2024 15:05:07 +0100 Subject: [PATCH 180/989] QtSupport: Visually merge QtKitAspect and QmakeKitAspect Change-Id: I000dba4726e26ddfd4df210d514200e8adacd989 Reviewed-by: hjk --- .../qmakeprojectmanager/qmakekitaspect.cpp | 3 +++ src/plugins/qtsupport/qtkitaspect.cpp | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp b/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp index 156d93be40e..0f4658acc8a 100644 --- a/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp +++ b/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp @@ -35,6 +35,9 @@ public: { refresh(); // set up everything according to kit m_lineEdit->setToolTip(ki->description()); + QSizePolicy p = m_lineEdit->sizePolicy(); + p.setHorizontalStretch(1); + m_lineEdit->setSizePolicy(p); connect(m_lineEdit, &QLineEdit::textEdited, this, &QmakeKitAspectImpl::mkspecWasChanged); } diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index bde243f7ef8..14cfe626324 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -19,6 +19,8 @@ #include #include +#include + #include #include #include @@ -26,6 +28,8 @@ #include #include +#include + using namespace ProjectExplorer; using namespace Utils; @@ -78,6 +82,23 @@ public: refresh(); }); } + +private: + void addToInnerLayout(Layouting::Layout &parentItem) override + { + if (const QList embedded = aspectsToEmbed(); !embedded.isEmpty()) { + Layouting::Layout layout(new QHBoxLayout); + KitAspect::addToInnerLayout(layout); + QSizePolicy p = comboBoxes().first()->sizePolicy(); + p.setHorizontalStretch(2); + comboBoxes().first()->setSizePolicy(p); + layout.addItem(Tr::tr("Mkspec:")); + embedded.first()->addToInnerLayout(layout); + parentItem.addItem(layout); + } else { + KitAspect::addToInnerLayout(parentItem); + } + } }; } // namespace Internal @@ -123,6 +144,7 @@ QtKitAspectFactory::QtKitAspectFactory() "A Qt version is required for qmake-based projects " "and optional when using other build systems.")); setPriority(26000); + setEmbeddableAspects({QmakeProjectManager::Constants::KIT_INFORMATION_ID}); } void QtKitAspectFactory::setup(Kit *k) From abefe66b3e9a8622838121e0cccf622ac0e36a2c Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 18 Nov 2024 14:43:53 +0100 Subject: [PATCH 181/989] QmlPreview: Simplify qmlChannel setup and passing Change-Id: I8cecb89e0d84f4398c988be00b6cf3db22b15552 Reviewed-by: Jarek Kobus --- .../qmlpreview/qmlpreviewruncontrol.cpp | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp index a82ad47e777..9b5001a27c3 100644 --- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp +++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp @@ -30,8 +30,6 @@ using namespace Utils; namespace QmlPreview { -static const Key QmlServerUrl = "QmlServerUrl"; - class RefreshTranslationWorker final : public RunWorker { public: @@ -69,8 +67,6 @@ public: QmlPreviewRunner(ProjectExplorer::RunControl *runControl, const QmlPreviewRunnerSetting &settings); - void setServerUrl(const QUrl &serverUrl); - signals: void loadFile(const QString &previewedFile, const QString &changedFile, const QByteArray &contents); @@ -140,7 +136,7 @@ QmlPreviewRunner::QmlPreviewRunner(RunControl *runControl, const QmlPreviewRunne void QmlPreviewRunner::start() { m_connectionManager.setTarget(runControl()->target()); - m_connectionManager.connectToServer(serverUrl()); + m_connectionManager.connectToServer(runControl()->qmlChannel()); reportStarted(); } @@ -150,16 +146,6 @@ void QmlPreviewRunner::stop() reportStopped(); } -void QmlPreviewRunner::setServerUrl(const QUrl &serverUrl) -{ - recordData(QmlServerUrl, serverUrl); -} - -QUrl QmlPreviewRunner::serverUrl() const -{ - return recordedData(QmlServerUrl).toUrl(); -} - QmlPreviewRunWorkerFactory::QmlPreviewRunWorkerFactory(QmlPreviewPlugin *plugin, const QmlPreviewRunnerSetting *runnerSettings) { @@ -195,16 +181,17 @@ public: : SimpleTargetRunner(runControl) { setId("LocalQmlPreviewSupport"); - const QUrl serverUrl = Utils::urlFromLocalSocket(); - QmlPreviewRunner *preview = qobject_cast( - runControl->createWorker(ProjectExplorer::Constants::QML_PREVIEW_RUNNER)); - preview->setServerUrl(serverUrl); + runControl->setQmlChannel(Utils::urlFromLocalSocket()); + + // Create QmlPreviewRunner + RunWorker *preview = + runControl->createWorker(ProjectExplorer::Constants::QML_PREVIEW_RUNNER); addStopDependency(preview); addStartDependency(preview); - setStartModifier([this, runControl, serverUrl] { + setStartModifier([this, runControl] { CommandLine cmd = commandLine(); if (const auto aspect = runControl->aspectData()) { @@ -226,7 +213,7 @@ public: } } - cmd.addArg(qmlDebugLocalArguments(QmlPreviewServices, serverUrl.path())); + cmd.addArg(qmlDebugLocalArguments(QmlPreviewServices, runControl->qmlChannel().path())); setCommandLine(cmd); forceRunOnHost(); From 42eacb967d8c0229062de40ba71433935b179309 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 18 Nov 2024 16:17:34 +0100 Subject: [PATCH 182/989] ProjectExplorer: Add convenience functions to add parts of a kit aspect No functional change intended. Change-Id: Iaea552dbae60a8f0a6423707276e9c6c1e80cf4f Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/kitaspect.cpp | 32 +++++++++++++++++------ src/plugins/projectexplorer/kitaspect.h | 6 ++++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index b14ef91630f..bcfced094c4 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -187,12 +187,9 @@ void KitAspect::makeReadOnly() la.comboBox->setEnabled(false); } -void KitAspect::addToInnerLayout(Layouting::Layout &parentItem) +void KitAspect::addToInnerLayout(Layouting::Layout &layout) { - for (const Private::ListAspect &la : std::as_const(d->listAspects)) { - addMutableAction(la.comboBox); - parentItem.addItem(la.comboBox); - } + addListAspectsToLayout(layout); } void KitAspect::addListAspectSpec(const ListAspectSpec &listAspectSpec) @@ -228,7 +225,7 @@ QList KitAspect::comboBoxes() const return Utils::transform(d->listAspects, &Private::ListAspect::comboBox); } -void KitAspect::addToLayoutImpl(Layouting::Layout &layout) +void KitAspect::addLabelToLayout(Layouting::Layout &layout) { auto label = createSubWidget(d->factory->displayName() + ':'); label->setToolTip(d->factory->description()); @@ -237,7 +234,18 @@ void KitAspect::addToLayoutImpl(Layouting::Layout &layout) }); layout.addItem(label); - addToInnerLayout(layout); +} + +void KitAspect::addListAspectsToLayout(Layouting::Layout &layout) +{ + for (const Private::ListAspect &la : std::as_const(d->listAspects)) { + addMutableAction(la.comboBox); + layout.addItem(la.comboBox); + } +} + +void KitAspect::addManageButtonToLayout(Layouting::Layout &layout) +{ if (d->managingPageId.isValid()) { d->manageButton = createSubWidget(msgManage()); connect(d->manageButton, &QPushButton::clicked, [this] { @@ -245,7 +253,15 @@ void KitAspect::addToLayoutImpl(Layouting::Layout &layout) }); layout.addItem(d->manageButton); } - layout.addItem(Layouting::br); +} + +void KitAspect::addToLayoutImpl(Layouting::Layout &layout) +{ + addLabelToLayout(layout); + addToInnerLayout(layout); + addManageButtonToLayout(layout); + + layout.flush(); } void KitAspect::addMutableAction(QWidget *child) diff --git a/src/plugins/projectexplorer/kitaspect.h b/src/plugins/projectexplorer/kitaspect.h index 780495a70dc..5cfd7577da1 100644 --- a/src/plugins/projectexplorer/kitaspect.h +++ b/src/plugins/projectexplorer/kitaspect.h @@ -132,12 +132,16 @@ public: // For layouting purposes only. QList comboBoxes() const; - virtual void addToInnerLayout(Layouting::Layout &parentItem); + virtual void addToInnerLayout(Layouting::Layout &layout); protected: virtual void makeReadOnly(); virtual Utils::Id settingsPageItemToPreselect() const { return {}; } + void addLabelToLayout(Layouting::Layout &layout); + void addListAspectsToLayout(Layouting::Layout &layout); + void addManageButtonToLayout(Layouting::Layout &layout); + // Convenience for aspects that provide a list model from which one value can be chosen. // It will be exposed via a QComboBox. class ListAspectSpec From ff38e32443b49a6bcae78235c1164a4ae71ae7ae Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 18 Nov 2024 16:23:36 +0100 Subject: [PATCH 183/989] Standardize parameter name for KitAspect::addToInnerLayout Call it 'layout' Change-Id: I57c4e569d3d6026fe84b0f4f8c384c6164262be9 Reviewed-by: Christian Kandeler --- .../cmakeprojectmanager/cmakekitaspect.cpp | 12 ++++++------ .../mesonprojectmanager/toolkitaspectwidget.cpp | 4 ++-- .../devicesupport/devicekitaspects.cpp | 16 ++++++++-------- src/plugins/projectexplorer/kitaspects.cpp | 10 +++++----- .../projectexplorer/toolchainkitaspect.cpp | 14 +++++++------- src/plugins/qbsprojectmanager/qbskitaspect.cpp | 6 +++--- .../qmakeprojectmanager/qmakekitaspect.cpp | 4 ++-- src/plugins/qtsupport/qtkitaspect.cpp | 14 +++++++------- 8 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp index 637f6a16300..849154940dc 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp @@ -348,11 +348,11 @@ private: // KitAspectWidget interface void makeReadOnly() override { m_changeButton->setEnabled(false); } - void addToInnerLayout(Layouting::Layout &parent) override + void addToInnerLayout(Layouting::Layout &layout) override { addMutableAction(m_label); - parent.addItem(m_label); - parent.addItem(m_changeButton); + layout.addItem(m_label); + layout.addItem(m_changeButton); } void refresh() override @@ -859,11 +859,11 @@ public: private: // KitAspectWidget interface - void addToInnerLayout(Layouting::Layout &parent) override + void addToInnerLayout(Layouting::Layout &layout) override { addMutableAction(m_summaryLabel); - parent.addItem(m_summaryLabel); - parent.addItem(m_manageButton); + layout.addItem(m_summaryLabel); + layout.addItem(m_manageButton); } void makeReadOnly() override diff --git a/src/plugins/mesonprojectmanager/toolkitaspectwidget.cpp b/src/plugins/mesonprojectmanager/toolkitaspectwidget.cpp index 79189470790..21a5f740bbb 100644 --- a/src/plugins/mesonprojectmanager/toolkitaspectwidget.cpp +++ b/src/plugins/mesonprojectmanager/toolkitaspectwidget.cpp @@ -41,10 +41,10 @@ private: void makeReadOnly() final { m_toolsComboBox->setEnabled(false); } - void addToInnerLayout(Layouting::Layout &parent) final + void addToInnerLayout(Layouting::Layout &layout) final { addMutableAction(m_toolsComboBox); - parent.addItem(m_toolsComboBox); + layout.addItem(m_toolsComboBox); } void refresh() final diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index e3c6d03d910..33dde8b3578 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -95,20 +95,20 @@ public: private: Id settingsPageItemToPreselect() const override { return DeviceAspect::deviceId(kit()); } - void addToInnerLayout(Layouting::Layout &parentItem) override + void addToInnerLayout(Layouting::Layout &layout) override { if (const QList embedded = aspectsToEmbed(); !embedded.isEmpty()) { - Layouting::Layout layout(new QHBoxLayout); - layout.addItem(Tr::tr("Type:")); - embedded.first()->addToInnerLayout(layout); - layout.addItem(Tr::tr("Device:")); - KitAspect::addToInnerLayout(layout); + Layouting::Layout box(new QHBoxLayout); + box.addItem(Tr::tr("Type:")); + embedded.first()->addToInnerLayout(box); + box.addItem(Tr::tr("Device:")); + KitAspect::addToInnerLayout(box); QSizePolicy p = comboBoxes().first()->sizePolicy(); p.setHorizontalStretch(1); comboBoxes().first()->setSizePolicy(p); - parentItem.addItem(layout); + layout.addItem(box); } else { - KitAspect::addToInnerLayout(parentItem); + KitAspect::addToInnerLayout(layout); } } }; diff --git a/src/plugins/projectexplorer/kitaspects.cpp b/src/plugins/projectexplorer/kitaspects.cpp index 89505f6c48a..fdbb0d63272 100644 --- a/src/plugins/projectexplorer/kitaspects.cpp +++ b/src/plugins/projectexplorer/kitaspects.cpp @@ -53,10 +53,10 @@ public: private: void makeReadOnly() override { m_chooser->setReadOnly(true); } - void addToInnerLayout(Layouting::Layout &builder) override + void addToInnerLayout(Layouting::Layout &layout) override { addMutableAction(m_chooser); - builder.addItem(Layouting::Span(2, m_chooser)); + layout.addItem(Layouting::Span(2, m_chooser)); } void refresh() override @@ -218,11 +218,11 @@ public: } private: - void addToInnerLayout(Layouting::Layout &builder) override + void addToInnerLayout(Layouting::Layout &layout) override { addMutableAction(m_mainWidget); - builder.addItem(m_mainWidget); - builder.addItem(m_manageButton); + layout.addItem(m_mainWidget); + layout.addItem(m_manageButton); } void makeReadOnly() override { m_manageButton->setEnabled(false); } diff --git a/src/plugins/projectexplorer/toolchainkitaspect.cpp b/src/plugins/projectexplorer/toolchainkitaspect.cpp index 6e0cc7cb53d..cd8db8f27b1 100644 --- a/src/plugins/projectexplorer/toolchainkitaspect.cpp +++ b/src/plugins/projectexplorer/toolchainkitaspect.cpp @@ -107,26 +107,26 @@ public: } private: - void addToInnerLayout(Layouting::Layout &builder) override + void addToInnerLayout(Layouting::Layout &layout) override { const auto mainWidget = createSubWidget(); mainWidget->setContentsMargins(0, 0, 0, 0); - const auto layout = new QGridLayout(mainWidget); - layout->setContentsMargins(0, 0, 0, 0); - layout->setColumnStretch(1, 2); + const auto grid = new QGridLayout(mainWidget); + grid->setContentsMargins(0, 0, 0, 0); + grid->setColumnStretch(1, 2); int row = 0; const QList cbList = comboBoxes(); QTC_ASSERT(cbList.size() == m_sortedLanguageCategories.size(), return); for (const LanguageCategory &lc : std::as_const(m_sortedLanguageCategories)) { - layout->addWidget( + grid->addWidget( new QLabel(ToolchainManager::displayNameOfLanguageCategory(lc) + ':'), row, 0); - layout->addWidget(cbList.at(row), row, 1); + grid->addWidget(cbList.at(row), row, 1); ++row; } addMutableAction(mainWidget); - builder.addItem(mainWidget); + layout.addItem(mainWidget); } QList m_sortedLanguageCategories; diff --git a/src/plugins/qbsprojectmanager/qbskitaspect.cpp b/src/plugins/qbsprojectmanager/qbskitaspect.cpp index e2700c5dec8..4de4e92e25d 100644 --- a/src/plugins/qbsprojectmanager/qbskitaspect.cpp +++ b/src/plugins/qbsprojectmanager/qbskitaspect.cpp @@ -35,11 +35,11 @@ private: void makeReadOnly() override { m_changeButton->setEnabled(false); } void refresh() override { m_contentLabel->setText(QbsKitAspect::representation(kit())); } - void addToInnerLayout(Layouting::Layout &parent) override + void addToInnerLayout(Layouting::Layout &layout) override { addMutableAction(m_contentLabel); - parent.addItem(m_contentLabel); - parent.addItem(m_changeButton); + layout.addItem(m_contentLabel); + layout.addItem(m_changeButton); } void changeProperties() diff --git a/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp b/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp index 0f4658acc8a..34d7ddfbd3b 100644 --- a/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp +++ b/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp @@ -44,10 +44,10 @@ public: ~QmakeKitAspectImpl() override { delete m_lineEdit; } private: - void addToInnerLayout(Layouting::Layout &parent) override + void addToInnerLayout(Layouting::Layout &layout) override { addMutableAction(m_lineEdit); - parent.addItem(m_lineEdit); + layout.addItem(m_lineEdit); } void makeReadOnly() override { m_lineEdit->setEnabled(false); } diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index 14cfe626324..b738278db4f 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -84,19 +84,19 @@ public: } private: - void addToInnerLayout(Layouting::Layout &parentItem) override + void addToInnerLayout(Layouting::Layout &layout) override { if (const QList embedded = aspectsToEmbed(); !embedded.isEmpty()) { - Layouting::Layout layout(new QHBoxLayout); - KitAspect::addToInnerLayout(layout); + Layouting::Layout box(new QHBoxLayout); + KitAspect::addToInnerLayout(box); QSizePolicy p = comboBoxes().first()->sizePolicy(); p.setHorizontalStretch(2); comboBoxes().first()->setSizePolicy(p); - layout.addItem(Tr::tr("Mkspec:")); - embedded.first()->addToInnerLayout(layout); - parentItem.addItem(layout); + box.addItem(Tr::tr("Mkspec:")); + embedded.first()->addToInnerLayout(box); + layout.addItem(box); } else { - KitAspect::addToInnerLayout(parentItem); + KitAspect::addToInnerLayout(layout); } } }; From 8425d8a5c24d3f880687faa5d35c291cdf3ed551 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 18 Nov 2024 16:47:36 +0100 Subject: [PATCH 184/989] AppManInferiorRunner: Remove private field Pass it via lambda capture instead. Change-Id: Ife0df546854f42e3f8c2e22755fe1cb4ebcb2ace Reviewed-by: hjk --- .../qtapplicationmanager/appmanagerruncontrol.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 4b2af98d469..4f694bbbc6f 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -100,8 +100,7 @@ public: AppManInferiorRunner(RunControl *runControl, bool usePerf, bool useGdbServer, bool useQmlServer, QmlDebugServicesPreset qmlServices) - : SimpleTargetRunner(runControl), - m_qmlServices(qmlServices) + : SimpleTargetRunner(runControl) { setId(AppManager::Constants::DEBUG_LAUNCHER_ID); setEssential(true); @@ -118,7 +117,7 @@ public: if (useQmlServer) runControl->requestQmlChannel(); - setStartModifier([this, runControl] { + setStartModifier([this, runControl, qmlServices] { FilePath controller = runControl->aspectData()->filePath; QString appId = runControl->aspectData()->value; QString instanceId = runControl->aspectData()->value; @@ -141,10 +140,8 @@ public: if (usesDebugChannel()) debugArgs.append(QString("gdbserver :%1").arg(debugChannel().port())); if (usesQmlChannel()) { - const QString qmlArgs = - qmlDebugCommandLineArguments(m_qmlServices, - QString("port:%1").arg(qmlChannel().port()), - true); + const QString qmlArgs = qmlDebugCommandLineArguments(qmlServices, + QString("port:%1").arg(qmlChannel().port()), true); debugArgs.append(QString("%program% %1 %arguments%") .arg(qmlArgs)); } cmd.addArg(debugArgs.join(' ')); @@ -174,9 +171,6 @@ public: appendMessage(Tr::tr("Using: %1.").arg(cmd.toUserOutput()), NormalMessageFormat); }); } - -private: - QmlDebugServicesPreset m_qmlServices; }; From a61e732ba0ee91f061e3272964d2eb0a1d3f2d33 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 18 Nov 2024 15:51:29 +0100 Subject: [PATCH 185/989] Themes: Introduce primitive color palette In the Figma-based design system, the "2024" light and dark theme color tokens reference colors from a primitives layer. Qt Creator was so far missing this indirection. This change adds the primitive layer as .ini file and replaces the #rgb values in the themes with references to the new layer. Fixes: DSGNSYSTM-9 Change-Id: I9ef358dee1f2e4c0e54f9f3ad97c6f3ae4618475 Reviewed-by: Marcus Tillmanns --- share/qtcreator/themes/dark.figmatokens | 70 +++++------ share/qtcreator/themes/light.figmatokens | 70 +++++------ share/qtcreator/themes/primitive-colors.inc | 121 ++++++++++++++++++++ 3 files changed, 193 insertions(+), 68 deletions(-) create mode 100644 share/qtcreator/themes/primitive-colors.inc diff --git a/share/qtcreator/themes/dark.figmatokens b/share/qtcreator/themes/dark.figmatokens index 0c63a7755dd..f9deb3e3757 100644 --- a/share/qtcreator/themes/dark.figmatokens +++ b/share/qtcreator/themes/dark.figmatokens @@ -1,48 +1,50 @@ ; Qt Creator Color Tokens - dark mode +[General] +Includes=primitive-colors.inc [Colors] -Token_Basic_Black=ff181818 -Token_Basic_White=ffFCFCFC +Token_Basic_Black=Primitive-Neutral-900 +Token_Basic_White=Primitive-Neutral-100 -Token_Accent_Default=ff12A75D -Token_Accent_Muted=ff12834B -Token_Accent_Subtle=ff14673E +Token_Accent_Default=Primitive-Neon-600 +Token_Accent_Muted=Primitive-Neon-700 +Token_Accent_Subtle=Primitive-Neon-800 -Token_Background_Default=ff1f1f1f -Token_Background_Muted=ff262626 -Token_Background_Subtle=ff2D2D2D +Token_Background_Default=Primitive-Neutral-850 +Token_Background_Muted=Primitive-Neutral-800 +Token_Background_Subtle=Primitive-Neutral-750 -Token_Foreground_Default=ff4A4A4A -Token_Foreground_Muted=ff3F3F3F -Token_Foreground_Subtle=ff353535 +Token_Foreground_Default=Primitive-Neutral-600 +Token_Foreground_Muted=Primitive-Neutral-650 +Token_Foreground_Subtle=Primitive-Neutral-700 -Token_Text_Default=ffF2F2F2 -Token_Text_Muted=ffAEAEAE -Token_Text_Subtle=ff595959 -Token_Text_Accent=ff1EC974 +Token_Text_Default=Primitive-Neutral-150 +Token_Text_Muted=Primitive-Neutral-350 +Token_Text_Subtle=Primitive-Neutral-550 +Token_Text_Accent=Primitive-Neon-500 -Token_Stroke_Strong=ffE3E3E3 -Token_Stroke_Muted=ff909090 -Token_Stroke_Subtle=ff4A4A4A +Token_Stroke_Strong=Primitive-Neutral-200 +Token_Stroke_Muted=Primitive-Neutral-450 +Token_Stroke_Subtle=Primitive-Neutral-650 -Token_Notification_Alert_Default=ffEFAD4C -Token_Notification_Alert_Muted=ffBC7A19 -Token_Notification_Alert_Subtle=ff31240F +Token_Notification_Alert_Default=Primitive-Yellow-400 +Token_Notification_Alert_Muted=Primitive-Yellow-600 +Token_Notification_Alert_Subtle=Primitive-Yellow-1000 -Token_Notification_Neutral_Default=ff8671EC -Token_Notification_Neutral_Muted=ff361EAB -Token_Notification_Neutral_Subtle=ff1E1450 +Token_Notification_Neutral_Default=Primitive-QAMidnight-300 +Token_Notification_Neutral_Muted=Primitive-QAMidnight-600 +Token_Notification_Neutral_Subtle=Primitive-QAMidnight-900 -Token_Notification_Danger_Default=ffE34269 -Token_Notification_Danger_Muted=ffB00F36 -Token_Notification_Danger_Subtle=ff33161C +Token_Notification_Danger_Default=Primitive-Red-400 +Token_Notification_Danger_Muted=Primitive-Red-600 +Token_Notification_Danger_Subtle=Primitive-Red-1000 -Token_Notification_Success_Default=ff1EC974 -Token_Notification_Success_Muted=ff12834B -Token_Notification_Success_Subtle=ff092C1B +Token_Notification_Success_Default=Primitive-Neon-500 +Token_Notification_Success_Muted=Primitive-Neon-700 +Token_Notification_Success_Subtle=Primitive-Neon-1000 -Token_Gradient01_Start=ff00414A -Token_Gradient01_End=ff12A75D -Token_Gradient02_Start=ff4A4A4A -Token_Gradient02_End=ff909090 +Token_Gradient01_Start=Primitive-Pine-700 +Token_Gradient01_End=Primitive-Neon-600 +Token_Gradient02_Start=Primitive-Neutral-600 +Token_Gradient02_End=Primitive-Neutral-450 diff --git a/share/qtcreator/themes/light.figmatokens b/share/qtcreator/themes/light.figmatokens index c156f14bb1f..657da85ce32 100644 --- a/share/qtcreator/themes/light.figmatokens +++ b/share/qtcreator/themes/light.figmatokens @@ -1,48 +1,50 @@ ; Qt Creator Color Tokens - light mode +[General] +Includes=primitive-colors.inc [Colors] -Token_Basic_Black=ff181818 -Token_Basic_White=ffFCFCFC +Token_Basic_Black=Primitive-Neutral-900 +Token_Basic_White=Primitive-Neutral-100 -Token_Accent_Default=ff1EC974 -Token_Accent_Muted=ff12A75D -Token_Accent_Subtle=ff12834B +Token_Accent_Default=Primitive-Neon-500 +Token_Accent_Muted=Primitive-Neon-600 +Token_Accent_Subtle=Primitive-Neon-700 -Token_Background_Default=ffFCFCFC -Token_Background_Muted=ffF2F2F2 -Token_Background_Subtle=ffE3E3E3 +Token_Background_Default=Primitive-Neutral-100 +Token_Background_Muted=Primitive-Neutral-150 +Token_Background_Subtle=Primitive-Neutral-200 -Token_Foreground_Default=ffBEBEBE -Token_Foreground_Muted=ffCDCDCD -Token_Foreground_Subtle=ffE3E3E3 +Token_Foreground_Default=Primitive-Neutral-300 +Token_Foreground_Muted=Primitive-Neutral-250 +Token_Foreground_Subtle=Primitive-Neutral-200 -Token_Text_Default=ff2D2D2D -Token_Text_Muted=ff595959 -Token_Text_Subtle=ffAEAEAE -Token_Text_Accent=ff12A75D +Token_Text_Default=Primitive-Neutral-750 +Token_Text_Muted=Primitive-Neutral-550 +Token_Text_Subtle=Primitive-Neutral-350 +Token_Text_Accent=Primitive-Neon-600 -Token_Stroke_Strong=ff595959 -Token_Stroke_Muted=ff909090 -Token_Stroke_Subtle=ffCDCDCD +Token_Stroke_Strong=Primitive-Neutral-550 +Token_Stroke_Muted=Primitive-Neutral-400 +Token_Stroke_Subtle=Primitive-Neutral-250 -Token_Notification_Alert_Default=ffBC7A19 -Token_Notification_Alert_Muted=ffEB991F -Token_Notification_Alert_Subtle=ffFFEBCD +Token_Notification_Alert_Default=Primitive-Yellow-600 +Token_Notification_Alert_Muted=Primitive-Yellow-500 +Token_Notification_Alert_Subtle=Primitive-Yellow-100 -Token_Notification_Neutral_Default=ff27138B -Token_Notification_Neutral_Muted=ff361EAB -Token_Notification_Neutral_Subtle=ffD9D2F9 +Token_Notification_Neutral_Default=Primitive-QAMidnight-700 +Token_Notification_Neutral_Muted=Primitive-QAMidnight-600 +Token_Notification_Neutral_Subtle=Primitive-QAMidnight-100 -Token_Notification_Danger_Default=ffB00F36 -Token_Notification_Danger_Muted=ffDC1343 -Token_Notification_Danger_Subtle=ffFACED9 +Token_Notification_Danger_Default=Primitive-Red-600 +Token_Notification_Danger_Muted=Primitive-Red-500 +Token_Notification_Danger_Subtle=Primitive-Red-100 -Token_Notification_Success_Default=ff12834B -Token_Notification_Success_Muted=ff12A75D -Token_Notification_Success_Subtle=ffDBFDEC +Token_Notification_Success_Default=Primitive-Neon-700 +Token_Notification_Success_Muted=Primitive-Neon-600 +Token_Notification_Success_Subtle=Primitive-Neon-100 -Token_Gradient01_Start=ff1EC974 -Token_Gradient01_End=ff0099A1 -Token_Gradient02_Start=ff9D9D9D -Token_Gradient02_End=ff595959 +Token_Gradient01_Start=Primitive-Neon-500 +Token_Gradient01_End=Primitive-Pine-600 +Token_Gradient02_Start=Primitive-Neutral-400 +Token_Gradient02_End=Primitive-Neutral-550 diff --git a/share/qtcreator/themes/primitive-colors.inc b/share/qtcreator/themes/primitive-colors.inc new file mode 100644 index 00000000000..eaf28a82bb2 --- /dev/null +++ b/share/qtcreator/themes/primitive-colors.inc @@ -0,0 +1,121 @@ +[Colors] + +Primitive-Neutral-000=ffffffff +Primitive-Neutral-100=fffcfcfc +Primitive-Neutral-150=fff2f2f2 +Primitive-Neutral-200=ffe3e3e3 +Primitive-Neutral-250=ffcdcdcd +Primitive-Neutral-300=ffbebebe +Primitive-Neutral-350=ffaeaeae +Primitive-Neutral-400=ff9d9d9d +Primitive-Neutral-450=ff909090 +Primitive-Neutral-500=ff737373 +Primitive-Neutral-550=ff595959 +Primitive-Neutral-600=ff4a4a4a +Primitive-Neutral-650=ff3f3f3f +Primitive-Neutral-700=ff353535 +Primitive-Neutral-750=ff2d2d2d +Primitive-Neutral-800=ff262626 +Primitive-Neutral-850=ff1f1f1f +Primitive-Neutral-900=ff181818 +Primitive-Neutral-950=ff121212 +Primitive-Neutral-1000=ff000000 + +Primitive-Neon-100=ffdffced +Primitive-Neon-200=ffc2f8da +Primitive-Neon-300=ff96f0bc +Primitive-Neon-400=ff5cdc8a +Primitive-Neon-500=ff4fc779 +Primitive-Neon-600=ff3fa561 +Primitive-Neon-700=ff32824e +Primitive-Neon-800=ff296640 +Primitive-Neon-900=ff194229 +Primitive-Neon-1000=ff102c1c + +Primitive-Pine-100=ffe3f4fc +Primitive-Pine-200=ffc2eafa +Primitive-Pine-300=ff8fdcf7 +Primitive-Pine-400=ff5cc9f1 +Primitive-Pine-500=ff44b4e1 +Primitive-Pine-600=ff3492c0 +Primitive-Pine-700=ff297595 +Primitive-Pine-800=ff236176 +Primitive-Pine-900=ff1e4e5e +Primitive-Pine-1000=ff124149 + +Primitive-Lemon-100=fff4f6ca +Primitive-Lemon-200=ffeef1a0 +Primitive-Lemon-300=ffebf074 +Primitive-Lemon-400=ffe3ec4e +Primitive-Lemon-500=ffdde83b +Primitive-Lemon-600=ffd0da37 +Primitive-Lemon-700=ffb5be2f +Primitive-Lemon-800=ff9aa327 +Primitive-Lemon-900=ff848b1f +Primitive-Lemon-1000=ff6f7419 + +Primitive-Moss-100=ffeaecdb +Primitive-Moss-200=ffd7ddba +Primitive-Moss-300=ffbcc792 +Primitive-Moss-400=ffa2af6f +Primitive-Moss-500=ff859452 +Primitive-Moss-600=ff67753f +Primitive-Moss-700=ff515b32 +Primitive-Moss-800=ff41492c +Primitive-Moss-900=ff383e28 +Primitive-Moss-1000=ff1d2014 + +Primitive-DS-100=ffbee8f6 +Primitive-DS-200=ffaae0f2 +Primitive-DS-300=ff81d2ed +Primitive-DS-400=ff5ec2e6 +Primitive-DS-500=ff44b4e1 +Primitive-DS-600=ff368fb4 +Primitive-DS-700=ff276c87 +Primitive-DS-800=ff19485a +Primitive-DS-900=ff123543 +Primitive-DS-1000=ff0a242d + +Primitive-QAViolet-100=ffefe9fe +Primitive-QAViolet-200=ffe2d6fd +Primitive-QAViolet-300=ffcab3fc +Primitive-QAViolet-400=ffad88fa +Primitive-QAViolet-500=ff8f5ff4 +Primitive-QAViolet-600=ff7843e7 +Primitive-QAViolet-700=ff6434cb +Primitive-QAViolet-800=ff562da6 +Primitive-QAViolet-900=ff482585 +Primitive-QAViolet-1000=ff2d1262 + +Primitive-QAMidnight-100=ffd8d3f7 +Primitive-QAMidnight-200=ffb6aef1 +Primitive-QAMidnight-300=ff8478e7 +Primitive-QAMidnight-400=ff6357cf +Primitive-QAMidnight-500=ff443aac +Primitive-QAMidnight-600=ff352ca7 +Primitive-QAMidnight-700=ff262088 +Primitive-QAMidnight-800=ff231d6d +Primitive-QAMidnight-900=ff1d184e +Primitive-QAMidnight-1000=ff181439 + +Primitive-Yellow-100=fffdeacf +Primitive-Yellow-200=fff3d5a9 +Primitive-Yellow-300=ffeec080 +Primitive-Yellow-400=ffe8ab58 +Primitive-Yellow-500=ffe39736 +Primitive-Yellow-600=ffb6792a +Primitive-Yellow-700=ff885b1f +Primitive-Yellow-800=ff5b3c14 +Primitive-Yellow-900=ff3d2c14 +Primitive-Yellow-1000=ff302411 + +Primitive-Red-100=fff5cfd9 +Primitive-Red-200=ffe9a5b7 +Primitive-Red-300=ffe0738f +Primitive-Red-400=ffd8456a +Primitive-Red-500=ffd01a46 +Primitive-Red-600=ffa71439 +Primitive-Red-700=ff7d0f2a +Primitive-Red-800=ff511121 +Primitive-Red-900=ff3e1821 +Primitive-Red-1000=ff31161c From 211ca6e27b93a8fafa3f64846640007d6f1ea937 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 19 Nov 2024 08:21:14 +0100 Subject: [PATCH 186/989] Utils: Add default ctors for Layouting::{Row,Column,Flow} Helpful when filling a layout manually. Change-Id: Id21a9ce1e280f999699529212a8bf713429524eb Reviewed-by: Marcus Tillmanns --- src/libs/utils/layoutbuilder.cpp | 19 ++++++++++++++++++- src/libs/utils/layoutbuilder.h | 3 +++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 99fbf5d9fa6..de6bc845ef4 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -626,6 +626,11 @@ void withFormAlignment(Layout *layout) // Flow +Flow::Flow() +{ + ptr = new FlowLayout; +} + Flow::Flow(std::initializer_list ps) { ptr = new FlowLayout; @@ -633,7 +638,12 @@ Flow::Flow(std::initializer_list ps) flush(); } -// Row & Column +// Row + +Row::Row() +{ + ptr = new QHBoxLayout; +} Row::Row(std::initializer_list ps) { @@ -642,6 +652,13 @@ Row::Row(std::initializer_list ps) flush(); } +// Column + +Column::Column() +{ + ptr = new QVBoxLayout; +} + Column::Column(std::initializer_list ps) { ptr = new QVBoxLayout; diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 08d71a14618..e1d0daf8d6e 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -155,6 +155,7 @@ public: using Implementation = QVBoxLayout; using I = Building::BuilderItem; + Column(); Column(std::initializer_list ps); }; @@ -164,6 +165,7 @@ public: using Implementation = QHBoxLayout; using I = Building::BuilderItem; + Row(); Row(std::initializer_list ps); }; @@ -190,6 +192,7 @@ public: class QTCREATOR_UTILS_EXPORT Flow : public Layout { public: + Flow(); Flow(std::initializer_list ps); }; From 19d200a3482bdd787038045c9f626284ad8b0858 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Wed, 6 Nov 2024 13:18:06 +0100 Subject: [PATCH 187/989] lsp: restart servers after configuration change Fix the connect to use the correct object: instead of connecting to the FilterProxy, connect to the underlying object. That allows to restart language servers whose configuration changed. Change-Id: I315aefe2a846086bbf74b50f6d3257c3880749cc Reviewed-by: David Schulz --- src/plugins/languageclient/languageclientsettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 5a8a0965ddd..4474d4a8d63 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -293,7 +293,7 @@ void LanguageClientSettingsPageWidget::applyCurrentSettings() if (m_currentSettings.setting->applyFromSettingsWidget(m_currentSettings.widget)) { auto index = m_settings.indexForSetting(m_currentSettings.setting); - emit m_settings.dataChanged(index, index); + emit m_settings.sourceModel()->dataChanged(index, index); } } From 2b5dc3d606bd17ae44a769945fcb8aa523aff701 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 18 Nov 2024 17:14:42 +0100 Subject: [PATCH 188/989] ProjectExplorer: Be transparent about what the "Force UTF-8" option does ... in the environment kit aspect. There is no reason to hide that from the user. Change-Id: Ia7e3bdccededb538a8615772d9096eb41e8d38b5 Reviewed-by: David Schulz --- src/plugins/projectexplorer/kitaspects.cpp | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/plugins/projectexplorer/kitaspects.cpp b/src/plugins/projectexplorer/kitaspects.cpp index fdbb0d63272..c0b7e772716 100644 --- a/src/plugins/projectexplorer/kitaspects.cpp +++ b/src/plugins/projectexplorer/kitaspects.cpp @@ -229,7 +229,7 @@ private: void refresh() override { - const EnvironmentItems changes = envWithoutMSVCEnglishEnforcement(); + const EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(kit()); const QString shortSummary = EnvironmentItem::toStringList(changes).join("; "); m_summaryLabel->setText(shortSummary.isEmpty() ? Tr::tr("No changes to apply.") : shortSummary); } @@ -240,10 +240,8 @@ private: EnvironmentDialog::Polisher polisher = [expander](QWidget *w) { VariableChooser::addSupportForChildWidgets(w, expander); }; - auto changes = EnvironmentDialog::getEnvironmentItems(m_summaryLabel, - envWithoutMSVCEnglishEnforcement(), - QString(), - polisher); + auto changes = EnvironmentDialog::getEnvironmentItems( + m_summaryLabel, EnvironmentKitAspect::environmentChanges(kit()), QString(), polisher); if (!changes) return; @@ -258,16 +256,6 @@ private: EnvironmentKitAspect::setEnvironmentChanges(kit(), *changes); } - EnvironmentItems envWithoutMSVCEnglishEnforcement() const - { - EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(kit()); - - if (HostOsInfo::isWindowsHost()) - changes.removeAll(forceMSVCEnglishItem()); - - return changes; - } - void initMSVCOutputSwitch(QVBoxLayout *layout) { m_vslangCheckbox = new QCheckBox(Tr::tr("Force UTF-8 MSVC compiler output")); From 2ea5361e0a28eead214f3ddc9851c15faf86c5b1 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 18 Nov 2024 17:34:36 +0100 Subject: [PATCH 189/989] ProjectExplorer: Improve code readability in EnvironmentKitAspect Change-Id: I6f19f8616b940457893ed065ae81646ae64f57a8 Reviewed-by: David Schulz --- src/plugins/projectexplorer/kitaspects.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/plugins/projectexplorer/kitaspects.cpp b/src/plugins/projectexplorer/kitaspects.cpp index c0b7e772716..a37c172f17e 100644 --- a/src/plugins/projectexplorer/kitaspects.cpp +++ b/src/plugins/projectexplorer/kitaspects.cpp @@ -263,14 +263,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(kit()))) - m_vslangCheckbox->setChecked(true); + m_vslangCheckbox->setChecked( + enforcesMSVCEnglish(EnvironmentKitAspect::environmentChanges(kit()))); connect(m_vslangCheckbox, &QCheckBox::clicked, this, [this](bool checked) { EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(kit()); - if (!checked && changes.indexOf(forceMSVCEnglishItem()) >= 0) - changes.removeAll(forceMSVCEnglishItem()); - if (checked && changes.indexOf(forceMSVCEnglishItem()) < 0) + const bool hasVsLangEntry = enforcesMSVCEnglish(changes); + if (checked && !hasVsLangEntry) changes.append(forceMSVCEnglishItem()); + else if (!checked && hasVsLangEntry) + changes.removeAll(forceMSVCEnglishItem()); EnvironmentKitAspect::setEnvironmentChanges(kit(), changes); }); } From e66ae4ac76c6caf995a29d9b98fe7323dec648a4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 18 Nov 2024 19:31:13 +0100 Subject: [PATCH 190/989] RunWorker: Remove recordData() / recordedData() methods Since there is no more usages of recordedData() - get rid of it. Thus storing any data without using them doesn't make sense. Change-Id: I1b527d22cc8a53b4f8df960ba9fd3d3436d7b822 Reviewed-by: hjk Reviewed-by: Ulf Hermann --- src/plugins/android/androidqmltoolingsupport.cpp | 5 +---- src/plugins/ios/iosrunner.cpp | 1 - src/plugins/projectexplorer/runcontrol.cpp | 11 ----------- src/plugins/projectexplorer/runcontrol.h | 3 --- .../qtapplicationmanager/appmanagerruncontrol.cpp | 1 - 5 files changed, 1 insertion(+), 20 deletions(-) diff --git a/src/plugins/android/androidqmltoolingsupport.cpp b/src/plugins/android/androidqmltoolingsupport.cpp index e7e6837754a..6c14f30c3fc 100644 --- a/src/plugins/android/androidqmltoolingsupport.cpp +++ b/src/plugins/android/androidqmltoolingsupport.cpp @@ -26,10 +26,7 @@ public: auto worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); worker->addStartDependency(this); - connect(runner, &AndroidRunner::qmlServerReady, this, [this, worker](const QUrl &server) { - worker->recordData("QmlServerUrl", server); - reportStarted(); - }); + connect(runner, &AndroidRunner::qmlServerReady, this, &RunWorker::reportStarted); } private: diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index c33959e1b5d..9172fcc07c9 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -735,7 +735,6 @@ void IosQmlProfilerSupport::start() Port qmlPort = m_runner->qmlServerPort(); serverUrl.setPort(qmlPort.number()); - m_profiler->recordData("QmlServerUrl", serverUrl); if (qmlPort.isValid()) reportStarted(); else diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index fb0609af6ec..9dd64d03112 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -235,7 +235,6 @@ public: QList stopDependencies; QString id; - Store data; bool supportsReRunning = true; bool essential = false; }; @@ -1951,16 +1950,6 @@ void RunWorker::setId(const QString &id) d->id = id; } -void RunWorker::recordData(const Key &channel, const QVariant &data) -{ - d->data[channel] = data; -} - -QVariant RunWorker::recordedData(const Key &channel) const -{ - return d->data[channel]; -} - void RunWorker::setSupportsReRunning(bool reRunningSupported) { d->supportsReRunning = reRunningSupported; diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 311a39f3440..4c37b1c9e78 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -56,9 +56,6 @@ public: void setId(const QString &id); - void recordData(const Utils::Key &channel, const QVariant &data); - QVariant recordedData(const Utils::Key &channel) const; - // Part of read-only interface of RunControl for convenience. void appendMessage(const QString &msg, Utils::OutputFormat format, bool appendNewLine = true); IDeviceConstPtr device() const; diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 4f694bbbc6f..978e2158b51 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -277,7 +277,6 @@ public: private: void start() final { - m_worker->recordData("QmlServerUrl", qmlChannel()); reportStarted(); } From 1c40dfd419363e3310f1972477d2b56d59639e08 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 14 Nov 2024 17:59:52 +0100 Subject: [PATCH 191/989] Plugins: Improve display names of plugins This introduces a field "DisplayName" to PluginSpec and the plugin spec json files. If present in the spec, PluginSpec::displayName returns it, or otherways falls back to more established fields. Fixes: QTCREATORBUG-31761 Change-Id: I4f4c4f3e33b17dfb2ec63644b1f50b3b9c6c024a Reviewed-by: Leena Miettinen Reviewed-by: Eike Ziller --- share/qtcreator/lua-plugins/luals/luals.lua | 3 ++- share/qtcreator/lua-plugins/luatests/luatests.lua | 3 ++- share/qtcreator/lua-plugins/rustls/rustls.lua | 3 ++- share/qtcreator/lua-plugins/tellajoke/tellajoke.lua | 3 ++- src/libs/extensionsystem/pluginspec.cpp | 10 ++++++++-- src/plugins/android/Android.json.in | 1 + .../appstatisticsmonitor/AppStatisticsMonitor.json.in | 1 + src/plugins/autotest/AutoTest.json.in | 1 + .../AutotoolsProjectManager.json.in | 1 + src/plugins/axivion/Axivion.json.in | 1 + src/plugins/baremetal/BareMetal.json.in | 1 + src/plugins/bazaar/Bazaar.json.in | 1 + src/plugins/beautifier/Beautifier.json.in | 1 + src/plugins/bineditor/BinEditor.json.in | 1 + src/plugins/boot2qt/Boot2Qt.json.in | 1 + src/plugins/clangcodemodel/ClangCodeModel.json.in | 1 + src/plugins/clangformat/ClangFormat.json.in | 1 + src/plugins/clangtools/ClangTools.json.in | 1 + src/plugins/classview/ClassView.json.in | 1 + src/plugins/clearcase/ClearCase.json.in | 1 + .../cmakeprojectmanager/CMakeProjectManager.json.in | 1 + src/plugins/coco/Coco.json.in | 1 + .../CompilationDatabaseProjectManager.json.in | 1 + src/plugins/compilerexplorer/CompilerExplorer.json.in | 1 + src/plugins/conan/Conan.json.in | 1 + src/plugins/copilot/Copilot.json.in | 1 + src/plugins/coreplugin/Core.json.in | 1 + src/plugins/cpaster/CodePaster.json.in | 1 + src/plugins/cppcheck/Cppcheck.json.in | 1 + src/plugins/cppeditor/CppEditor.json.in | 1 + src/plugins/ctfvisualizer/CtfVisualizer.json.in | 1 + src/plugins/cvs/CVS.json.in | 1 + src/plugins/debugger/Debugger.json.in | 1 + src/plugins/designer/Designer.json.in | 1 + src/plugins/diffeditor/DiffEditor.json.in | 1 + src/plugins/docker/Docker.json.in | 1 + src/plugins/effectcomposer/EffectComposer.json.in | 1 + src/plugins/emacskeys/EmacsKeys.json.in | 1 + src/plugins/extensionmanager/ExtensionManager.json.in | 1 + src/plugins/fakevim/FakeVim.json.in | 1 + src/plugins/fossil/Fossil.json.in | 1 + .../GenericProjectManager.json.in | 1 + src/plugins/git/Git.json.in | 1 + src/plugins/gitlab/GitLab.json.in | 1 + src/plugins/glsleditor/GLSLEditor.json.in | 1 + src/plugins/haskell/Haskell.json.in | 1 + src/plugins/helloworld/HelloWorld.json.in | 1 + src/plugins/help/Help.json.in | 1 + src/plugins/imageviewer/ImageViewer.json.in | 1 + src/plugins/incredibuild/IncrediBuild.json.in | 1 + src/plugins/insight/Insight.json.in | 1 + src/plugins/ios/Ios.json.in | 1 + src/plugins/languageclient/LanguageClient.json.in | 1 + .../lualanguageclient/LuaLanguageClient.json.in | 1 + src/plugins/lua/Lua.json.in | 1 + src/plugins/macros/Macros.json.in | 1 + src/plugins/marketplace/Marketplace.json.in | 1 + src/plugins/mcusupport/McuSupport.json.in | 1 + src/plugins/mercurial/Mercurial.json.in | 1 + .../mesonprojectmanager/MesonProjectManager.json.in | 1 + src/plugins/modeleditor/ModelEditor.json.in | 1 + src/plugins/nim/Nim.json.in | 1 + src/plugins/perforce/Perforce.json.in | 1 + src/plugins/perfprofiler/PerfProfiler.json.in | 1 + src/plugins/projectexplorer/ProjectExplorer.json.in | 1 + src/plugins/python/Python.json.in | 1 + .../qbsprojectmanager/QbsProjectManager.json.in | 1 + .../qmakeprojectmanager/QmakeProjectManager.json.in | 1 + src/plugins/qmldesigner/QmlDesigner.json.in | 1 + src/plugins/qmldesignerbase/QmlDesignerBase.json.in | 1 + src/plugins/qmldesignerlite/QmlDesignerLite.json.in | 1 + src/plugins/qmljseditor/QmlJSEditor.json.in | 1 + src/plugins/qmljstools/QmlJSTools.json.in | 1 + src/plugins/qmlpreview/QmlPreview.json.in | 1 + src/plugins/qmlprofiler/QmlProfiler.json.in | 1 + .../qmlprojectmanager/QmlProjectManager.json.in | 1 + src/plugins/qnx/Qnx.json.in | 1 + .../QtApplicationManagerIntegration.json.in | 1 + src/plugins/qtsupport/QtSupport.json.in | 1 + src/plugins/remotelinux/RemoteLinux.json.in | 1 + src/plugins/resourceeditor/ResourceEditor.json.in | 1 + src/plugins/saferenderer/SafeRenderer.json.in | 1 + src/plugins/screenrecorder/ScreenRecorder.json.in | 1 + src/plugins/scxmleditor/ScxmlEditor.json.in | 1 + src/plugins/serialterminal/SerialTerminal.json.in | 1 + src/plugins/silversearcher/SilverSearcher.json.in | 1 + src/plugins/squish/Squish.json.in | 1 + src/plugins/studiowelcome/StudioWelcome.json.in | 1 + src/plugins/subversion/Subversion.json.in | 1 + src/plugins/terminal/Terminal.json.in | 1 + src/plugins/texteditor/TextEditor.json.in | 1 + src/plugins/todo/Todo.json.in | 1 + src/plugins/updateinfo/UpdateInfo.json.in | 1 + src/plugins/valgrind/Valgrind.json.in | 1 + src/plugins/vcpkg/Vcpkg.json.in | 1 + src/plugins/vcsbase/VcsBase.json.in | 1 + src/plugins/webassembly/WebAssembly.json.in | 1 + src/plugins/welcome/Welcome.json.in | 1 + 98 files changed, 109 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/lua-plugins/luals/luals.lua b/share/qtcreator/lua-plugins/luals/luals.lua index f14c88f4fe0..2489998bf55 100644 --- a/share/qtcreator/lua-plugins/luals/luals.lua +++ b/share/qtcreator/lua-plugins/luals/luals.lua @@ -2,7 +2,8 @@ -- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 return { Id = "lualanguageserver", - Name = "Lua Language Server", + DisplayName = "Lua Language Server", + Name = "LuaLanguageServer", Version = "1.0.0", CompatVersion = "1.0.0", VendorId = "theqtcompany", diff --git a/share/qtcreator/lua-plugins/luatests/luatests.lua b/share/qtcreator/lua-plugins/luatests/luatests.lua index ba2ec28f42e..41094780bf9 100644 --- a/share/qtcreator/lua-plugins/luatests/luatests.lua +++ b/share/qtcreator/lua-plugins/luatests/luatests.lua @@ -2,7 +2,8 @@ -- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 return { Id = "luatests", - Name = "Lua Tests", + DisplayName = "Lua Tests", + Name = "LuaTests", Version = "1.0.0", CompatVersion = "1.0.0", VendorId = "theqtcompany", diff --git a/share/qtcreator/lua-plugins/rustls/rustls.lua b/share/qtcreator/lua-plugins/rustls/rustls.lua index b3a1d6de598..df90fd085cf 100644 --- a/share/qtcreator/lua-plugins/rustls/rustls.lua +++ b/share/qtcreator/lua-plugins/rustls/rustls.lua @@ -2,7 +2,8 @@ -- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 return { Id = "rustlanguageserver", - Name = "Rust Language Server", + DisplayName = "Rust Language Server", + Name = "RustLanguageServer", Version = "1.0.0", CompatVersion = "1.0.0", VendorId = "theqtcompany", diff --git a/share/qtcreator/lua-plugins/tellajoke/tellajoke.lua b/share/qtcreator/lua-plugins/tellajoke/tellajoke.lua index b409d04b037..2f72952881d 100644 --- a/share/qtcreator/lua-plugins/tellajoke/tellajoke.lua +++ b/share/qtcreator/lua-plugins/tellajoke/tellajoke.lua @@ -42,7 +42,8 @@ end return { Id = "tellajoke", - Name = "Tell A Joke", + DisplayName = "Tell a Joke", + Name = "TellAJoke", Version = "1.0.0", CompatVersion = "1.0.0", VendorId = "theqtcompany", diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp index bb58e36a28d..90e33dbbfbe 100644 --- a/src/libs/extensionsystem/pluginspec.cpp +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -187,6 +187,7 @@ public: ExtensionSystem::PerformanceData performanceData; QString id; + QString displayName; QString name; QString version; QString compatVersion; @@ -267,12 +268,13 @@ QString PluginSpec::id() const } /*! - Returns either name(), or id() if name() is empty. If both are empty, returns "". + Returns either DisplayName, name(), or id() if name() is empty. If all are empty, + returns "". */ QString PluginSpec::displayName() const { return Utils::findOr( - QStringList{name(), id(), filePath().fileName()}, + QStringList{d->displayName, name(), id(), filePath().fileName()}, "", std::not_fn(&QString::isEmpty)); } @@ -727,6 +729,7 @@ PluginSpecs PluginSpec::enableDependenciesIndirectly(bool enableTestDependencies namespace { const char PLUGIN_METADATA[] = "MetaData"; const char PLUGIN_NAME[] = "Name"; + const char PLUGIN_DISPLAYNAME[] = "DisplayName"; const char PLUGIN_ID[] = "Id"; const char PLUGIN_VERSION[] = "Version"; const char PLUGIN_COMPATVERSION[] = "CompatVersion"; @@ -936,6 +939,9 @@ Utils::expected_str PluginSpecPrivate::readMetaData(const QJsonObject &dat if (auto r = assignOr(name, PLUGIN_NAME, id); !r.has_value()) return reportError(r.error()); + if (auto r = assignOr(displayName, PLUGIN_DISPLAYNAME, name); !r.has_value()) + return reportError(r.error()); + if (auto r = assign(version, PLUGIN_VERSION); !r.has_value()) return reportError(r.error()); diff --git a/src/plugins/android/Android.json.in b/src/plugins/android/Android.json.in index 281f55d72ad..a410aa83c27 100644 --- a/src/plugins/android/Android.json.in +++ b/src/plugins/android/Android.json.in @@ -1,5 +1,6 @@ { "Id" : "android", + "DisplayName" : "Android", "Name" : "Android", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in b/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in index 9877f2409e1..3c68b1bf391 100644 --- a/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in +++ b/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in @@ -1,5 +1,6 @@ { "Id" : "appstatisticsmonitor", + "DisplayName" : "Application Statistics Monitor", "Name" : "AppStatisticsMonitor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/autotest/AutoTest.json.in b/src/plugins/autotest/AutoTest.json.in index 5a31166aa56..aadb77fcea3 100644 --- a/src/plugins/autotest/AutoTest.json.in +++ b/src/plugins/autotest/AutoTest.json.in @@ -1,5 +1,6 @@ { "Id" : "autotest", + "DisplayName" : "Tests", "Name" : "AutoTest", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/autotoolsprojectmanager/AutotoolsProjectManager.json.in b/src/plugins/autotoolsprojectmanager/AutotoolsProjectManager.json.in index 6ec7e5ab042..76ac64def6f 100644 --- a/src/plugins/autotoolsprojectmanager/AutotoolsProjectManager.json.in +++ b/src/plugins/autotoolsprojectmanager/AutotoolsProjectManager.json.in @@ -1,5 +1,6 @@ { "Id" : "autotoolsprojectmanager", + "DisplayName" : "Autotools", "Name" : "AutotoolsProjectManager", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/axivion/Axivion.json.in b/src/plugins/axivion/Axivion.json.in index 3844ec2d702..01efc15898c 100644 --- a/src/plugins/axivion/Axivion.json.in +++ b/src/plugins/axivion/Axivion.json.in @@ -1,5 +1,6 @@ { "Id" : "axivion", + "DisplayName" : "Axivion", "Name" : "Axivion", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/baremetal/BareMetal.json.in b/src/plugins/baremetal/BareMetal.json.in index 402318e74fa..bf049ed930e 100644 --- a/src/plugins/baremetal/BareMetal.json.in +++ b/src/plugins/baremetal/BareMetal.json.in @@ -1,5 +1,6 @@ { "Id" : "baremetal", + "DisplayName" : "Bare Metal", "Name" : "BareMetal", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/bazaar/Bazaar.json.in b/src/plugins/bazaar/Bazaar.json.in index 81c8402586f..e725b785734 100644 --- a/src/plugins/bazaar/Bazaar.json.in +++ b/src/plugins/bazaar/Bazaar.json.in @@ -1,5 +1,6 @@ { "Id" : "bazaar", + "DisplayName" : "Bazaar", "Name" : "Bazaar", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/beautifier/Beautifier.json.in b/src/plugins/beautifier/Beautifier.json.in index 66f1f0c1892..30af11483e2 100644 --- a/src/plugins/beautifier/Beautifier.json.in +++ b/src/plugins/beautifier/Beautifier.json.in @@ -1,5 +1,6 @@ { "Id" : "beautifier", + "DisplayName" : "Beautifier", "Name" : "Beautifier", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/bineditor/BinEditor.json.in b/src/plugins/bineditor/BinEditor.json.in index 8c2d6719e62..74617404c82 100644 --- a/src/plugins/bineditor/BinEditor.json.in +++ b/src/plugins/bineditor/BinEditor.json.in @@ -1,5 +1,6 @@ { "Id" : "bineditor", + "DisplayName" : "Binary Editor", "Name" : "BinEditor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/boot2qt/Boot2Qt.json.in b/src/plugins/boot2qt/Boot2Qt.json.in index 4c9fb822684..c077313c287 100644 --- a/src/plugins/boot2qt/Boot2Qt.json.in +++ b/src/plugins/boot2qt/Boot2Qt.json.in @@ -1,5 +1,6 @@ { "Id" : "boot2qt", + "DisplayName" : "Boot to Qt", "Name" : "Boot2Qt", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/clangcodemodel/ClangCodeModel.json.in b/src/plugins/clangcodemodel/ClangCodeModel.json.in index 11c09e7bc86..b8de3d42331 100644 --- a/src/plugins/clangcodemodel/ClangCodeModel.json.in +++ b/src/plugins/clangcodemodel/ClangCodeModel.json.in @@ -1,5 +1,6 @@ { "Id" : "clangcodemodel", + "DisplayName" : "Clang Code Model", "Name" : "ClangCodeModel", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/clangformat/ClangFormat.json.in b/src/plugins/clangformat/ClangFormat.json.in index ca5f57628c0..52578a1451f 100644 --- a/src/plugins/clangformat/ClangFormat.json.in +++ b/src/plugins/clangformat/ClangFormat.json.in @@ -1,5 +1,6 @@ { "Id" : "clangformat", + "DisplayName" : "ClangFormat", "Name" : "ClangFormat", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/clangtools/ClangTools.json.in b/src/plugins/clangtools/ClangTools.json.in index d11f67d478b..86d6c566c22 100644 --- a/src/plugins/clangtools/ClangTools.json.in +++ b/src/plugins/clangtools/ClangTools.json.in @@ -1,5 +1,6 @@ { "Id" : "clangtools", + "DisplayName" : "Clang Tools", "Name" : "ClangTools", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/classview/ClassView.json.in b/src/plugins/classview/ClassView.json.in index 20fbf512478..34950eff937 100644 --- a/src/plugins/classview/ClassView.json.in +++ b/src/plugins/classview/ClassView.json.in @@ -1,5 +1,6 @@ { "Id" : "classview", + "DisplayName" : "Class View", "Name" : "ClassView", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/clearcase/ClearCase.json.in b/src/plugins/clearcase/ClearCase.json.in index 753d57f0ecc..b03432538bb 100644 --- a/src/plugins/clearcase/ClearCase.json.in +++ b/src/plugins/clearcase/ClearCase.json.in @@ -1,5 +1,6 @@ { "Id" : "clearcase", + "DisplayName" : "ClearCase", "Name" : "ClearCase", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in b/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in index b34a5b09254..f1d07e9a19a 100644 --- a/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in +++ b/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in @@ -1,5 +1,6 @@ { "Id" : "cmakeprojectmanager", + "DisplayName" : "CMake", "Name" : "CMakeProjectManager", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/coco/Coco.json.in b/src/plugins/coco/Coco.json.in index e9eb090aa42..dac881ce6fa 100644 --- a/src/plugins/coco/Coco.json.in +++ b/src/plugins/coco/Coco.json.in @@ -1,5 +1,6 @@ { "Id" : "coco", + "DisplayName" : "Coco", "Name" : "Coco", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/compilationdatabaseprojectmanager/CompilationDatabaseProjectManager.json.in b/src/plugins/compilationdatabaseprojectmanager/CompilationDatabaseProjectManager.json.in index a8d99321507..e7c6b3fdebd 100644 --- a/src/plugins/compilationdatabaseprojectmanager/CompilationDatabaseProjectManager.json.in +++ b/src/plugins/compilationdatabaseprojectmanager/CompilationDatabaseProjectManager.json.in @@ -1,5 +1,6 @@ { "Id" : "compilationdatabaseprojectmanager", + "DisplayName" : "Compilation Databases", "Name" : "CompilationDatabaseProjectManager", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/compilerexplorer/CompilerExplorer.json.in b/src/plugins/compilerexplorer/CompilerExplorer.json.in index f658c207a20..1aed608ab91 100644 --- a/src/plugins/compilerexplorer/CompilerExplorer.json.in +++ b/src/plugins/compilerexplorer/CompilerExplorer.json.in @@ -1,5 +1,6 @@ { "Id" : "compilerexplorer", + "DisplayName" : "Compiler Explorer", "Name" : "CompilerExplorer", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/conan/Conan.json.in b/src/plugins/conan/Conan.json.in index 2020545b380..b7a744070e6 100644 --- a/src/plugins/conan/Conan.json.in +++ b/src/plugins/conan/Conan.json.in @@ -1,5 +1,6 @@ { "Id" : "conan", + "DisplayName" : "Conan", "Name" : "Conan", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/copilot/Copilot.json.in b/src/plugins/copilot/Copilot.json.in index 9bdffdad8df..9a677db72fe 100644 --- a/src/plugins/copilot/Copilot.json.in +++ b/src/plugins/copilot/Copilot.json.in @@ -1,5 +1,6 @@ { "Id" : "copilot", + "DisplayName" : "GitHub Copilot", "Name" : "Copilot", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/coreplugin/Core.json.in b/src/plugins/coreplugin/Core.json.in index 4bab32c95be..6895cfda193 100644 --- a/src/plugins/coreplugin/Core.json.in +++ b/src/plugins/coreplugin/Core.json.in @@ -1,5 +1,6 @@ { "Id" : "core", + "DisplayName" : "Core", "Name" : "Core", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/cpaster/CodePaster.json.in b/src/plugins/cpaster/CodePaster.json.in index 17c18c5ac96..214e7f6a39f 100644 --- a/src/plugins/cpaster/CodePaster.json.in +++ b/src/plugins/cpaster/CodePaster.json.in @@ -1,5 +1,6 @@ { "Id" : "codepaster", + "DisplayName" : "Code Paster", "Name" : "CodePaster", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/cppcheck/Cppcheck.json.in b/src/plugins/cppcheck/Cppcheck.json.in index ce8e0b60676..27c5faa6e0b 100644 --- a/src/plugins/cppcheck/Cppcheck.json.in +++ b/src/plugins/cppcheck/Cppcheck.json.in @@ -1,5 +1,6 @@ { "Id" : "cppcheck", + "DisplayName" : "Cppcheck", "Name" : "Cppcheck", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/cppeditor/CppEditor.json.in b/src/plugins/cppeditor/CppEditor.json.in index 1133e32ae0b..5cc7c7b87df 100644 --- a/src/plugins/cppeditor/CppEditor.json.in +++ b/src/plugins/cppeditor/CppEditor.json.in @@ -1,5 +1,6 @@ { "Id" : "cppeditor", + "DisplayName" : "C++ Editor", "Name" : "CppEditor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/ctfvisualizer/CtfVisualizer.json.in b/src/plugins/ctfvisualizer/CtfVisualizer.json.in index 66e0dad243c..3e0a4e53612 100644 --- a/src/plugins/ctfvisualizer/CtfVisualizer.json.in +++ b/src/plugins/ctfvisualizer/CtfVisualizer.json.in @@ -1,5 +1,6 @@ { "Id" : "ctfvisualizer", + "DisplayName" : "CTF Visualizer", "Name" : "CtfVisualizer", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/cvs/CVS.json.in b/src/plugins/cvs/CVS.json.in index 25a1d6bffee..4415bd02fbb 100644 --- a/src/plugins/cvs/CVS.json.in +++ b/src/plugins/cvs/CVS.json.in @@ -1,5 +1,6 @@ { "Id" : "cvs", + "DisplayName" : "CVS", "Name" : "CVS", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/debugger/Debugger.json.in b/src/plugins/debugger/Debugger.json.in index 55473621156..744d159d2ee 100644 --- a/src/plugins/debugger/Debugger.json.in +++ b/src/plugins/debugger/Debugger.json.in @@ -1,5 +1,6 @@ { "Id" : "debugger", + "DisplayName" : "Debugger", "Name" : "Debugger", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/designer/Designer.json.in b/src/plugins/designer/Designer.json.in index 55cf85e404f..02faff32339 100644 --- a/src/plugins/designer/Designer.json.in +++ b/src/plugins/designer/Designer.json.in @@ -1,5 +1,6 @@ { "Id" : "designer", + "DisplayName" : "Qt Widgets Designer", "Name" : "Designer", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/diffeditor/DiffEditor.json.in b/src/plugins/diffeditor/DiffEditor.json.in index 63f5180ed1c..d220004268e 100644 --- a/src/plugins/diffeditor/DiffEditor.json.in +++ b/src/plugins/diffeditor/DiffEditor.json.in @@ -1,5 +1,6 @@ { "Id" : "diffeditor", + "DisplayName" : "Diff Viewer", "Name" : "DiffEditor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/docker/Docker.json.in b/src/plugins/docker/Docker.json.in index 208d9190247..26626f484c2 100644 --- a/src/plugins/docker/Docker.json.in +++ b/src/plugins/docker/Docker.json.in @@ -1,5 +1,6 @@ { "Id" : "docker", + "DisplayName" : "Docker", "Name" : "Docker", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/effectcomposer/EffectComposer.json.in b/src/plugins/effectcomposer/EffectComposer.json.in index 9d95d2dd40d..24f16eaf1f6 100644 --- a/src/plugins/effectcomposer/EffectComposer.json.in +++ b/src/plugins/effectcomposer/EffectComposer.json.in @@ -1,5 +1,6 @@ { "Id" : "effectcomposer", + "DisplayName" : "Effect Composer", "Name" : "EffectComposer", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/emacskeys/EmacsKeys.json.in b/src/plugins/emacskeys/EmacsKeys.json.in index 7e9cc7443f1..abc4cbd0995 100644 --- a/src/plugins/emacskeys/EmacsKeys.json.in +++ b/src/plugins/emacskeys/EmacsKeys.json.in @@ -1,5 +1,6 @@ { "Id" : "emacskeys", + "DisplayName" : "Emacs Keys", "Name" : "EmacsKeys", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/extensionmanager/ExtensionManager.json.in b/src/plugins/extensionmanager/ExtensionManager.json.in index aad40b1627c..6f9597a35e7 100644 --- a/src/plugins/extensionmanager/ExtensionManager.json.in +++ b/src/plugins/extensionmanager/ExtensionManager.json.in @@ -1,5 +1,6 @@ { "Id" : "extensionmanager", + "DisplayName" : "Extension Manager", "Name" : "ExtensionManager", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/fakevim/FakeVim.json.in b/src/plugins/fakevim/FakeVim.json.in index d0742580fa7..a3dbe77b20d 100644 --- a/src/plugins/fakevim/FakeVim.json.in +++ b/src/plugins/fakevim/FakeVim.json.in @@ -1,5 +1,6 @@ { "Id" : "fakevim", + "DisplayName" : "FakeVim", "Name" : "FakeVim", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/fossil/Fossil.json.in b/src/plugins/fossil/Fossil.json.in index 524cf8f7fbd..ccc9856d2bc 100644 --- a/src/plugins/fossil/Fossil.json.in +++ b/src/plugins/fossil/Fossil.json.in @@ -1,5 +1,6 @@ { "Id" : "fossil", + "DisplayName" : "Fossil", "Name" : "Fossil", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/genericprojectmanager/GenericProjectManager.json.in b/src/plugins/genericprojectmanager/GenericProjectManager.json.in index 78833814efd..a716c09953d 100644 --- a/src/plugins/genericprojectmanager/GenericProjectManager.json.in +++ b/src/plugins/genericprojectmanager/GenericProjectManager.json.in @@ -1,5 +1,6 @@ { "Id" : "genericprojectmanager", + "DisplayName" : "Generic Project Manager", "Name" : "GenericProjectManager", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/git/Git.json.in b/src/plugins/git/Git.json.in index 87ab8db9f0a..6c6b476b880 100644 --- a/src/plugins/git/Git.json.in +++ b/src/plugins/git/Git.json.in @@ -1,5 +1,6 @@ { "Id" : "git", + "DisplayName" : "Git", "Name" : "Git", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/gitlab/GitLab.json.in b/src/plugins/gitlab/GitLab.json.in index 17786156531..8f02f2b5734 100644 --- a/src/plugins/gitlab/GitLab.json.in +++ b/src/plugins/gitlab/GitLab.json.in @@ -1,5 +1,6 @@ { "Id" : "gitlab", + "DisplayName" : "GitLab", "Name" : "GitLab", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/glsleditor/GLSLEditor.json.in b/src/plugins/glsleditor/GLSLEditor.json.in index 812da3c7136..68982412a92 100644 --- a/src/plugins/glsleditor/GLSLEditor.json.in +++ b/src/plugins/glsleditor/GLSLEditor.json.in @@ -1,5 +1,6 @@ { "Id" : "glsleditor", + "DisplayName" : "GLSL Editor", "Name" : "GLSLEditor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/haskell/Haskell.json.in b/src/plugins/haskell/Haskell.json.in index ebdb9297473..bb1413197a1 100644 --- a/src/plugins/haskell/Haskell.json.in +++ b/src/plugins/haskell/Haskell.json.in @@ -1,5 +1,6 @@ { "Id" : "haskell", + "DisplayName" : "Haskell", "Name" : "Haskell", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/helloworld/HelloWorld.json.in b/src/plugins/helloworld/HelloWorld.json.in index 255d4142cf8..e432e996e75 100644 --- a/src/plugins/helloworld/HelloWorld.json.in +++ b/src/plugins/helloworld/HelloWorld.json.in @@ -1,5 +1,6 @@ { "Id" : "helloworld", + "DisplayName" : "Hello World", "Name" : "HelloWorld", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/help/Help.json.in b/src/plugins/help/Help.json.in index 399404e2725..346b79c0342 100644 --- a/src/plugins/help/Help.json.in +++ b/src/plugins/help/Help.json.in @@ -1,5 +1,6 @@ { "Id" : "help", + "DisplayName" : "Help", "Name" : "Help", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/imageviewer/ImageViewer.json.in b/src/plugins/imageviewer/ImageViewer.json.in index 90f91f19744..62d94e8e943 100644 --- a/src/plugins/imageviewer/ImageViewer.json.in +++ b/src/plugins/imageviewer/ImageViewer.json.in @@ -1,5 +1,6 @@ { "Id" : "imageviewer", + "DisplayName" : "Image Viewer", "Name" : "ImageViewer", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/incredibuild/IncrediBuild.json.in b/src/plugins/incredibuild/IncrediBuild.json.in index 40944329c77..6867a202783 100644 --- a/src/plugins/incredibuild/IncrediBuild.json.in +++ b/src/plugins/incredibuild/IncrediBuild.json.in @@ -1,5 +1,6 @@ { "Id" : "incredibuild", + "DisplayName" : "IncrediBuild", "Name" : "IncrediBuild", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/insight/Insight.json.in b/src/plugins/insight/Insight.json.in index c60a1e9aef7..1d92564ed4a 100644 --- a/src/plugins/insight/Insight.json.in +++ b/src/plugins/insight/Insight.json.in @@ -1,5 +1,6 @@ { "Id" : "insight", + "DisplayName" : "Insight", "Name" : "Insight", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/ios/Ios.json.in b/src/plugins/ios/Ios.json.in index 63ff3c1669e..981aa47a59b 100644 --- a/src/plugins/ios/Ios.json.in +++ b/src/plugins/ios/Ios.json.in @@ -1,5 +1,6 @@ { "Id" : "ios", + "DisplayName" : "iOS", "Name" : "Ios", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/languageclient/LanguageClient.json.in b/src/plugins/languageclient/LanguageClient.json.in index 7203b4991ca..db6c43ae697 100644 --- a/src/plugins/languageclient/LanguageClient.json.in +++ b/src/plugins/languageclient/LanguageClient.json.in @@ -1,5 +1,6 @@ { "Id" : "languageclient", + "DisplayName" : "Language Client", "Name" : "LanguageClient", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/languageclient/lualanguageclient/LuaLanguageClient.json.in b/src/plugins/languageclient/lualanguageclient/LuaLanguageClient.json.in index 4c5f2cd47da..c40f821a572 100644 --- a/src/plugins/languageclient/lualanguageclient/LuaLanguageClient.json.in +++ b/src/plugins/languageclient/lualanguageclient/LuaLanguageClient.json.in @@ -1,5 +1,6 @@ { "Id" : "lualanguageclient", + "DisplayName" : "Lua Language Client", "Name" : "LuaLanguageClient", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/lua/Lua.json.in b/src/plugins/lua/Lua.json.in index 7d8cf80f54b..e4c1fac2d49 100644 --- a/src/plugins/lua/Lua.json.in +++ b/src/plugins/lua/Lua.json.in @@ -1,5 +1,6 @@ { "Id" : "lua", + "DisplayName" : "Lua", "Name" : "Lua", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/macros/Macros.json.in b/src/plugins/macros/Macros.json.in index 03b8b64ece1..4e47a804fae 100644 --- a/src/plugins/macros/Macros.json.in +++ b/src/plugins/macros/Macros.json.in @@ -1,5 +1,6 @@ { "Id" : "macros", + "DisplayName" : "Macros", "Name" : "Macros", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/marketplace/Marketplace.json.in b/src/plugins/marketplace/Marketplace.json.in index 087410eeb2e..8a41da400da 100644 --- a/src/plugins/marketplace/Marketplace.json.in +++ b/src/plugins/marketplace/Marketplace.json.in @@ -1,5 +1,6 @@ { "Id" : "marketplace", + "DisplayName" : "Qt Marketplace", "Name" : "Marketplace", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/mcusupport/McuSupport.json.in b/src/plugins/mcusupport/McuSupport.json.in index 6058a4301aa..8e6c2a29824 100644 --- a/src/plugins/mcusupport/McuSupport.json.in +++ b/src/plugins/mcusupport/McuSupport.json.in @@ -1,5 +1,6 @@ { "Id" : "mcusupport", + "DisplayName" : "Qt for MCUs", "Name" : "McuSupport", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/mercurial/Mercurial.json.in b/src/plugins/mercurial/Mercurial.json.in index 86972f7fb5f..d8125d77ba2 100644 --- a/src/plugins/mercurial/Mercurial.json.in +++ b/src/plugins/mercurial/Mercurial.json.in @@ -1,5 +1,6 @@ { "Id" : "mercurial", + "DisplayName" : "Mercurial", "Name" : "Mercurial", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/mesonprojectmanager/MesonProjectManager.json.in b/src/plugins/mesonprojectmanager/MesonProjectManager.json.in index 6aa737741c7..dd20b1b6fc3 100644 --- a/src/plugins/mesonprojectmanager/MesonProjectManager.json.in +++ b/src/plugins/mesonprojectmanager/MesonProjectManager.json.in @@ -1,5 +1,6 @@ { "Id" : "mesonprojectmanager", + "DisplayName" : "Meson", "Name" : "MesonProjectManager", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/modeleditor/ModelEditor.json.in b/src/plugins/modeleditor/ModelEditor.json.in index a9616c0911a..8ebcf4cd5a2 100644 --- a/src/plugins/modeleditor/ModelEditor.json.in +++ b/src/plugins/modeleditor/ModelEditor.json.in @@ -1,5 +1,6 @@ { "Id" : "modeleditor", + "DisplayName" : "Model Editor", "Name" : "ModelEditor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/nim/Nim.json.in b/src/plugins/nim/Nim.json.in index 2978b848172..086d0cf02b6 100644 --- a/src/plugins/nim/Nim.json.in +++ b/src/plugins/nim/Nim.json.in @@ -1,5 +1,6 @@ { "Id" : "nim", + "DisplayName" : "Nim", "Name" : "Nim", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/perforce/Perforce.json.in b/src/plugins/perforce/Perforce.json.in index 076fcd377be..78ae0d81409 100644 --- a/src/plugins/perforce/Perforce.json.in +++ b/src/plugins/perforce/Perforce.json.in @@ -1,5 +1,6 @@ { "Id" : "perforce", + "DisplayName" : "Perforce", "Name" : "Perforce", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/perfprofiler/PerfProfiler.json.in b/src/plugins/perfprofiler/PerfProfiler.json.in index 4b16ad20dee..cb1d5d897a8 100644 --- a/src/plugins/perfprofiler/PerfProfiler.json.in +++ b/src/plugins/perfprofiler/PerfProfiler.json.in @@ -1,5 +1,6 @@ { "Id" : "perfprofiler", + "DisplayName" : "Perf Profiler", "Name" : "PerfProfiler", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/projectexplorer/ProjectExplorer.json.in b/src/plugins/projectexplorer/ProjectExplorer.json.in index f8325ef5598..7e8d2a8f253 100644 --- a/src/plugins/projectexplorer/ProjectExplorer.json.in +++ b/src/plugins/projectexplorer/ProjectExplorer.json.in @@ -1,5 +1,6 @@ { "Id" : "projectexplorer", + "DisplayName" : "Project Explorer", "Name" : "ProjectExplorer", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/python/Python.json.in b/src/plugins/python/Python.json.in index 830abffde38..3b48fccca11 100644 --- a/src/plugins/python/Python.json.in +++ b/src/plugins/python/Python.json.in @@ -1,5 +1,6 @@ { "Id" : "python", + "DisplayName" : "Python", "Name" : "Python", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qbsprojectmanager/QbsProjectManager.json.in b/src/plugins/qbsprojectmanager/QbsProjectManager.json.in index ab22e19641c..a4b8ae1892c 100644 --- a/src/plugins/qbsprojectmanager/QbsProjectManager.json.in +++ b/src/plugins/qbsprojectmanager/QbsProjectManager.json.in @@ -1,5 +1,6 @@ { "Id" : "qbsprojectmanager", + "DisplayName" : "Qbs", "Name" : "QbsProjectManager", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qmakeprojectmanager/QmakeProjectManager.json.in b/src/plugins/qmakeprojectmanager/QmakeProjectManager.json.in index 831dd1ac059..86452c8c27d 100644 --- a/src/plugins/qmakeprojectmanager/QmakeProjectManager.json.in +++ b/src/plugins/qmakeprojectmanager/QmakeProjectManager.json.in @@ -1,5 +1,6 @@ { "Id" : "qmakeprojectmanager", + "DisplayName" : "qmake", "Name" : "QmakeProjectManager", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qmldesigner/QmlDesigner.json.in b/src/plugins/qmldesigner/QmlDesigner.json.in index a1ecd958cee..97d96ebfc4a 100644 --- a/src/plugins/qmldesigner/QmlDesigner.json.in +++ b/src/plugins/qmldesigner/QmlDesigner.json.in @@ -1,5 +1,6 @@ { "Id" : "qmldesigner", + "DisplayName" : "Qt Quick Designer", "Name" : "QmlDesigner", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qmldesignerbase/QmlDesignerBase.json.in b/src/plugins/qmldesignerbase/QmlDesignerBase.json.in index acdebf57376..78c3416a472 100644 --- a/src/plugins/qmldesignerbase/QmlDesignerBase.json.in +++ b/src/plugins/qmldesignerbase/QmlDesignerBase.json.in @@ -1,5 +1,6 @@ { "Id" : "qmldesignerbase", + "DisplayName" : "Qt Quick Designer Base", "Name" : "QmlDesignerBase", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qmldesignerlite/QmlDesignerLite.json.in b/src/plugins/qmldesignerlite/QmlDesignerLite.json.in index 098fa19e59d..b8aeccc166a 100644 --- a/src/plugins/qmldesignerlite/QmlDesignerLite.json.in +++ b/src/plugins/qmldesignerlite/QmlDesignerLite.json.in @@ -1,5 +1,6 @@ { "Id" : "qmldesignerlite", + "DisplayName" : "Qt Quick Designer Lite", "Name" : "QmlDesignerLite", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qmljseditor/QmlJSEditor.json.in b/src/plugins/qmljseditor/QmlJSEditor.json.in index cc49f04b9d7..3f4dfbd9c06 100644 --- a/src/plugins/qmljseditor/QmlJSEditor.json.in +++ b/src/plugins/qmljseditor/QmlJSEditor.json.in @@ -1,5 +1,6 @@ { "Id" : "qmljseditor", + "DisplayName" : "QML/JS Editor", "Name" : "QmlJSEditor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qmljstools/QmlJSTools.json.in b/src/plugins/qmljstools/QmlJSTools.json.in index c784f720d9b..482ae8a98f1 100644 --- a/src/plugins/qmljstools/QmlJSTools.json.in +++ b/src/plugins/qmljstools/QmlJSTools.json.in @@ -1,5 +1,6 @@ { "Id" : "qmljstools", + "DisplayName" : "QML Tools", "Name" : "QmlJSTools", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qmlpreview/QmlPreview.json.in b/src/plugins/qmlpreview/QmlPreview.json.in index b1b05773fdb..c9e5abb78ad 100644 --- a/src/plugins/qmlpreview/QmlPreview.json.in +++ b/src/plugins/qmlpreview/QmlPreview.json.in @@ -1,5 +1,6 @@ { "Id" : "qmlpreview", + "DisplayName" : "QML Preview", "Name" : "QmlPreview", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qmlprofiler/QmlProfiler.json.in b/src/plugins/qmlprofiler/QmlProfiler.json.in index c03f0d4db5b..e043cd57715 100644 --- a/src/plugins/qmlprofiler/QmlProfiler.json.in +++ b/src/plugins/qmlprofiler/QmlProfiler.json.in @@ -1,5 +1,6 @@ { "Id" : "qmlprofiler", + "DisplayName" : "QML Profiler", "Name" : "QmlProfiler", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qmlprojectmanager/QmlProjectManager.json.in b/src/plugins/qmlprojectmanager/QmlProjectManager.json.in index b2e3f8ca7cc..9eed3287894 100644 --- a/src/plugins/qmlprojectmanager/QmlProjectManager.json.in +++ b/src/plugins/qmlprojectmanager/QmlProjectManager.json.in @@ -1,5 +1,6 @@ { "Id" : "qmlprojectmanager", + "DisplayName" : "QML Project Manager", "Name" : "QmlProjectManager", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qnx/Qnx.json.in b/src/plugins/qnx/Qnx.json.in index 6b52873b8a9..2343e342e11 100644 --- a/src/plugins/qnx/Qnx.json.in +++ b/src/plugins/qnx/Qnx.json.in @@ -1,5 +1,6 @@ { "Id" : "qnx", + "DisplayName" : "QNX", "Name" : "Qnx", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qtapplicationmanager/QtApplicationManagerIntegration.json.in b/src/plugins/qtapplicationmanager/QtApplicationManagerIntegration.json.in index b4b1cbe50aa..3bf2de71880 100644 --- a/src/plugins/qtapplicationmanager/QtApplicationManagerIntegration.json.in +++ b/src/plugins/qtapplicationmanager/QtApplicationManagerIntegration.json.in @@ -1,5 +1,6 @@ { "Id" : "qtapplicationmanagerintegration", + "DisplayName" : "Qt Application Manager", "Name" : "QtApplicationManagerIntegration", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/qtsupport/QtSupport.json.in b/src/plugins/qtsupport/QtSupport.json.in index 23a4c6559ad..fb1571c3302 100644 --- a/src/plugins/qtsupport/QtSupport.json.in +++ b/src/plugins/qtsupport/QtSupport.json.in @@ -1,5 +1,6 @@ { "Id" : "qtsupport", + "DisplayName" : "Qt Support", "Name" : "QtSupport", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/remotelinux/RemoteLinux.json.in b/src/plugins/remotelinux/RemoteLinux.json.in index eae3624065c..814b65a59c1 100644 --- a/src/plugins/remotelinux/RemoteLinux.json.in +++ b/src/plugins/remotelinux/RemoteLinux.json.in @@ -1,5 +1,6 @@ { "Id" : "remotelinux", + "DisplayName" : "Remote Linux", "Name" : "RemoteLinux", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/resourceeditor/ResourceEditor.json.in b/src/plugins/resourceeditor/ResourceEditor.json.in index d998c3454ca..566d69508e5 100644 --- a/src/plugins/resourceeditor/ResourceEditor.json.in +++ b/src/plugins/resourceeditor/ResourceEditor.json.in @@ -1,5 +1,6 @@ { "Id" : "resourceeditor", + "DisplayName" : "Resource Editor", "Name" : "ResourceEditor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/saferenderer/SafeRenderer.json.in b/src/plugins/saferenderer/SafeRenderer.json.in index 262783ba6fe..a6fe783ca4f 100644 --- a/src/plugins/saferenderer/SafeRenderer.json.in +++ b/src/plugins/saferenderer/SafeRenderer.json.in @@ -1,5 +1,6 @@ { "Id" : "saferenderer", + "DisplayName" : "Qt Safe Renderer", "Name" : "SafeRenderer", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/screenrecorder/ScreenRecorder.json.in b/src/plugins/screenrecorder/ScreenRecorder.json.in index a5ec9ad1107..f96ee97d7b9 100644 --- a/src/plugins/screenrecorder/ScreenRecorder.json.in +++ b/src/plugins/screenrecorder/ScreenRecorder.json.in @@ -1,5 +1,6 @@ { "Id" : "screenrecorder", + "DisplayName" : "Screen Recorder", "Name" : "ScreenRecorder", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/scxmleditor/ScxmlEditor.json.in b/src/plugins/scxmleditor/ScxmlEditor.json.in index bb8d206c312..1ddb13b56d2 100644 --- a/src/plugins/scxmleditor/ScxmlEditor.json.in +++ b/src/plugins/scxmleditor/ScxmlEditor.json.in @@ -1,5 +1,6 @@ { "Id" : "scxmleditor", + "DisplayName" : "SCXML Editor", "Name" : "ScxmlEditor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/serialterminal/SerialTerminal.json.in b/src/plugins/serialterminal/SerialTerminal.json.in index 3144f2ce925..832803e9db9 100644 --- a/src/plugins/serialterminal/SerialTerminal.json.in +++ b/src/plugins/serialterminal/SerialTerminal.json.in @@ -1,5 +1,6 @@ { "Id" : "serialterminal", + "DisplayName" : "Serial Terminal", "Name" : "SerialTerminal", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/silversearcher/SilverSearcher.json.in b/src/plugins/silversearcher/SilverSearcher.json.in index 912bc0260f7..b442660060e 100644 --- a/src/plugins/silversearcher/SilverSearcher.json.in +++ b/src/plugins/silversearcher/SilverSearcher.json.in @@ -1,5 +1,6 @@ { "Id" : "silversearcher", + "DisplayName" : "Silver Searcher", "Name" : "SilverSearcher", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/squish/Squish.json.in b/src/plugins/squish/Squish.json.in index 192ced53b99..75fbdbe5c6f 100644 --- a/src/plugins/squish/Squish.json.in +++ b/src/plugins/squish/Squish.json.in @@ -1,5 +1,6 @@ { "Id" : "squish", + "DisplayName" : "Squish", "Name" : "Squish", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/studiowelcome/StudioWelcome.json.in b/src/plugins/studiowelcome/StudioWelcome.json.in index a0ab57a0810..3000469ed83 100644 --- a/src/plugins/studiowelcome/StudioWelcome.json.in +++ b/src/plugins/studiowelcome/StudioWelcome.json.in @@ -1,5 +1,6 @@ { "Id" : "studiowelcome", + "DisplayName" : "Qt Design Studio Welcome", "Name" : "StudioWelcome", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/subversion/Subversion.json.in b/src/plugins/subversion/Subversion.json.in index b94c0ca94e0..1941eb222c4 100644 --- a/src/plugins/subversion/Subversion.json.in +++ b/src/plugins/subversion/Subversion.json.in @@ -1,5 +1,6 @@ { "Id" : "subversion", + "DisplayName" : "Subversion", "Name" : "Subversion", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/terminal/Terminal.json.in b/src/plugins/terminal/Terminal.json.in index bce8751a912..bb9ec85fea7 100644 --- a/src/plugins/terminal/Terminal.json.in +++ b/src/plugins/terminal/Terminal.json.in @@ -1,5 +1,6 @@ { "Id" : "terminal", + "DisplayName" : "Terminal", "Name" : "Terminal", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/texteditor/TextEditor.json.in b/src/plugins/texteditor/TextEditor.json.in index 3da549f27b6..a5558b5864b 100644 --- a/src/plugins/texteditor/TextEditor.json.in +++ b/src/plugins/texteditor/TextEditor.json.in @@ -1,5 +1,6 @@ { "Id" : "texteditor", + "DisplayName" : "Text Editor", "Name" : "TextEditor", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/todo/Todo.json.in b/src/plugins/todo/Todo.json.in index 2e011dccf4a..72870191189 100644 --- a/src/plugins/todo/Todo.json.in +++ b/src/plugins/todo/Todo.json.in @@ -1,5 +1,6 @@ { "Id" : "todo", + "DisplayName" : "To Do", "Name" : "Todo", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/updateinfo/UpdateInfo.json.in b/src/plugins/updateinfo/UpdateInfo.json.in index c29b60b6c31..c4be9b44f4f 100644 --- a/src/plugins/updateinfo/UpdateInfo.json.in +++ b/src/plugins/updateinfo/UpdateInfo.json.in @@ -1,5 +1,6 @@ { "Id" : "updateinfo", + "DisplayName" : "Update Info", "Name" : "UpdateInfo", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/valgrind/Valgrind.json.in b/src/plugins/valgrind/Valgrind.json.in index 11d2401cff4..8dd588afc15 100644 --- a/src/plugins/valgrind/Valgrind.json.in +++ b/src/plugins/valgrind/Valgrind.json.in @@ -1,5 +1,6 @@ { "Id" : "valgrind", + "DisplayName" : "Valgrind", "Name" : "Valgrind", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/vcpkg/Vcpkg.json.in b/src/plugins/vcpkg/Vcpkg.json.in index 55d26f233dc..ca1bf3c02ae 100644 --- a/src/plugins/vcpkg/Vcpkg.json.in +++ b/src/plugins/vcpkg/Vcpkg.json.in @@ -1,5 +1,6 @@ { "Id" : "vcpkg", + "DisplayName" : "Vcpkg", "Name" : "Vcpkg", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/vcsbase/VcsBase.json.in b/src/plugins/vcsbase/VcsBase.json.in index c1461a30b88..9d024c506a3 100644 --- a/src/plugins/vcsbase/VcsBase.json.in +++ b/src/plugins/vcsbase/VcsBase.json.in @@ -1,5 +1,6 @@ { "Id" : "vcsbase", + "DisplayName" : "Version Control Systems", "Name" : "VcsBase", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/webassembly/WebAssembly.json.in b/src/plugins/webassembly/WebAssembly.json.in index cc8d732a1b2..7eb012c691e 100644 --- a/src/plugins/webassembly/WebAssembly.json.in +++ b/src/plugins/webassembly/WebAssembly.json.in @@ -1,5 +1,6 @@ { "Id" : "webassembly", + "DisplayName" : "WebAssembly", "Name" : "WebAssembly", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", diff --git a/src/plugins/welcome/Welcome.json.in b/src/plugins/welcome/Welcome.json.in index 1e8c7f79697..5924d07cbee 100644 --- a/src/plugins/welcome/Welcome.json.in +++ b/src/plugins/welcome/Welcome.json.in @@ -1,5 +1,6 @@ { "Id" : "welcome", + "DisplayName" : "Welcome", "Name" : "Welcome", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", From 17f864979ce7d9e9ce0b9aacfddb0eb703363c1c Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 19 Nov 2024 14:30:49 +0100 Subject: [PATCH 192/989] Android: Adjust to changes in Qt 6.9 Qt 6.9 changes the format of the module JSON files. Adjust to those changes, and make sure that we still can read the old format. Fixes: QTCREATORBUG-32000 Change-Id: Iefe545521bebb25dbdd4bbb2083813c97059e6b2 Reviewed-by: Alessandro Portale --- src/plugins/android/androidqtversion.cpp | 78 ++++++++++++++++++++++-- src/plugins/android/androidqtversion.h | 3 +- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index 411a640fd87..2c932ad42c1 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -29,6 +29,7 @@ #include +#include #include #include #include @@ -158,7 +159,7 @@ AndroidQtVersion::BuiltWith AndroidQtVersion::builtWith(bool *ok) const if (coreModuleJson.exists()) { Utils::FileReader reader; if (reader.fetch(coreModuleJson)) - return parseBuiltWith(reader.data(), ok); + return parseModulesCoreJson(reader.data(), ok); } if (ok) @@ -175,12 +176,10 @@ static int versionFromPlatformString(const QString &string, bool *ok = nullptr) return match.hasMatch() ? match.captured(1).toInt(ok) : -1; } -AndroidQtVersion::BuiltWith AndroidQtVersion::parseBuiltWith(const QByteArray &modulesCoreJsonData, - bool *ok) +static AndroidQtVersion::BuiltWith parseBuiltWith(const QJsonObject &jsonObject, bool *ok) { bool validPlatformString = false; AndroidQtVersion::BuiltWith result; - const QJsonObject jsonObject = QJsonDocument::fromJson(modulesCoreJsonData).object(); if (const QJsonValue builtWith = jsonObject.value("built_with"); !builtWith.isUndefined()) { if (const QJsonValue android = builtWith["android"]; !android.isUndefined()) { if (const QJsonValue apiVersion = android["api_version"]; !apiVersion.isUndefined()) { @@ -201,6 +200,48 @@ AndroidQtVersion::BuiltWith AndroidQtVersion::parseBuiltWith(const QByteArray &m return result; } +static AndroidQtVersion::BuiltWith parsePlatforms(const QJsonObject &jsonObject, bool *ok) +{ + AndroidQtVersion::BuiltWith result; + if (ok) + *ok = false; + for (const QJsonValue &platformValue : jsonObject.value("platforms").toArray()) { + const QJsonObject platform = platformValue.toObject(); + if (platform.value("name").toString() != QLatin1String("Android")) + continue; + for (const QJsonValue &targetsValue : platform.value("targets").toArray()) { + const QJsonObject target = targetsValue.toObject(); + const QString apiVersionString = target.value("api_version").toString(); + if (apiVersionString.isNull()) + return {}; + bool apiVersionOK = false; + result.apiVersion = versionFromPlatformString(apiVersionString, &apiVersionOK); + if (!apiVersionOK) + return {}; + const QString ndkVersionString = target.value("ndk_version").toString(); + if (ndkVersionString.isNull()) + return {}; + result.ndkVersion = QVersionNumber::fromString(ndkVersionString); + break; + } + } + if (ok) + *ok = true; + return result; +} + +AndroidQtVersion::BuiltWith AndroidQtVersion::parseModulesCoreJson(const QByteArray &data, bool *ok) +{ + AndroidQtVersion::BuiltWith result; + const QJsonObject jsonObject = QJsonDocument::fromJson(data).object(); + const int schemaVersion = jsonObject.value("schema_version").toInt(1); + if (schemaVersion >= 2) + result = parsePlatforms(jsonObject, ok); + else + result = parseBuiltWith(jsonObject, ok); + return result; +} + void AndroidQtVersion::parseMkSpec(ProFileEvaluator *evaluator) const { m_androidAbis = evaluator->values("ALL_ANDROID_ABIS"); @@ -306,6 +347,33 @@ void AndroidQtVersionTest::testAndroidQtVersionParseBuiltWith_data() << true << QVersionNumber(25, 1, 8937393) << 31; + + QTest::newRow("Android Qt 6.9") + << R"({ + "schema_version": 2, + "name": "Core", + "repository": "qtbase", + "version": "6.9.0", + "platforms": [ + { + "name": "Android", + "version": "1", + "compiler_id": "Clang", + "compiler_version": "17.0.2", + "targets": [ + { + "api_version": "android-34", + "ndk_version": "26.1.10909125", + "architecture": "arm", + "abi": "arm-little_endian-ilp32-eabi" + } + ] + } + ] + })" + << true + << QVersionNumber(26, 1, 10909125) + << 34; } void AndroidQtVersionTest::testAndroidQtVersionParseBuiltWith() @@ -317,7 +385,7 @@ void AndroidQtVersionTest::testAndroidQtVersionParseBuiltWith() bool ok = false; const AndroidQtVersion::BuiltWith bw = - AndroidQtVersion::parseBuiltWith(modulesCoreJson.toUtf8(), &ok); + AndroidQtVersion::parseModulesCoreJson(modulesCoreJson.toUtf8(), &ok); QCOMPARE(ok, hasInfo); QCOMPARE(bw.apiVersion, apiVersion); QCOMPARE(bw.ndkVersion, ndkVersion); diff --git a/src/plugins/android/androidqtversion.h b/src/plugins/android/androidqtversion.h index 14ec91d3fca..ceddb76520f 100644 --- a/src/plugins/android/androidqtversion.h +++ b/src/plugins/android/androidqtversion.h @@ -35,7 +35,8 @@ public: int apiVersion = -1; QVersionNumber ndkVersion; }; - static BuiltWith parseBuiltWith(const QByteArray &modulesCoreJsonData, bool *ok = nullptr); + static BuiltWith parseModulesCoreJson(const QByteArray &modulesCoreJsonData, + bool *ok = nullptr); BuiltWith builtWith(bool *ok = nullptr) const; bool isAndroidQtVersion() const override { return true; }; From 6df814b47221611913c4090b9a3ca516272bb656 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 15 Nov 2024 16:39:54 +0100 Subject: [PATCH 193/989] Debugger: Avoid a warning in a manual test Change-Id: I54b34434384e0decde28a4f7e1decdd51b8871c1 Reviewed-by: Christian Stenger --- tests/manual/debugger/simple/simple_test_plugin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/manual/debugger/simple/simple_test_plugin.cpp b/tests/manual/debugger/simple/simple_test_plugin.cpp index b4862208a05..e5115f7c1f6 100644 --- a/tests/manual/debugger/simple/simple_test_plugin.cpp +++ b/tests/manual/debugger/simple/simple_test_plugin.cpp @@ -9,6 +9,7 @@ public: Something() { int i = 0; ++i; + Q_UNUSED(i) return; } }; From d3102b23ff3b13e46bb27e5a71c2af16a1a73cdd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 19 Nov 2024 15:23:45 +0100 Subject: [PATCH 194/989] IosRunner: Remove unused local variables Amends e66ae4ac76c6caf995a29d9b98fe7323dec648a4 Change-Id: I1e81e4bc2d940bd04efe138cbaa542ed82a3a177 Reviewed-by: hjk --- src/plugins/ios/iosrunner.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index 9172fcc07c9..b10142d753e 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -725,16 +725,12 @@ IosQmlProfilerSupport::IosQmlProfilerSupport(RunControl *runControl) void IosQmlProfilerSupport::start() { - QUrl serverUrl; QTcpServer server; const bool isListening = server.listen(QHostAddress::LocalHost) || server.listen(QHostAddress::LocalHostIPv6); QTC_ASSERT(isListening, return); - serverUrl.setScheme(Utils::urlTcpScheme()); - serverUrl.setHost(server.serverAddress().toString()); - Port qmlPort = m_runner->qmlServerPort(); - serverUrl.setPort(qmlPort.number()); + const Port qmlPort = m_runner->qmlServerPort(); if (qmlPort.isValid()) reportStarted(); else From c231639a3591e73b0e8e4a921e3f29d8b1c47943 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 11 Nov 2024 12:47:35 +0100 Subject: [PATCH 195/989] LanguageClient: render hint and info diagnostics differently Currently hint and information diagnostics are rendered as warnings. Add and use a new color for those type of diagnostics. Fixes: QTCREATORBUG-31878 Change-Id: I2fdd01213b32bd5dc433b925a1a44c0db480f422 Reviewed-by: Alessandro Portale --- share/qtcreator/themes/2024.tokenmapping | 1 + share/qtcreator/themes/dark.creatortheme | 2 ++ share/qtcreator/themes/default.creatortheme | 2 ++ .../themes/design-light.creatortheme | 2 ++ share/qtcreator/themes/design.creatortheme | 2 ++ share/qtcreator/themes/flat-dark.creatortheme | 2 ++ .../qtcreator/themes/flat-light.creatortheme | 2 ++ share/qtcreator/themes/flat.creatortheme | 2 ++ src/libs/utils/theme/theme.h | 1 + .../languageclient/diagnosticmanager.cpp | 35 +++++++++++++------ 10 files changed, 40 insertions(+), 11 deletions(-) diff --git a/share/qtcreator/themes/2024.tokenmapping b/share/qtcreator/themes/2024.tokenmapping index 3c7636e3234..ab1d4a9ba7b 100644 --- a/share/qtcreator/themes/2024.tokenmapping +++ b/share/qtcreator/themes/2024.tokenmapping @@ -11,6 +11,7 @@ BadgeLabelTextColorChecked=Token_Text_Default BadgeLabelTextColorUnchecked=Token_Text_Default CodeModel_Error_TextMarkColor=error CodeModel_Warning_TextMarkColor=warning +CodeModel_Info_TextMarkColor=info ComboBoxTextColor=Token_Text_Muted DockWidgetResizeHandleColor=Token_Stroke_Subtle EditorPlaceholderColor=Token_Background_Muted diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index c5834e3e104..e12a4d893c3 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -16,6 +16,7 @@ normalBackground=ff333333 alternateBackground=ff515151 error=ffd84044 warning=ffe0b716 +info=ff1f75cc splitterColor=ff313131 textColorLink=ff8ab4f8 textColorLinkVisited=ffc58af9 @@ -406,6 +407,7 @@ ProjectExplorer_TaskWarn_TextMarkColor=warning CodeModel_Error_TextMarkColor=error CodeModel_Warning_TextMarkColor=warning +CodeModel_Info_TextMarkColor=info PaletteWindow=normalBackground PaletteWindowText=text diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 28200acfd7a..f822eaa287a 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -10,6 +10,7 @@ textDisabled=88a0a0a0 toolBarItem=ffdcdcdc error=ffdf4f4f warning=ffecbc1c +info=ff4f8fff shadowBackground=ff232323 splitterColor=ff151515 qmlDesignerButtonColor=ff4c4e50 @@ -399,6 +400,7 @@ ProjectExplorer_TaskWarn_TextMarkColor=warning CodeModel_Error_TextMarkColor=error CodeModel_Warning_TextMarkColor=warning +CodeModel_Info_TextMarkColor=info QmlDesigner_BackgroundColor=qmlDesignerButtonColor QmlDesigner_HighlightColor=ff46a2da diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme index 2b741ddc061..c1ea7e6fb57 100644 --- a/share/qtcreator/themes/design-light.creatortheme +++ b/share/qtcreator/themes/design-light.creatortheme @@ -20,6 +20,7 @@ stop_error=ffec7373 run_success=ff52c23b error=ffdf4f4f warning=ffecbc1c +info=ff4f9df8 splitter=ffbdbebf qmlDesignerButtonColor=fff8f8f8 textColorLink=ff007af4 @@ -410,6 +411,7 @@ ProjectExplorer_TaskWarn_TextMarkColor=warning CodeModel_Error_TextMarkColor=error CodeModel_Warning_TextMarkColor=warning +CodeModel_Info_TextMarkColor=info ;new colors QmlDesigner_BackgroundColor=qmlDesignerButtonColor diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme index 6b438645bd3..eae2107700e 100644 --- a/share/qtcreator/themes/design.creatortheme +++ b/share/qtcreator/themes/design.creatortheme @@ -19,6 +19,7 @@ normalBackground=ff262728 alternateBackground=ff353637 error=ffdf4f4f warning=ffecbc1c +info=ff4f8fff splitter=ff474747 textColorLink=ff007af4 textColorLinkVisited=ffa57aff @@ -414,6 +415,7 @@ ProjectExplorer_TaskWarn_TextMarkColor=warning CodeModel_Error_TextMarkColor=error CodeModel_Warning_TextMarkColor=warning +CodeModel_Info_TextMarkColor=info ;Designer Main colors diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index 3a6e8fa6b05..100a5e8c74c 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -20,6 +20,7 @@ normalBackground=ff2E2F30 alternateBackground=ff353637 error=ffdf4f4f warning=ffecbc1c +info=ff4f8fff splitter=ff06080A textColorLink=ff007af4 textColorLinkVisited=ffa57aff @@ -410,6 +411,7 @@ ProjectExplorer_TaskWarn_TextMarkColor=warning CodeModel_Error_TextMarkColor=error CodeModel_Warning_TextMarkColor=warning +CodeModel_Info_TextMarkColor=info QmlDesigner_BackgroundColor=qmlDesignerButtonColor QmlDesigner_HighlightColor=ff1d545c diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index df98e8b31e5..7d39156e23a 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -20,6 +20,7 @@ run_success=ff52c23b splitter=ffbdbebf error=ffdf4f4f warning=ffecbc1c +info=ff4f8df0 textColorLink=PaletteLink textColorLinkVisited=PaletteLinkVisited backgroundColorDisabled=PaletteWindowDisabled @@ -410,6 +411,7 @@ ProjectExplorer_TaskWarn_TextMarkColor=warning CodeModel_Error_TextMarkColor=error CodeModel_Warning_TextMarkColor=warning +CodeModel_Info_TextMarkColor=info QmlDesigner_BackgroundColor=qmlDesignerButtonColor QmlDesigner_HighlightColor=ff46a2da diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index 4b89f096101..9e9d14e7fd0 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -17,6 +17,7 @@ normalBackground=PaletteWindow alternateBackground=PaletteAlternateBase error=ffdf4f4f warning=ffecbc1c +info=ff4f83f1 splitter=ff313131 textColorLink=PaletteLink textColorLinkVisited=PaletteLinkVisited @@ -407,6 +408,7 @@ ProjectExplorer_TaskWarn_TextMarkColor=warning CodeModel_Error_TextMarkColor=error CodeModel_Warning_TextMarkColor=warning +CodeModel_Info_TextMarkColor=info QmlDesigner_BackgroundColor=qmlDesignerButtonColor QmlDesigner_HighlightColor=ff46a2da diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 9540324154d..4f3f167b065 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -171,6 +171,7 @@ public: CodeModel_Error_TextMarkColor, CodeModel_Warning_TextMarkColor, + CodeModel_Info_TextMarkColor, /* Output panes */ diff --git a/src/plugins/languageclient/diagnosticmanager.cpp b/src/plugins/languageclient/diagnosticmanager.cpp index c437a9f1be6..d584f83134d 100644 --- a/src/plugins/languageclient/diagnosticmanager.cpp +++ b/src/plugins/languageclient/diagnosticmanager.cpp @@ -39,13 +39,19 @@ public: { setLineAnnotation(diag.message()); setToolTip(diag.message()); - const bool isError - = diag.severity().value_or(DiagnosticSeverity::Hint) == DiagnosticSeverity::Error; - setColor(isError ? Theme::CodeModel_Error_TextMarkColor - : Theme::CodeModel_Warning_TextMarkColor); - - setIcon(isError ? Icons::CODEMODEL_ERROR.icon() - : Icons::CODEMODEL_WARNING.icon()); + switch (diag.severity().value_or(DiagnosticSeverity::Hint)) { + case DiagnosticSeverity::Error: + setColor(Theme::CodeModel_Error_TextMarkColor); + setIcon(Icons::CODEMODEL_ERROR.icon()); + break; + case DiagnosticSeverity::Warning: + setColor(Theme::CodeModel_Warning_TextMarkColor); + setIcon(Icons::CODEMODEL_WARNING.icon()); + break; + default: + setColor(Theme::CodeModel_Info_TextMarkColor); + break; + } } }; @@ -257,16 +263,23 @@ void DiagnosticManager::setForceCreateTasks(bool forceCreateTasks) QTextEdit::ExtraSelection DiagnosticManager::createDiagnosticSelection( const LanguageServerProtocol::Diagnostic &diagnostic, QTextDocument *textDocument) const { + const DiagnosticSeverity severity = diagnostic.severity().value_or(DiagnosticSeverity::Warning); + TextStyle style; + if (severity == DiagnosticSeverity::Error) + style = C_ERROR; + else if (severity == DiagnosticSeverity::Warning) + style = C_ERROR; + else + return {}; + QTextCursor cursor(textDocument); cursor.setPosition(diagnostic.range().start().toPositionInDocument(textDocument)); cursor.setPosition(diagnostic.range().end().toPositionInDocument(textDocument), QTextCursor::KeepAnchor); - const FontSettings &fontSettings = TextEditorSettings::fontSettings(); - const DiagnosticSeverity severity = diagnostic.severity().value_or(DiagnosticSeverity::Warning); - const TextStyle style = severity == DiagnosticSeverity::Error ? C_ERROR : C_WARNING; + const QTextCharFormat format = TextEditorSettings::fontSettings().toTextCharFormat(style); - return QTextEdit::ExtraSelection{cursor, fontSettings.toTextCharFormat(style)}; + return QTextEdit::ExtraSelection{cursor, format}; } void DiagnosticManager::setExtraSelectionsId(const Utils::Id &extraSelectionsId) From e6592acb5281b2afa5dfe694475075bbdb0dad43 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 18 Nov 2024 10:41:57 +0100 Subject: [PATCH 196/989] LanguageClient: Export function to restart clients for a setting Fixes: QTCREATORBUG-32015 Change-Id: I03d7e78c710a490a19a4e743389868d24ebeae84 Reviewed-by: Sami Shalayel --- .../languageclient/languageclientmanager.cpp | 120 +++++++++--------- .../languageclient/languageclientmanager.h | 1 + 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 857162903bf..5cecf79a411 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -294,74 +294,78 @@ void LanguageClientManager::applySettings() const QList restarts = LanguageClientSettings::changedSettings(); LanguageClientSettings::toSettings(Core::ICore::settings(), managerInstance->m_currentSettings); - for (BaseSettings *setting : restarts) { - QList documents; - const QList currentClients = clientsForSetting(setting); - for (Client *client : currentClients) { - documents << managerInstance->m_clientForDocument.keys(client); - shutdownClient(client); + for (BaseSettings *settings : restarts) + applySettings(settings); +} + +void LanguageClientManager::applySettings(BaseSettings *setting) +{ + QList documents; + const QList currentClients = clientsForSetting(setting); + for (Client *client : currentClients) { + documents << managerInstance->m_clientForDocument.keys(client); + shutdownClient(client); + } + for (auto document : std::as_const(documents)) + managerInstance->m_clientForDocument.remove(document); + if (!setting->isValid() || !setting->m_enabled) + return; + switch (setting->m_startBehavior) { + case BaseSettings::AlwaysOn: { + Client *client = startClient(setting); + for (TextEditor::TextDocument *document : std::as_const(documents)) + managerInstance->m_clientForDocument[document] = client; + break; + } + case BaseSettings::RequiresFile: { + Client *client = nullptr; + for (TextEditor::TextDocument *previousDocument : std::as_const(documents)) { + if (setting->m_languageFilter.isSupported(previousDocument)) { + if (!client) + client = startClient(setting); + openDocumentWithClient(previousDocument, client); + } } - for (auto document : std::as_const(documents)) - managerInstance->m_clientForDocument.remove(document); - if (!setting->isValid() || !setting->m_enabled) - continue; - switch (setting->m_startBehavior) { - case BaseSettings::AlwaysOn: { - Client *client = startClient(setting); - for (TextEditor::TextDocument *document : std::as_const(documents)) - managerInstance->m_clientForDocument[document] = client; - break; - } - case BaseSettings::RequiresFile: { - Client *client = nullptr; - for (TextEditor::TextDocument *previousDocument : std::as_const(documents)) { - if (setting->m_languageFilter.isSupported(previousDocument)) { + const QList &openedDocuments = Core::DocumentModel::openedDocuments(); + for (Core::IDocument *document : openedDocuments) { + if (documents.contains(document)) + continue; // already handled above + if (auto textDocument = qobject_cast(document)) { + if (setting->m_languageFilter.isSupported(document)) { if (!client) client = startClient(setting); - openDocumentWithClient(previousDocument, client); + client->openDocument(textDocument); } } - const QList &openedDocuments = Core::DocumentModel::openedDocuments(); - for (Core::IDocument *document : openedDocuments) { - if (documents.contains(document)) - continue; // already handled above - if (auto textDocument = qobject_cast(document)) { - if (setting->m_languageFilter.isSupported(document)) { + } + break; + } + case BaseSettings::RequiresProject: { + const QList &openedDocuments = Core::DocumentModel::openedDocuments(); + QHash clientForProject; + for (Core::IDocument *document : openedDocuments) { + auto textDocument = qobject_cast(document); + if (!textDocument || !setting->m_languageFilter.isSupported(textDocument)) + continue; + const Utils::FilePath filePath = textDocument->filePath(); + for (ProjectExplorer::Project *project : + ProjectExplorer::ProjectManager::projects()) { + if (project->isKnownFile(filePath)) { + Client *client = clientForProject[project]; + if (!client) { + client = startClient(setting, project); if (!client) - client = startClient(setting); - client->openDocument(textDocument); + continue; + clientForProject[project] = client; } + client->openDocument(textDocument); } } - break; - } - case BaseSettings::RequiresProject: { - const QList &openedDocuments = Core::DocumentModel::openedDocuments(); - QHash clientForProject; - for (Core::IDocument *document : openedDocuments) { - auto textDocument = qobject_cast(document); - if (!textDocument || !setting->m_languageFilter.isSupported(textDocument)) - continue; - const Utils::FilePath filePath = textDocument->filePath(); - for (ProjectExplorer::Project *project : - ProjectExplorer::ProjectManager::projects()) { - if (project->isKnownFile(filePath)) { - Client *client = clientForProject[project]; - if (!client) { - client = startClient(setting, project); - if (!client) - continue; - clientForProject[project] = client; - } - client->openDocument(textDocument); - } - } - } - break; - } - default: - break; } + break; + } + default: + break; } } diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index e14352881d2..d39844e16d0 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -52,6 +52,7 @@ public: const TextEditor::TextDocument *doc, bool onlyReachable = true); static void applySettings(); + static void applySettings(BaseSettings *settings); static QList currentSettings(); static void registerClientSettings(BaseSettings *settings); static void enableClientSettings(const QString &settingsId, bool enable = true); From 365f7d28abfba778dd8f2ec06865427dc2e6f5cc Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 1 Oct 2024 14:28:53 +0200 Subject: [PATCH 197/989] AppMan: Simplify some of the worker code Change-Id: I3ad028c53545c4a75e17ca7409828c3593d0a58e Reviewed-by: Jarek Kobus --- .../appmanagerruncontrol.cpp | 107 ++++++++---------- 1 file changed, 46 insertions(+), 61 deletions(-) diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 978e2158b51..dccb6528e24 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -97,26 +97,17 @@ public: class AppManInferiorRunner : public SimpleTargetRunner { public: - AppManInferiorRunner(RunControl *runControl, - bool usePerf, bool useGdbServer, bool useQmlServer, - QmlDebugServicesPreset qmlServices) + AppManInferiorRunner(RunControl *runControl, QmlDebugServicesPreset qmlServices) : SimpleTargetRunner(runControl) { setId(AppManager::Constants::DEBUG_LAUNCHER_ID); setEssential(true); - if (usePerf) { + if (usesPerfChannel()) { suppressDefaultStdOutHandling(); runControl->setProperty("PerfProcess", QVariant::fromValue(process())); - runControl->requestPerfChannel(); } - if (useGdbServer) - runControl->requestDebugChannel(); - - if (useQmlServer) - runControl->requestQmlChannel(); - setStartModifier([this, runControl, qmlServices] { FilePath controller = runControl->aspectData()->filePath; QString appId = runControl->aspectData()->value; @@ -178,45 +169,50 @@ public: class AppManagerDebugSupport final : public Debugger::DebuggerRunTool { -private: - FilePath m_symbolFile; - AppManInferiorRunner *m_debuggee = nullptr; - public: AppManagerDebugSupport(RunControl *runControl) : DebuggerRunTool(runControl) { setId("ApplicationManagerPlugin.Debug.Support"); - m_debuggee = new AppManInferiorRunner(runControl, false, isCppDebugging(), isQmlDebugging(), - QmlDebuggerServices); + if (isCppDebugging()) + runControl->requestDebugChannel(); + if (isQmlDebugging()) + runControl->requestQmlChannel(); - addStartDependency(m_debuggee); - addStopDependency(m_debuggee); + auto debuggee = new AppManInferiorRunner(runControl, QmlDebuggerServices); - Target *target = runControl->target(); - - const Internal::TargetInformation targetInformation(target); - if (!targetInformation.isValid()) - return; - - if (targetInformation.manifest.isQmlRuntime()) { - m_symbolFile = getToolFilePath(Constants::APPMAN_LAUNCHER_QML, - target->kit(), - RunDeviceKitAspect::device(target->kit())); - } else if (targetInformation.manifest.isNativeRuntime()) { - m_symbolFile = Utils::findOrDefault(target->buildSystem()->applicationTargets(), [&](const BuildTargetInfo &ti) { - return ti.buildKey == targetInformation.manifest.code || ti.projectFilePath.toString() == targetInformation.manifest.code; - }).targetFilePath; - } else { - reportFailure(Tr::tr("Cannot debug: Only QML and native applications are supported.")); - } + addStartDependency(debuggee); + addStopDependency(debuggee); } private: void start() override { - if (m_symbolFile.isEmpty()) { + Target *target = runControl()->target(); + + const Internal::TargetInformation targetInformation(target); + if (!targetInformation.isValid()) { + reportFailure(Tr::tr("Cannot debug: Invalid target information")); + return; + } + + FilePath symbolFile; + + if (targetInformation.manifest.isQmlRuntime()) { + symbolFile = getToolFilePath(Constants::APPMAN_LAUNCHER_QML, + target->kit(), + RunDeviceKitAspect::device(target->kit())); + } else if (targetInformation.manifest.isNativeRuntime()) { + symbolFile = Utils::findOrDefault(target->buildSystem()->applicationTargets(), + [&](const BuildTargetInfo &ti) { + return ti.buildKey == targetInformation.manifest.code + || ti.projectFilePath.toString() == targetInformation.manifest.code; + }).targetFilePath; + } else { + reportFailure(Tr::tr("Cannot debug: Only QML and native applications are supported.")); + } + if (symbolFile.isEmpty()) { reportFailure(Tr::tr("Cannot debug: Local executable is not set.")); return; } @@ -232,7 +228,7 @@ private: setUseContinueInsteadOfRun(true); setContinueAfterAttach(true); setRemoteChannel(debugChannel()); - setSymbolFile(m_symbolFile); + setSymbolFile(symbolFile); QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(runControl()->kit()); if (version) { @@ -261,27 +257,19 @@ public: { setId("AppManagerQmlToolingSupport"); + runControl->requestQmlChannel(); QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); - m_runner = new AppManInferiorRunner(runControl, false, false, true, services); - addStartDependency(m_runner); - addStopDependency(m_runner); + auto runner = new AppManInferiorRunner(runControl, services); + addStartDependency(runner); + addStopDependency(runner); - m_worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); - m_worker->addStartDependency(this); - addStopDependency(m_worker); + auto worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); + worker->addStartDependency(this); + addStopDependency(worker); // Make sure the QML Profiler is stopped before the appman-controller - m_runner->addStopDependency(m_worker); + runner->addStopDependency(worker); } - -private: - void start() final - { - reportStarted(); - } - - AppManInferiorRunner *m_runner = nullptr; - RunWorker *m_worker = nullptr; }; // AppManagerDevicePerfProfilerSupport @@ -294,14 +282,11 @@ public: { setId("AppManagerPerfProfilerSupport"); - m_profilee = new AppManInferiorRunner(runControl, true, false, false, - NoQmlDebugServices); - addStartDependency(m_profilee); - addStopDependency(m_profilee); + runControl->requestPerfChannel(); + auto profilee = new AppManInferiorRunner(runControl, NoQmlDebugServices); + addStartDependency(profilee); + addStopDependency(profilee); } - -private: - AppManInferiorRunner *m_profilee = nullptr; }; // Factories From f0be03f06e38892bdb089f572fc5dde937ee04bc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 15:32:23 +0100 Subject: [PATCH 198/989] RunControl: Pass usedPorts into getNextChannel() Change-Id: I2f332ea9b9071ead4ef59ec5b5126dc0e2b684ac Reviewed-by: hjk --- src/plugins/projectexplorer/runcontrol.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 9dd64d03112..edd5d1d0a89 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -358,7 +358,7 @@ public: void checkAutoDeleteAndEmitStopped(); void enablePortsGatherer(); - QUrl getNextChannel(); + QUrl getNextChannel(const QList &usedPorts); RunControl *q; Id runMode; @@ -601,16 +601,17 @@ void RunControlPrivate::startPortsGathererIfNeededAndContinueStart() connect(portsGatherer.get(), &DeviceUsedPortsGatherer::done, this, [this](bool success) { if (success) { portList = device->freePorts(); + const QList usedPorts = portsGatherer->usedPorts(); q->appendMessage(Tr::tr("Found %n free ports.", nullptr, portList.count()) + '\n', NormalMessageFormat); if (useDebugChannel) - debugChannel = getNextChannel(); + debugChannel = getNextChannel(usedPorts); if (useQmlChannel) - qmlChannel = getNextChannel(); + qmlChannel = getNextChannel(usedPorts); if (usePerfChannel) - perfChannel = getNextChannel(); + perfChannel = getNextChannel(usedPorts); if (useWorkerChannel) - workerChannel = getNextChannel(); + workerChannel = getNextChannel(usedPorts); continueStart(); } else { @@ -634,16 +635,15 @@ void RunControlPrivate::enablePortsGatherer() portsGatherer = std::make_unique(); } -QUrl RunControlPrivate::getNextChannel() +QUrl RunControlPrivate::getNextChannel(const QList &usedPorts) { - QTC_ASSERT(portsGatherer, return {}); QUrl result; result.setScheme(urlTcpScheme()); if (q->device()->extraData(Constants::SSH_FORWARD_DEBUGSERVER_PORT).toBool()) result.setHost("localhost"); else result.setHost(q->device()->toolControlChannel(IDevice::ControlChannelHint()).host()); - result.setPort(portList.getNextFreePort(portsGatherer->usedPorts()).number()); + result.setPort(portList.getNextFreePort(usedPorts).number()); return result; } From 81b49c41f409799ec29d64f3bab68b6b2c85ed14 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 15:35:37 +0100 Subject: [PATCH 199/989] RunControl: Get rid of portList field Use local PortList instead. Change-Id: I76f6438e2e5d3c0058534f3c9950c1d0ad640da4 Reviewed-by: hjk --- src/plugins/projectexplorer/runcontrol.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index edd5d1d0a89..9b76858b06c 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -358,14 +358,13 @@ public: void checkAutoDeleteAndEmitStopped(); void enablePortsGatherer(); - QUrl getNextChannel(const QList &usedPorts); + QUrl getNextChannel(PortList *portList, const QList &usedPorts); RunControl *q; Id runMode; TaskTreeRunner m_taskTreeRunner; std::unique_ptr portsGatherer; - PortList portList; }; } // Internal @@ -600,18 +599,18 @@ void RunControlPrivate::startPortsGathererIfNeededAndContinueStart() connect(portsGatherer.get(), &DeviceUsedPortsGatherer::done, this, [this](bool success) { if (success) { - portList = device->freePorts(); + PortList portList = device->freePorts(); const QList usedPorts = portsGatherer->usedPorts(); q->appendMessage(Tr::tr("Found %n free ports.", nullptr, portList.count()) + '\n', NormalMessageFormat); if (useDebugChannel) - debugChannel = getNextChannel(usedPorts); + debugChannel = getNextChannel(&portList, usedPorts); if (useQmlChannel) - qmlChannel = getNextChannel(usedPorts); + qmlChannel = getNextChannel(&portList, usedPorts); if (usePerfChannel) - perfChannel = getNextChannel(usedPorts); + perfChannel = getNextChannel(&portList, usedPorts); if (useWorkerChannel) - workerChannel = getNextChannel(usedPorts); + workerChannel = getNextChannel(&portList, usedPorts); continueStart(); } else { @@ -635,7 +634,7 @@ void RunControlPrivate::enablePortsGatherer() portsGatherer = std::make_unique(); } -QUrl RunControlPrivate::getNextChannel(const QList &usedPorts) +QUrl RunControlPrivate::getNextChannel(PortList *portList, const QList &usedPorts) { QUrl result; result.setScheme(urlTcpScheme()); @@ -643,7 +642,7 @@ QUrl RunControlPrivate::getNextChannel(const QList &usedPorts) result.setHost("localhost"); else result.setHost(q->device()->toolControlChannel(IDevice::ControlChannelHint()).host()); - result.setPort(portList.getNextFreePort(usedPorts).number()); + result.setPort(portList->getNextFreePort(usedPorts).number()); return result; } From 2af6e0e9843b1673c390f234c04590733b94da20 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 15:46:20 +0100 Subject: [PATCH 200/989] RunControl: Remove unused enablePortsGatherer() method Change-Id: I6716fe6fdc2fbbf0cd93642c3085d751a37dc2b6 Reviewed-by: hjk --- src/plugins/projectexplorer/runcontrol.cpp | 5 ----- src/plugins/projectexplorer/runcontrol.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 9b76858b06c..605f255d81b 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -623,11 +623,6 @@ void RunControlPrivate::startPortsGathererIfNeededAndContinueStart() portsGatherer->start(); } -void RunControl::enablePortsGatherer() -{ - d->enablePortsGatherer(); -} - void RunControlPrivate::enablePortsGatherer() { if (!portsGatherer) diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 4c37b1c9e78..850117d6764 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -240,8 +240,6 @@ public: static bool canRun(Utils::Id runMode, Utils::Id deviceType, Utils::Id runConfigId); void postMessage(const QString &msg, Utils::OutputFormat format, bool appendNewLine = true); - void enablePortsGatherer(); - void requestDebugChannel(); bool usesDebugChannel() const; QUrl debugChannel() const; From 4665f0ec343cb2aca6737cc222f5957fbad6eedf Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 19 Nov 2024 17:57:19 +0100 Subject: [PATCH 201/989] ProjectExplorer: Dissolve kitaspects.{h,cpp} Move the remaining classes into their own files. Change-Id: I301e72004c21446fa9b8f15942bb042218b0ecef Reviewed-by: hjk --- src/plugins/android/androidconfigurations.cpp | 3 +- src/plugins/android/androiddeployqtstep.cpp | 2 +- src/plugins/android/androiddevice.cpp | 2 +- src/plugins/android/androidmanifesteditor.cpp | 2 +- .../androidpackageinstallationstep.cpp | 2 +- src/plugins/android/androidplugin.cpp | 2 +- .../android/androidrunconfiguration.cpp | 2 +- src/plugins/android/androidrunner.cpp | 2 +- src/plugins/android/javalanguageserver.cpp | 2 +- src/plugins/autotest/autotestunittests.cpp | 2 +- src/plugins/autotest/testconfiguration.cpp | 2 +- .../baremetal/baremetaldebugsupport.cpp | 2 +- src/plugins/boot2qt/qdbrunconfiguration.cpp | 2 +- .../boot2qt/qdbstopapplicationstep.cpp | 2 +- src/plugins/clangcodemodel/clangdclient.cpp | 2 +- src/plugins/clangcodemodel/clangutils.cpp | 2 +- src/plugins/clangtools/clangtool.cpp | 2 +- src/plugins/clangtools/clangtoolsplugin.cpp | 2 +- .../clangtoolspreconfiguredsessiontests.cpp | 2 +- .../clangtools/clangtoolsunittests.cpp | 2 +- .../builddirparameters.cpp | 2 +- .../cmakebuildconfiguration.cpp | 4 +- .../cmakeprojectmanager/cmakebuildstep.cpp | 3 +- .../cmakeprojectmanager/cmakebuildsystem.cpp | 2 +- .../cmakeprojectmanager/cmakekitaspect.cpp | 3 +- .../cmakeprojectmanager/cmakeproject.cpp | 2 +- .../cmakeprojectimporter.cpp | 3 +- .../cmakeprojectmanager.cpp | 2 +- .../compilationdatabaseproject.cpp | 2 +- .../compilationdatabasetests.cpp | 2 +- src/plugins/conan/conaninstallstep.cpp | 2 +- src/plugins/cppcheck/cppcheckplugin.cpp | 2 +- src/plugins/cppeditor/cppmodelmanager.cpp | 3 +- src/plugins/cppeditor/projectinfo.cpp | 2 +- .../debugger/analyzer/startremotedialog.cpp | 2 +- src/plugins/debugger/debuggerdialogs.cpp | 2 +- src/plugins/debugger/debuggerkitaspect.cpp | 3 +- src/plugins/debugger/debuggerplugin.cpp | 3 +- .../debuggerrunconfigurationaspect.cpp | 2 +- src/plugins/debugger/debuggerruncontrol.cpp | 3 +- .../debugger/unstartedappwatcherdialog.cpp | 3 +- src/plugins/docker/dockerdevice.cpp | 2 +- src/plugins/docker/kitdetector.cpp | 3 +- .../genericprojectmanager/genericproject.cpp | 2 +- .../incredibuild/makecommandbuilder.cpp | 2 +- src/plugins/ios/iosbuildconfiguration.cpp | 2 +- src/plugins/ios/iosbuildstep.cpp | 3 +- src/plugins/ios/iosconfigurations.cpp | 4 +- src/plugins/ios/iosdeploystep.cpp | 6 +- src/plugins/ios/iosdevice.cpp | 2 +- src/plugins/ios/iosdsymbuildstep.cpp | 2 +- src/plugins/ios/iosrunconfiguration.cpp | 2 +- src/plugins/ios/iosrunner.cpp | 2 +- src/plugins/ios/iossimulator.cpp | 2 +- src/plugins/mcusupport/mcukitmanager.cpp | 5 +- src/plugins/mcusupport/test/unittest.cpp | 2 +- .../mesonprojectmanager/mesonbuildsystem.cpp | 2 +- .../mesonprojectmanager/mesonproject.cpp | 2 +- src/plugins/nim/project/nimbuildsystem.cpp | 2 +- .../nim/project/nimcompilerbuildstep.cpp | 2 +- src/plugins/nim/project/nimproject.cpp | 2 +- src/plugins/perfprofiler/perfdatareader.cpp | 3 +- .../perfprofiler/perfprofilerruncontrol.cpp | 2 +- src/plugins/perfprofiler/perfprofilertool.cpp | 2 +- src/plugins/perfprofiler/perfsettings.cpp | 2 +- .../perfprofiler/perftracepointdialog.cpp | 2 +- src/plugins/projectexplorer/CMakeLists.txt | 3 +- src/plugins/projectexplorer/buildaspects.cpp | 2 +- .../projectexplorer/buildconfiguration.cpp | 2 +- src/plugins/projectexplorer/buildmanager.cpp | 2 +- src/plugins/projectexplorer/buildstep.cpp | 2 +- .../projectexplorer/deployconfiguration.cpp | 2 +- .../devicesupport/devicecheckbuildstep.cpp | 2 +- .../devicesupport/deviceprocessesdialog.cpp | 2 +- .../projectexplorer/devicesupport/idevice.cpp | 3 +- ...itaspects.cpp => environmentkitaspect.cpp} | 169 +----------------- .../{kitaspects.h => environmentkitaspect.h} | 18 +- src/plugins/projectexplorer/extracompiler.cpp | 2 +- src/plugins/projectexplorer/kit.cpp | 2 +- src/plugins/projectexplorer/kitaspect.cpp | 2 +- src/plugins/projectexplorer/kitmanager.cpp | 3 +- .../kitmanagerconfigwidget.cpp | 2 +- src/plugins/projectexplorer/makestep.cpp | 3 +- .../projectexplorer/parseissuesdialog.cpp | 4 +- src/plugins/projectexplorer/project.cpp | 3 +- .../projectexplorer/projectexplorer.cpp | 2 +- .../projectexplorer/projectexplorer.qbs | 3 +- .../projectexplorer/projectimporter.cpp | 3 +- .../projectexplorer/rawprojectpart.cpp | 4 +- .../projectexplorer/runconfiguration.cpp | 2 +- .../runconfigurationaspects.cpp | 2 +- src/plugins/projectexplorer/runcontrol.cpp | 2 +- .../projectexplorer/sysrootkitaspect.cpp | 168 +++++++++++++++++ .../projectexplorer/sysrootkitaspect.h | 24 +++ src/plugins/projectexplorer/target.cpp | 2 +- .../projectexplorer/toolchainkitaspect.cpp | 2 +- src/plugins/python/pythonsettings.cpp | 2 +- .../defaultpropertyprovider.cpp | 4 +- .../qbsbuildconfiguration.cpp | 2 +- src/plugins/qbsprojectmanager/qbsproject.cpp | 2 +- .../qbsprojectmanager/qbsprojectimporter.cpp | 3 +- .../qmakebuildconfiguration.cpp | 4 +- .../qmakeprojectmanager/qmakekitaspect.cpp | 2 +- .../qmakeprojectmanager/qmakemakestep.cpp | 2 +- .../qmakeprojectmanager/qmakeproject.cpp | 4 +- .../qmakeprojectimporter.cpp | 4 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 4 +- .../qmakeprojectmanager/wizards/qtwizard.cpp | 2 +- .../components/toolbar/toolbarbackend.cpp | 2 +- .../qmlpreviewplugin/qmlpreviewactions.cpp | 2 +- src/plugins/qmljstools/qmljsmodelmanager.cpp | 2 +- .../qmlpreviewfileontargetfinder.cpp | 2 +- src/plugins/qmlpreview/qmlpreviewplugin.cpp | 2 +- .../qmlprofiler/qmlprofilerattachdialog.cpp | 2 +- .../qmlprofilerdetailsrewriter.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilerplugin.cpp | 2 +- .../qmlprofiler/qmlprofilerruncontrol.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +- .../tests/qmlprofilerdetailsrewriter_test.cpp | 2 +- .../buildsystem/qmlbuildsystem.cpp | 2 +- src/plugins/qmlprojectmanager/qmlproject.cpp | 2 +- .../qmlprojectrunconfiguration.cpp | 2 +- src/plugins/qnx/qnxdebugsupport.cpp | 2 +- src/plugins/qnx/qnxplugin.cpp | 3 +- src/plugins/qnx/qnxsettingspage.cpp | 5 +- .../appmanagercreatepackagestep.cpp | 2 +- .../appmanagerdeployconfigurationfactory.cpp | 2 +- .../appmanagerdeploypackagestep.cpp | 2 +- .../appmanagerinstallpackagestep.cpp | 2 +- .../appmanagerrunconfiguration.cpp | 2 +- .../appmanagerruncontrol.cpp | 3 +- .../appmanagertargetinformation.cpp | 2 +- src/plugins/qtsupport/baseqtversion.cpp | 4 +- src/plugins/qtsupport/qtkitaspect.cpp | 3 +- src/plugins/qtsupport/qtprojectimporter.cpp | 2 +- .../abstractremotelinuxdeploystep.cpp | 2 +- .../remotelinux/deploymenttimeinfo.cpp | 3 +- src/plugins/remotelinux/genericdeploystep.cpp | 2 +- src/plugins/remotelinux/makeinstallstep.cpp | 2 +- .../remotelinuxenvironmentaspect.cpp | 2 +- .../remotelinuxrunconfiguration.cpp | 2 +- .../studiowelcome/studiowelcomeplugin.cpp | 4 +- src/plugins/valgrind/memchecktool.cpp | 3 +- src/plugins/valgrind/valgrindengine.cpp | 2 +- 144 files changed, 396 insertions(+), 320 deletions(-) rename src/plugins/projectexplorer/{kitaspects.cpp => environmentkitaspect.cpp} (59%) rename src/plugins/projectexplorer/{kitaspects.h => environmentkitaspect.h} (56%) create mode 100644 src/plugins/projectexplorer/sysrootkitaspect.cpp create mode 100644 src/plugins/projectexplorer/sysrootkitaspect.h diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 07ccde1f263..bc757e81889 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -14,12 +14,13 @@ #include #include +#include #include -#include #include #include #include #include +#include #include #include diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 0db55016889..0a0717d26cd 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 316e2470396..363646f0006 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/android/androidmanifesteditor.cpp b/src/plugins/android/androidmanifesteditor.cpp index e2deb3288f0..b344b4a3a0a 100644 --- a/src/plugins/android/androidmanifesteditor.cpp +++ b/src/plugins/android/androidmanifesteditor.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp index 1595180196d..4c020b2ab97 100644 --- a/src/plugins/android/androidpackageinstallationstep.cpp +++ b/src/plugins/android/androidpackageinstallationstep.cpp @@ -12,12 +12,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 50217a6f8c0..3e268bc16ed 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index a8aa3bc95c9..78e7baae2c5 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index ce641ea6a33..6b8150ec037 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -9,7 +9,7 @@ #include "androidrunnerworker.h" #include "androidutils.h" -#include +#include #include #include #include diff --git a/src/plugins/android/javalanguageserver.cpp b/src/plugins/android/javalanguageserver.cpp index fbeebd8418d..fbf02616d8b 100644 --- a/src/plugins/android/javalanguageserver.cpp +++ b/src/plugins/android/javalanguageserver.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/autotest/autotestunittests.cpp b/src/plugins/autotest/autotestunittests.cpp index d1fd8880ab1..5e61e8ea07a 100644 --- a/src/plugins/autotest/autotestunittests.cpp +++ b/src/plugins/autotest/autotestunittests.cpp @@ -15,10 +15,10 @@ #include -#include #include #include #include +#include #include diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp index abd166876a2..a2579bf74ae 100644 --- a/src/plugins/autotest/testconfiguration.cpp +++ b/src/plugins/autotest/testconfiguration.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/baremetal/baremetaldebugsupport.cpp b/src/plugins/baremetal/baremetaldebugsupport.cpp index 521289650fd..0e71da2f3f2 100644 --- a/src/plugins/baremetal/baremetaldebugsupport.cpp +++ b/src/plugins/baremetal/baremetaldebugsupport.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/boot2qt/qdbrunconfiguration.cpp b/src/plugins/boot2qt/qdbrunconfiguration.cpp index b3f1484d5e9..cbeb71c4d10 100644 --- a/src/plugins/boot2qt/qdbrunconfiguration.cpp +++ b/src/plugins/boot2qt/qdbrunconfiguration.cpp @@ -9,8 +9,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp index 4f3e2741e62..550327e6521 100644 --- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp +++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp @@ -6,8 +6,8 @@ #include "qdbconstants.h" #include "qdbtr.h" +#include #include -#include #include #include diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 2184ecbcf8a..1b3cf54f0e0 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -44,8 +44,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index c85062982ec..2de8d875e7f 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 3bc92f403bc..e4d993b7d9c 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include diff --git a/src/plugins/clangtools/clangtoolsplugin.cpp b/src/plugins/clangtools/clangtoolsplugin.cpp index a39799612a2..85f886fc1c4 100644 --- a/src/plugins/clangtools/clangtoolsplugin.cpp +++ b/src/plugins/clangtools/clangtoolsplugin.cpp @@ -36,7 +36,7 @@ #include -#include +#include #include #include diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp index e33f91af331..50af71274be 100644 --- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp +++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp @@ -12,13 +12,13 @@ #include #include -#include #include #include #include #include #include #include +#include #include #include diff --git a/src/plugins/clangtools/clangtoolsunittests.cpp b/src/plugins/clangtools/clangtoolsunittests.cpp index a5bf4f10ef6..d8906aee27e 100644 --- a/src/plugins/clangtools/clangtoolsunittests.cpp +++ b/src/plugins/clangtools/clangtoolsunittests.cpp @@ -14,11 +14,11 @@ #include #include -#include #include #include #include #include +#include #include diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.cpp b/src/plugins/cmakeprojectmanager/builddirparameters.cpp index 0785ca8d959..02169fdd19b 100644 --- a/src/plugins/cmakeprojectmanager/builddirparameters.cpp +++ b/src/plugins/cmakeprojectmanager/builddirparameters.cpp @@ -10,7 +10,7 @@ #include "cmaketoolmanager.h" #include -#include +#include #include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 29be8db113e..f920c647757 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -31,11 +31,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -44,8 +44,10 @@ #include #include #include +#include #include #include +#include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 042a23903ce..50a389e2d27 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -24,10 +24,10 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index d5ccb107cf5..c3bce2741cc 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -26,8 +26,8 @@ #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp index 849154940dc..1b7ece214cc 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp @@ -15,15 +15,16 @@ #include +#include #include #include -#include #include #include #include #include #include #include +#include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index f81f89af69b..e488b8772ae 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -13,12 +13,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 4613b68ed7a..e55a49132ce 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -17,11 +17,12 @@ #include #include -#include #include #include +#include #include #include +#include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index dcb595cb7a3..50a849f7a1a 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -39,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp index 5976f347d82..7d4752d4407 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp @@ -17,13 +17,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp index b2a2995f30c..f4d47f20e5b 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/conan/conaninstallstep.cpp b/src/plugins/conan/conaninstallstep.cpp index 7dd5dc56cae..8bacae0eeb3 100644 --- a/src/plugins/conan/conaninstallstep.cpp +++ b/src/plugins/conan/conaninstallstep.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -20,6 +19,7 @@ #include #include #include +#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/cppcheck/cppcheckplugin.cpp b/src/plugins/cppcheck/cppcheckplugin.cpp index 341b25db029..248223eecd8 100644 --- a/src/plugins/cppcheck/cppcheckplugin.cpp +++ b/src/plugins/cppcheck/cppcheckplugin.cpp @@ -19,12 +19,12 @@ #include -#include #include #include #include #include #include +#include #include #include diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index d9a5c7e6f2f..6b67a5f9755 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -48,7 +48,6 @@ #include #include -#include #include #include #include @@ -57,7 +56,9 @@ #include #include #include +#include #include +#include #include #include diff --git a/src/plugins/cppeditor/projectinfo.cpp b/src/plugins/cppeditor/projectinfo.cpp index e25070044bd..00dd40040e4 100644 --- a/src/plugins/cppeditor/projectinfo.cpp +++ b/src/plugins/cppeditor/projectinfo.cpp @@ -4,7 +4,7 @@ #include "projectinfo.h" #include -#include +#include #include #include #include diff --git a/src/plugins/debugger/analyzer/startremotedialog.cpp b/src/plugins/debugger/analyzer/startremotedialog.cpp index c8dd079122a..d1bb259df7c 100644 --- a/src/plugins/debugger/analyzer/startremotedialog.cpp +++ b/src/plugins/debugger/analyzer/startremotedialog.cpp @@ -7,9 +7,9 @@ #include +#include #include #include -#include #include #include diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 3ced7bd8d3b..c6842c6b2c3 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -9,8 +9,8 @@ #include +#include #include -#include #include #include #include diff --git a/src/plugins/debugger/debuggerkitaspect.cpp b/src/plugins/debugger/debuggerkitaspect.cpp index 3f9aeecb26e..946f1e1ca3e 100644 --- a/src/plugins/debugger/debuggerkitaspect.cpp +++ b/src/plugins/debugger/debuggerkitaspect.cpp @@ -8,11 +8,12 @@ #include "debuggertr.h" #include +#include #include #include -#include #include #include +#include #include #include diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 8d0d4320ff7..f91c392f4c7 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -57,11 +57,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -75,6 +75,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index 4bd1dec9675..80ce3cba330 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 1549a5e94b8..bb30d87460d 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -19,7 +19,6 @@ #include #include #include // For the environment -#include #include #include #include @@ -27,6 +26,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/plugins/debugger/unstartedappwatcherdialog.cpp b/src/plugins/debugger/unstartedappwatcherdialog.cpp index f46992ac799..cc1c13c5415 100644 --- a/src/plugins/debugger/unstartedappwatcherdialog.cpp +++ b/src/plugins/debugger/unstartedappwatcherdialog.cpp @@ -8,15 +8,16 @@ #include "debuggertr.h" #include +#include #include #include -#include #include #include #include #include #include #include +#include #include #include diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index ffe0cb84e33..8f6e839ba35 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/docker/kitdetector.cpp b/src/plugins/docker/kitdetector.cpp index f0e3f0c8026..ddd5c174712 100644 --- a/src/plugins/docker/kitdetector.cpp +++ b/src/plugins/docker/kitdetector.cpp @@ -7,11 +7,12 @@ #include +#include #include -#include #include #include #include +#include #include #include diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index f35f985230d..554d3629bf9 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/incredibuild/makecommandbuilder.cpp b/src/plugins/incredibuild/makecommandbuilder.cpp index 9a100427ab7..f9fb4a59587 100644 --- a/src/plugins/incredibuild/makecommandbuilder.cpp +++ b/src/plugins/incredibuild/makecommandbuilder.cpp @@ -7,11 +7,11 @@ #include #include -#include #include #include #include #include +#include #include // Compile-time only diff --git a/src/plugins/ios/iosbuildconfiguration.cpp b/src/plugins/ios/iosbuildconfiguration.cpp index cdccff57fa4..eadda24575c 100644 --- a/src/plugins/ios/iosbuildconfiguration.cpp +++ b/src/plugins/ios/iosbuildconfiguration.cpp @@ -7,7 +7,7 @@ #include "iosconstants.h" #include "iostr.h" -#include +#include #include #include diff --git a/src/plugins/ios/iosbuildstep.cpp b/src/plugins/ios/iosbuildstep.cpp index c9d396ddd46..bc3fdc29801 100644 --- a/src/plugins/ios/iosbuildstep.cpp +++ b/src/plugins/ios/iosbuildstep.cpp @@ -11,13 +11,14 @@ #include #include #include -#include #include #include #include #include +#include #include #include +#include #include #include diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index b9eeea159be..6fd35cb6234 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -12,14 +12,16 @@ #include -#include #include +#include #include #include #include #include #include #include +#include +#include #include #include diff --git a/src/plugins/ios/iosdeploystep.cpp b/src/plugins/ios/iosdeploystep.cpp index 85b18ff59df..e9825fb6ce1 100644 --- a/src/plugins/ios/iosdeploystep.cpp +++ b/src/plugins/ios/iosdeploystep.cpp @@ -12,12 +12,12 @@ #include "iostr.h" #include +#include +#include +#include #include #include #include -#include -#include -#include #include diff --git a/src/plugins/ios/iosdevice.cpp b/src/plugins/ios/iosdevice.cpp index abf0c0dc79c..61fe5641234 100644 --- a/src/plugins/ios/iosdevice.cpp +++ b/src/plugins/ios/iosdevice.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/ios/iosdsymbuildstep.cpp b/src/plugins/ios/iosdsymbuildstep.cpp index c0aa4a06eea..8753f7062ea 100644 --- a/src/plugins/ios/iosdsymbuildstep.cpp +++ b/src/plugins/ios/iosdsymbuildstep.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp index df7cc2bff64..42c6fc455cd 100644 --- a/src/plugins/ios/iosrunconfiguration.cpp +++ b/src/plugins/ios/iosrunconfiguration.cpp @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index b10142d753e..7f111ea351e 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/ios/iossimulator.cpp b/src/plugins/ios/iossimulator.cpp index 13877d9c143..a5f3fbb3464 100644 --- a/src/plugins/ios/iossimulator.cpp +++ b/src/plugins/ios/iossimulator.cpp @@ -5,7 +5,7 @@ #include "iosconstants.h" #include "iostr.h" -#include +#include #include #include diff --git a/src/plugins/mcusupport/mcukitmanager.cpp b/src/plugins/mcusupport/mcukitmanager.cpp index d095d5cbd6d..194c5efd840 100644 --- a/src/plugins/mcusupport/mcukitmanager.cpp +++ b/src/plugins/mcusupport/mcukitmanager.cpp @@ -23,10 +23,13 @@ #include #include -#include +#include +#include #include #include #include +#include +#include #include #include diff --git a/src/plugins/mcusupport/test/unittest.cpp b/src/plugins/mcusupport/test/unittest.cpp index 2bbdfdfc318..4465f5a066d 100644 --- a/src/plugins/mcusupport/test/unittest.cpp +++ b/src/plugins/mcusupport/test/unittest.cpp @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/mesonprojectmanager/mesonbuildsystem.cpp b/src/plugins/mesonprojectmanager/mesonbuildsystem.cpp index 022f24000af..249a6b23b63 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildsystem.cpp +++ b/src/plugins/mesonprojectmanager/mesonbuildsystem.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/mesonprojectmanager/mesonproject.cpp b/src/plugins/mesonprojectmanager/mesonproject.cpp index 159423881ea..74bc1838067 100644 --- a/src/plugins/mesonprojectmanager/mesonproject.cpp +++ b/src/plugins/mesonprojectmanager/mesonproject.cpp @@ -10,10 +10,10 @@ #include -#include #include #include #include +#include using namespace ProjectExplorer; diff --git a/src/plugins/nim/project/nimbuildsystem.cpp b/src/plugins/nim/project/nimbuildsystem.cpp index 5ffd852c41a..b8425df69a2 100644 --- a/src/plugins/nim/project/nimbuildsystem.cpp +++ b/src/plugins/nim/project/nimbuildsystem.cpp @@ -6,9 +6,9 @@ #include "nimconstants.h" #include "nimbleproject.h" -#include #include #include +#include #include #include diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp index aaf6ff42969..8c2dfa67c40 100644 --- a/src/plugins/nim/project/nimcompilerbuildstep.cpp +++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp @@ -10,11 +10,11 @@ #include #include -#include #include #include #include #include +#include #include #include diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp index 33f09d19328..53e91b88a80 100644 --- a/src/plugins/nim/project/nimproject.cpp +++ b/src/plugins/nim/project/nimproject.cpp @@ -9,10 +9,10 @@ #include -#include #include #include #include +#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/perfprofiler/perfdatareader.cpp b/src/plugins/perfprofiler/perfdatareader.cpp index 5c690e8d276..8f02fea9e06 100644 --- a/src/plugins/perfprofiler/perfdatareader.cpp +++ b/src/plugins/perfprofiler/perfdatareader.cpp @@ -11,12 +11,13 @@ #include #include -#include #include #include #include +#include #include #include +#include #include #include diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp index b279f9d101c..78348d411c7 100644 --- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp +++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index 8c3698b3bd7..731b5f0c7c9 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -20,11 +20,11 @@ #include #include -#include #include #include #include #include +#include #include #include diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp index 2cf1f9e14d9..8192b464b67 100644 --- a/src/plugins/perfprofiler/perfsettings.cpp +++ b/src/plugins/perfprofiler/perfsettings.cpp @@ -11,9 +11,9 @@ #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/perfprofiler/perftracepointdialog.cpp b/src/plugins/perfprofiler/perftracepointdialog.cpp index b219e8ed7b8..331c0ea6d33 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.cpp +++ b/src/plugins/perfprofiler/perftracepointdialog.cpp @@ -4,8 +4,8 @@ #include "perfprofilertr.h" #include "perftracepointdialog.h" +#include #include -#include #include #include #include diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index 5ee0019a6b6..c98db1a5cad 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -73,6 +73,7 @@ add_qtc_plugin(ProjectExplorer editorsettingspropertiespage.cpp editorsettingspropertiespage.h environmentaspect.cpp environmentaspect.h environmentaspectwidget.cpp environmentaspectwidget.h + environmentkitaspect.cpp environmentkitaspect.h environmentwidget.cpp environmentwidget.h expanddata.cpp expanddata.h extraabi.cpp extraabi.h @@ -104,7 +105,6 @@ add_qtc_plugin(ProjectExplorer jsonwizard/jsonwizardscannergenerator.cpp jsonwizard/jsonwizardscannergenerator.h kit.cpp kit.h kitaspect.cpp kitaspect.h - kitaspects.cpp kitaspects.h kitchooser.cpp kitchooser.h kitfeatureprovider.h kitmanager.cpp kitmanager.h @@ -162,6 +162,7 @@ add_qtc_plugin(ProjectExplorer showineditortaskhandler.cpp showineditortaskhandler.h showoutputtaskhandler.cpp showoutputtaskhandler.h simpleprojectwizard.cpp simpleprojectwizard.h + sysrootkitaspect.cpp sysrootkitaspect.h target.cpp target.h targetsettingspanel.cpp targetsettingspanel.h targetsetuppage.cpp targetsetuppage.h diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp index e62a5bb3d5f..dfaf86205dd 100644 --- a/src/plugins/projectexplorer/buildaspects.cpp +++ b/src/plugins/projectexplorer/buildaspects.cpp @@ -5,8 +5,8 @@ #include "buildconfiguration.h" #include "buildpropertiessettings.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/idevice.h" -#include "kitaspects.h" #include "projectexplorerconstants.h" #include "projectexplorer.h" #include "projectexplorersettings.h" diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index e309c3826ac..9f2e3b32fda 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -10,9 +10,9 @@ #include "buildstepspage.h" #include "buildsystem.h" #include "customparser.h" +#include "devicesupport/devicekitaspects.h" #include "environmentwidget.h" #include "kit.h" -#include "kitaspects.h" #include "namedwidget.h" #include "projectexplorerconstants.h" #include "projectexplorer.h" diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp index 7d801bc2690..554c9d55cc8 100644 --- a/src/plugins/projectexplorer/buildmanager.cpp +++ b/src/plugins/projectexplorer/buildmanager.cpp @@ -7,9 +7,9 @@ #include "buildsystem.h" #include "compileoutputwindow.h" #include "deployconfiguration.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/devicemanager.h" #include "kit.h" -#include "kitaspects.h" #include "project.h" #include "projectexplorer.h" #include "projectexplorerconstants.h" diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 9b0f6836aef..a45d6189159 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -7,7 +7,7 @@ #include "buildsteplist.h" #include "customparser.h" #include "deployconfiguration.h" -#include "kitaspects.h" +#include "devicesupport/devicekitaspects.h" #include "project.h" #include "projectexplorerconstants.h" #include "sanitizerparser.h" diff --git a/src/plugins/projectexplorer/deployconfiguration.cpp b/src/plugins/projectexplorer/deployconfiguration.cpp index 1ea0465f5e8..9789af02bc3 100644 --- a/src/plugins/projectexplorer/deployconfiguration.cpp +++ b/src/plugins/projectexplorer/deployconfiguration.cpp @@ -6,7 +6,7 @@ #include "buildconfiguration.h" #include "buildsteplist.h" #include "deploymentdataview.h" -#include "kitaspects.h" +#include "devicesupport/devicekitaspects.h" #include "project.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" diff --git a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp index 7f2989876ec..d70b6b50752 100644 --- a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp @@ -4,10 +4,10 @@ #include "devicecheckbuildstep.h" #include "../buildstep.h" -#include "../kitaspects.h" #include "../projectexplorerconstants.h" #include "../projectexplorertr.h" +#include "devicekitaspects.h" #include "devicemanager.h" #include "idevicefactory.h" diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp index 4321ba2e277..c0154db77d1 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceprocessesdialog.cpp @@ -3,9 +3,9 @@ #include "deviceprocessesdialog.h" +#include "devicekitaspects.h" #include "idevice.h" #include "processlist.h" -#include "../kitaspects.h" #include "../kitchooser.h" #include "../projectexplorertr.h" diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 860c271a5a7..94baa513daf 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -3,12 +3,12 @@ #include "idevice.h" +#include "devicekitaspects.h" #include "devicemanager.h" #include "idevicefactory.h" #include "sshparameters.h" #include "../kit.h" -#include "../kitaspects.h" #include "../projectexplorericons.h" #include "../projectexplorertr.h" #include "../target.h" @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/src/plugins/projectexplorer/kitaspects.cpp b/src/plugins/projectexplorer/environmentkitaspect.cpp similarity index 59% rename from src/plugins/projectexplorer/kitaspects.cpp rename to src/plugins/projectexplorer/environmentkitaspect.cpp index a37c172f17e..19b56be9cc0 100644 --- a/src/plugins/projectexplorer/kitaspects.cpp +++ b/src/plugins/projectexplorer/environmentkitaspect.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "kitaspects.h" +#include "environmentkitaspect.h" #include "projectexplorertr.h" #include "kit.h" @@ -30,160 +30,6 @@ using namespace Utils; namespace ProjectExplorer { -// -------------------------------------------------------------------------- -// SysRootKitAspect: -// -------------------------------------------------------------------------- - -namespace Internal { -class SysRootKitAspectImpl : public KitAspect -{ -public: - SysRootKitAspectImpl(Kit *k, const KitAspectFactory *factory) : KitAspect(k, factory) - { - m_chooser = createSubWidget(); - m_chooser->setExpectedKind(PathChooser::ExistingDirectory); - m_chooser->setHistoryCompleter("PE.SysRoot.History"); - m_chooser->setFilePath(SysRootKitAspect::sysRoot(k)); - connect(m_chooser, &PathChooser::textChanged, - this, &SysRootKitAspectImpl::pathWasChanged); - } - - ~SysRootKitAspectImpl() override { delete m_chooser; } - -private: - void makeReadOnly() override { m_chooser->setReadOnly(true); } - - void addToInnerLayout(Layouting::Layout &layout) override - { - addMutableAction(m_chooser); - layout.addItem(Layouting::Span(2, m_chooser)); - } - - void refresh() override - { - if (!m_ignoreChanges.isLocked()) - m_chooser->setFilePath(SysRootKitAspect::sysRoot(kit())); - } - - void pathWasChanged() - { - const GuardLocker locker(m_ignoreChanges); - SysRootKitAspect::setSysRoot(kit(), m_chooser->filePath()); - } - - PathChooser *m_chooser; - Guard m_ignoreChanges; -}; - -class SysRootKitAspectFactory : public KitAspectFactory -{ -public: - SysRootKitAspectFactory(); - - Tasks validate(const Kit *k) const override; - KitAspect *createKitAspect(Kit *k) const override; - ItemList toUserOutput(const Kit *k) const override; - void addToMacroExpander(Kit *kit, MacroExpander *expander) const override; -}; - -SysRootKitAspectFactory::SysRootKitAspectFactory() -{ - setId(SysRootKitAspect::id()); - setDisplayName(Tr::tr("Sysroot")); - setDescription(Tr::tr("The root directory of the system image to use.
" - "Leave empty when building for the desktop.")); - setPriority(27000); -} - -Tasks SysRootKitAspectFactory::validate(const Kit *k) const -{ - Tasks result; - const FilePath dir = SysRootKitAspect::sysRoot(k); - if (dir.isEmpty()) - return result; - - if (dir.startsWith("target:") || dir.startsWith("remote:")) - return result; - - if (!dir.exists()) { - result << BuildSystemTask(Task::Warning, - Tr::tr("Sys Root \"%1\" does not exist in the file system.").arg(dir.toUserOutput())); - } else if (!dir.isDir()) { - result << BuildSystemTask(Task::Warning, - Tr::tr("Sys Root \"%1\" is not a directory.").arg(dir.toUserOutput())); - } else if (dir.dirEntries(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) { - result << BuildSystemTask(Task::Warning, - Tr::tr("Sys Root \"%1\" is empty.").arg(dir.toUserOutput())); - } - return result; -} - -KitAspect *SysRootKitAspectFactory::createKitAspect(Kit *k) const -{ - QTC_ASSERT(k, return nullptr); - - return new Internal::SysRootKitAspectImpl(k, this); -} - -KitAspectFactory::ItemList SysRootKitAspectFactory::toUserOutput(const Kit *k) const -{ - return {{Tr::tr("Sys Root"), SysRootKitAspect::sysRoot(k).toUserOutput()}}; -} - -void SysRootKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expander) const -{ - QTC_ASSERT(kit, return); - - expander->registerFileVariables("SysRoot", Tr::tr("Sys Root"), [kit] { - return SysRootKitAspect::sysRoot(kit); - }); -} - -const SysRootKitAspectFactory theSyRootKitAspectFactory; - -} // namespace Internal - -Id SysRootKitAspect::id() -{ - return "PE.Profile.SysRoot"; -} - -FilePath SysRootKitAspect::sysRoot(const Kit *k) -{ - if (!k) - return {}; - - if (!k->value(SysRootKitAspect::id()).toString().isEmpty()) - return FilePath::fromSettings(k->value(SysRootKitAspect::id())); - - for (Toolchain *tc : ToolchainKitAspect::toolChains(k)) { - if (!tc->sysRoot().isEmpty()) - return FilePath::fromString(tc->sysRoot()); - } - return {}; -} - -void SysRootKitAspect::setSysRoot(Kit *k, const FilePath &v) -{ - if (!k) - return; - - for (Toolchain *tc : ToolchainKitAspect::toolChains(k)) { - if (!tc->sysRoot().isEmpty()) { - // It's the sysroot from toolchain, don't set it. - if (tc->sysRoot() == v.toString()) - return; - - // We've changed the default toolchain sysroot, set it. - break; - } - } - k->setValue(SysRootKitAspect::id(), v.toString()); -} - -// -------------------------------------------------------------------------- -// EnvironmentKitAspect: -// -------------------------------------------------------------------------- static EnvironmentItem forceMSVCEnglishItem() { static EnvironmentItem item("VSLANG", "1033"); @@ -281,7 +127,6 @@ private: QCheckBox *m_vslangCheckbox; QWidget *m_mainWidget; }; -} // namespace Internal class EnvironmentKitAspectFactory : public KitAspectFactory { @@ -333,8 +178,8 @@ void EnvironmentKitAspectFactory::fix(Kit *k) void EnvironmentKitAspectFactory::addToBuildEnvironment(const Kit *k, Environment &env) const { const QStringList values - = transform(EnvironmentItem::toStringList(EnvironmentKitAspect::environmentChanges(k)), - [k](const QString &v) { return k->macroExpander()->expand(v); }); + = transform(EnvironmentItem::toStringList(EnvironmentKitAspect::environmentChanges(k)), + [k](const QString &v) { return k->macroExpander()->expand(v); }); env.modify(EnvironmentItem::fromStringList(values)); } @@ -352,9 +197,13 @@ KitAspect *EnvironmentKitAspectFactory::createKitAspect(Kit *k) const KitAspectFactory::ItemList EnvironmentKitAspectFactory::toUserOutput(const Kit *k) const { return {{Tr::tr("Environment"), - EnvironmentItem::toStringList(EnvironmentKitAspect::environmentChanges(k)).join("
")}}; + EnvironmentItem::toStringList(EnvironmentKitAspect::environmentChanges(k)).join("
")}}; } +const EnvironmentKitAspectFactory theEnvironmentKitAspectFactory; + +} // namespace Internal + Id EnvironmentKitAspect::id() { return "PE.Profile.Environment"; @@ -373,6 +222,4 @@ void EnvironmentKitAspect::setEnvironmentChanges(Kit *k, const EnvironmentItems k->setValue(EnvironmentKitAspect::id(), EnvironmentItem::toStringList(changes)); } -const EnvironmentKitAspectFactory theEnvironmentKitAspectFactory; - } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/kitaspects.h b/src/plugins/projectexplorer/environmentkitaspect.h similarity index 56% rename from src/plugins/projectexplorer/kitaspects.h rename to src/plugins/projectexplorer/environmentkitaspect.h index 1c9b785a744..b7ebc155576 100644 --- a/src/plugins/projectexplorer/kitaspects.h +++ b/src/plugins/projectexplorer/environmentkitaspect.h @@ -3,24 +3,14 @@ #pragma once -#include "abi.h" -#include "devicesupport/devicekitaspects.h" -#include "toolchainkitaspect.h" +#include "projectexplorer_export.h" -#include +#include + +namespace Utils { class Id; } namespace ProjectExplorer { class Kit; -class Toolchain; -class ToolchainBundle; - -class PROJECTEXPLORER_EXPORT SysRootKitAspect -{ -public: - static Utils::Id id(); - static Utils::FilePath sysRoot(const Kit *k); - static void setSysRoot(Kit *k, const Utils::FilePath &v); -}; class PROJECTEXPLORER_EXPORT EnvironmentKitAspect { diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index 59531898a1c..e72ce3772dd 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -4,7 +4,7 @@ #include "extracompiler.h" #include "buildmanager.h" -#include "kitaspects.h" +#include "environmentkitaspect.h" #include "projectmanager.h" #include "target.h" diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp index 25f420bdd9e..828e02eb084 100644 --- a/src/plugins/projectexplorer/kit.cpp +++ b/src/plugins/projectexplorer/kit.cpp @@ -3,10 +3,10 @@ #include "kit.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/idevice.h" #include "devicesupport/idevicefactory.h" #include "kitaspect.h" -#include "kitaspects.h" #include "kitmanager.h" #include "ioutputparser.h" #include "osparser.h" diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index bcfced094c4..c8fabb17792 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -3,8 +3,8 @@ #include "kitaspect.h" +#include "devicesupport/devicekitaspects.h" #include "kit.h" -#include "kitaspects.h" #include "projectexplorertr.h" #include diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index 563cf19b0a7..b2754fa47f3 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -4,13 +4,14 @@ #include "kitmanager.h" #include "abi.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/idevicefactory.h" #include "kit.h" #include "kitfeatureprovider.h" #include "kitaspect.h" -#include "kitaspects.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" +#include "toolchainkitaspect.h" #include "toolchainmanager.h" #include diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index 73c7dac7588..dd2014dca8c 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -3,10 +3,10 @@ #include "kitmanagerconfigwidget.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/idevicefactory.h" #include "kit.h" #include "kitaspect.h" -#include "kitaspects.h" #include "kitmanager.h" #include "projectexplorertr.h" #include "task.h" diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index 6a4db951059..c5fd71101e3 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -4,16 +4,17 @@ #include "makestep.h" #include "buildconfiguration.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/idevice.h" #include "gnumakeparser.h" #include "kit.h" -#include "kitaspects.h" #include "processparameters.h" #include "projectexplorer.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" #include "target.h" #include "toolchain.h" +#include "toolchainkitaspect.h" #include #include diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp index af1d3928c25..290833045a6 100644 --- a/src/plugins/projectexplorer/parseissuesdialog.cpp +++ b/src/plugins/projectexplorer/parseissuesdialog.cpp @@ -3,11 +3,11 @@ #include "parseissuesdialog.h" -#include "kitaspects.h" +#include "devicesupport/devicekitaspects.h" #include "kitchooser.h" #include "kitmanager.h" -#include "projectexplorerconstants.h" #include "projectexplorertr.h" +#include "projectexplorerconstants.h" #include "taskhub.h" #include diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 1400e8e86ba..2385a7d4c13 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -7,10 +7,10 @@ #include "buildinfo.h" #include "buildsystem.h" #include "deployconfiguration.h" +#include "devicesupport/devicekitaspects.h" #include "editorconfiguration.h" #include "environmentaspect.h" #include "kit.h" -#include "kitaspects.h" #include "msvctoolchain.h" #include "projectexplorer.h" #include "projectexplorerconstants.h" @@ -21,6 +21,7 @@ #include "runconfigurationaspects.h" #include "target.h" #include "taskhub.h" +#include "toolchainkitaspect.h" #include "toolchainmanager.h" #include "userfileaccessor.h" diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index bc0e95c2a18..6d3ca9fb772 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -36,6 +36,7 @@ #include "devicesupport/desktopdevice.h" #include "devicesupport/desktopdevicefactory.h" #include "devicesupport/devicecheckbuildstep.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/devicemanager.h" #include "devicesupport/devicesettingspage.h" #include "devicesupport/sshsettings.h" @@ -49,7 +50,6 @@ #include "jsonwizard/jsonwizardscannergenerator.h" #include "jsonwizard/jsonwizardpagefactory_p.h" #include "kitfeatureprovider.h" -#include "kitaspects.h" #include "kitmanager.h" #include "miniprojecttargetselector.h" #include "namedwidget.h" diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index dc2547cf1f9..8ce76b16010 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -61,6 +61,7 @@ QtcPlugin { "editorsettingspropertiespage.cpp", "editorsettingspropertiespage.h", "environmentaspect.cpp", "environmentaspect.h", "environmentaspectwidget.cpp", "environmentaspectwidget.h", + "environmentkitaspect.cpp", "environmentkitaspect.h", "environmentwidget.cpp", "environmentwidget.h", "expanddata.cpp", "expanddata.h", "extraabi.cpp", "extraabi.h", @@ -77,7 +78,6 @@ QtcPlugin { "itaskhandler.h", "kit.cpp", "kit.h", "kitaspect.cpp", "kitaspect.h", - "kitaspects.cpp", "kitaspects.h", "kitchooser.cpp", "kitchooser.h", "kitfeatureprovider.h", "kitmanager.cpp", "kitmanager.h", @@ -135,6 +135,7 @@ QtcPlugin { "showineditortaskhandler.cpp", "showineditortaskhandler.h", "showoutputtaskhandler.cpp", "showoutputtaskhandler.h", "simpleprojectwizard.cpp", "simpleprojectwizard.h", + "sysrootkitaspect.cpp", "sysrootkitaspect.h", "target.cpp", "target.h", "targetsettingspanel.cpp", "targetsettingspanel.h", "targetsetuppage.cpp", "targetsetuppage.h", diff --git a/src/plugins/projectexplorer/projectimporter.cpp b/src/plugins/projectexplorer/projectimporter.cpp index 239f27e89b9..a4c7df4e61b 100644 --- a/src/plugins/projectexplorer/projectimporter.cpp +++ b/src/plugins/projectexplorer/projectimporter.cpp @@ -4,13 +4,14 @@ #include "projectimporter.h" #include "buildinfo.h" +#include "devicesupport/devicekitaspects.h" #include "kit.h" -#include "kitaspects.h" #include "kitmanager.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" #include "target.h" #include "toolchain.h" +#include "toolchainkitaspect.h" #include "toolchainmanager.h" #include diff --git a/src/plugins/projectexplorer/rawprojectpart.cpp b/src/plugins/projectexplorer/rawprojectpart.cpp index bad242f5380..0825b6b6914 100644 --- a/src/plugins/projectexplorer/rawprojectpart.cpp +++ b/src/plugins/projectexplorer/rawprojectpart.cpp @@ -6,9 +6,11 @@ #include "abi.h" #include "buildconfiguration.h" #include "buildsystem.h" -#include "kitaspects.h" +#include "devicesupport/devicekitaspects.h" #include "project.h" #include "target.h" +#include "sysrootkitaspect.h" +#include "toolchainkitaspect.h" #include diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index e1490c6d3b3..22c6282c698 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -5,8 +5,8 @@ #include "buildconfiguration.h" #include "buildsystem.h" +#include "devicesupport/devicekitaspects.h" #include "environmentaspect.h" -#include "kitaspects.h" #include "project.h" #include "projectexplorer.h" #include "projectexplorerconstants.h" diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index 965131465a8..138e740c724 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -3,10 +3,10 @@ #include "runconfigurationaspects.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/devicemanager.h" #include "devicesupport/idevice.h" #include "environmentaspect.h" -#include "kitaspects.h" #include "projectexplorer.h" #include "projectexplorersettings.h" #include "projectexplorertr.h" diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 605f255d81b..6fef5669272 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -6,13 +6,13 @@ #include "appoutputpane.h" #include "buildconfiguration.h" #include "customparser.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/devicemanager.h" #include "devicesupport/deviceusedportsgatherer.h" #include "devicesupport/idevice.h" #include "devicesupport/idevicefactory.h" #include "devicesupport/sshparameters.h" #include "devicesupport/sshsettings.h" -#include "kitaspects.h" #include "project.h" #include "projectexplorer.h" #include "projectexplorerconstants.h" diff --git a/src/plugins/projectexplorer/sysrootkitaspect.cpp b/src/plugins/projectexplorer/sysrootkitaspect.cpp new file mode 100644 index 00000000000..32013226dbb --- /dev/null +++ b/src/plugins/projectexplorer/sysrootkitaspect.cpp @@ -0,0 +1,168 @@ +// 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 "sysrootkitaspect.h" + +#include "kit.h" +#include "kitaspect.h" +#include "projectexplorertr.h" +#include "toolchain.h" +#include "toolchainkitaspect.h" + +#include +#include +#include +#include +#include + +using namespace Utils; + +namespace ProjectExplorer { +namespace Internal { +class SysRootKitAspectImpl : public KitAspect +{ +public: + SysRootKitAspectImpl(Kit *k, const KitAspectFactory *factory) : KitAspect(k, factory) + { + m_chooser = createSubWidget(); + m_chooser->setExpectedKind(PathChooser::ExistingDirectory); + m_chooser->setHistoryCompleter("PE.SysRoot.History"); + m_chooser->setFilePath(SysRootKitAspect::sysRoot(k)); + connect(m_chooser, &PathChooser::textChanged, + this, &SysRootKitAspectImpl::pathWasChanged); + } + + ~SysRootKitAspectImpl() override { delete m_chooser; } + +private: + void makeReadOnly() override { m_chooser->setReadOnly(true); } + + void addToInnerLayout(Layouting::Layout &layout) override + { + addMutableAction(m_chooser); + layout.addItem(Layouting::Span(2, m_chooser)); + } + + void refresh() override + { + if (!m_ignoreChanges.isLocked()) + m_chooser->setFilePath(SysRootKitAspect::sysRoot(kit())); + } + + void pathWasChanged() + { + const GuardLocker locker(m_ignoreChanges); + SysRootKitAspect::setSysRoot(kit(), m_chooser->filePath()); + } + + PathChooser *m_chooser; + Guard m_ignoreChanges; +}; + +class SysRootKitAspectFactory : public KitAspectFactory +{ +public: + SysRootKitAspectFactory(); + + Tasks validate(const Kit *k) const override; + KitAspect *createKitAspect(Kit *k) const override; + ItemList toUserOutput(const Kit *k) const override; + void addToMacroExpander(Kit *kit, MacroExpander *expander) const override; +}; + +SysRootKitAspectFactory::SysRootKitAspectFactory() +{ + setId(SysRootKitAspect::id()); + setDisplayName(Tr::tr("Sysroot")); + setDescription(Tr::tr("The root directory of the system image to use.
" + "Leave empty when building for the desktop.")); + setPriority(27000); +} + +Tasks SysRootKitAspectFactory::validate(const Kit *k) const +{ + Tasks result; + const FilePath dir = SysRootKitAspect::sysRoot(k); + if (dir.isEmpty()) + return result; + + if (dir.startsWith("target:") || dir.startsWith("remote:")) + return result; + + if (!dir.exists()) { + result << BuildSystemTask(Task::Warning, + Tr::tr("Sys Root \"%1\" does not exist in the file system.").arg(dir.toUserOutput())); + } else if (!dir.isDir()) { + result << BuildSystemTask(Task::Warning, + Tr::tr("Sys Root \"%1\" is not a directory.").arg(dir.toUserOutput())); + } else if (dir.dirEntries(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) { + result << BuildSystemTask(Task::Warning, + Tr::tr("Sys Root \"%1\" is empty.").arg(dir.toUserOutput())); + } + return result; +} + +KitAspect *SysRootKitAspectFactory::createKitAspect(Kit *k) const +{ + QTC_ASSERT(k, return nullptr); + + return new Internal::SysRootKitAspectImpl(k, this); +} + +KitAspectFactory::ItemList SysRootKitAspectFactory::toUserOutput(const Kit *k) const +{ + return {{Tr::tr("Sys Root"), SysRootKitAspect::sysRoot(k).toUserOutput()}}; +} + +void SysRootKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expander) const +{ + QTC_ASSERT(kit, return); + + expander->registerFileVariables("SysRoot", Tr::tr("Sys Root"), [kit] { + return SysRootKitAspect::sysRoot(kit); + }); +} + +const SysRootKitAspectFactory theSyRootKitAspectFactory; + +} // namespace Internal + +Id SysRootKitAspect::id() +{ + return "PE.Profile.SysRoot"; +} + +FilePath SysRootKitAspect::sysRoot(const Kit *k) +{ + if (!k) + return {}; + + if (!k->value(SysRootKitAspect::id()).toString().isEmpty()) + return FilePath::fromSettings(k->value(SysRootKitAspect::id())); + + for (Toolchain *tc : ToolchainKitAspect::toolChains(k)) { + if (!tc->sysRoot().isEmpty()) + return FilePath::fromString(tc->sysRoot()); + } + return {}; +} + +void SysRootKitAspect::setSysRoot(Kit *k, const FilePath &v) +{ + if (!k) + return; + + for (Toolchain *tc : ToolchainKitAspect::toolChains(k)) { + if (!tc->sysRoot().isEmpty()) { + // It's the sysroot from toolchain, don't set it. + if (tc->sysRoot() == v.toString()) + return; + + // We've changed the default toolchain sysroot, set it. + break; + } + } + k->setValue(SysRootKitAspect::id(), v.toString()); +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/sysrootkitaspect.h b/src/plugins/projectexplorer/sysrootkitaspect.h new file mode 100644 index 00000000000..86dcb390a21 --- /dev/null +++ b/src/plugins/projectexplorer/sysrootkitaspect.h @@ -0,0 +1,24 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "projectexplorer_export.h" + +namespace Utils { +class FilePath; +class Id; +} // namespace Utils + +namespace ProjectExplorer { +class Kit; + +class PROJECTEXPLORER_EXPORT SysRootKitAspect +{ +public: + static Utils::Id id(); + static Utils::FilePath sysRoot(const Kit *k); + static void setSysRoot(Kit *k, const Utils::FilePath &v); +}; + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index eb6105273b6..42c52c17018 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -10,9 +10,9 @@ #include "buildtargetinfo.h" #include "deployconfiguration.h" #include "deploymentdata.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/devicemanager.h" #include "kit.h" -#include "kitaspects.h" #include "kitmanager.h" #include "miniprojecttargetselector.h" #include "project.h" diff --git a/src/plugins/projectexplorer/toolchainkitaspect.cpp b/src/plugins/projectexplorer/toolchainkitaspect.cpp index cd8db8f27b1..77ea6a6981b 100644 --- a/src/plugins/projectexplorer/toolchainkitaspect.cpp +++ b/src/plugins/projectexplorer/toolchainkitaspect.cpp @@ -3,10 +3,10 @@ #include "toolchainkitaspect.h" +#include "devicesupport/devicekitaspects.h" #include "devicesupport/idevice.h" #include "kit.h" #include "kitaspect.h" -#include "kitaspects.h" #include "kitmanager.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 49091b886c9..58e5d11f81b 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index e64e8a51523..f3caa25d261 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -12,11 +12,13 @@ #include #include #include +#include #include #include #include -#include #include +#include +#include #include #include #include diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp index 9fe3a05895a..5bcce759105 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 7f865948d79..2a14b493ecd 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp b/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp index 4e31b8d765c..8fdfd9d3c0d 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp @@ -10,12 +10,13 @@ #include #include #include -#include #include #include #include #include +#include #include +#include #include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index 5eac58e8087..ab6454e05c0 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -24,14 +24,16 @@ #include #include #include +#include #include -#include #include #include #include #include +#include #include #include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp b/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp index 34d7ddfbd3b..dbe3c559798 100644 --- a/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp +++ b/src/plugins/qmakeprojectmanager/qmakekitaspect.cpp @@ -7,9 +7,9 @@ #include "qmakeprojectmanagertr.h" #include -#include #include #include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp index ae8b370b778..1f5a292467a 100644 --- a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp @@ -14,12 +14,12 @@ #include #include -#include #include #include #include #include #include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 150851f7adc..fd0a65f6373 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -25,19 +25,21 @@ #include #include #include +#include #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp index 220e18a12ea..2e85cb71911 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp @@ -12,10 +12,10 @@ #include "qmakestep.h" #include -#include -#include #include +#include #include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index e94a2678e45..1f34696df15 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -16,15 +16,17 @@ #include #include +#include #include -#include #include #include #include #include #include +#include #include #include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp b/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp index c76e0be174c..a4493d6361d 100644 --- a/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp index e30545387f9..3c76b93c9c6 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -27,7 +27,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp index 93a03772103..b7af3845e26 100644 --- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp +++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp @@ -10,7 +10,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index 71fd60cbc31..b724566c567 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp b/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp index 731b523b027..e1e2ca05f3e 100644 --- a/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp +++ b/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp @@ -3,8 +3,8 @@ #include "qmlpreviewfileontargetfinder.h" +#include #include -#include #include #include #include diff --git a/src/plugins/qmlpreview/qmlpreviewplugin.cpp b/src/plugins/qmlpreview/qmlpreviewplugin.cpp index 47e0589f5e3..c60225607a8 100644 --- a/src/plugins/qmlpreview/qmlpreviewplugin.cpp +++ b/src/plugins/qmlpreview/qmlpreviewplugin.cpp @@ -22,8 +22,8 @@ #include +#include #include -#include #include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilerattachdialog.cpp b/src/plugins/qmlprofiler/qmlprofilerattachdialog.cpp index 37b96931ab2..ce4e834ef6b 100644 --- a/src/plugins/qmlprofiler/qmlprofilerattachdialog.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerattachdialog.cpp @@ -4,7 +4,7 @@ #include "qmlprofilerattachdialog.h" #include "qmlprofilertr.h" -#include +#include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp b/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp index 5fb1f203ef6..04f8319f5b0 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp @@ -4,7 +4,7 @@ #include "qmlprofilerdetailsrewriter.h" #include -#include +#include #include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp index 6faec4b4c23..c55ea64a345 100644 --- a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index 2f7bfb488ff..43666ab5ff1 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index da6bc556d7a..e7834d1209e 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -33,9 +33,9 @@ #include #include +#include #include #include -#include #include #include #include diff --git a/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp b/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp index 4539948be37..1aab728f4a4 100644 --- a/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp +++ b/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp @@ -6,11 +6,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp index 80ff0532e2c..2eae7475c83 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp @@ -27,8 +27,8 @@ #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index bdcf1837532..6e8cfd8a827 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -10,8 +10,8 @@ #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index fd333c6f898..4fe33ae0579 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -15,9 +15,9 @@ #include #include +#include #include #include -#include #include #include #include diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index 27f2fa33ecb..aeffc7e5982 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -14,11 +14,11 @@ #include #include +#include #include #include #include #include -#include #include #include #include diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index 8db9af65f14..5cb805f74fd 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -22,11 +22,12 @@ #include #include #include -#include +#include #include #include #include #include +#include #include diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 6d46b6c2c01..a5db2b60423 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -15,13 +15,16 @@ #include #include +#include #include #include -#include +#include #include #include +#include #include #include +#include #include #include diff --git a/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.cpp index 7c6c31a6133..d918e24dc20 100644 --- a/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp index a2596ad45c9..102933f47e1 100644 --- a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp @@ -9,8 +9,8 @@ #include "appmanagertr.h" #include +#include #include -#include #include #include diff --git a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp index f7e027d8b92..242b9ccd36f 100644 --- a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp index a5a75613def..35f573dd9c8 100644 --- a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp @@ -15,8 +15,8 @@ #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp index f1671bfdc7e..edb97c0186e 100644 --- a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp @@ -11,8 +11,8 @@ #include "appmanagertr.h" #include "appmanagerutilities.h" +#include #include -#include #include #include diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index dccb6528e24..812206c8243 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -20,12 +20,13 @@ #include #include #include +#include #include -#include #include #include #include #include +#include #include #include diff --git a/src/plugins/qtapplicationmanager/appmanagertargetinformation.cpp b/src/plugins/qtapplicationmanager/appmanagertargetinformation.cpp index 4891353953f..166a0ddd2cc 100644 --- a/src/plugins/qtapplicationmanager/appmanagertargetinformation.cpp +++ b/src/plugins/qtapplicationmanager/appmanagertargetinformation.cpp @@ -7,7 +7,7 @@ #include "appmanagerconstants.h" -#include +#include #include #include #include diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 82598fdc265..98aaeb3b657 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -22,14 +22,16 @@ #include #include +#include #include -#include #include #include #include #include +#include #include #include +#include #include #include diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index b738278db4f..fb0d7a4a504 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -10,13 +10,14 @@ #include "qttestparser.h" #include "qtversionmanager.h" +#include #include #include -#include #include #include #include #include +#include #include #include diff --git a/src/plugins/qtsupport/qtprojectimporter.cpp b/src/plugins/qtsupport/qtprojectimporter.cpp index 17cb7a1cefe..c2210da5e9b 100644 --- a/src/plugins/qtsupport/qtprojectimporter.cpp +++ b/src/plugins/qtsupport/qtprojectimporter.cpp @@ -8,8 +8,8 @@ #include "qtversionmanager.h" #include -#include #include +#include #include #include diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp index 9077efdd629..e4d44ea458b 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp @@ -7,8 +7,8 @@ #include "remotelinuxtr.h" #include +#include #include -#include #include diff --git a/src/plugins/remotelinux/deploymenttimeinfo.cpp b/src/plugins/remotelinux/deploymenttimeinfo.cpp index 084d73dc9b2..309d3f021df 100644 --- a/src/plugins/remotelinux/deploymenttimeinfo.cpp +++ b/src/plugins/remotelinux/deploymenttimeinfo.cpp @@ -4,9 +4,10 @@ #include "deploymenttimeinfo.h" #include +#include #include #include -#include +#include #include #include diff --git a/src/plugins/remotelinux/genericdeploystep.cpp b/src/plugins/remotelinux/genericdeploystep.cpp index 5ea55a7f97f..805c82fc5f3 100644 --- a/src/plugins/remotelinux/genericdeploystep.cpp +++ b/src/plugins/remotelinux/genericdeploystep.cpp @@ -10,10 +10,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index 604c41f2182..1a2519a3af8 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp b/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp index bae288e3a4b..6503283f927 100644 --- a/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp +++ b/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp @@ -8,9 +8,9 @@ #include +#include #include #include -#include #include #include diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp index 6952ec11095..0b74373c0e6 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp @@ -10,8 +10,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 5d63bed1f71..7ba2f9b84c8 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -14,14 +14,14 @@ #include #include -#include "projectexplorer/target.h" +#include #include #include -#include #include #include #include #include +#include #include #include diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index a7e2ddefb93..5b4fa2365a3 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -32,8 +32,8 @@ #include #include +#include #include -#include #include #include #include @@ -42,6 +42,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 9f399f9d464..f3f8fd07981 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -13,8 +13,8 @@ #include +#include #include -#include #include #include From afffc3feda890ab03b2c9d6ea1333db204ef4688 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 09:32:05 +0100 Subject: [PATCH 202/989] DiffEditor: Remove unused static variable Change-Id: I7269efdf152d3aaee3675c98bb408ea5a90fa899 Reviewed-by: hjk --- src/plugins/diffeditor/diffeditorplugin.cpp | 8 -------- src/plugins/diffeditor/diffeditorplugin.h | 1 - 2 files changed, 9 deletions(-) diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 1f62df2e592..80c5e575eb8 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -514,17 +514,9 @@ void DiffEditorPluginPrivate::diffExternalFiles() reload(documentId, title, filePath1.toString(), filePath2.toString()); } -static DiffEditorPlugin *s_instance = nullptr; - -DiffEditorPlugin::DiffEditorPlugin() -{ - s_instance = this; -} - DiffEditorPlugin::~DiffEditorPlugin() { delete d; - s_instance = nullptr; } void DiffEditorPlugin::initialize() diff --git a/src/plugins/diffeditor/diffeditorplugin.h b/src/plugins/diffeditor/diffeditorplugin.h index 9888628daac..eb1712cf24c 100644 --- a/src/plugins/diffeditor/diffeditorplugin.h +++ b/src/plugins/diffeditor/diffeditorplugin.h @@ -26,7 +26,6 @@ class DiffEditorPlugin final : public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "DiffEditor.json") public: - DiffEditorPlugin(); ~DiffEditorPlugin(); void initialize() final; From b960a6e2b994ab8133ef8e856ce142d1237878d1 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 20 Nov 2024 11:13:16 +0100 Subject: [PATCH 203/989] Fix filter actions in output views The IDs were generated from the class name via metaObject, but since can be set up from the output view's constructor, that information can be broken ("Core::IOutputPane"). This was broken before for the AppOutputPane, but now we got conflicts from multiple ones. Change-Id: I1729005067a9fc645f414de98955b8d6f7954d86 Reviewed-by: hjk --- src/plugins/autotest/testresultspane.cpp | 2 +- src/plugins/coreplugin/ioutputpane.h | 3 ++- src/plugins/coreplugin/messagemanager.cpp | 2 +- src/plugins/coreplugin/outputpanemanager.cpp | 14 ++++++++------ src/plugins/projectexplorer/appoutputpane.cpp | 2 +- .../projectexplorer/compileoutputwindow.cpp | 2 +- src/plugins/projectexplorer/taskwindow.cpp | 2 +- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/plugins/autotest/testresultspane.cpp b/src/plugins/autotest/testresultspane.cpp index 3ea4b503ef8..d30c42e14b6 100644 --- a/src/plugins/autotest/testresultspane.cpp +++ b/src/plugins/autotest/testresultspane.cpp @@ -128,7 +128,7 @@ TestResultsPane::TestResultsPane(QObject *parent) : m_textOutput->setReadOnly(true); m_outputWidget->addWidget(m_textOutput); - setupFilterUi("AutoTest.TextOutput.Filter"); + setupFilterUi("AutoTest.TextOutput.Filter", "Autotest::Internal::TestResultsPane"); setupContext("AutoTest.TextOutput", m_textOutput); setFilteringEnabled(false); setZoomButtonsEnabled(false); diff --git a/src/plugins/coreplugin/ioutputpane.h b/src/plugins/coreplugin/ioutputpane.h index e51f74a6fff..dcf91403e2d 100644 --- a/src/plugins/coreplugin/ioutputpane.h +++ b/src/plugins/coreplugin/ioutputpane.h @@ -78,7 +78,7 @@ protected: void setDisplayName(const QString &name); void setPriorityInStatusBar(int priority); - void setupFilterUi(const Utils::Key &historyKey); + void setupFilterUi(const Utils::Key &historyKey, const QString &actionSuffix); QString filterText() const; bool filterUsesRegexp() const { return m_filterRegexp; } bool filterIsInverted() const { return m_invertFilter; } @@ -106,6 +106,7 @@ private: Utils::Id m_id; QString m_displayName; int m_priority = -1; + QString m_filterActionSuffix; QToolButton *m_zoomInButton; QToolButton *m_zoomOutButton; QAction *m_filterActionRegexp = nullptr; diff --git a/src/plugins/coreplugin/messagemanager.cpp b/src/plugins/coreplugin/messagemanager.cpp index e72400bc99d..f74defc51bd 100644 --- a/src/plugins/coreplugin/messagemanager.cpp +++ b/src/plugins/coreplugin/messagemanager.cpp @@ -52,7 +52,7 @@ public: connect(this, &IOutputPane::fontChanged, m_widget, &OutputWindow::setBaseFont); connect(this, &IOutputPane::wheelZoomEnabledChanged, m_widget, &OutputWindow::setWheelZoomEnabled); - setupFilterUi("MessageOutputPane.Filter"); + setupFilterUi("MessageOutputPane.Filter", "Core::Internal::MessageOutputWindow"); setFilteringEnabled(true); setupContext(Constants::C_GENERAL_OUTPUT_PANE, m_widget); } diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index ec30f0701a0..7da3ab02c60 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -377,8 +377,10 @@ void IOutputPane::setWheelZoomEnabled(bool enabled) emit wheelZoomEnabledChanged(enabled); } -void IOutputPane::setupFilterUi(const Key &historyKey) +void IOutputPane::setupFilterUi(const Key &historyKey, const QString &actionSuffix) { + m_filterActionSuffix = actionSuffix; + ActionBuilder filterRegexpAction(this, filterRegexpActionId()); filterRegexpAction.setText(Tr::tr("Use Regular Expressions")); filterRegexpAction.setCheckable(true); @@ -505,27 +507,27 @@ void IOutputPane::setRegularExpressions(bool regularExpressions) Id IOutputPane::filterRegexpActionId() const { - return Id("OutputFilter.RegularExpressions").withSuffix(metaObject()->className()); + return Id("OutputFilter.RegularExpressions").withSuffix(m_filterActionSuffix); } Id IOutputPane::filterCaseSensitivityActionId() const { - return Id("OutputFilter.CaseSensitive").withSuffix(metaObject()->className()); + return Id("OutputFilter.CaseSensitive").withSuffix(m_filterActionSuffix); } Id IOutputPane::filterInvertedActionId() const { - return Id("OutputFilter.Invert").withSuffix(metaObject()->className()); + return Id("OutputFilter.Invert").withSuffix(m_filterActionSuffix); } Id IOutputPane::filterBeforeActionId() const { - return Id("OutputFilter.BeforeContext").withSuffix(metaObject()->className()); + return Id("OutputFilter.BeforeContext").withSuffix(m_filterActionSuffix); } Id IOutputPane::filterAfterActionId() const { - return Id("OutputFilter.AfterContext").withSuffix(metaObject()->className()); + return Id("OutputFilter.AfterContext").withSuffix(m_filterActionSuffix); } void IOutputPane::setCaseSensitive(bool caseSensitive) diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index 22e76bd27ae..67420d692a2 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -214,7 +214,7 @@ AppOutputPane::AppOutputPane() : connect(ProjectManager::instance(), &ProjectManager::projectRemoved, this, &AppOutputPane::projectRemoved); - setupFilterUi("AppOutputPane.Filter"); + setupFilterUi("AppOutputPane.Filter", "ProjectExplorer::Internal::AppOutputPane"); setFilteringEnabled(false); setZoomButtonsEnabled(false); setupContext("Core.AppOutputPane", m_tabWidget); diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp index 91f9902149c..3da5117cea2 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.cpp +++ b/src/plugins/projectexplorer/compileoutputwindow.cpp @@ -82,7 +82,7 @@ CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) : updateFontSettings(); updateZoomEnabled(); - setupFilterUi("CompileOutputPane.Filter"); + setupFilterUi("CompileOutputPane.Filter", "ProjectExplorer::Internal::CompileOutputPane"); setFilteringEnabled(true); connect(this, &IOutputPane::zoomInRequested, m_outputWindow, &Core::OutputWindow::zoomIn); diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 298ed4580ec..7a3945f82ad 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -221,7 +221,7 @@ TaskWindow::TaskWindow() : d(std::make_unique()) d->m_categoriesButton->setMenu(d->m_categoriesMenu); - setupFilterUi("IssuesPane.Filter"); + setupFilterUi("IssuesPane.Filter", "ProjectExplorer::Internal::TaskWindow"); setFilteringEnabled(true); TaskHub *hub = &taskHub(); From e5939b9a652ee7bb0c8fb0af715027c8a155a637 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 10:41:40 +0100 Subject: [PATCH 204/989] DiffEditor: Dismantle diffeditorplugin.h Move the content into cpp file. Change-Id: I227801fc2d2a0fd7b755e818f9ef4f64d1f7e5b6 Reviewed-by: hjk --- src/plugins/diffeditor/CMakeLists.txt | 2 +- src/plugins/diffeditor/diffeditor.qbs | 1 - src/plugins/diffeditor/diffeditorplugin.cpp | 49 +++++++++++++++------ src/plugins/diffeditor/diffeditorplugin.h | 47 -------------------- 4 files changed, 37 insertions(+), 62 deletions(-) delete mode 100644 src/plugins/diffeditor/diffeditorplugin.h diff --git a/src/plugins/diffeditor/CMakeLists.txt b/src/plugins/diffeditor/CMakeLists.txt index fb4766d4a05..34b075c97a4 100644 --- a/src/plugins/diffeditor/CMakeLists.txt +++ b/src/plugins/diffeditor/CMakeLists.txt @@ -9,7 +9,7 @@ add_qtc_plugin(DiffEditor diffeditorcontroller.cpp diffeditorcontroller.h diffeditordocument.cpp diffeditordocument.h diffeditoricons.h - diffeditorplugin.cpp diffeditorplugin.h + diffeditorplugin.cpp diffeditorwidgetcontroller.cpp diffeditorwidgetcontroller.h diffenums.h diffutils.cpp diffutils.h diff --git a/src/plugins/diffeditor/diffeditor.qbs b/src/plugins/diffeditor/diffeditor.qbs index 0611bdea4c1..2d46f7004ae 100644 --- a/src/plugins/diffeditor/diffeditor.qbs +++ b/src/plugins/diffeditor/diffeditor.qbs @@ -25,7 +25,6 @@ QtcPlugin { "diffeditordocument.cpp", "diffeditordocument.h", "diffeditorplugin.cpp", - "diffeditorplugin.h", "diffeditorwidgetcontroller.cpp", "diffeditorwidgetcontroller.h", "diffenums.h", diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 80c5e575eb8..9948f34085b 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -1,7 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "diffeditorplugin.h" #include "diffeditorconstants.h" #include "diffeditorcontroller.h" #include "diffeditordocument.h" @@ -10,9 +9,12 @@ #include #include +#include #include #include +#include + #include #include @@ -361,13 +363,20 @@ QList DiffExternalFilesController::reloadInputList() const ///////////////// - static TextDocument *currentTextDocument() { return qobject_cast(EditorManager::currentDocument()); } -DiffEditorServiceImpl::DiffEditorServiceImpl() = default; +class DiffEditorServiceImpl final : public QObject, public DiffService +{ + Q_OBJECT + Q_INTERFACES(Core::DiffService) + +public: + void diffFiles(const QString &leftFileName, const QString &rightFileName) final; + void diffModifiedFiles(const QStringList &fileNames) final; +}; template void reload(const QString &vcsId, const QString &displayName, Args &&...args) @@ -414,6 +423,30 @@ public: DiffEditorServiceImpl m_service; }; +class DiffEditorPlugin final : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "DiffEditor.json") + +public: + ~DiffEditorPlugin() { delete d; } + + void initialize() final { d = new DiffEditorPluginPrivate; } + +private: + class DiffEditorPluginPrivate *d = nullptr; + +#ifdef WITH_TESTS +private slots: + void testMakePatch_data(); + void testMakePatch(); + void testReadPatch_data(); + void testReadPatch(); + void testFilterPatch_data(); + void testFilterPatch(); +#endif // WITH_TESTS +}; + DiffEditorPluginPrivate::DiffEditorPluginPrivate() { setupDiffEditorFactory(); @@ -514,16 +547,6 @@ void DiffEditorPluginPrivate::diffExternalFiles() reload(documentId, title, filePath1.toString(), filePath2.toString()); } -DiffEditorPlugin::~DiffEditorPlugin() -{ - delete d; -} - -void DiffEditorPlugin::initialize() -{ - d = new DiffEditorPluginPrivate; -} - } // namespace DiffEditor::Internal #ifdef WITH_TESTS diff --git a/src/plugins/diffeditor/diffeditorplugin.h b/src/plugins/diffeditor/diffeditorplugin.h deleted file mode 100644 index eb1712cf24c..00000000000 --- a/src/plugins/diffeditor/diffeditorplugin.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include - -namespace DiffEditor::Internal { - -class DiffEditorServiceImpl : public QObject, public Core::DiffService -{ - Q_OBJECT - Q_INTERFACES(Core::DiffService) - -public: - DiffEditorServiceImpl(); - - void diffFiles(const QString &leftFileName, const QString &rightFileName) override; - void diffModifiedFiles(const QStringList &fileNames) override; -}; - -class DiffEditorPlugin final : public ExtensionSystem::IPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "DiffEditor.json") - -public: - ~DiffEditorPlugin(); - - void initialize() final; - -private: - class DiffEditorPluginPrivate *d = nullptr; - -#ifdef WITH_TESTS -private slots: - void testMakePatch_data(); - void testMakePatch(); - void testReadPatch_data(); - void testReadPatch(); - void testFilterPatch_data(); - void testFilterPatch(); -#endif // WITH_TESTS -}; - -} // namespace DiffEditor::Internal From 8a249c93ef1605f5bd88f2b445d8093db5c9e7cc Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 15 Nov 2024 13:58:17 +0100 Subject: [PATCH 205/989] Utils: disable atomic save on windows fat file system Fixes: QTCREATORBUG-29942 Change-Id: I10e0b541a364b7929bc2fa37fdc4f6e504f6b675 Reviewed-by: Eike Ziller --- src/libs/utils/fileutils.cpp | 38 +++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index c47c648c88a..3cbeb387474 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -36,6 +36,7 @@ #endif #include #include +#include #endif #ifdef Q_OS_MACOS @@ -172,6 +173,40 @@ bool FileSaverBase::setResult(QXmlStreamWriter *stream) // FileSaver +static bool saveFileSupportedFileSystem(const FilePath &path) +{ +#ifdef Q_OS_WIN + const HANDLE handle = CreateFile((wchar_t *) path.toUserOutput().utf16(), + 0, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle != INVALID_HANDLE_VALUE) { + FILESYSTEM_STATISTICS stats; + DWORD bytesReturned; + bool success = DeviceIoControl( + handle, + FSCTL_FILESYSTEM_GET_STATISTICS, + NULL, + 0, + &stats, + sizeof(stats), + &bytesReturned, + NULL); + CloseHandle(handle); + if (success || GetLastError() == ERROR_MORE_DATA) { + return stats.FileSystemType != FILESYSTEM_STATISTICS_TYPE_FAT + && stats.FileSystemType != FILESYSTEM_STATISTICS_TYPE_EXFAT; + } + } +#else + Q_UNUSED(path); +#endif + return true; +} + FileSaver::FileSaver(const FilePath &filePath, QIODevice::OpenMode mode) { m_filePath = filePath; @@ -193,7 +228,8 @@ FileSaver::FileSaver(const FilePath &filePath, QIODevice::OpenMode mode) const bool readOnlyOrAppend = mode & (QIODevice::ReadOnly | QIODevice::Append); m_isSafe = !readOnlyOrAppend && !filePath.hasHardLinks() - && !qtcEnvironmentVariableIsSet("QTC_DISABLE_ATOMICSAVE"); + && !qtcEnvironmentVariableIsSet("QTC_DISABLE_ATOMICSAVE") + && saveFileSupportedFileSystem(filePath); if (m_isSafe) m_file.reset(new SaveFile(filePath)); else From bc1f013432b5068b6a36fd656a90a0e5b5be4c2c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 11:02:13 +0100 Subject: [PATCH 206/989] DiffEditor: Remove private indirection Change-Id: Iecd9a7e5de84118ea5c3ab0bdc1d44a9582bccb5 Reviewed-by: hjk --- src/plugins/diffeditor/diffeditorplugin.cpp | 50 ++++++++------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 9948f34085b..dd750efef6e 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -406,11 +406,13 @@ void DiffEditorServiceImpl::diffModifiedFiles(const QStringList &fileNames) reload(documentId, title, fileNames); } -class DiffEditorPluginPrivate : public QObject +class DiffEditorPlugin final : public ExtensionSystem::IPlugin { -public: - DiffEditorPluginPrivate(); + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "DiffEditor.json") +private: + void initialize() final; void updateDiffCurrentFileAction(); void updateDiffOpenFilesAction(); void diffCurrentFile(); @@ -421,20 +423,6 @@ public: QAction *m_diffOpenFilesAction = nullptr; DiffEditorServiceImpl m_service; -}; - -class DiffEditorPlugin final : public ExtensionSystem::IPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "DiffEditor.json") - -public: - ~DiffEditorPlugin() { delete d; } - - void initialize() final { d = new DiffEditorPluginPrivate; } - -private: - class DiffEditorPluginPrivate *d = nullptr; #ifdef WITH_TESTS private slots: @@ -447,7 +435,7 @@ private slots: #endif // WITH_TESTS }; -DiffEditorPluginPrivate::DiffEditorPluginPrivate() +void DiffEditorPlugin::initialize() { setupDiffEditorFactory(); @@ -461,43 +449,43 @@ DiffEditorPluginPrivate::DiffEditorPluginPrivate() m_diffCurrentFileAction = new QAction(Tr::tr("Diff Current File"), this); Command *diffCurrentFileCommand = ActionManager::registerAction(m_diffCurrentFileAction, "DiffEditor.DiffCurrentFile"); diffCurrentFileCommand->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+H") : Tr::tr("Ctrl+H"))); - connect(m_diffCurrentFileAction, &QAction::triggered, this, &DiffEditorPluginPrivate::diffCurrentFile); + connect(m_diffCurrentFileAction, &QAction::triggered, this, &DiffEditorPlugin::diffCurrentFile); diffContainer->addAction(diffCurrentFileCommand); m_diffOpenFilesAction = new QAction(Tr::tr("Diff Open Files"), this); Command *diffOpenFilesCommand = ActionManager::registerAction(m_diffOpenFilesAction, "DiffEditor.DiffOpenFiles"); diffOpenFilesCommand->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Shift+H") : Tr::tr("Ctrl+Shift+H"))); - connect(m_diffOpenFilesAction, &QAction::triggered, this, &DiffEditorPluginPrivate::diffOpenFiles); + connect(m_diffOpenFilesAction, &QAction::triggered, this, &DiffEditorPlugin::diffOpenFiles); diffContainer->addAction(diffOpenFilesCommand); QAction *diffExternalFilesAction = new QAction(Tr::tr("Diff External Files..."), this); Command *diffExternalFilesCommand = ActionManager::registerAction(diffExternalFilesAction, "DiffEditor.DiffExternalFiles"); - connect(diffExternalFilesAction, &QAction::triggered, this, &DiffEditorPluginPrivate::diffExternalFiles); + connect(diffExternalFilesAction, &QAction::triggered, this, &DiffEditorPlugin::diffExternalFiles); diffContainer->addAction(diffExternalFilesCommand); connect(EditorManager::instance(), &EditorManager::currentEditorChanged, - this, &DiffEditorPluginPrivate::updateDiffCurrentFileAction); + this, &DiffEditorPlugin::updateDiffCurrentFileAction); connect(EditorManager::instance(), &EditorManager::currentDocumentStateChanged, - this, &DiffEditorPluginPrivate::updateDiffCurrentFileAction); + this, &DiffEditorPlugin::updateDiffCurrentFileAction); connect(EditorManager::instance(), &EditorManager::editorOpened, - this, &DiffEditorPluginPrivate::updateDiffOpenFilesAction); + this, &DiffEditorPlugin::updateDiffOpenFilesAction); connect(EditorManager::instance(), &EditorManager::editorsClosed, - this, &DiffEditorPluginPrivate::updateDiffOpenFilesAction); + this, &DiffEditorPlugin::updateDiffOpenFilesAction); connect(EditorManager::instance(), &EditorManager::documentStateChanged, - this, &DiffEditorPluginPrivate::updateDiffOpenFilesAction); + this, &DiffEditorPlugin::updateDiffOpenFilesAction); updateDiffCurrentFileAction(); updateDiffOpenFilesAction(); } -void DiffEditorPluginPrivate::updateDiffCurrentFileAction() +void DiffEditorPlugin::updateDiffCurrentFileAction() { auto textDocument = currentTextDocument(); const bool enabled = textDocument && textDocument->isModified(); m_diffCurrentFileAction->setEnabled(enabled); } -void DiffEditorPluginPrivate::updateDiffOpenFilesAction() +void DiffEditorPlugin::updateDiffOpenFilesAction() { const bool enabled = anyOf(DocumentModel::openedDocuments(), [](IDocument *doc) { QTC_ASSERT(doc, return false); @@ -506,7 +494,7 @@ void DiffEditorPluginPrivate::updateDiffOpenFilesAction() m_diffOpenFilesAction->setEnabled(enabled); } -void DiffEditorPluginPrivate::diffCurrentFile() +void DiffEditorPlugin::diffCurrentFile() { auto textDocument = currentTextDocument(); if (!textDocument) @@ -521,14 +509,14 @@ void DiffEditorPluginPrivate::diffCurrentFile() reload(documentId, title, fileName); } -void DiffEditorPluginPrivate::diffOpenFiles() +void DiffEditorPlugin::diffOpenFiles() { const QString documentId = Constants::DIFF_EDITOR_PLUGIN + QLatin1String(".DiffOpenFiles"); const QString title = Tr::tr("Diff Open Files"); reload(documentId, title); } -void DiffEditorPluginPrivate::diffExternalFiles() +void DiffEditorPlugin::diffExternalFiles() { const FilePath filePath1 = FileUtils::getOpenFilePath(nullptr, Tr::tr("Select First File for Diff")); if (filePath1.isEmpty()) From d45193d12e947b5d9ecb558c820c05631e705686 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 19 Nov 2024 17:13:29 +0100 Subject: [PATCH 207/989] Libs: Make static QRegularExpression instances static const Change-Id: Ie5a2675651bd83128123cc18601141ba11a13e81 Reviewed-by: hjk --- src/libs/qmldebug/qmloutputparser.cpp | 2 +- src/libs/qmleditorwidgets/fontsizespinbox.cpp | 3 +- src/libs/qmljs/qmljscheck.cpp | 5 +- src/libs/qmljs/qmljsdocument.cpp | 6 +- src/libs/qmljs/qmljsfindexportedcpptypes.cpp | 2 +- src/libs/qmljs/qmljsplugindumper.cpp | 2 +- src/libs/qmljs/qmljsscopechain.cpp | 2 +- src/libs/qmljs/qmljsutils.cpp | 2 +- .../utils/classnamevalidatinglineedit.cpp | 5 +- src/libs/utils/commandline.cpp | 6 +- src/libs/utils/differ.cpp | 6 +- src/libs/utils/fileutils.cpp | 12 ++-- src/libs/utils/htmldocextractor.cpp | 61 ++++++++++++------- src/libs/utils/persistentsettings.cpp | 2 +- src/libs/utils/processinfo.cpp | 2 +- 15 files changed, 72 insertions(+), 46 deletions(-) diff --git a/src/libs/qmldebug/qmloutputparser.cpp b/src/libs/qmldebug/qmloutputparser.cpp index 5d0e07025f7..b1416134e85 100644 --- a/src/libs/qmldebug/qmloutputparser.cpp +++ b/src/libs/qmldebug/qmloutputparser.cpp @@ -59,7 +59,7 @@ void QmlOutputParser::processOutput(const QString &output) if (status.startsWith(waitingForConnection)) { status.remove(0, waitingForConnection.size()); // chop of 'Waiting for connection ' - static QRegularExpression waitingTcp( + static const QRegularExpression waitingTcp( QString::fromLatin1(Constants::STR_ON_PORT_PATTERN)); const QRegularExpressionMatch match = waitingTcp.match(status); if (match.hasMatch()) { diff --git a/src/libs/qmleditorwidgets/fontsizespinbox.cpp b/src/libs/qmleditorwidgets/fontsizespinbox.cpp index 39fd48cbdda..274073c61b2 100644 --- a/src/libs/qmleditorwidgets/fontsizespinbox.cpp +++ b/src/libs/qmleditorwidgets/fontsizespinbox.cpp @@ -69,7 +69,8 @@ void FontSizeSpinBox::onEditingFinished() QValidator::State FontSizeSpinBox::validate (QString &input, int &p) const { - QRegularExpressionValidator v(QRegularExpression(QLatin1String("\\d+\\s*(px|pt)")), nullptr); + static const QRegularExpression regex("\\d+\\s*(px|pt)"); + QRegularExpressionValidator v(regex, nullptr); return v.validate(input, p); } diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index f5e0baead4d..968a96c1fa9 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -1010,7 +1010,8 @@ static bool checkTopLevelBindingForParentReference(ExpressionStatement *expStmt, SourceLocation location = locationFromRange(expStmt->firstSourceLocation(), expStmt->lastSourceLocation()); QString stmtSource = source.mid(int(location.begin()), int(location.length)); - if (stmtSource.contains(QRegularExpression("(^|\\W)parent\\."))) + static const QRegularExpression regex("(^|\\W)parent\\."); + if (stmtSource.contains(regex)) return true; return false; @@ -1718,7 +1719,7 @@ void Check::addMessage(StaticAnalysis::Type type, const SourceLocation &location void Check::scanCommentsForAnnotations() { m_disabledMessageTypesByLine.clear(); - const QRegularExpression disableCommentPattern = Message::suppressionPattern(); + static const QRegularExpression disableCommentPattern = Message::suppressionPattern(); const QList comments = _doc->engine()->comments(); for (const SourceLocation &commentLoc : comments) { diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index cd98110cae4..b9fa153386e 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -489,8 +489,8 @@ void Snapshot::insertLibraryInfo(const Utils::FilePath &path, const LibraryInfo } QStringList splitPath = path.path().split(QLatin1Char('/')); - const QRegularExpression vNr(QLatin1String("^(.+)\\.([0-9]+)(?:\\.([0-9]+))?$")); - const QRegularExpression safeName(QLatin1String("^[a-zA-Z_][[a-zA-Z0-9_]*$")); + static const QRegularExpression vNr(QLatin1String("^(.+)\\.([0-9]+)(?:\\.([0-9]+))?$")); + static const QRegularExpression safeName(QLatin1String("^[a-zA-Z_][[a-zA-Z0-9_]*$")); for (const ImportKey &importKey : std::as_const(packages)) { if (importKey.splitPath.size() == 1 && importKey.splitPath.at(0).isEmpty() && splitPath.length() > 0) { // relocatable @@ -519,8 +519,6 @@ void Snapshot::insertLibraryInfo(const Utils::FilePath &path, const LibraryInfo } } if (cImport.possibleExports.isEmpty() && splitPath.size() > 0) { - const QRegularExpression vNr(QLatin1String("^(.+)\\.([0-9]+)(?:\\.([0-9]+))?$")); - const QRegularExpression safeName(QLatin1String("^[a-zA-Z_][[a-zA-Z0-9_]*$")); int majorVersion = LanguageUtils::ComponentVersion::NoVersion; int minorVersion = LanguageUtils::ComponentVersion::NoVersion; diff --git a/src/libs/qmljs/qmljsfindexportedcpptypes.cpp b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp index 36125539776..14f9b146fa7 100644 --- a/src/libs/qmljs/qmljsfindexportedcpptypes.cpp +++ b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp @@ -280,7 +280,7 @@ protected: } if (packageName.isEmpty() && _compound) { // check the comments in _compound for annotations - const QRegularExpression uriAnnotation(QLatin1String("@uri\\s*([\\w\\.]*)")); + static const QRegularExpression uriAnnotation(QLatin1String("@uri\\s*([\\w\\.]*)")); // scan every comment between the pipes in // {| diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index 1a79ffdcc06..fa6358e4a2a 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -376,7 +376,7 @@ Utils::FilePath PluginDumper::buildQmltypesPath(const QString &name) const QString qualifiedName; QString version; - QRegularExpression import("^(?[\\w|\\.]+)\\s+(?\\d+)\\.(?\\d+)$"); + static const QRegularExpression import("^(?[\\w|\\.]+)\\s+(?\\d+)\\.(?\\d+)$"); QRegularExpressionMatch m = import.match(name); if (m.hasMatch()) { qualifiedName = m.captured("name"); diff --git a/src/libs/qmljs/qmljsscopechain.cpp b/src/libs/qmljs/qmljsscopechain.cpp index 1465aab5aad..234bca685e3 100644 --- a/src/libs/qmljs/qmljsscopechain.cpp +++ b/src/libs/qmljs/qmljsscopechain.cpp @@ -271,7 +271,7 @@ void ScopeChain::update() const static void addInstantiatingComponents(ContextPtr context, QmlComponentChain *chain) { - const QRegularExpression importCommentPattern(QLatin1String("@scope\\s+(.*)")); + static const QRegularExpression importCommentPattern("@scope\\s+(.*)"); for (const SourceLocation &commentLoc : chain->document()->engine()->comments()) { const QString &comment = chain->document()->source().mid(commentLoc.begin(), commentLoc.length); diff --git a/src/libs/qmljs/qmljsutils.cpp b/src/libs/qmljs/qmljsutils.cpp index e33a6b3e809..d34b4713c93 100644 --- a/src/libs/qmljs/qmljsutils.cpp +++ b/src/libs/qmljs/qmljsutils.cpp @@ -189,7 +189,7 @@ const QString undefinedVersion = QLatin1String("-1.-1"); * undefined version (-1.-1) or if it is empty. False otherwise. */ bool QmlJS::maybeModuleVersion(const QString &version) { - QRegularExpression re(QLatin1String("^\\d+\\.-?\\d+$")); + static const QRegularExpression re(QLatin1String("^\\d+\\.-?\\d+$")); return version.isEmpty() || version == undefinedVersion || re.match(version).hasMatch(); } diff --git a/src/libs/utils/classnamevalidatinglineedit.cpp b/src/libs/utils/classnamevalidatinglineedit.cpp index 3515abef023..8fbb826c885 100644 --- a/src/libs/utils/classnamevalidatinglineedit.cpp +++ b/src/libs/utils/classnamevalidatinglineedit.cpp @@ -131,7 +131,7 @@ QString ClassNameValidatingLineEdit::createClassName(const QString &name) { // Remove spaces and convert the adjacent characters to uppercase QString className = name; - const QRegularExpression spaceMatcher(" +(\\w)"); + static const QRegularExpression spaceMatcher(" +(\\w)"); QTC_CHECK(spaceMatcher.isValid()); while (true) { const QRegularExpressionMatch match = spaceMatcher.match(className); @@ -141,7 +141,8 @@ QString ClassNameValidatingLineEdit::createClassName(const QString &name) } // Filter out any remaining invalid characters - className.remove(QRegularExpression("[^a-zA-Z0-9_]")); + static const QRegularExpression regexp("[^a-zA-Z0-9_]"); + className.remove(regexp); // If the first character is numeric, prefix the name with a "_" if (className.at(0).isNumber()) { diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index 1da60c3565c..cf451a8cbd5 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -558,7 +558,8 @@ static QString quoteArgWin(const QString &arg) // Quotes are escaped and their preceding backslashes are doubled. // It's impossible to escape anything inside a quoted string on cmd // level, so the outer quoting must be "suspended". - ret.replace(QRegularExpression(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\"")); + static const QRegularExpression regexp("(\\\\*)\""); + ret.replace(regexp, QLatin1String("\"\\1\\1\\^\"\"")); // The argument must not end with a \ since this would be interpreted // as escaping the quote -- rather put the \ behind the quote: e.g. // rather use "foo"\ than "foo\" @@ -955,7 +956,8 @@ bool ProcessArgs::expandMacros(QString *cmd, const FindMacro &findMacro, OsType // Our expansion rules trigger in any context if (state.dquote) { // We are within a double-quoted string. Escape relevant meta characters. - rsts.replace(QRegularExpression(QLatin1String("([$`\"\\\\])")), QLatin1String("\\\\1")); + static const QRegularExpression regexp("([$`\"\\\\])"); + rsts.replace(regexp, QLatin1String("\\\\1")); } else if (state.current == MxSingleQuote) { // We are within a single-quoted string. "Suspend" single-quoting and put a // single escaped quote for each single quote inside the string. diff --git a/src/libs/utils/differ.cpp b/src/libs/utils/differ.cpp index bc7dda6f302..8c347071490 100644 --- a/src/libs/utils/differ.cpp +++ b/src/libs/utils/differ.cpp @@ -178,9 +178,9 @@ static QList cleanupOverlaps(const QList &diffList) static int cleanupSemanticsScore(const QString &text1, const QString &text2) { - const QRegularExpression blankLineEnd("\\n\\r?\\n$"); - const QRegularExpression blankLineStart("^\\r?\\n\\r?\\n"); - const QRegularExpression sentenceEnd("\\. $"); + static const QRegularExpression blankLineEnd("\\n\\r?\\n$"); + static const QRegularExpression blankLineStart("^\\r?\\n\\r?\\n"); + static const QRegularExpression sentenceEnd("\\. $"); if (text1.isEmpty() || text2.isEmpty()) // Edges return 6; diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 3cbeb387474..edd06b5658c 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -782,10 +782,14 @@ Result FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &t QString FileUtils::fileSystemFriendlyName(const QString &name) { QString result = name; - result.replace(QRegularExpression(QLatin1String("\\W")), QLatin1String("_")); - result.replace(QRegularExpression(QLatin1String("_+")), QLatin1String("_")); // compact _ - result.remove(QRegularExpression(QLatin1String("^_*"))); // remove leading _ - result.remove(QRegularExpression(QLatin1String("_+$"))); // remove trailing _ + static const QRegularExpression nonWordEx("\\W"); + result.replace(nonWordEx, QLatin1String("_")); + static const QRegularExpression subsequentUnderscoreEx("_+"); + result.replace(subsequentUnderscoreEx, QLatin1String("_")); + static const QRegularExpression leadingUnderscoreEx("^_*"); + result.remove(leadingUnderscoreEx); + static const QRegularExpression trailingUnderscoreEx("_+$"); + result.remove(trailingUnderscoreEx); if (result.isEmpty()) result = QLatin1String("unknown"); return result; diff --git a/src/libs/utils/htmldocextractor.cpp b/src/libs/utils/htmldocextractor.cpp index 90f61b72a12..fb1b4a1cf2d 100644 --- a/src/libs/utils/htmldocextractor.cpp +++ b/src/libs/utils/htmldocextractor.cpp @@ -69,7 +69,8 @@ QString HtmlDocExtractor::getFunctionDescription(const QString &html, startMark.append(QLatin1String("[overload1]")); } else { QString complement = mark.right(mark.length() - parenthesis); - complement.remove(QRegularExpression("[\\(\\), ]")); + static const QRegularExpression regex("[\\(\\), ]"); + complement.remove(regex); startMark.append(complement); } } @@ -247,32 +248,38 @@ void HtmlDocExtractor::processOutput(QString *html) const void HtmlDocExtractor::stripAllHtml(QString *html) { - html->remove(QRegularExpression("<.*?>")); + static const QRegularExpression regexp("<.*?>"); + html->remove(regexp); } void HtmlDocExtractor::stripHeadings(QString *html) { - html->remove(QRegularExpression("|")); + static const QRegularExpression regexp("|"); + html->remove(regexp); } void HtmlDocExtractor::stripLinks(QString *html) { - html->remove(QRegularExpression("|")); + static const QRegularExpression regexp("|"); + html->remove(regexp); } void HtmlDocExtractor::stripHorizontalLines(QString *html) { - html->remove(QRegularExpression("")); + static const QRegularExpression regexp(""); + html->remove(regexp); } void HtmlDocExtractor::stripDivs(QString *html) { - html->remove(QRegularExpression("||")); + static const QRegularExpression regexp("||"); + html->remove(regexp); } void HtmlDocExtractor::stripTagsStyles(QString *html) { - html->replace(QRegularExpression("<(.*?\\s+)class=\".*?\">"), "<\\1>"); + static const QRegularExpression regexp("<(.*?\\s+)class=\".*?\">"); + html->replace(regexp, "<\\1>"); } void HtmlDocExtractor::stripTeletypes(QString *html) @@ -283,7 +290,8 @@ void HtmlDocExtractor::stripTeletypes(QString *html) void HtmlDocExtractor::stripImagens(QString *html) { - html->remove(QRegularExpression("")); + static const QRegularExpression regexp(""); + html->remove(regexp); } void HtmlDocExtractor::stripBold(QString *html) @@ -299,33 +307,44 @@ void HtmlDocExtractor::stripEmptyParagraphs(QString *html) void HtmlDocExtractor::replaceNonStyledHeadingsForBold(QString *html) { - const QRegularExpression hStart(""); - const QRegularExpression hEnd(""); + static const QRegularExpression hStart(""); + static const QRegularExpression hEnd(""); html->replace(hStart, QLatin1String("

")); html->replace(hEnd, QLatin1String("

")); } void HtmlDocExtractor::replaceTablesForSimpleLines(QString *html) { - html->replace(QRegularExpression("(?:

)?"), QLatin1String("

")); - html->replace(QLatin1String(""), QLatin1String("

")); - html->remove(QRegularExpression("")); + static const QRegularExpression regexp01("(?:

)?"); + html->replace(regexp01, QLatin1String("

")); + static const QRegularExpression regexp02(""); + html->replace(regexp02, QLatin1String("

")); + static const QRegularExpression regexp03(""); + html->remove(regexp03); html->remove(QLatin1String("")); - html->remove(QRegularExpression("")); + static const QRegularExpression regexp04(""); + html->remove(regexp04); html->remove(QLatin1String("")); - html->remove(QRegularExpression(".*?")); + static const QRegularExpression regexp05(".*?"); + html->remove(regexp05); html->replace(QLatin1String(" remove(QRegularExpression("

")); - html->remove(QRegularExpression("")); - html->remove(QRegularExpression("(?:

)?")); - html->replace(QRegularExpression(""), QLatin1String("    ")); + static const QRegularExpression regexp06("

"); + html->remove(regexp06); + static const QRegularExpression regexp07(""); + html->remove(regexp07); + static const QRegularExpression regexp08("(?:

)?"); + html->remove(regexp08); + static const QRegularExpression regexp09(""); + html->replace(regexp09, QLatin1String("    ")); html->replace(QLatin1String(""), QLatin1String("
")); } void HtmlDocExtractor::replaceListsForSimpleLines(QString *html) { - html->remove(QRegularExpression("<(?:ul|ol).*?>")); - html->remove(QRegularExpression("")); + static const QRegularExpression listStart("<(?:ul|ol).*?>"); + html->remove(listStart); + static const QRegularExpression listEnd(""); + html->remove(listEnd); html->replace(QLatin1String("
  • "), QLatin1String("    ")); html->replace(QLatin1String("
  • "), QLatin1String("
    ")); } diff --git a/src/libs/utils/persistentsettings.cpp b/src/libs/utils/persistentsettings.cpp index a9888356f4b..2b65aa0ce58 100644 --- a/src/libs/utils/persistentsettings.cpp +++ b/src/libs/utils/persistentsettings.cpp @@ -39,7 +39,7 @@ static QString rectangleToString(const QRect &r) static QRect stringToRectangle(const QString &v) { - static QRegularExpression pattern("^(\\d+)x(\\d+)([-+]\\d+)([-+]\\d+)$"); + static const QRegularExpression pattern("^(\\d+)x(\\d+)([-+]\\d+)([-+]\\d+)$"); Q_ASSERT(pattern.isValid()); const QRegularExpressionMatch match = pattern.match(v); return match.hasMatch() ? diff --git a/src/libs/utils/processinfo.cpp b/src/libs/utils/processinfo.cpp index 4cc9d15ba31..89f732295c6 100644 --- a/src/libs/utils/processinfo.cpp +++ b/src/libs/utils/processinfo.cpp @@ -154,7 +154,7 @@ static QList getProcessesUsingPidin(const FilePath &pidin) return processes; lines.pop_front(); // drop headers - const QRegularExpression re("\\s*(\\d+)\\s+(.*){(.*)}"); + static const QRegularExpression re("\\s*(\\d+)\\s+(.*){(.*)}"); for (const QString &line : std::as_const(lines)) { const QRegularExpressionMatch match = re.match(line); From 7c97a2b9f81adefc4fa03908e84865d77f5c4b5a Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 20 Nov 2024 12:19:18 +0100 Subject: [PATCH 208/989] Plugins A-L: Make static QRegularExpression instances static const Change-Id: I6de1ddd036b654472b0a8cc020dc1dbf1bc1d270 Reviewed-by: hjk --- .../autotest/qtest/qttestoutputreader.cpp | 2 +- .../debugservers/uvsc/uvscserverprovider.cpp | 2 +- src/plugins/baremetal/iarewparser.cpp | 8 ++-- src/plugins/baremetal/keilparser.cpp | 14 +++--- src/plugins/bazaar/bazaarclient.cpp | 4 +- src/plugins/bazaar/bazaarcommitwidget.cpp | 3 +- .../artisticstyle/artisticstyle.cpp | 3 +- src/plugins/clangcodemodel/clangdclient.cpp | 2 +- src/plugins/clearcase/clearcaseplugin.cpp | 13 +++--- src/plugins/clearcase/clearcasesync.cpp | 5 ++- src/plugins/clearcase/versionselector.cpp | 6 +-- .../cmakeautocompleter.cpp | 3 +- .../cmakeprojectmanager.cpp | 2 +- .../compilationdatabaseutils.cpp | 7 +-- .../coreplugin/dialogs/externaltoolconfig.cpp | 3 +- src/plugins/coreplugin/documentmanager.cpp | 2 +- .../cpaster/pastebindotcomprotocol.cpp | 10 ++--- .../cppeditor/compileroptionsbuilder.cpp | 3 +- src/plugins/cppeditor/cpptoolsreuse.cpp | 3 +- src/plugins/cppeditor/doxygengenerator.cpp | 5 ++- .../quickfixes/bringidentifierintoscope.cpp | 4 +- .../quickfixes/convertnumericliteral.cpp | 2 +- .../quickfixes/insertfunctiondefinition.cpp | 2 +- src/plugins/cvs/cvsutils.cpp | 4 +- src/plugins/debugger/cdb/cdbengine.cpp | 6 +-- src/plugins/debugger/gdb/gdbengine.cpp | 6 +-- src/plugins/debugger/lldb/lldbengine.cpp | 6 ++- .../debugger/peripheralregisterhandler.cpp | 8 ++-- .../debugger/qml/qmlinspectoragent.cpp | 2 +- src/plugins/debugger/simplifytype.cpp | 6 +-- src/plugins/debugger/watchhandler.cpp | 2 +- src/plugins/diffeditor/diffutils.cpp | 11 ++--- src/plugins/fakevim/fakevimhandler.cpp | 45 ++++++++++++------- src/plugins/fossil/fossilclient.cpp | 8 ++-- src/plugins/fossil/fossilplugin.cpp | 3 +- src/plugins/git/gerrit/gerritserver.cpp | 2 +- src/plugins/git/giteditor.cpp | 2 +- src/plugins/help/searchwidget.cpp | 3 +- .../incredibuild/cmakecommandbuilder.cpp | 2 +- .../incredibuild/makecommandbuilder.cpp | 4 +- src/plugins/ios/iosrunner.cpp | 6 ++- .../languageclientcompletionassist.cpp | 2 +- src/plugins/lua/bindings/translate.cpp | 4 +- src/plugins/lua/luaengine.cpp | 3 +- 44 files changed, 138 insertions(+), 105 deletions(-) diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp index 99693357a05..2208e53075b 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.cpp +++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp @@ -316,7 +316,7 @@ static QStringList extractFunctionInformation(const QString &testClassName, const QString &lineWithoutResultType, ResultType resultType) { - static QRegularExpression classInformation("^(.+?)\\((.*?)\\)(.*)$"); + static const QRegularExpression classInformation("^(.+?)\\((.*?)\\)(.*)$"); QStringList result; const QRegularExpressionMatch match = classInformation.match(lineWithoutResultType); if (match.hasMatch()) { diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp index 33e1196623d..0ae7e91c52f 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp @@ -242,7 +242,7 @@ public: explicit HexValueValidator(QObject *parent = nullptr) : QRegularExpressionValidator(parent) { - const QRegularExpression re("^0x[0-9a-fA-F]{1,8}"); + static const QRegularExpression re("^0x[0-9a-fA-F]{1,8}"); setRegularExpression(re); } }; diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp index 286cb0e1686..0cc4117d012 100644 --- a/src/plugins/baremetal/iarewparser.cpp +++ b/src/plugins/baremetal/iarewparser.cpp @@ -56,7 +56,7 @@ void IarParser::amendFilePath() bool IarParser::parseErrorOrFatalErrorDetailsMessage1(const QString &lne) { - const QRegularExpression re("^(Error|Fatal error)\\[(.+)\\]:\\s(.+)\\s\\[(.+)$"); + static const QRegularExpression re("^(Error|Fatal error)\\[(.+)\\]:\\s(.+)\\s\\[(.+)$"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return false; @@ -79,7 +79,7 @@ bool IarParser::parseErrorOrFatalErrorDetailsMessage1(const QString &lne) bool IarParser::parseErrorOrFatalErrorDetailsMessage2(const QString &lne) { - const QRegularExpression re("^.*(Error|Fatal error)\\[(.+)\\]:\\s(.+)$"); + static const QRegularExpression re("^.*(Error|Fatal error)\\[(.+)\\]:\\s(.+)$"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return false; @@ -99,7 +99,7 @@ bool IarParser::parseErrorOrFatalErrorDetailsMessage2(const QString &lne) OutputLineParser::Result IarParser::parseWarningOrErrorOrFatalErrorDetailsMessage1(const QString &lne) { - const QRegularExpression re("^\"(.+)\",(\\d+)?\\s+(Warning|Error|Fatal error)\\[(.+)\\].+$"); + static const QRegularExpression re("^\"(.+)\",(\\d+)?\\s+(Warning|Error|Fatal error)\\[(.+)\\].+$"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return Status::NotHandled; @@ -132,7 +132,7 @@ bool IarParser::parseErrorInCommandLineMessage(const QString &lne) bool IarParser::parseErrorMessage1(const QString &lne) { - const QRegularExpression re("^(Error)\\[(.+)\\]:\\s(.+)$"); + static const QRegularExpression re("^(Error)\\[(.+)\\]:\\s(.+)$"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return false; diff --git a/src/plugins/baremetal/keilparser.cpp b/src/plugins/baremetal/keilparser.cpp index 64bf64e46fd..5a5df91ccc7 100644 --- a/src/plugins/baremetal/keilparser.cpp +++ b/src/plugins/baremetal/keilparser.cpp @@ -49,7 +49,7 @@ void KeilParser::newTask(const Task &task) OutputLineParser::Result KeilParser::parseArmWarningOrErrorDetailsMessage(const QString &lne) { - const QRegularExpression re("^\"(.+)\", line (\\d+).*:\\s+(Warning|Error):(\\s+|.+)([#|L].+)$"); + static const QRegularExpression re("^\"(.+)\", line (\\d+).*:\\s+(Warning|Error):(\\s+|.+)([#|L].+)$"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return Status::NotHandled; @@ -69,7 +69,7 @@ OutputLineParser::Result KeilParser::parseArmWarningOrErrorDetailsMessage(const bool KeilParser::parseArmErrorOrFatalErorrMessage(const QString &lne) { - const QRegularExpression re("^(Error|Fatal error):\\s(.+)$"); + static const QRegularExpression re("^(Error|Fatal error):\\s(.+)$"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return false; @@ -84,7 +84,7 @@ bool KeilParser::parseArmErrorOrFatalErorrMessage(const QString &lne) OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage1(const QString &lne) { - const QRegularExpression re("^\\*{3} (WARNING|ERROR) (\\w+) IN LINE (\\d+) OF (.+\\.\\S+): (.+)$"); + static const QRegularExpression re("^\\*{3} (WARNING|ERROR) (\\w+) IN LINE (\\d+) OF (.+\\.\\S+): (.+)$"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return Status::NotHandled; @@ -105,7 +105,7 @@ OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage1(con OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage2(const QString &lne) { - const QRegularExpression re("^\\*{3} (WARNING|ERROR) (#\\w+) IN (\\d+) \\((.+), LINE \\d+\\): (.+)$"); + static const QRegularExpression re("^\\*{3} (WARNING|ERROR) (#\\w+) IN (\\d+) \\((.+), LINE \\d+\\): (.+)$"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return Status::NotHandled; @@ -126,7 +126,7 @@ OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage2(con bool KeilParser::parseMcs51WarningOrFatalErrorMessage(const QString &lne) { - const QRegularExpression re("^\\*{3} (WARNING|FATAL ERROR) (.+)$"); + static const QRegularExpression re("^\\*{3} (WARNING|FATAL ERROR) (.+)$"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return false; @@ -139,7 +139,7 @@ bool KeilParser::parseMcs51WarningOrFatalErrorMessage(const QString &lne) bool KeilParser::parseMcs51FatalErrorMessage2(const QString &lne) { - const QRegularExpression re("^(A|C)51 FATAL[ |-]ERROR"); + static const QRegularExpression re("^(A|C)51 FATAL[ |-]ERROR"); const QRegularExpressionMatch match = re.match(lne); if (!match.hasMatch()) return false; @@ -155,7 +155,7 @@ bool KeilParser::parseMcs51FatalErrorMessage2(const QString &lne) static bool hasDetailsEntry(const QString &trimmedLine) { - const QRegularExpression re("^([0-9A-F]{4})"); + static const QRegularExpression re("^([0-9A-F]{4})"); const QRegularExpressionMatch match = re.match(trimmedLine); return match.hasMatch(); } diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp index 03e882279fb..77005d410b3 100644 --- a/src/plugins/bazaar/bazaarclient.cpp +++ b/src/plugins/bazaar/bazaarclient.cpp @@ -95,8 +95,8 @@ BranchInfo BazaarClient::synchronousBranchQuery(const FilePath &repositoryRoot) QTextStream ts(&branchConfFile); QString branchLocation; QString isBranchBound; - QRegularExpression branchLocationRx("bound_location\\s*=\\s*(.+)$"); - QRegularExpression isBranchBoundRx("bound\\s*=\\s*(.+)$"); + static const QRegularExpression branchLocationRx("bound_location\\s*=\\s*(.+)$"); + static const QRegularExpression isBranchBoundRx("bound\\s*=\\s*(.+)$"); while (!ts.atEnd() && (branchLocation.isEmpty() || isBranchBound.isEmpty())) { const QString line = ts.readLine(); QRegularExpressionMatch match = branchLocationRx.match(line); diff --git a/src/plugins/bazaar/bazaarcommitwidget.cpp b/src/plugins/bazaar/bazaarcommitwidget.cpp index 465395e0aef..d0535806651 100644 --- a/src/plugins/bazaar/bazaarcommitwidget.cpp +++ b/src/plugins/bazaar/bazaarcommitwidget.cpp @@ -172,7 +172,8 @@ QString BazaarCommitWidget::committer() const QStringList BazaarCommitWidget::fixedBugs() const { - return m_bazaarCommitPanel->fixedBugsLineEdit->text().split(QRegularExpression("\\s+")); + static const QRegularExpression regexp("\\s+"); + return m_bazaarCommitPanel->fixedBugsLineEdit->text().split(regexp); } bool BazaarCommitWidget::isLocalOptionEnabled() const diff --git a/src/plugins/beautifier/artisticstyle/artisticstyle.cpp b/src/plugins/beautifier/artisticstyle/artisticstyle.cpp index ca8d089410b..af6e28dccd6 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstyle.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstyle.cpp @@ -140,8 +140,9 @@ public: for (const QString &key : std::as_const(keys)) stream.writeTextElement(Constants::DOCUMENTATION_XMLKEY, key); stream.writeEndElement(); + static const QRegularExpression regexp("^\\-"); const QString text = "

    " - + keys.filter(QRegularExpression("^\\-")).join(", ") + "

    " + + keys.filter(regexp).join(", ") + "

    " + (docu.join(' ').toHtmlEscaped()) + "

    "; stream.writeTextElement(Constants::DOCUMENTATION_XMLDOC, text); stream.writeEndElement(); diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 1b3cf54f0e0..ecad1dfb167 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -799,7 +799,7 @@ QVersionNumber ClangdClient::versionNumber() const if (d->versionNumber) return d->versionNumber.value(); - const QRegularExpression versionPattern("^clangd version (\\d+)\\.(\\d+)\\.(\\d+).*$"); + static const QRegularExpression versionPattern("^clangd version (\\d+)\\.(\\d+)\\.(\\d+).*$"); QTC_CHECK(versionPattern.isValid()); const QRegularExpressionMatch match = versionPattern.match(serverVersion()); if (match.isValid()) { diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index cd9ec09482a..97261aafded 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -434,7 +434,8 @@ FileStatus::Status ClearCasePluginPrivate::getFileStatus(const FilePath &fileNam return FileStatus::Derived; // find first whitespace. anything before that is not interesting - const int wspos = buffer.indexOf(QRegularExpression("\\s")); + static const QRegularExpression regexp("\\s"); + const int wspos = buffer.indexOf(regexp); if (buffer.lastIndexOf(QLatin1String("CHECKEDOUT"), wspos) != -1) return FileStatus::CheckedOut; else @@ -1281,7 +1282,8 @@ void ClearCasePluginPrivate::diffActivity() // pre-first version. only for the first occurrence if (filever[file].first.isEmpty()) { - int verpos = shortver.lastIndexOf(QRegularExpression("[^0-9]")) + 1; + static const QRegularExpression regexp("[^0-9]"); + int verpos = shortver.lastIndexOf(regexp) + 1; int vernum = shortver.mid(verpos).toInt(); if (vernum) --vernum; @@ -1839,7 +1841,7 @@ bool ClearCasePluginPrivate::vcsCheckIn(const FilePath &messageFile, const QStri } const CommandResult result = runCleartool(m_checkInView, args, RunFlags::ShowStdOut, nullptr, 10); - const QRegularExpression checkedIn("Checked in \\\"([^\"]*)\\\""); + static const QRegularExpression checkedIn("Checked in \\\"([^\"]*)\\\""); QRegularExpressionMatch match = checkedIn.match(result.cleanedStdOut()); bool anySucceeded = false; int offset = match.capturedStart(); @@ -2077,7 +2079,8 @@ bool ClearCasePluginPrivate::ccCheckUcm(const QString &viewname, const FilePath const QString catcsData = runCleartoolProc(workingDir, {"catcs", "-tag", viewname}).cleanedStdOut(); // check output for the word "ucm" - return catcsData.indexOf(QRegularExpression("(^|\\n)ucm\\n")) != -1; + static const QRegularExpression regexp("(^|\\n)ucm\\n"); + return catcsData.indexOf(regexp) != -1; } bool ClearCasePluginPrivate::managesFile(const FilePath &workingDirectory, const QString &fileName) const @@ -2115,7 +2118,7 @@ void ClearCasePluginPrivate::updateStreamAndView() {"lsstream", "-fmt", "%n\\t%[def_deliver_tgt]Xp"}).cleanedStdOut(); const int tabPos = result.indexOf(QLatin1Char('\t')); m_stream = result.left(tabPos); - const QRegularExpression intStreamExp("stream:([^@]*)"); + static const QRegularExpression intStreamExp("stream:([^@]*)"); const QRegularExpressionMatch match = intStreamExp.match(result.mid(tabPos + 1)); if (match.hasMatch()) m_intStream = match.captured(1); diff --git a/src/plugins/clearcase/clearcasesync.cpp b/src/plugins/clearcase/clearcasesync.cpp index a92ab7da7bd..1680391c576 100644 --- a/src/plugins/clearcase/clearcasesync.cpp +++ b/src/plugins/clearcase/clearcasesync.cpp @@ -95,14 +95,15 @@ void ClearCaseSync::processCleartoolLsLine(const QDir &viewRootDir, const QStrin return; // find first whitespace. anything before that is not interesting - const int wspos = buffer.indexOf(QRegularExpression("\\s")); + static const QRegularExpression regexp("\\s"); + const int wspos = buffer.indexOf(regexp); const QString absFile = viewRootDir.absoluteFilePath( QDir::fromNativeSeparators(buffer.left(atatpos))); QTC_CHECK(QFileInfo::exists(absFile)); QTC_CHECK(!absFile.isEmpty()); - const QRegularExpression reState("^\\s*\\[[^\\]]*\\]"); // [hijacked]; [loaded but missing] + static const QRegularExpression reState("^\\s*\\[[^\\]]*\\]"); // [hijacked]; [loaded but missing] const QRegularExpressionMatch match = reState.match(buffer.mid(wspos + 1)); if (match.hasMatch()) { const QString ccState = match.captured(); diff --git a/src/plugins/clearcase/versionselector.cpp b/src/plugins/clearcase/versionselector.cpp index 4d3dd16059f..ba329d51b82 100644 --- a/src/plugins/clearcase/versionselector.cpp +++ b/src/plugins/clearcase/versionselector.cpp @@ -102,21 +102,21 @@ bool VersionSelector::readValues() { QString line; line = m_stream->readLine(); - const QRegularExpression id("Version ID: (.*)"); + static const QRegularExpression id("Version ID: (.*)"); const QRegularExpressionMatch idMatch = id.match(line); if (!idMatch.hasMatch()) return false; m_versionID = idMatch.captured(1); line = m_stream->readLine(); - const QRegularExpression owner("Created by: (.*)"); + static const QRegularExpression owner("Created by: (.*)"); const QRegularExpressionMatch ownerMatch = owner.match(line); if (!ownerMatch.hasMatch()) return false; m_createdBy = ownerMatch.captured(1); line = m_stream->readLine(); - const QRegularExpression dateTimeRE("Created on: (.*)"); + static const QRegularExpression dateTimeRE("Created on: (.*)"); const QRegularExpressionMatch dateTimeMatch = dateTimeRE.match(line); if (!dateTimeMatch.hasMatch()) return false; diff --git a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp index 1f520a86bf5..893f3b5e1a6 100644 --- a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp @@ -89,7 +89,8 @@ QString CMakeAutoCompleter::insertMatchingQuote(const QTextCursor &cursor, int CMakeAutoCompleter::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor) { const QString line = cursor.block().text().trimmed(); - if (line.contains(QRegularExpression(QStringLiteral("^(endfunction|endmacro|endif|endforeach|endwhile|endblock)\\w*\\(")))) + static const QRegularExpression regexp("^(endfunction|endmacro|endif|endforeach|endwhile|endblock)\\w*\\("); + if (line.contains(regexp)) tabSettings().indentLine(cursor.block(), tabSettings().indentationColumn(cursor.block().text())); return 0; } diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index 50a849f7a1a..d4b5602c4d6 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -109,7 +109,7 @@ void CMakeManager::openCMakeUrl(const QUrl &url) { QString urlPrefix = "https://cmake.org/cmake/help/"; - QRegularExpression version("^.*\\.([0-9])\\.([0-9]+)\\.[0-9]+$"); + static const QRegularExpression version("^.*\\.([0-9])\\.([0-9]+)\\.[0-9]+$"); auto match = version.match(url.authority()); if (match.hasMatch()) urlPrefix.append(QString("v%1.%2").arg(match.captured(1)).arg(match.captured(2))); diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp index 5e07c2c2050..7f68eedb934 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp @@ -206,7 +206,8 @@ QStringList splitCommandLine(QString commandLine, QSet &flagsCache) // Remove escaped quotes. commandLine.replace("\\\"", "'"); - for (const QString &part : commandLine.split(QRegularExpression("\""))) { + static const QRegularExpression splitRegexp("\""); + for (const QString &part : commandLine.split(splitRegexp)) { if (insideQuotes) { const QString quotedPart = "\"" + part + "\""; if (result.last().endsWith("=")) { @@ -217,8 +218,8 @@ QStringList splitCommandLine(QString commandLine, QSet &flagsCache) result.append(*flagIt); } } else { // If 's' is outside quotes ... - for (const QString &flag : - part.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts)) { + static const QRegularExpression regexp("\\s+"); + for (const QString &flag : part.split(regexp, Qt::SkipEmptyParts)) { auto flagIt = flagsCache.insert(flag); result.append(*flagIt); } diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp index 95d37354da6..5f57b5719cf 100644 --- a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp +++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp @@ -778,7 +778,8 @@ static FilePath getUserFilePath(const QString &proposalFileName) static QString idFromDisplayName(const QString &displayName) { QString id = displayName; - id.remove(QRegularExpression("&(?!&)")); + static const QRegularExpression regexp("&(?!&)"); + id.remove(regexp); QChar *c = id.data(); while (!c->isNull()) { if (!c->isLetterOrNumber()) diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 0ebffb50b20..e2529372be6 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -803,7 +803,7 @@ FilePath DocumentManager::getSaveFileName(const QString &title, const FilePath & // first one from the filter is appended. if (selectedFilter && *selectedFilter != allFilesFilterString()) { // Mime database creates filter strings like this: Anything here (*.foo *.bar) - const QRegularExpression regExp(QLatin1String(".*\\s+\\((.*)\\)$")); + static const QRegularExpression regExp(QLatin1String(".*\\s+\\((.*)\\)$")); QRegularExpressionMatchIterator matchIt = regExp.globalMatch(*selectedFilter); if (matchIt.hasNext()) { bool suffixOk = false; diff --git a/src/plugins/cpaster/pastebindotcomprotocol.cpp b/src/plugins/cpaster/pastebindotcomprotocol.cpp index 639408737ce..bd6113a3369 100644 --- a/src/plugins/cpaster/pastebindotcomprotocol.cpp +++ b/src/plugins/cpaster/pastebindotcomprotocol.cpp @@ -220,7 +220,7 @@ struct Attribute { static QList toAttributes(QStringView attributes) { QList result; - const QRegularExpression att("\\s+([a-zA-Z]+)\\s*=\\s*('.*?'|\".*?\")"); + static const QRegularExpression att("\\s+([a-zA-Z]+)\\s*=\\s*('.*?'|\".*?\")"); QRegularExpressionMatchIterator it = att.globalMatch(attributes.toString()); while (it.hasNext()) { const QRegularExpressionMatch match = it.next(); @@ -338,7 +338,7 @@ static inline QStringList parseLists(QIODevice *io, QString *errorMessage) QString dataStr = QString::fromUtf8(data); // remove comments if any - const QRegularExpression comment("", QRegularExpression::MultilineOption); + static const QRegularExpression comment("", QRegularExpression::MultilineOption); for ( ;; ) { const QRegularExpressionMatch match = comment.match(dataStr); if (!match.hasMatch()) @@ -346,9 +346,9 @@ static inline QStringList parseLists(QIODevice *io, QString *errorMessage) dataStr.remove(match.capturedStart(), match.capturedLength()); } - const QRegularExpression tag("<(/?)\\s*([a-zA-Z][a-zA-Z0-9]*)(.*?)(/?)\\s*>", - QRegularExpression::MultilineOption); - const QRegularExpression wsOnly("^\\s+$", QRegularExpression::MultilineOption); + static const QRegularExpression tag("<(/?)\\s*([a-zA-Z][a-zA-Z0-9]*)(.*?)(/?)\\s*>", + QRegularExpression::MultilineOption); + static const QRegularExpression wsOnly("^\\s+$", QRegularExpression::MultilineOption); QRegularExpressionMatchIterator it = tag.globalMatch(dataStr); while (it.hasNext()) { const QRegularExpressionMatch match = it.next(); diff --git a/src/plugins/cppeditor/compileroptionsbuilder.cpp b/src/plugins/cppeditor/compileroptionsbuilder.cpp index 8bd1219a5d2..62f1c564746 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder.cpp +++ b/src/plugins/cppeditor/compileroptionsbuilder.cpp @@ -342,7 +342,8 @@ void CompilerOptionsBuilder::insertWrappedHeaders(const QStringList &relPaths) args << (includeUserPathOption + QDir::toNativeSeparators(fullPath)); } - const int index = m_options.indexOf(QRegularExpression("\\A-I.*\\z")); + static const QRegularExpression regexp("\\A-I.*\\z"); + const int index = m_options.indexOf(regexp); if (index < 0) add(args); else diff --git a/src/plugins/cppeditor/cpptoolsreuse.cpp b/src/plugins/cppeditor/cpptoolsreuse.cpp index 109943123b1..a78b7d8d5fd 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.cpp +++ b/src/plugins/cppeditor/cpptoolsreuse.cpp @@ -116,7 +116,8 @@ QStringList identifierWordsUnderCursor(const QTextCursor &tc) break; QTextCursor temp(endCursor); temp.setPosition(startCursor.position(), QTextCursor::KeepAnchor); - results.append(temp.selectedText().remove(QRegularExpression("\\s"))); + static const QRegularExpression rexgexp("\\s"); + results.append(temp.selectedText().remove(rexgexp)); // possibly skip :: temp = startCursor; skipCharsBackward(&temp, isSpace); diff --git a/src/plugins/cppeditor/doxygengenerator.cpp b/src/plugins/cppeditor/doxygengenerator.cpp index d2555ab5643..5857f51785f 100644 --- a/src/plugins/cppeditor/doxygengenerator.cpp +++ b/src/plugins/cppeditor/doxygengenerator.cpp @@ -64,11 +64,12 @@ QString DoxygenGenerator::generate(QTextCursor cursor, // remove attributes like [[nodiscard]] because // Document::Ptr::parse(Document::ParseDeclaration) fails on attributes - static QRegularExpression attribute("\\[\\s*\\[.*\\]\\s*\\]"); + static const QRegularExpression attribute("\\[\\s*\\[.*\\]\\s*\\]"); declCandidate.replace(attribute, ""); declCandidate.replace("Q_INVOKABLE", ""); - declCandidate.remove(QRegularExpression(R"(\s*(public|protected|private)\s*:\s*)")); + static const QRegularExpression accessSpecifier(R"(\s*(public|protected|private)\s*:\s*)"); + declCandidate.remove(accessSpecifier); declCandidate.replace(QChar::ParagraphSeparator, QLatin1Char('\n')); // Let's append a closing brace in the case we got content like 'class MyType {' diff --git a/src/plugins/cppeditor/quickfixes/bringidentifierintoscope.cpp b/src/plugins/cppeditor/quickfixes/bringidentifierintoscope.cpp index 9b34a09628c..c745ebdffef 100644 --- a/src/plugins/cppeditor/quickfixes/bringidentifierintoscope.cpp +++ b/src/plugins/cppeditor/quickfixes/bringidentifierintoscope.cpp @@ -276,9 +276,9 @@ private: } else if (visitor.firstNamespace()) { insertPos = file->startOf(visitor.firstNamespace()); } else { + static const QRegularExpression regexp("^\\s*#include .*$"); const QTextCursor tc = file->document()->find( - QRegularExpression("^\\s*#include .*$"), - m_symbolPos, + regexp, m_symbolPos, QTextDocument::FindBackward | QTextDocument::FindCaseSensitively); if (!tc.isNull()) insertPos = tc.position() + 1; diff --git a/src/plugins/cppeditor/quickfixes/convertnumericliteral.cpp b/src/plugins/cppeditor/quickfixes/convertnumericliteral.cpp index 6fb5becf348..fe50475bc9c 100644 --- a/src/plugins/cppeditor/quickfixes/convertnumericliteral.cpp +++ b/src/plugins/cppeditor/quickfixes/convertnumericliteral.cpp @@ -178,7 +178,7 @@ private: replacement.append('0'); } else { std::bitset::digits> b(value); - QRegularExpression re("^[0]*"); + static const QRegularExpression re("^[0]*"); replacement.append(QString::fromStdString(b.to_string()).remove(re)); } auto op = new ConvertNumericLiteralOp(interface, start, start + numberLength, replacement); diff --git a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp index 0f9f8461380..9853f10eee4 100644 --- a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp +++ b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp @@ -172,7 +172,7 @@ public: QString input = prettyType; int index = 0; while (input.startsWith("template")) { - QRegularExpression templateRegex("template\\s*<[^>]*>"); + static const QRegularExpression templateRegex("template\\s*<[^>]*>"); QRegularExpressionMatch match = templateRegex.match(input); if (match.hasMatch()) { index += match.captured().size() + 1; diff --git a/src/plugins/cvs/cvsutils.cpp b/src/plugins/cvs/cvsutils.cpp index 0b5e81e64a7..1287a74ade2 100644 --- a/src/plugins/cvs/cvsutils.cpp +++ b/src/plugins/cvs/cvsutils.cpp @@ -43,8 +43,8 @@ QList parseLogEntries(const QString &o, ParseState state = FileState; const QString workingFilePrefix = QLatin1String("Working file: "); - const QRegularExpression statusPattern(QLatin1String("^date: ([\\d\\-]+) .*commitid: ([^;]+);$")); - const QRegularExpression revisionPattern(QLatin1String("^revision ([\\d\\.]+)$")); + static const QRegularExpression statusPattern(QLatin1String("^date: ([\\d\\-]+) .*commitid: ([^;]+);$")); + static const QRegularExpression revisionPattern(QLatin1String("^revision ([\\d\\.]+)$")); const QChar slash = QLatin1Char('/'); Q_ASSERT(statusPattern.isValid() && revisionPattern.isValid()); const QString fileSeparator = QLatin1String("============================================================================="); diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 5dbc8948769..16aab0c920c 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2198,7 +2198,7 @@ static inline bool checkCommandToken(const QString &tokenPrefix, const QString & // and the pdb files are installed in a path discoverable by the debugger void CdbEngine::checkQtSdkPdbFiles(const QString &module) { - const QRegularExpression qtCoreModuleRegExp("(Qt\\dCored).dll"); + static const QRegularExpression qtCoreModuleRegExp("(Qt\\dCored).dll"); const QRegularExpressionMatch match = qtCoreModuleRegExp.match(module); if (!match.hasMatch()) return; @@ -2348,7 +2348,7 @@ void CdbEngine::parseOutputLine(QString line) } const char versionString[] = "Microsoft (R) Windows Debugger Version"; if (line.startsWith(versionString)) { - const QRegularExpression versionRegEx("(\\d+)\\.(\\d+)\\.\\d+\\.\\d+"); + static const QRegularExpression versionRegEx("(\\d+)\\.(\\d+)\\.\\d+\\.\\d+"); const QRegularExpressionMatch match = versionRegEx.match(line); if (match.hasMatch()) { bool ok = true; @@ -2366,7 +2366,7 @@ void CdbEngine::parseOutputLine(QString line) } else if (line.startsWith("ModLoad: ")) { // output(64): ModLoad: 00007ffb`842b0000 00007ffb`843ee000 C:\Windows\system32\KERNEL32.DLL // output(32): ModLoad: 00007ffb 00007ffb C:\Windows\system32\KERNEL32.DLL - const QRegularExpression moduleRegExp("[0-9a-fA-F]+(`[0-9a-fA-F]+)? [0-9a-fA-F]+(`[0-9a-fA-F]+)? (.*)"); + static const QRegularExpression moduleRegExp("[0-9a-fA-F]+(`[0-9a-fA-F]+)? [0-9a-fA-F]+(`[0-9a-fA-F]+)? (.*)"); const QRegularExpressionMatch match = moduleRegExp.match(line); if (match.hasMatch()) { const QString module = match.captured(3).trimmed(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index fa8646d73e0..21cb36f7715 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1408,7 +1408,7 @@ void GdbEngine::handleStop2(const GdbMi &data) showStatusMessage(bp->msgBreakpointTriggered(threadId)); const QString commands = bp->command().trimmed(); // Can be either c or cont[inue] - const QRegularExpression contExp("(^|\\n)\\s*c(ont(i(n(ue?)?)?)?)?$"); + static const QRegularExpression contExp("(^|\\n)\\s*c(ont(i(n(ue?)?)?)?)?$"); QTC_CHECK(contExp.isValid()); if (contExp.match(commands).hasMatch()) { notifyInferiorRunRequested(); @@ -2371,7 +2371,7 @@ void GdbEngine::handleBreakCondition(const DebuggerResponse &, const Breakpoint void GdbEngine::updateTracepointCaptures(const Breakpoint &bp) { - static QRegularExpression capsRegExp( + static const QRegularExpression capsRegExp( "(^|[^\\\\])(\\$(ADDRESS|CALLER|CALLSTACK|FILEPOS|FUNCTION|PID|PNAME|TICK|TID|TNAME)" "|{[^}]+})"); QString message = bp->globalBreakpoint()->requestedParameters().message; @@ -3516,7 +3516,7 @@ void GdbEngine::handlePeripheralRegisterListValues( const QString output = response.consoleStreamOutput; // Regexp to match for '0x50060800:\t0\n'. - const QRegularExpression re("^(0x[0-9A-Fa-f]+):\\t(\\d+)\\n$"); + static const QRegularExpression re("^(0x[0-9A-Fa-f]+):\\t(\\d+)\\n$"); const QRegularExpressionMatch m = re.match(output); if (!m.hasMatch()) return; diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 45cb3f829ba..a3f2c5c32e1 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -112,8 +112,10 @@ void LldbEngine::runCommand(const DebuggerCommand &command) QString token = QString::number(tok); QString function = cmd.function + "(" + cmd.argsToPython() + ")"; QString msg = token + function + '\n'; - if (cmd.flags == Silent) - msg.replace(QRegularExpression("\"environment\":.[^]]*."), ""); + if (cmd.flags == Silent) { + static const QRegularExpression regexp("\"environment\":.[^]]*."); + msg.replace(regexp, ""); + } if (cmd.flags == NeedsFullStop) { cmd.flags &= ~NeedsFullStop; if (state() == InferiorRunOk) { diff --git a/src/plugins/debugger/peripheralregisterhandler.cpp b/src/plugins/debugger/peripheralregisterhandler.cpp index 100212c149d..413074cc0d5 100644 --- a/src/plugins/debugger/peripheralregisterhandler.cpp +++ b/src/plugins/debugger/peripheralregisterhandler.cpp @@ -118,22 +118,22 @@ static quint64 valueFromString(const QString &string, PeripheralRegisterFormat f bool *ok) { if (fmt == PeripheralRegisterFormat::Hexadecimal) { - const QRegularExpression re("^(0x)?([0-9A-F]+)$"); + static const QRegularExpression re("^(0x)?([0-9A-F]+)$"); const QRegularExpressionMatch m = re.match(string); if (m.hasMatch()) return m.captured(2).toULongLong(ok, 16); } else if (fmt == PeripheralRegisterFormat::Decimal) { - const QRegularExpression re("^([0-9]+)$"); + static const QRegularExpression re("^([0-9]+)$"); const QRegularExpressionMatch m = re.match(string); if (m.hasMatch()) return m.captured(1).toULongLong(ok, 10); } else if (fmt == PeripheralRegisterFormat::Octal) { - const QRegularExpression re("^(0)?([0-7]+)$"); + static const QRegularExpression re("^(0)?([0-7]+)$"); const QRegularExpressionMatch m = re.match(string); if (m.hasMatch()) return m.captured(2).toULongLong(ok, 8); } else if (fmt == PeripheralRegisterFormat::Binary) { - const QRegularExpression re("^(0b)?([0-1]+)$"); + static const QRegularExpression re("^(0b)?([0-1]+)$"); const QRegularExpressionMatch m = re.match(string); if (m.hasMatch()) return m.captured(2).toULongLong(ok, 2); diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp index 2769d49cd60..4f02adcfc88 100644 --- a/src/plugins/debugger/qml/qmlinspectoragent.cpp +++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp @@ -534,7 +534,7 @@ void QmlInspectorAgent::buildDebugIdHashRecursive(const ObjectReference &ref) // handle the case where the url contains the revision number encoded. // (for object created by the debugger) - const QRegularExpression rx("^(.*)_(\\d+):(\\d+)$"); + static const QRegularExpression rx("^(.*)_(\\d+):(\\d+)$"); const QRegularExpressionMatch match = rx.match(fileUrl.path()); if (match.hasMatch()) { fileUrl.setPath(match.captured(1)); diff --git a/src/plugins/debugger/simplifytype.cpp b/src/plugins/debugger/simplifytype.cpp index 1caa29093a0..56e79ea0433 100644 --- a/src/plugins/debugger/simplifytype.cpp +++ b/src/plugins/debugger/simplifytype.cpp @@ -102,7 +102,7 @@ QString simplifyType(const QString &typeIn) type.replace("std::__cxx11::", "std::"); type.replace("std::__1::", "std::"); type.replace("std::__debug::", "std::"); - QRegularExpression simpleStringRE("std::basic_string ?"); + static const QRegularExpression simpleStringRE("std::basic_string ?"); type.replace(simpleStringRE, "std::string"); // Normalize space + ptr. @@ -124,7 +124,7 @@ QString simplifyType(const QString &typeIn) type = type.mid(16, type.size() - 31); // std::ifstream - QRegularExpression ifstreamRE("std::basic_ifstream\\s*?>"); + static const QRegularExpression ifstreamRE("std::basic_ifstream\\s*?>"); QTC_ASSERT(ifstreamRE.isValid(), return typeIn); const QRegularExpressionMatch match = ifstreamRE.match(type); if (match.hasMatch()) @@ -133,7 +133,7 @@ QString simplifyType(const QString &typeIn) // std::__1::hash_node::value_type -> int if (isLibCpp) { - QRegularExpression hashNodeRE("std::__hash_node<([^<>]*),\\s*void\\s*@>::value_type"); + static const QRegularExpression hashNodeRE("std::__hash_node<([^<>]*),\\s*void\\s*@>::value_type"); QTC_ASSERT(hashNodeRE.isValid(), return typeIn); const QRegularExpressionMatch match = hashNodeRE.match(type); if (match.hasMatch()) diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index a8b49c54b1f..a0fd11af6a7 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -910,7 +910,7 @@ static QString displayName(const WatchItem *item) // prepend '*'s to indicate where autodereferencing has taken place if (item->autoDerefCount > 0) { // add parentheses for everything except simple variable names (e.g. pointer arithmetics,...) - QRegularExpression variableNameRegex("^[a-zA-Z0-9_]+$"); + static const QRegularExpression variableNameRegex("^[a-zA-Z0-9_]+$"); bool addParanthesis = !variableNameRegex.match(result).hasMatch(); if (addParanthesis) result = "(" + result; diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index afb75203037..6a5c579a7c1 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -845,15 +845,15 @@ static FileData readDiffHeaderAndChunks(QStringView headerAndChunks, bool *ok) FileData fileData; bool readOk = false; - const QRegularExpression leftFileRegExp( + static const QRegularExpression leftFileRegExp( "(?:\\n|^)-{3} " // "--- " "([^\\t\\n]+)" // "fileName1" "(?:\\t[^\\n]*)*\\n"); // optionally followed by: \t anything \t anything ...) - const QRegularExpression rightFileRegExp( + static const QRegularExpression rightFileRegExp( "^\\+{3} " // "+++ " "([^\\t\\n]+)" // "fileName2" "(?:\\t[^\\n]*)*\\n"); // optionally followed by: \t anything \t anything ...) - const QRegularExpression binaryRegExp( + static const QRegularExpression binaryRegExp( "^Binary files ([^\\t\\n]+) and ([^\\t\\n]+) differ$"); // followed either by leftFileRegExp @@ -895,7 +895,8 @@ static FileData readDiffHeaderAndChunks(QStringView headerAndChunks, bool *ok) static void readDiffPatch(QPromise> &promise, QStringView patch) { - const QRegularExpression diffRegExp("(?:\\n|^)" // new line of the beginning of a patch + static const QRegularExpression diffRegExp( + "(?:\\n|^)" // new line of the beginning of a patch "(" // either "-{3} " // --- "[^\\t\\n]+" // filename1 @@ -1282,7 +1283,7 @@ void DiffUtils::readPatchWithPromise(QPromise> &promise, const Q promise.setProgressValue(0); QStringView croppedPatch = QStringView(patch); // Crop e.g. "-- \n2.10.2.windows.1\n\n" at end of file - const QRegularExpression formatPatchEndingRegExp("(\\n-- \\n\\S*\\n\\n$)"); + static const QRegularExpression formatPatchEndingRegExp("(\\n-- \\n\\S*\\n\\n$)"); const QRegularExpressionMatch match = formatPatchEndingRegExp.match(croppedPatch); if (match.hasMatch()) croppedPatch = croppedPatch.left(match.capturedStart() + 1); diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 29257505f21..fe9c28706e8 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -408,8 +408,9 @@ static QRegularExpression vimPatternToQtPattern(const QString &needle) // FIXME: Option smartcase should be used only if search was typed by user. const bool smartCaseOption = settings().smartCase(); + static const QRegularExpression regexp("[A-Z]"); const bool initialIgnoreCase = settings().ignoreCase() - && !(smartCaseOption && needle.contains(QRegularExpression("[A-Z]"))); + && !(smartCaseOption && needle.contains(regexp)); bool ignorecase = initialIgnoreCase; @@ -639,10 +640,11 @@ static void bracketSearchBackward(QTextCursor *tc, const QString &needleExp, int static void bracketSearchForward(QTextCursor *tc, const QString &needleExp, int repeat, bool searchWithCommand) { - QRegularExpression re(searchWithCommand ? QString("^\\}|^\\{") : needleExp); + static const QRegularExpression reWithCommand("^\\}|^\\{"); + const QRegularExpression reNeedle(needleExp); QTextCursor tc2 = *tc; tc2.setPosition(tc2.position() + 1); - searchForward(&tc2, re, &repeat); + searchForward(&tc2, searchWithCommand ? reWithCommand : reNeedle, &repeat); if (repeat <= 1) { if (tc2.isNull()) { tc->setPosition(tc->document()->characterCount() - 1, KeepAnchor); @@ -2702,7 +2704,8 @@ void FakeVimHandler::Private::commitInsertState() lastInsertion.prepend(QString("").repeated(insertState.deletes)); // Remove indentation. - lastInsertion.replace(QRegularExpression("(^|\n)[\\t ]+"), "\\1"); + static const QRegularExpression regexp("(^|\n)[\\t ]+"); + lastInsertion.replace(regexp, "\\1"); } void FakeVimHandler::Private::invalidateInsertState() @@ -4816,7 +4819,8 @@ bool FakeVimHandler::Private::handleReplaceSubMode(const Input &input) ++range.endPos; // Replace each character but preserve lines. transformText(range, [&c](const QString &text) { - return QString(text).replace(QRegularExpression("[^\\n]"), c); + static const QRegularExpression regexp("[^\\n]"); + return QString(text).replace(regexp, c); }); } else if (count() <= rightDist()) { pushUndoState(); @@ -5778,7 +5782,8 @@ bool FakeVimHandler::Private::parseExCommand(QString *line, ExCommand *cmd) cmd->cmd = line->mid(0, i).trimmed(); // command arguments starts with first non-letter character - cmd->args = cmd->cmd.section(QRegularExpression("(?=[^a-zA-Z])"), 1); + static const QRegularExpression regexp("(?=[^a-zA-Z])"); + cmd->args = cmd->cmd.section(regexp, 1); if (!cmd->args.isEmpty()) { cmd->cmd.chop(cmd->args.size()); cmd->args = cmd->args.trimmed(); @@ -5798,7 +5803,8 @@ bool FakeVimHandler::Private::parseExCommand(QString *line, ExCommand *cmd) bool FakeVimHandler::Private::parseLineRange(QString *line, ExCommand *cmd) { // remove leading colons and spaces - line->remove(QRegularExpression("^\\s*(:+\\s*)*")); + static const QRegularExpression regexp("^\\s*(:+\\s*)*"); + line->remove(regexp); // special case ':!...' (use invalid range) if (line->startsWith('!')) { @@ -5857,7 +5863,8 @@ bool FakeVimHandler::Private::handleExSubstituteCommand(const ExCommand &cmd) int count = 1; QString line = cmd.args; - const QRegularExpressionMatch match = QRegularExpression("\\d+$").match(line); + static const QRegularExpression regexp("\\d+$"); + const QRegularExpressionMatch match = regexp.match(line); if (match.hasMatch()) { count = match.captured().toInt(); line = line.left(match.capturedStart()).trimmed(); @@ -6021,8 +6028,9 @@ bool FakeVimHandler::Private::handleExMapCommand(const ExCommand &cmd0) // :map break; } - const QString lhs = args.section(QRegularExpression("\\s+"), 0, 0); - const QString rhs = args.section(QRegularExpression("\\s+"), 1); + static const QRegularExpression regexp("\\s+"); + const QString lhs = args.section(regexp, 0, 0); + const QString rhs = args.section(regexp, 1); if ((rhs.isNull() && type != Unmap) || (!rhs.isNull() && type == Unmap)) { // FIXME: Dump mappings here. //qDebug() << g.mappings; @@ -7662,7 +7670,8 @@ void FakeVimHandler::Private::toggleComment(const Range &range) : commentString.size(); line.replace(line.indexOf(commentString), sizeToReplace, ""); } else { - const int indexOfFirstNonSpace = line.indexOf(QRegularExpression("[^\\s]")); + static const QRegularExpression regexp("[^\\s]"); + const int indexOfFirstNonSpace = line.indexOf(regexp); line = line.left(indexOfFirstNonSpace) + commentString + " " + line.right(line.size() - indexOfFirstNonSpace); } } @@ -7903,10 +7912,13 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace) const int blockNumber = m_cursor.blockNumber(); const QString currentLine = lineContents(blockNumber + 1); + static const QRegularExpression cppStyleRegexp("^\\s*\\/\\/"); + static const QRegularExpression cStyleRegexp("^\\s*\\/?\\*"); + static const QRegularExpression pythonStyleRegexp("^\\s*#"); const bool startingLineIsComment - = currentLine.contains(QRegularExpression("^\\s*\\/\\/")) // Cpp-style - || currentLine.contains(QRegularExpression("^\\s*\\/?\\*")) // C-style - || currentLine.contains(QRegularExpression("^\\s*#")); // Python/Shell-style + = currentLine.contains(cppStyleRegexp) + || currentLine.contains(cStyleRegexp) + || currentLine.contains(pythonStyleRegexp); for (int i = qMax(count - 2, 0); i >= 0 && blockNumber < document()->blockCount(); --i) { moveBehindEndOfLine(); @@ -8988,7 +9000,7 @@ bool FakeVimHandler::Private::changeNumberTextObject(int count) const int posMin = m_cursor.positionInBlock() + 1; // find first decimal, hexadecimal or octal number under or after cursor position - QRegularExpression re("(0[xX])(0*[0-9a-fA-F]+)|(0)(0*[0-7]+)(?=\\D|$)|(\\d+)"); + static const QRegularExpression re("(0[xX])(0*[0-9a-fA-F]+)|(0)(0*[0-7]+)(?=\\D|$)|(\\d+)"); QRegularExpressionMatch match; QRegularExpressionMatchIterator it = re.globalMatch(lineText); while (true) { @@ -9035,7 +9047,8 @@ bool FakeVimHandler::Private::changeNumberTextObject(int count) // convert hexadecimal number to upper-case if last letter was upper-case if (hex) { - const int lastLetter = num.lastIndexOf(QRegularExpression("[a-fA-F]")); + static const QRegularExpression regexp("[a-fA-F]"); + const int lastLetter = num.lastIndexOf(regexp); if (lastLetter != -1 && num[lastLetter].isUpper()) repl = repl.toUpper(); } diff --git a/src/plugins/fossil/fossilclient.cpp b/src/plugins/fossil/fossilclient.cpp index a0db9820500..843397fa2c4 100644 --- a/src/plugins/fossil/fossilclient.cpp +++ b/src/plugins/fossil/fossilclient.cpp @@ -227,7 +227,7 @@ unsigned int FossilClient::synchronousBinaryVersion() const // fossil version: // "This is fossil version 1.27 [ccdefa355b] 2013-09-30 11:47:18 UTC" - QRegularExpression versionPattern("(\\d+)\\.(\\d+)"); + static const QRegularExpression versionPattern("(\\d+)\\.(\\d+)"); QTC_ASSERT(versionPattern.isValid(), return 0); QRegularExpressionMatch versionMatch = versionPattern.match(output); QTC_ASSERT(versionMatch.hasMatch(), return 0); @@ -317,8 +317,8 @@ QStringList FossilClient::parseRevisionCommentLine(const QString &commentLine) { // "comment: This is a (test) commit message (user: the.name)" - const QRegularExpression commentRx("^comment:\\s+(.*)\\s\\(user:\\s(.*)\\)$", - QRegularExpression::CaseInsensitiveOption); + static const QRegularExpression commentRx("^comment:\\s+(.*)\\s\\(user:\\s(.*)\\)$", + QRegularExpression::CaseInsensitiveOption); QTC_ASSERT(commentRx.isValid(), return {}); const QRegularExpressionMatch match = commentRx.match(commentLine); @@ -354,7 +354,7 @@ RevisionInfo FossilClient::synchronousRevisionQuery(const FilePath &workingDirec QString commentMsg; QString committer; - const QRegularExpression idRx("([0-9a-f]{5,40})"); + static const QRegularExpression idRx("([0-9a-f]{5,40})"); QTC_ASSERT(idRx.isValid(), return {}); const QString hashToken = diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 46b285e5bc4..999e3f2edb8 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -744,7 +744,8 @@ bool FossilPluginPrivate::activateCommit() if (!branch.isEmpty()) { // @TODO: make enquote utility function QString enquotedBranch = branch; - if (branch.contains(QRegularExpression("\\s"))) + static const QRegularExpression regexp("\\s"); + if (branch.contains(regexp)) enquotedBranch = QString("\"") + branch + "\""; extraOptions << "--branch" << enquotedBranch; } diff --git a/src/plugins/git/gerrit/gerritserver.cpp b/src/plugins/git/gerrit/gerritserver.cpp index 869bbc0871d..ab70ae46c05 100644 --- a/src/plugins/git/gerrit/gerritserver.cpp +++ b/src/plugins/git/gerrit/gerritserver.cpp @@ -240,7 +240,7 @@ int GerritServer::testConnection() } if (result.exitCode() == CertificateError) return CertificateError; - const QRegularExpression errorRegexp("returned error: (\\d+)"); + static const QRegularExpression errorRegexp("returned error: (\\d+)"); QRegularExpressionMatch match = errorRegexp.match(result.cleanedStdErr()); if (match.hasMatch()) return match.captured(1).toInt(); diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp index aa5cd86be34..5f1b46e02ab 100644 --- a/src/plugins/git/giteditor.cpp +++ b/src/plugins/git/giteditor.cpp @@ -324,7 +324,7 @@ FilePath GitEditorWidget::fileNameForLine(int line) const // 7971b6e7 share/qtcreator/dumper/dumper.py (hjk QTextBlock block = document()->findBlockByLineNumber(line - 1); QTC_ASSERT(block.isValid(), return source()); - static QRegularExpression renameExp("^" CHANGE_PATTERN "\\s+([^(]+)"); + static const QRegularExpression renameExp("^" CHANGE_PATTERN "\\s+([^(]+)"); const QRegularExpressionMatch match = renameExp.match(block.text()); if (match.hasMatch()) { const QString fileName = match.captured(1).trimmed(); diff --git a/src/plugins/help/searchwidget.cpp b/src/plugins/help/searchwidget.cpp index 65da6febb0d..ef932ba15b3 100644 --- a/src/plugins/help/searchwidget.cpp +++ b/src/plugins/help/searchwidget.cpp @@ -245,7 +245,8 @@ void SearchWidget::contextMenuEvent(QContextMenuEvent *contextMenuEvent) QStringList SearchWidget::currentSearchTerms() const { - return searchEngine->searchInput().split(QRegularExpression("\\W+"), Qt::SkipEmptyParts); + static const QRegularExpression regexp("\\W+"); + return searchEngine->searchInput().split(regexp, Qt::SkipEmptyParts); } // #pragma mark -- SearchSideBarItem diff --git a/src/plugins/incredibuild/cmakecommandbuilder.cpp b/src/plugins/incredibuild/cmakecommandbuilder.cpp index 8732601cbc4..7743b3143fd 100644 --- a/src/plugins/incredibuild/cmakecommandbuilder.cpp +++ b/src/plugins/incredibuild/cmakecommandbuilder.cpp @@ -53,7 +53,7 @@ QString CMakeCommandBuilder::defaultArguments() const QString CMakeCommandBuilder::setMultiProcessArg(QString args) { - QRegularExpression regExp("\\s*\\-j\\s+\\d+"); + static const QRegularExpression regExp("\\s*\\-j\\s+\\d+"); args.remove(regExp); args.append(" -- -j 200"); diff --git a/src/plugins/incredibuild/makecommandbuilder.cpp b/src/plugins/incredibuild/makecommandbuilder.cpp index f9fb4a59587..bffd0770ee8 100644 --- a/src/plugins/incredibuild/makecommandbuilder.cpp +++ b/src/plugins/incredibuild/makecommandbuilder.cpp @@ -51,14 +51,14 @@ QString MakeCommandBuilder::setMultiProcessArg(QString args) // jom -j 200 if (cmd.baseName().compare("jom", Qt::CaseSensitivity::CaseInsensitive) == 0) { - QRegularExpression regExp("\\s*\\-j\\s+\\d+"); + static const QRegularExpression regExp("\\s*\\-j\\s+\\d+"); args.remove(regExp); args.append(" -j 200"); } // make -j200 else if ((cmd.baseName().compare("make", Qt::CaseSensitivity::CaseInsensitive) == 0) || (cmd.baseName().compare("gmake", Qt::CaseSensitivity::CaseInsensitive) == 0)) { - QRegularExpression regExp("\\s*\\-j\\d+"); + static const QRegularExpression regExp("\\s*\\-j\\d+"); args.remove(regExp); args.append(" -j200"); } diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index 7f111ea351e..287210da4c7 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -60,6 +60,8 @@ using namespace Tasking; namespace Ios::Internal { +char QML_DEBUGGER_WAITING[] = "QML Debugger: Waiting for connection on port ([0-9]+)..."; + static QString identifierForRunControl(RunControl *runControl) { const IosDeviceTypeAspect::Data *data = runControl->aspectData(); @@ -621,7 +623,7 @@ void IosRunner::handleGotInferiorPid(IosToolHandler *handler, const FilePath &bu void IosRunner::handleAppOutput(IosToolHandler *handler, const QString &output) { Q_UNUSED(handler) - QRegularExpression qmlPortRe("QML Debugger: Waiting for connection on port ([0-9]+)..."); + static const QRegularExpression qmlPortRe(QString::fromLatin1(QML_DEBUGGER_WAITING)); const QRegularExpressionMatch match = qmlPortRe.match(output); QString res(output); if (match.hasMatch() && m_qmlServerPort.isValid()) @@ -632,7 +634,7 @@ void IosRunner::handleAppOutput(IosToolHandler *handler, const QString &output) void IosRunner::handleMessage(const QString &msg) { QString res(msg); - QRegularExpression qmlPortRe("QML Debugger: Waiting for connection on port ([0-9]+)..."); + static const QRegularExpression qmlPortRe(QString::fromLatin1(QML_DEBUGGER_WAITING)); const QRegularExpressionMatch match = qmlPortRe.match(msg); if (match.hasMatch() && m_qmlServerPort.isValid()) res.replace(match.captured(1), QString::number(m_qmlServerPort.number())); diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp index 7919de0de81..abdd308b51e 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.cpp +++ b/src/plugins/languageclient/languageclientcompletionassist.cpp @@ -78,7 +78,7 @@ void LanguageClientCompletionItem::apply(TextEditorWidget *editorWidget, QTextCursor cursor = editorWidget->textCursorAt(pos); cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); const QString blockTextUntilPosition = cursor.selectedText(); - static QRegularExpression identifier("[a-zA-Z_][a-zA-Z0-9_]*$"); + static const QRegularExpression identifier("[a-zA-Z_][a-zA-Z0-9_]*$"); QRegularExpressionMatch match = identifier.match(blockTextUntilPosition); int matchLength = match.hasMatch() ? match.capturedLength(0) : 0; length = qMax(length, matchLength); diff --git a/src/plugins/lua/bindings/translate.cpp b/src/plugins/lua/bindings/translate.cpp index 7c5cb140166..aec22c23ce1 100644 --- a/src/plugins/lua/bindings/translate.cpp +++ b/src/plugins/lua/bindings/translate.cpp @@ -11,8 +11,8 @@ void setupTranslateModule() { autoRegister([](sol::state_view lua) { const ScriptPluginSpec *pluginSpec = lua.get("PluginSpec"); - const QString trContext - = QString(pluginSpec->name).replace(QRegularExpression("[^a-zA-Z]"), "_"); + static const QRegularExpression regexp("[^a-zA-Z]"); + const QString trContext = QString(pluginSpec->name).replace(regexp, "_"); lua["tr"] = [trContext](const char *text) -> QString { return QCoreApplication::translate(trContext.toUtf8().constData(), text); diff --git a/src/plugins/lua/luaengine.cpp b/src/plugins/lua/luaengine.cpp index dca1bb25733..a641bfbd03b 100644 --- a/src/plugins/lua/luaengine.cpp +++ b/src/plugins/lua/luaengine.cpp @@ -116,7 +116,8 @@ void prepareLuaState( const expected_str tmpDir = HostOsInfo::root().tmpDir(); QTC_ASSERT_EXPECTED(tmpDir, return); QString id = name; - id = id.replace(QRegularExpression("[^a-zA-Z0-9_]"), "_").toLower(); + static const QRegularExpression regexp("[^a-zA-Z0-9_]"); + id = id.replace(regexp, "_").toLower(); ScriptPluginSpec::setup(lua, id, name, appDataPath, *tmpDir); for (const auto &[name, func] : d->m_providers.asKeyValueRange()) { From 116d5224e9409c4ed9b914a92b9d5ca9675fb357 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 20 Nov 2024 12:19:53 +0100 Subject: [PATCH 209/989] Plugins M-V: Make static QRegularExpression instances static const Change-Id: I291e61ac30786dfceda330d3dc73352da719c7d0 Reviewed-by: hjk --- src/plugins/mercurial/mercurialcommitwidget.cpp | 4 ++-- src/plugins/mesonprojectmanager/buildoptionsmodel.cpp | 4 ++-- src/plugins/nim/project/nimtoolchain.cpp | 2 +- src/plugins/perforce/pendingchangesdialog.cpp | 2 +- src/plugins/perforce/perforceplugin.cpp | 7 ++++--- src/plugins/perforce/perforcesubmiteditor.cpp | 7 ++++--- src/plugins/projectexplorer/abi.cpp | 3 ++- src/plugins/projectexplorer/gcctoolchain.cpp | 2 +- src/plugins/projectexplorer/kitmanagerconfigwidget.cpp | 2 +- src/plugins/projectexplorer/msvctoolchain.cpp | 4 ++-- src/plugins/projectexplorer/userfileaccessor.cpp | 3 ++- src/plugins/python/pyside.cpp | 2 +- src/plugins/python/pythonbuildsystem.cpp | 2 +- src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp | 2 +- src/plugins/qbsprojectmanager/qbsprofilemanager.cpp | 3 ++- src/plugins/qmakeprojectmanager/addlibrarywizard.cpp | 2 +- .../customwidgetwizard/plugingenerator.cpp | 3 ++- src/plugins/qmljseditor/qmljshoverhandler.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp | 2 +- src/plugins/qmlprojectmanager/projectfilecontenttools.cpp | 6 +++--- src/plugins/qnx/qnxversionnumber.cpp | 3 ++- src/plugins/qnx/slog2inforunner.cpp | 4 ++-- src/plugins/qtsupport/baseqtversion.cpp | 5 +++-- src/plugins/scxmleditor/common/structure.cpp | 4 ++-- .../plugin_interface/scattributeitemdelegate.cpp | 5 ++--- src/plugins/squish/objectsmapeditorwidget.cpp | 2 +- src/plugins/squish/propertyitemdelegate.cpp | 2 +- src/plugins/terminal/terminalsettings.cpp | 2 +- .../texteditor/codeassist/documentcontentcompletion.cpp | 2 +- src/plugins/texteditor/storagesettings.cpp | 2 +- src/plugins/texteditor/texteditor.cpp | 7 ++++--- src/plugins/valgrind/memchecktool.cpp | 3 ++- 32 files changed, 57 insertions(+), 48 deletions(-) diff --git a/src/plugins/mercurial/mercurialcommitwidget.cpp b/src/plugins/mercurial/mercurialcommitwidget.cpp index d1d1a7b37b9..fb74e8af7aa 100644 --- a/src/plugins/mercurial/mercurialcommitwidget.cpp +++ b/src/plugins/mercurial/mercurialcommitwidget.cpp @@ -169,8 +169,8 @@ QString MercurialCommitWidget::repoRoot() const QString MercurialCommitWidget::cleanupDescription(const QString &input) const { - const QRegularExpression commentLine(QLatin1String("^HG:[^\\n]*(\\n|$)"), - QRegularExpression::MultilineOption); + static const QRegularExpression commentLine(QLatin1String("^HG:[^\\n]*(\\n|$)"), + QRegularExpression::MultilineOption); QString message = input; message.remove(commentLine); return message; diff --git a/src/plugins/mesonprojectmanager/buildoptionsmodel.cpp b/src/plugins/mesonprojectmanager/buildoptionsmodel.cpp index 702176b517a..8019be45566 100644 --- a/src/plugins/mesonprojectmanager/buildoptionsmodel.cpp +++ b/src/plugins/mesonprojectmanager/buildoptionsmodel.cpp @@ -15,9 +15,9 @@ namespace MesonProjectManager::Internal { -static QRegularExpression ®Exp() +static const QRegularExpression ®Exp() { - static QRegularExpression s_regexp{R"('([^']+)'+|([^', ]+)[, ]*)"}; + static const QRegularExpression s_regexp{R"('([^']+)'+|([^', ]+)[, ]*)"}; return s_regexp; } diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp index d333e618537..e083ae5b172 100644 --- a/src/plugins/nim/project/nimtoolchain.cpp +++ b/src/plugins/nim/project/nimtoolchain.cpp @@ -107,7 +107,7 @@ bool NimToolchain::parseVersion(const FilePath &path, std::tuple const QString version = process.readAllStandardOutput().section('\n', 0, 0); if (version.isEmpty()) return false; - const QRegularExpression regex("(\\d+)\\.(\\d+)\\.(\\d+)"); + static const QRegularExpression regex("(\\d+)\\.(\\d+)\\.(\\d+)"); const QRegularExpressionMatch match = regex.match(version); if (!match.hasMatch()) return false; diff --git a/src/plugins/perforce/pendingchangesdialog.cpp b/src/plugins/perforce/pendingchangesdialog.cpp index 84b10a8a072..61ab54514ea 100644 --- a/src/plugins/perforce/pendingchangesdialog.cpp +++ b/src/plugins/perforce/pendingchangesdialog.cpp @@ -29,7 +29,7 @@ PendingChangesDialog::PendingChangesDialog(const QString &data, QWidget *parent) connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); if (!data.isEmpty()) { - const QRegularExpression r(QLatin1String("Change\\s(\\d+?).*?\\s\\*?pending\\*?\\s(.+?)\n")); + static const QRegularExpression r("Change\\s(\\d+?).*?\\s\\*?pending\\*?\\s(.+?)\n"); QListWidgetItem *item; QRegularExpressionMatchIterator it = r.globalMatch(data); while (it.hasNext()) { diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 665f54b5769..389879afe96 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -731,7 +731,8 @@ void PerforcePluginPrivate::startSubmitProject() const QStringList filesLines = filesResult.stdOut.split(QLatin1Char('\n')); QStringList depotFileNames; for (const QString &line : filesLines) { - depotFileNames.append(line.left(line.lastIndexOf(QRegularExpression("#[0-9]+\\s-\\s")))); + static const QRegularExpression regexp("#[0-9]+\\s-\\s"); + depotFileNames.append(line.left(line.lastIndexOf(regexp))); } if (depotFileNames.isEmpty()) { VcsOutputWindow::appendWarning(Tr::tr("Project has no files")); @@ -1447,7 +1448,7 @@ QString PerforcePluginPrivate::clientFilePath(const QString &serverFilePath) if (response.error) return {}; - const QRegularExpression r("\\.\\.\\.\\sclientFile\\s(.+?)\n"); + static const QRegularExpression r("\\.\\.\\.\\sclientFile\\s(.+?)\n"); const QRegularExpressionMatch match = r.match(response.stdOut); return match.hasMatch() ? match.captured(1).trimmed() : QString(); } @@ -1462,7 +1463,7 @@ QString PerforcePluginPrivate::pendingChangesData() if (userResponse.error) return {}; - const QRegularExpression r("User\\sname:\\s(\\S+?)\\s*?\n"); + static const QRegularExpression r("User\\sname:\\s(\\S+?)\\s*?\n"); QTC_ASSERT(r.isValid(), return QString()); const QRegularExpressionMatch match = r.match(userResponse.stdOut); const QString user = match.hasMatch() ? match.captured(1).trimmed() : QString(); diff --git a/src/plugins/perforce/perforcesubmiteditor.cpp b/src/plugins/perforce/perforcesubmiteditor.cpp index 9b6f8240d4c..e066cb367e6 100644 --- a/src/plugins/perforce/perforcesubmiteditor.cpp +++ b/src/plugins/perforce/perforcesubmiteditor.cpp @@ -48,7 +48,7 @@ bool PerforceSubmitEditor::setFileContents(const QByteArray &contents) bool PerforceSubmitEditor::parseText(QString text) { - QRegularExpression formField(QLatin1String("^\\S+:")); + static const QRegularExpression formField("^\\S+:"); const QString newLine = QString(QLatin1Char('\n')); int matchLen; @@ -94,7 +94,7 @@ void PerforceSubmitEditor::updateFields() lines.removeFirst(); // that is the line break after 'Description:' lines.removeLast(); // that is the empty line at the end - const QRegularExpression leadingTabPattern("^\\t"); + static const QRegularExpression leadingTabPattern("^\\t"); QTC_CHECK(leadingTabPattern.isValid()); lines.replaceInStrings(leadingTabPattern, QString()); @@ -122,7 +122,8 @@ void PerforceSubmitEditor::updateEntries() while (!lines.empty() && lines.last().isEmpty()) lines.removeLast(); // Description - lines.replaceInStrings(QRegularExpression("^"), tab); + static const QRegularExpression regexp("^"); + lines.replaceInStrings(regexp, tab); m_entries.insert(QLatin1String("Description"), newLine + lines.join(newLine) + QLatin1String("\n\n")); QString files = newLine; // Re-build the file spec 'file#add' from the user data diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 3f6b392f1e4..1cde394ec8e 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -472,7 +472,8 @@ Abi Abi::abiFromTargetTriplet(const QString &triple) if (machine.isEmpty()) return {}; - const QStringList parts = machine.split(QRegularExpression("[ /-]")); + static const QRegularExpression splitRegexp("[ /-]"); + const QStringList parts = machine.split(splitRegexp); Architecture arch = UnknownArchitecture; OS os = UnknownOS; diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index e1382e6f22e..9b4513e203b 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -454,7 +454,7 @@ void GccToolchain::setInstallDir(const FilePath &installDir) QString GccToolchain::defaultDisplayName() const { QString type = typeDisplayName(); - const QRegularExpression regexp(binaryRegexp); + static const QRegularExpression regexp(binaryRegexp); const QRegularExpressionMatch match = regexp.match(compilerCommand().fileName()); if (match.lastCapturedIndex() >= 1) type += ' ' + match.captured(1); diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index dd2014dca8c..5cdca7c87be 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -60,7 +60,7 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k, bool &isDefaultKit, bool "which for example determines the name of the shadow build directory." "

    ").arg(QLatin1String("Kit:FileSystemName")); m_fileSystemFriendlyNameLineEdit->setToolTip(toolTip); - QRegularExpression fileSystemFriendlyNameRegexp(QLatin1String("^[A-Za-z0-9_-]*$")); + static const QRegularExpression fileSystemFriendlyNameRegexp(QLatin1String("^[A-Za-z0-9_-]*$")); Q_ASSERT(fileSystemFriendlyNameRegexp.isValid()); m_fileSystemFriendlyNameLineEdit->setValidator(new QRegularExpressionValidator(fileSystemFriendlyNameRegexp, m_fileSystemFriendlyNameLineEdit)); diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 132c9afe8a4..e977f776f8c 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -2284,8 +2284,8 @@ ClangClInfo ClangClInfo::getInfo(const FilePath &filePath) static const auto parser = [](const QString &stdOut, const QString &) { ClangClInfo info; - const QRegularExpressionMatch versionMatch - = QRegularExpression("clang version (\\d+(\\.\\d+)+)").match(stdOut); + static const QRegularExpression regexp("clang version (\\d+(\\.\\d+)+)"); + const QRegularExpressionMatch versionMatch = regexp.match(stdOut); if (versionMatch.hasMatch()) info.m_version = QVersionNumber::fromString(versionMatch.captured(1)); const QString targetKey = "Target:"; diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp index 173594c19f8..e3854d69008 100644 --- a/src/plugins/projectexplorer/userfileaccessor.cpp +++ b/src/plugins/projectexplorer/userfileaccessor.cpp @@ -176,7 +176,8 @@ namespace { static QString generateSuffix(const QString &suffix) { QString result = suffix; - result.replace(QRegularExpression("[^a-zA-Z0-9_.-]"), QString('_')); // replace fishy character + static const QRegularExpression regexp("[^a-zA-Z0-9_.-]"); + result.replace(regexp, QString('_')); // replace fishy character if (!result.startsWith('.')) result.prepend('.'); return result; diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index 7010e099ffa..bdccde1f3fb 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -74,7 +74,7 @@ QString PySideInstaller::usedPySide(const QString &text, const QString &mimeType { using namespace Python::Constants; if (mimeType == C_PY_MIMETYPE || mimeType == C_PY3_MIMETYPE || mimeType == C_PY_GUI_MIMETYPE) { - static QRegularExpression + static const QRegularExpression scanner("^\\s*(import|from)\\s+(PySide\\d)", QRegularExpression::MultilineOption); const QRegularExpressionMatch match = scanner.match(text); return match.captured(2); diff --git a/src/plugins/python/pythonbuildsystem.cpp b/src/plugins/python/pythonbuildsystem.cpp index 619e59ad527..f091aea2bc7 100644 --- a/src/plugins/python/pythonbuildsystem.cpp +++ b/src/plugins/python/pythonbuildsystem.cpp @@ -370,7 +370,7 @@ void PythonBuildSystem::parse() */ static void expandEnvironmentVariables(const Environment &env, QString &string) { - const QRegularExpression candidate("\\$\\$\\((.+)\\)"); + static const QRegularExpression candidate("\\$\\$\\((.+)\\)"); QRegularExpressionMatch match; int index = string.indexOf(candidate, 0, &match); diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index f3caa25d261..0ea8d83e55d 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -361,7 +361,7 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor } if (targetAbi.os() == ProjectExplorer::Abi::DarwinOS) { // Reverse engineer the Xcode developer path from the compiler path - const QRegularExpression compilerRe( + static const QRegularExpression compilerRe( QStringLiteral("^(?.*)/Toolchains/(?:.+)\\.xctoolchain/usr/bin$")); const QRegularExpressionMatch compilerReMatch = compilerRe.match(cxxCompilerPath.absolutePath().toString()); if (compilerReMatch.hasMatch()) { diff --git a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp index b7f831b8dee..8fea3e1a2ed 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp @@ -48,7 +48,8 @@ static QString toJSLiteral(const bool b) static QString toJSLiteral(const QString &str) { QString js = str; - js.replace(QRegularExpression("([\\\\\"])"), "\\\\1"); + static const QRegularExpression regexp("([\\\\\"])"); + js.replace(regexp, "\\\\1"); js.prepend('"'); js.append('"'); return js; diff --git a/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp b/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp index c6500df0cfd..01c172823a7 100644 --- a/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp +++ b/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp @@ -32,7 +32,7 @@ const char qt_file_dialog_filter_reg_exp[] = static QStringList qt_clean_filter_list(const QString &filter) { - const QRegularExpression regexp(qt_file_dialog_filter_reg_exp); + static const QRegularExpression regexp(qt_file_dialog_filter_reg_exp); const QRegularExpressionMatch match = regexp.match(filter); QString f = filter; if (match.hasMatch()) diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp index 0a36120a64b..6f77db462a4 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp @@ -24,7 +24,8 @@ namespace QmakeProjectManager::Internal { static QString headerGuard(const QString &header) { - return header.toUpper().replace(QRegularExpression("[^A-Z0-9]+"), QString("_")); + static const QRegularExpression regexp("[^A-Z0-9]+"); + return header.toUpper().replace(regexp, QString("_")); } struct ProjectContents { diff --git a/src/plugins/qmljseditor/qmljshoverhandler.cpp b/src/plugins/qmljseditor/qmljshoverhandler.cpp index c1ef69982f7..f17ec289254 100644 --- a/src/plugins/qmljseditor/qmljshoverhandler.cpp +++ b/src/plugins/qmljseditor/qmljshoverhandler.cpp @@ -158,7 +158,7 @@ bool QmlJSHoverHandler::setQmlTypeHelp(const ScopeChain &scopeChain, const Docum const HelpItem::Links links = helpItem.links(); // Check if the module name contains a major version. - static QRegularExpression version("^([^\\d]*)(\\d+)\\.*\\d*$"); + static const QRegularExpression version("^([^\\d]*)(\\d+)\\.*\\d*$"); const QRegularExpressionMatch m = version.match(moduleName); if (m.hasMatch()) { QMap filteredUrlMap; diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index fa0c9f77db1..75834aaf60c 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -219,7 +219,7 @@ static QString getInitialDetails(const QmlEventType &event) if (event.rangeType() == Javascript) details = Tr::tr("anonymous function"); } else { - QRegularExpression rewrite(QLatin1String("^\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)$")); + static const QRegularExpression rewrite("^\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)$"); QRegularExpressionMatch match = rewrite.match(details); if (match.hasMatch()) details = match.captured(1) + QLatin1String(": ") + match.captured(3); diff --git a/src/plugins/qmlprojectmanager/projectfilecontenttools.cpp b/src/plugins/qmlprojectmanager/projectfilecontenttools.cpp index e432967624d..7b12642ce29 100644 --- a/src/plugins/qmlprojectmanager/projectfilecontenttools.cpp +++ b/src/plugins/qmlprojectmanager/projectfilecontenttools.cpp @@ -84,7 +84,7 @@ const QString getMainQmlFile(const Utils::FilePath &projectFilePath) { const QString defaultReturn = "content/App.qml"; const QString data = readFileContents(projectFilePath); - QRegularExpression regexp(R"x(mainFile: "(.*)")x"); + static const QRegularExpression regexp(R"x(mainFile: "(.*)")x"); QRegularExpressionMatch match = regexp.match(data); if (!match.hasMatch()) return defaultReturn; @@ -105,8 +105,8 @@ const Resolution resolutionFromConstants(const Utils::FilePath &projectFilePath) if (!reader.fetch(Utils::FilePath::fromString(fileName))) return {}; const QByteArray data = reader.data(); - const QRegularExpression regexpWidth(R"x(readonly\s+property\s+int\s+width:\s+(\d*))x"); - const QRegularExpression regexpHeight(R"x(readonly\s+property\s+int\s+height:\s+(\d*))x"); + static const QRegularExpression regexpWidth(R"x(readonly\s+property\s+int\s+width:\s+(\d*))x"); + static const QRegularExpression regexpHeight(R"x(readonly\s+property\s+int\s+height:\s+(\d*))x"); int width = -1; int height = -1; QRegularExpressionMatch match = regexpHeight.match(QString::fromUtf8(data)); diff --git a/src/plugins/qnx/qnxversionnumber.cpp b/src/plugins/qnx/qnxversionnumber.cpp index ea7521a4b2c..c9abf93b4ba 100644 --- a/src/plugins/qnx/qnxversionnumber.cpp +++ b/src/plugins/qnx/qnxversionnumber.cpp @@ -66,7 +66,8 @@ QString QnxVersionNumber::segment(int index) const QnxVersionNumber QnxVersionNumber::fromTargetName(const QString &targetName) { - return fromFileName(targetName, QRegularExpression("^target_(.*)$")); + static const QRegularExpression regexp("^target_(.*)$"); + return fromFileName(targetName, regexp); } QnxVersionNumber QnxVersionNumber::fromFileName(const QString &fileName, const QRegularExpression ®Exp) diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index 2c7bf6716c8..6feaad06aa3 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -106,8 +106,8 @@ void Slog2InfoRunner::processLogLine(const QString &line) // The "\\s+(\\b.*)?$" represents a space followed by a message. We are unable to determinate // how many spaces represent separators and how many are a part of the messages, so resulting // messages has all whitespaces at the beginning of the message trimmed. - static QRegularExpression regexp(QLatin1String( - "^[a-zA-Z]+\\s+([0-9]+ [0-9]+:[0-9]+:[0-9]+.[0-9]+)\\s+(\\S+)(\\s+(\\S+))?\\s+([0-9]+)\\s+(.*)?$")); + static const QRegularExpression regexp( + "^[a-zA-Z]+\\s+([0-9]+ [0-9]+:[0-9]+:[0-9]+.[0-9]+)\\s+(\\S+)(\\s+(\\S+))?\\s+([0-9]+)\\s+(.*)?$"); const QRegularExpressionMatch match = regexp.match(line); if (!match.hasMatch()) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 98aaeb3b657..28cc8b9c672 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1824,7 +1824,7 @@ FilePath QtVersionPrivate::mkspecFromVersionInfo(const QHash if (temp.size() == 2) { QString possibleFullPath = QString::fromLocal8Bit(temp.at(1).trimmed().constData()); if (possibleFullPath.contains('$')) { // QTBUG-28792 - const QRegularExpression rex("\\binclude\\(([^)]+)/qmake\\.conf\\)"); + static const QRegularExpression rex("\\binclude\\(([^)]+)/qmake\\.conf\\)"); const QRegularExpressionMatch match = rex.match(QString::fromLocal8Bit(f2.readAll())); if (match.hasMatch()) { possibleFullPath = mkspecFullPath.toString() + '/' @@ -2134,7 +2134,8 @@ static QStringList extractFieldsFromBuildString(const QByteArray &buildString) if (buildString.isEmpty() || buildString.size() > 4096) return {}; - const QRegularExpression buildStringMatcher("^Qt " + static const QRegularExpression buildStringMatcher( + "^Qt " "([\\d\\.a-zA-Z]*) " // Qt version "\\(" "([\\w_-]+) " // Abi information diff --git a/src/plugins/scxmleditor/common/structure.cpp b/src/plugins/scxmleditor/common/structure.cpp index f709379d34d..1ea5d9bb7a0 100644 --- a/src/plugins/scxmleditor/common/structure.cpp +++ b/src/plugins/scxmleditor/common/structure.cpp @@ -41,8 +41,8 @@ QWidget *TreeItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewI if (index.isValid()) { auto edit = new QLineEdit(parent); edit->setFocusPolicy(Qt::StrongFocus); - QRegularExpression rx("^(?!xml)[_a-z][a-z0-9-._]*$"); - rx.setPatternOptions(QRegularExpression::CaseInsensitiveOption); + static const QRegularExpression rx("^(?!xml)[_a-z][a-z0-9-._]*$", + QRegularExpression::CaseInsensitiveOption); edit->setValidator(new QRegularExpressionValidator(rx, parent)); return edit; } diff --git a/src/plugins/scxmleditor/plugin_interface/scattributeitemdelegate.cpp b/src/plugins/scxmleditor/plugin_interface/scattributeitemdelegate.cpp index 0121ddf191a..4e322f7849f 100644 --- a/src/plugins/scxmleditor/plugin_interface/scattributeitemdelegate.cpp +++ b/src/plugins/scxmleditor/plugin_interface/scattributeitemdelegate.cpp @@ -28,9 +28,8 @@ QWidget *SCAttributeItemDelegate::createEditor(QWidget *parent, const QStyleOpti if (index.column() == 0) { auto edit = new QLineEdit(parent); edit->setFocusPolicy(Qt::StrongFocus); - QRegularExpression rx("^(?!xml)[_a-z][a-z0-9-._]*$"); - rx.setPatternOptions(QRegularExpression::CaseInsensitiveOption); - + static const QRegularExpression rx("^(?!xml)[_a-z][a-z0-9-._]*$", + QRegularExpression::CaseInsensitiveOption); edit->setValidator(new QRegularExpressionValidator(rx, parent)); return edit; } diff --git a/src/plugins/squish/objectsmapeditorwidget.cpp b/src/plugins/squish/objectsmapeditorwidget.cpp index e689a5a2962..6819c0f3866 100644 --- a/src/plugins/squish/objectsmapeditorwidget.cpp +++ b/src/plugins/squish/objectsmapeditorwidget.cpp @@ -514,7 +514,7 @@ void ObjectsMapEditorWidget::onPasteSymbolicNameTriggered() return; // if name is not valid at all refuse to do anything - const QRegularExpression validName("^:[^\t\n\r\f\b\v\a]+$"); + static const QRegularExpression validName("^:[^\t\n\r\f\b\v\a]+$"); if (!validName.match(symbolicName).hasMatch()) return; diff --git a/src/plugins/squish/propertyitemdelegate.cpp b/src/plugins/squish/propertyitemdelegate.cpp index d859db864b7..fa21bc8f9ed 100644 --- a/src/plugins/squish/propertyitemdelegate.cpp +++ b/src/plugins/squish/propertyitemdelegate.cpp @@ -137,7 +137,7 @@ ValidatingPropertyNameLineEdit::ValidatingPropertyNameLineEdit(const QStringList if (!edit) return false; - const QRegularExpression identifier("^[a-zA-Z0-9_]+$"); + static const QRegularExpression identifier("^[a-zA-Z0-9_]+$"); const QString &value = edit->text(); return !m_forbidden.contains(value) && identifier.match(value).hasMatch(); diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index f14766918da..4ac13061798 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -87,7 +87,7 @@ static expected_str loadXdefaults(const FilePath &path) if (!readResult) return make_unexpected(readResult.error()); - QRegularExpression re(R"(.*\*(color[0-9]{1,2}|foreground|background):\s*(#[0-9a-f]{6}))"); + static const QRegularExpression re(R"(.*\*(color[0-9]{1,2}|foreground|background):\s*(#[0-9a-f]{6}))"); for (const QByteArray &line : readResult->split('\n')) { if (line.trimmed().startsWith('!')) diff --git a/src/plugins/texteditor/codeassist/documentcontentcompletion.cpp b/src/plugins/texteditor/codeassist/documentcontentcompletion.cpp index d994238f4a3..d825e6049f5 100644 --- a/src/plugins/texteditor/codeassist/documentcontentcompletion.cpp +++ b/src/plugins/texteditor/codeassist/documentcontentcompletion.cpp @@ -80,7 +80,7 @@ IAssistProposal *DocumentContentCompletionProcessor::performAsync() const QString wordUnderCursor = interface()->textAt(pos, length); const QString text = interface()->textDocument()->toPlainText(); - const QRegularExpression wordRE("([\\p{L}_][\\p{L}0-9_]{2,})"); + static const QRegularExpression wordRE("([\\p{L}_][\\p{L}0-9_]{2,})"); QSet words; QRegularExpressionMatchIterator it = wordRE.globalMatch(text); int wordUnderCursorFound = 0; diff --git a/src/plugins/texteditor/storagesettings.cpp b/src/plugins/texteditor/storagesettings.cpp index 81b9ceace46..69026ab9152 100644 --- a/src/plugins/texteditor/storagesettings.cpp +++ b/src/plugins/texteditor/storagesettings.cpp @@ -66,7 +66,7 @@ bool StorageSettings::removeTrailingWhitespace(const QString &fileName) const const QString ignoreFileTypesRegExp(R"(\s*((?>\*\.)?[\w\d\.\*]+)[,;]?\s*)"); // use the ignore-files regex to extract the specified file patterns - QRegularExpression re(ignoreFileTypesRegExp); + static const QRegularExpression re(ignoreFileTypesRegExp); QRegularExpressionMatchIterator iter = re.globalMatch(m_ignoreFileTypes); while (iter.hasNext()) { diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 1ae3b953b73..f44fa7b7baf 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -2457,7 +2457,8 @@ void TextEditorWidget::joinLines() QString cutLine = c.selectedText(); // Collapse leading whitespaces to one or insert whitespace - cutLine.replace(QRegularExpression(QLatin1String("^\\s*")), QLatin1String(" ")); + static const QRegularExpression regexp("^\\s*"); + cutLine.replace(regexp, QLatin1String(" ")); c.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); c.removeSelectedText(); @@ -8815,7 +8816,7 @@ void TextEditorWidget::autoIndent() void TextEditorWidget::rewrapParagraph() { const int paragraphWidth = marginSettings().m_marginColumn; - const QRegularExpression anyLettersOrNumbers("\\w"); + static const QRegularExpression anyLettersOrNumbers("\\w"); const TabSettings ts = d->m_document->tabSettings(); QTextCursor cursor = textCursor(); @@ -8868,7 +8869,7 @@ void TextEditorWidget::rewrapParagraph() } // Find end of paragraph. - const QRegularExpression immovableDoxygenCommand(doxygenPrefix + "[@\\\\][a-zA-Z]{2,}"); + static const QRegularExpression immovableDoxygenCommand(doxygenPrefix + "[@\\\\][a-zA-Z]{2,}"); QTC_CHECK(immovableDoxygenCommand.isValid()); while (cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor)) { QString text = cursor.block().text(); diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 5b4fa2365a3..b7430ca8eb7 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -1155,7 +1155,8 @@ HeobDialog::HeobDialog(QWidget *parent) : QtcSettings *settings = Core::ICore::settings(); bool hasSelProfile = settings->contains(heobProfileC); const QString selProfile = hasSelProfile ? settings->value(heobProfileC).toString() : "Heob"; - m_profiles = settings->childGroups().filter(QRegularExpression("^Heob\\.Profile\\.")); + static const QRegularExpression regexp("^Heob\\.Profile\\."); + m_profiles = settings->childGroups().filter(regexp); auto layout = new QVBoxLayout; // disable resizing From 72fcd8553943a74c925982e279c21b89d725bcfc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 18 Nov 2024 19:32:51 +0100 Subject: [PATCH 210/989] Qnx: Remove unused arg Amends 4bddce64f5880c8e26d1e9fc2cfe444b1d1358d5 Change-Id: Ie1b344714f6759733a7e25649a856c86e6bbbcf8 Reviewed-by: hjk --- src/plugins/qnx/slog2inforunner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index 6feaad06aa3..4cb635f0d2e 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -37,7 +37,7 @@ void Slog2InfoRunner::start() const auto onTestSetup = [this](Process &process) { process.setCommand(CommandLine{device()->filePath("slog2info")}); }; - const auto onTestDone = [this](DoneWith result) { + const auto onTestDone = [this] { appendMessage(Tr::tr("Warning: \"slog2info\" is not found on the device, " "debug output not available."), ErrorMessageFormat); }; From 9549329b07eb332848f7cdab9fdbf32ad75e9ed6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 14:28:40 +0100 Subject: [PATCH 211/989] RemoteLinux: Inline RemoteLinuxDebugWorker Task-number: QTCREATORBUG-29168 Change-Id: Iad8304d96a850f52863fa848fe703d81ef6f1d72 Reviewed-by: hjk --- src/plugins/debugger/debuggerruncontrol.cpp | 5 +++ src/plugins/debugger/debuggerruncontrol.h | 6 ++- .../remotelinux/remotelinuxdebugsupport.cpp | 42 ++++++++----------- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index bb30d87460d..fcf291e24e2 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -743,6 +743,11 @@ void DebuggerRunTool::setUsePortsGatherer(bool useCpp, bool useQml) runControl()->requestQmlChannel(); } +void DebuggerRunTool::setupPortsGatherer() +{ + setUsePortsGatherer(isCppDebugging(), isQmlDebugging()); +} + void DebuggerRunTool::setSolibSearchPath(const Utils::FilePaths &list) { m_runParameters.solibSearchPath = list; diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index 4a2898fc3cd..460313f245c 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -81,6 +81,10 @@ public: Internal::DebuggerRunParameters &runParameters() { return m_runParameters; } + void setLldbPlatform(const QString &platform); + void addQmlServerInferiorCommandLineArgumentIfNeeded(); + void setupPortsGatherer(); + protected: bool isCppDebugging() const; bool isQmlDebugging() const; @@ -88,11 +92,9 @@ protected: void setUsePortsGatherer(bool useCpp, bool useQml); void addSolibSearchDir(const QString &str); - void addQmlServerInferiorCommandLineArgumentIfNeeded(); void modifyDebuggerEnvironment(const Utils::EnvironmentItems &item); void addSearchDirectory(const Utils::FilePath &dir); - void setLldbPlatform(const QString &platform); void setRemoteChannel(const QUrl &url); void setUseTargetAsync(bool on); void setSkipExecutableValidation(bool on); diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp index b9552f09953..3a92ec267b7 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp @@ -18,29 +18,6 @@ using namespace Utils; namespace RemoteLinux::Internal { -class RemoteLinuxDebugWorker final : public DebuggerRunTool -{ -public: - explicit RemoteLinuxDebugWorker(RunControl *runControl) - : DebuggerRunTool(runControl, DoNotAllowTerminal) - { - setId("RemoteLinuxDebugWorker"); - - setUsePortsGatherer(isCppDebugging(), isQmlDebugging()); - addQmlServerInferiorCommandLineArgumentIfNeeded(); - setUseDebugServer({}, true, true); - - setStartMode(AttachToRemoteServer); - setCloseMode(KillAndExitMonitorAtClose); - setUseExtendedRemote(true); - - if (runControl->device()->osType() == Utils::OsTypeMac) - setLldbPlatform("remote-macosx"); - else - setLldbPlatform("remote-linux"); - } -}; - class RemoteLinuxQmlToolingSupport final : public SimpleTargetRunner { public: @@ -93,7 +70,24 @@ class RemoteLinuxDebugWorkerFactory final : public ProjectExplorer::RunWorkerFac public: RemoteLinuxDebugWorkerFactory() { - setProduct(); + setProducer([](RunControl *rc) { + auto debugger = new DebuggerRunTool(rc, DebuggerRunTool::DoNotAllowTerminal); + debugger->setId("RemoteLinuxDebugWorker"); + + debugger->setupPortsGatherer(); + debugger->addQmlServerInferiorCommandLineArgumentIfNeeded(); + debugger->setUseDebugServer({}, true, true); + + debugger->setStartMode(AttachToRemoteServer); + debugger->setCloseMode(KillAndExitMonitorAtClose); + debugger->setUseExtendedRemote(true); + + if (rc->device()->osType() == Utils::OsTypeMac) + debugger->setLldbPlatform("remote-macosx"); + else + debugger->setLldbPlatform("remote-linux"); + return debugger; + }); addSupportedRunMode(ProjectExplorer::Constants::DEBUG_RUN_MODE); addSupportedDeviceType(Constants::GenericLinuxOsType); setSupportedRunConfigs(supportedRunConfigs()); From 78a9ba2a0f700af54f71c092f2e8d7db65a6f595 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 14 Nov 2024 10:32:35 +0100 Subject: [PATCH 212/989] Utils: Replace FileUtils class by a FileUtils namespace Change-Id: I33be0a11cef008d7cc6ed7472ffadf6c98b50797 Reviewed-by: Eike Ziller --- src/libs/utils/fileutils.cpp | 127 +++++++++++++++---------------- src/libs/utils/fileutils.h | 140 +++++++++++++++++------------------ 2 files changed, 135 insertions(+), 132 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index edd06b5658c..a713292c142 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -311,21 +311,23 @@ TempFileSaver::~TempFileSaver() } /*! - \class Utils::FileUtils + \namespace Utils::FileUtils \inmodule QtCreator - \brief The FileUtils class contains file and directory related convenience + \brief The FileUtils namespace contains file and directory related convenience functions. */ +namespace FileUtils { #ifdef QT_GUI_LIB -FileUtils::CopyAskingForOverwrite::CopyAskingForOverwrite(QWidget *dialogParent, const std::function &postOperation) +CopyAskingForOverwrite::CopyAskingForOverwrite(QWidget *dialogParent, + const std::function &postOperation) : m_parent(dialogParent) , m_postOperation(postOperation) {} -FileUtils::CopyHelper FileUtils::CopyAskingForOverwrite::operator()() +CopyHelper CopyAskingForOverwrite::operator()() { CopyHelper helperFunction = [this](const FilePath &src, const FilePath &dest, QString *error) { bool copyFile = true; @@ -373,13 +375,13 @@ FileUtils::CopyHelper FileUtils::CopyAskingForOverwrite::operator()() return helperFunction; } -FilePaths FileUtils::CopyAskingForOverwrite::files() const +FilePaths CopyAskingForOverwrite::files() const { return m_files; } #endif // QT_GUI_LIB -FilePath FileUtils::commonPath(const FilePaths &paths) +FilePath commonPath(const FilePaths &paths) { if (paths.isEmpty()) return {}; @@ -425,17 +427,6 @@ FilePath FileUtils::commonPath(const FilePaths &paths) return result; } -#ifdef Q_OS_WIN -template <> -void withNtfsPermissions(const std::function &task) -{ - qt_ntfs_permission_lookup++; - task(); - qt_ntfs_permission_lookup--; -} -#endif - - #ifdef QT_WIDGETS_LIB static QUrl filePathToQUrl(const FilePath &filePath) @@ -511,7 +502,7 @@ FilePath firstOrEmpty(const FilePaths &filePaths) return filePaths.isEmpty() ? FilePath() : filePaths.first(); } -bool FileUtils::hasNativeFileDialog() +bool hasNativeFileDialog() { static std::optional hasNative; if (!hasNative.has_value()) { @@ -524,14 +515,14 @@ bool FileUtils::hasNativeFileDialog() return *hasNative; } -FilePath FileUtils::getOpenFilePath(QWidget *parent, - const QString &caption, - const FilePath &dir, - const QString &filter, - QString *selectedFilter, - QFileDialog::Options options, - bool fromDeviceIfShiftIsPressed, - bool forceNonNativeDialog) +FilePath getOpenFilePath(QWidget *parent, + const QString &caption, + const FilePath &dir, + const QString &filter, + QString *selectedFilter, + QFileDialog::Options options, + bool fromDeviceIfShiftIsPressed, + bool forceNonNativeDialog) { forceNonNativeDialog = forceNonNativeDialog || dir.needsDevice(); #ifdef QT_GUI_LIB @@ -553,13 +544,13 @@ FilePath FileUtils::getOpenFilePath(QWidget *parent, QFileDialog::AcceptOpen)); } -FilePath FileUtils::getSaveFilePath(QWidget *parent, - const QString &caption, - const FilePath &dir, - const QString &filter, - QString *selectedFilter, - QFileDialog::Options options, - bool forceNonNativeDialog) +FilePath getSaveFilePath(QWidget *parent, + const QString &caption, + const FilePath &dir, + const QString &filter, + QString *selectedFilter, + QFileDialog::Options options, + bool forceNonNativeDialog) { forceNonNativeDialog = forceNonNativeDialog || dir.needsDevice(); @@ -576,12 +567,12 @@ FilePath FileUtils::getSaveFilePath(QWidget *parent, QFileDialog::AcceptSave)); } -FilePath FileUtils::getExistingDirectory(QWidget *parent, - const QString &caption, - const FilePath &dir, - QFileDialog::Options options, - bool fromDeviceIfShiftIsPressed, - bool forceNonNativeDialog) +FilePath getExistingDirectory(QWidget *parent, + const QString &caption, + const FilePath &dir, + QFileDialog::Options options, + bool fromDeviceIfShiftIsPressed, + bool forceNonNativeDialog) { forceNonNativeDialog = forceNonNativeDialog || dir.needsDevice(); @@ -604,12 +595,12 @@ FilePath FileUtils::getExistingDirectory(QWidget *parent, QFileDialog::AcceptOpen)); } -FilePaths FileUtils::getOpenFilePaths(QWidget *parent, - const QString &caption, - const FilePath &dir, - const QString &filter, - QString *selectedFilter, - QFileDialog::Options options) +FilePaths getOpenFilePaths(QWidget *parent, + const QString &caption, + const FilePath &dir, + const QString &filter, + QString *selectedFilter, + QFileDialog::Options options) { bool forceNonNativeDialog = dir.needsDevice(); @@ -704,7 +695,7 @@ FilePathInfo::FileFlags fileInfoFlagsfromStatMode(const QString &hexString, int return result; } -FilePathInfo FileUtils::filePathInfoFromTriple(const QString &infos, int modeBase) +FilePathInfo filePathInfoFromTriple(const QString &infos, int modeBase) { const QStringList parts = infos.split(' ', Qt::SkipEmptyParts); if (parts.size() != 3) @@ -717,10 +708,10 @@ FilePathInfo FileUtils::filePathInfoFromTriple(const QString &infos, int modeBas return {size, flags, dt}; } -bool FileUtils::copyRecursively(const FilePath &srcFilePath, - const FilePath &tgtFilePath, - QString *error, - CopyHelper copyHelper) +bool copyRecursively(const FilePath &srcFilePath, + const FilePath &tgtFilePath, + QString *error, + CopyHelper copyHelper) { if (srcFilePath.isDir()) { if (!tgtFilePath.ensureWritableDir()) { @@ -753,7 +744,7 @@ bool FileUtils::copyRecursively(const FilePath &srcFilePath, Returns whether the operation succeeded. */ -Result FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath) +Result copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath) { if (!srcFilePath.exists()) return Result::Error(Tr::tr("File %1 does not exist.").arg(srcFilePath.toUserOutput())); @@ -779,7 +770,7 @@ Result FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &t return srcFilePath.copyFile(tgtFilePath); } -QString FileUtils::fileSystemFriendlyName(const QString &name) +QString fileSystemFriendlyName(const QString &name) { QString result = name; static const QRegularExpression nonWordEx("\\W"); @@ -795,13 +786,13 @@ QString FileUtils::fileSystemFriendlyName(const QString &name) return result; } -int FileUtils::indexOfQmakeUnfriendly(const QString &name, int startpos) +int indexOfQmakeUnfriendly(const QString &name, int startpos) { static const QRegularExpression checkRegExp(QLatin1String("[^a-zA-Z0-9_.-]")); return checkRegExp.match(name, startpos).capturedStart(); } -QString FileUtils::qmakeFriendlyName(const QString &name) +QString qmakeFriendlyName(const QString &name) { QString result = name; @@ -814,14 +805,14 @@ QString FileUtils::qmakeFriendlyName(const QString &name) return fileSystemFriendlyName(result); } -bool FileUtils::makeWritable(const FilePath &path) +bool makeWritable(const FilePath &path) { return path.setPermissions(path.permissions() | QFile::WriteUser); } // makes sure that capitalization of directories is canonical on Windows and macOS. // This mimics the logic in QDeclarative_isFileCaseCorrect -QString FileUtils::normalizedPathName(const QString &name) +QString normalizedPathName(const QString &name) { #ifdef Q_OS_WIN const QString nativeSeparatorName(QDir::toNativeSeparators(name)); @@ -842,7 +833,7 @@ QString FileUtils::normalizedPathName(const QString &name) #endif } -FilePath FileUtils::commonPath(const FilePath &oldCommonPath, const FilePath &filePath) +FilePath commonPath(const FilePath &oldCommonPath, const FilePath &filePath) { FilePath newCommonPath = oldCommonPath; while (!newCommonPath.isEmpty() && !filePath.isChildOf(newCommonPath)) @@ -850,12 +841,12 @@ FilePath FileUtils::commonPath(const FilePath &oldCommonPath, const FilePath &fi return newCommonPath.canonicalPath(); } -FilePath FileUtils::homePath() +FilePath homePath() { return FilePath::fromUserInput(QDir::homePath()); } -expected_str FileUtils::scratchBufferFilePath(const QString &pattern) +expected_str scratchBufferFilePath(const QString &pattern) { QString tmp = pattern; QFileInfo fi(tmp); @@ -876,12 +867,12 @@ expected_str FileUtils::scratchBufferFilePath(const QString &pattern) return FilePath::fromString(file.fileName()); } -FilePaths FileUtils::toFilePathList(const QStringList &paths) +FilePaths toFilePathList(const QStringList &paths) { return transform(paths, &FilePath::fromString); } -qint64 FileUtils::bytesAvailableFromDFOutput(const QByteArray &dfOutput) +qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput) { const auto lines = filtered(dfOutput.split('\n'), [](const QByteArray &line) { return line.size() > 0; }); @@ -903,7 +894,7 @@ qint64 FileUtils::bytesAvailableFromDFOutput(const QByteArray &dfOutput) return -1; } -FilePaths FileUtils::usefulExtraSearchPaths() +FilePaths usefulExtraSearchPaths() { if (HostOsInfo::isMacHost()) { return {"/opt/homebrew/bin"}; @@ -917,4 +908,16 @@ FilePaths FileUtils::usefulExtraSearchPaths() return {}; } +} // namespace FileUtils + +#ifdef Q_OS_WIN +template <> +void withNtfsPermissions(const std::function &task) +{ + qt_ntfs_permission_lookup++; + task(); + qt_ntfs_permission_lookup--; +} +#endif + } // namespace Utils diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index d78dbb03ffa..a894d33a403 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -21,7 +21,6 @@ QT_BEGIN_NAMESPACE class QDataStream; class QTextStream; -class QWidget; class QXmlStreamWriter; // for withNtfsPermissions @@ -31,94 +30,95 @@ extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; QT_END_NAMESPACE namespace Utils { +namespace FileUtils { -class CommandLine; - -class QTCREATOR_UTILS_EXPORT FileUtils +using CopyHelper = std::function; +#ifdef QT_GUI_LIB +class QTCREATOR_UTILS_EXPORT CopyAskingForOverwrite { public: - using CopyHelper = std::function; -#ifdef QT_GUI_LIB - class QTCREATOR_UTILS_EXPORT CopyAskingForOverwrite - { - public: - CopyAskingForOverwrite(QWidget *dialogParent, - const std::function &postOperation = {}); - CopyHelper operator()(); - FilePaths files() const; + CopyAskingForOverwrite(QWidget *dialogParent, + const std::function &postOperation = {}); + CopyHelper operator()(); + FilePaths files() const; - private: - QWidget *m_parent; - FilePaths m_files; - std::function m_postOperation; - bool m_overwriteAll = false; - bool m_skipAll = false; - }; +private: + QWidget *m_parent; + FilePaths m_files; + std::function m_postOperation; + bool m_overwriteAll = false; + bool m_skipAll = false; +}; #endif // QT_GUI_LIB - static bool copyRecursively( - const FilePath &srcFilePath, - const FilePath &tgtFilePath, - QString *error, - CopyHelper helper); +QTCREATOR_UTILS_EXPORT bool copyRecursively( + const FilePath &srcFilePath, + const FilePath &tgtFilePath, + QString *error, + CopyHelper helper); - static Result copyIfDifferent(const FilePath &srcFilePath, - const FilePath &tgtFilePath); - static QString fileSystemFriendlyName(const QString &name); - static int indexOfQmakeUnfriendly(const QString &name, int startpos = 0); - static QString qmakeFriendlyName(const QString &name); - static bool makeWritable(const FilePath &path); - static QString normalizedPathName(const QString &name); +QTCREATOR_UTILS_EXPORT Result copyIfDifferent(const FilePath &srcFilePath, + const FilePath &tgtFilePath); +QTCREATOR_UTILS_EXPORT QString fileSystemFriendlyName(const QString &name); +QTCREATOR_UTILS_EXPORT int indexOfQmakeUnfriendly(const QString &name, int startpos = 0); +QTCREATOR_UTILS_EXPORT QString qmakeFriendlyName(const QString &name); +QTCREATOR_UTILS_EXPORT bool makeWritable(const FilePath &path); +QTCREATOR_UTILS_EXPORT QString normalizedPathName(const QString &name); - static FilePath commonPath(const FilePath &oldCommonPath, const FilePath &fileName); - static FilePath commonPath(const FilePaths &paths); - static FilePath homePath(); - static expected_str scratchBufferFilePath(const QString &pattern); +QTCREATOR_UTILS_EXPORT FilePath commonPath(const FilePath &oldCommonPath, const FilePath &fileName); +QTCREATOR_UTILS_EXPORT FilePath commonPath(const FilePaths &paths); +QTCREATOR_UTILS_EXPORT FilePath homePath(); +QTCREATOR_UTILS_EXPORT expected_str scratchBufferFilePath(const QString &pattern); - static FilePaths toFilePathList(const QStringList &paths); +QTCREATOR_UTILS_EXPORT FilePaths toFilePathList(const QStringList &paths); - static qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput); +QTCREATOR_UTILS_EXPORT qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput); - static FilePathInfo filePathInfoFromTriple(const QString &infos, int modeBase); +QTCREATOR_UTILS_EXPORT FilePathInfo filePathInfoFromTriple(const QString &infos, int modeBase); - //! Returns known paths like /opt/homebrew on macOS that might not be in PATH - static FilePaths usefulExtraSearchPaths(); +//! Returns known paths like /opt/homebrew on macOS that might not be in PATH +QTCREATOR_UTILS_EXPORT FilePaths usefulExtraSearchPaths(); #ifdef QT_WIDGETS_LIB - static bool hasNativeFileDialog(); +QTCREATOR_UTILS_EXPORT bool hasNativeFileDialog(); - static FilePath getOpenFilePath(QWidget *parent, - const QString &caption, - const FilePath &dir = {}, - const QString &filter = {}, - QString *selectedFilter = nullptr, - QFileDialog::Options options = {}, - bool fromDeviceIfShiftIsPressed = false, - bool forceNonNativeDialog = false); +QTCREATOR_UTILS_EXPORT FilePath getOpenFilePath( + QWidget *parent, + const QString &caption, + const FilePath &dir = {}, + const QString &filter = {}, + QString *selectedFilter = nullptr, + QFileDialog::Options options = {}, + bool fromDeviceIfShiftIsPressed = false, + bool forceNonNativeDialog = false); - static FilePath getSaveFilePath(QWidget *parent, - const QString &caption, - const FilePath &dir = {}, - const QString &filter = {}, - QString *selectedFilter = nullptr, - QFileDialog::Options options = {}, - bool forceNonNativeDialog = false); +QTCREATOR_UTILS_EXPORT FilePath getSaveFilePath( + QWidget *parent, + const QString &caption, + const FilePath &dir = {}, + const QString &filter = {}, + QString *selectedFilter = nullptr, + QFileDialog::Options options = {}, + bool forceNonNativeDialog = false); - static FilePath getExistingDirectory(QWidget *parent, - const QString &caption, - const FilePath &dir = {}, - QFileDialog::Options options = QFileDialog::ShowDirsOnly, - bool fromDeviceIfShiftIsPressed = false, - bool forceNonNativeDialog = false); +QTCREATOR_UTILS_EXPORT FilePath getExistingDirectory( + QWidget *parent, + const QString &caption, + const FilePath &dir = {}, + QFileDialog::Options options = QFileDialog::ShowDirsOnly, + bool fromDeviceIfShiftIsPressed = false, + bool forceNonNativeDialog = false); - static FilePaths getOpenFilePaths(QWidget *parent, - const QString &caption, - const FilePath &dir = {}, - const QString &filter = {}, - QString *selectedFilter = nullptr, - QFileDialog::Options options = {}); +QTCREATOR_UTILS_EXPORT FilePaths getOpenFilePaths( + QWidget *parent, + const QString &caption, + const FilePath &dir = {}, + const QString &filter = {}, + QString *selectedFilter = nullptr, + QFileDialog::Options options = {}); #endif -}; + +} // namespace FileUtils // for actually finding out if e.g. directories are writable on Windows #ifdef Q_OS_WIN From 431c501c2c1c9287154f1507323e8c120c53b903 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 15:20:45 +0100 Subject: [PATCH 213/989] PE: Promote protected methods to public in SimpleTargetRunner And in DebuggerRunTool. Task-number: QTCREATORBUG-29168 Change-Id: Iaf46cc940dec80db07edb7f159ed477c3e1ce009 Reviewed-by: hjk --- src/plugins/debugger/debuggerruncontrol.h | 1 - src/plugins/projectexplorer/runcontrol.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index 460313f245c..1e7c92b29b5 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -85,7 +85,6 @@ public: void addQmlServerInferiorCommandLineArgumentIfNeeded(); void setupPortsGatherer(); -protected: bool isCppDebugging() const; bool isQmlDebugging() const; diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 850117d6764..326660bb03a 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -287,7 +287,6 @@ public: explicit SimpleTargetRunner(RunControl *runControl); ~SimpleTargetRunner() override; -protected: void setStartModifier(const std::function &startModifier); Utils::CommandLine commandLine() const; From 1791db4e96ccb57842b888649965e7583b601fbe Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 14:06:02 +0100 Subject: [PATCH 214/989] Debugger: Inline RemoteAttachRunner Task-number: QTCREATORBUG-29168 Change-Id: Ie346d7f4d9d02fd7cbf80d3ec05ffad5fa268fe3 Reviewed-by: hjk --- src/plugins/debugger/debuggerplugin.cpp | 29 ++++++++----------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index f91c392f4c7..af452f8bf94 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1708,25 +1708,6 @@ void DebuggerPluginPrivate::startRemoteCdbSession() debugger->startRunControl(); } -class RemoteAttachRunner : public DebuggerRunTool -{ -public: - RemoteAttachRunner(RunControl *runControl, ProcessHandle pid) - : DebuggerRunTool(runControl) - { - setId("AttachToRunningProcess"); - setUsePortsGatherer(true, false); - setUseDebugServer(pid, false, false); - - setStartMode(AttachToRemoteProcess); - setCloseMode(DetachAtClose); - - // setInferiorExecutable(localExecutable); - setUseContinueInsteadOfRun(true); - setContinueAfterAttach(false); - } -}; - void DebuggerPluginPrivate::attachToRunningApplication() { auto kitChooser = new KitChooser; @@ -1755,7 +1736,15 @@ void DebuggerPluginPrivate::attachToRunningApplication() runControl->setKit(kit); //: %1: PID runControl->setDisplayName(Tr::tr("Process %1").arg(processInfo.processId)); - auto debugger = new RemoteAttachRunner(runControl, ProcessHandle(processInfo.processId)); + runControl->requestDebugChannel(); + + auto debugger = new DebuggerRunTool(runControl); + debugger->setId("AttachToRunningProcess"); + debugger->setUseDebugServer(ProcessHandle(processInfo.processId), false, false); + debugger->setStartMode(AttachToRemoteProcess); + debugger->setCloseMode(DetachAtClose); + debugger->setUseContinueInsteadOfRun(true); + debugger->setContinueAfterAttach(false); debugger->startRunControl(); } } From 7f8788a77ff1757a8991603aefa7b62f539ce9b4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 14:41:59 +0100 Subject: [PATCH 215/989] ProjectExplorer: Add IDevice::portsGatheringRecipe() It's going to replace portsGatheringMethod(). Using recipe is more general and it enables many process runs or using different task types, e.g. NetworkQueryTask. Change-Id: Ic330a41cf3b5268e0f763b1b7584dbe1d689671e Reviewed-by: Christian Kandeler --- src/plugins/android/androiddevice.cpp | 30 +++++++++++++++++++ src/plugins/android/androiddevice.h | 2 ++ .../projectexplorer/devicesupport/idevice.cpp | 21 +++++++++++-- .../projectexplorer/devicesupport/idevice.h | 3 ++ 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 363646f0006..0d5fb804c73 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include #include #include @@ -625,6 +627,34 @@ DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation()); } +ExecutableItem AndroidDevice::portsGatheringRecipe(const Storage &output) const +{ + const Storage serialNumberStorage; + const Storage input; + + const auto hasSerialNumber = [this, serialNumberStorage] { + if (machineType() == Hardware) + *serialNumberStorage = extraData(Constants::AndroidSerialNumber).toString(); + return machineType() == Hardware; + }; + + const auto onSerialNumberSetup = [this, input, serialNumberStorage] { + const CommandLine cmd{AndroidConfig::adbToolPath(), + {adbSelector(*serialNumberStorage), "shell" , "netstat", "-a", "-n" }}; + *input = {freePorts(), cmd}; + }; + + return Group { + serialNumberStorage, + input, + If (!Sync(hasSerialNumber)) >> Then { + serialNumberRecipe(avdName(), serialNumberStorage), + }, + Sync(onSerialNumberSetup), + portsFromProcessRecipe(input, output) + }; +} + PortsGatheringMethod AndroidDevice::portsGatheringMethod() const { return { diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index 3ae700e6347..eca0fb7d09b 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -58,6 +58,8 @@ private: ProjectExplorer::IDeviceWidget *createWidget() override; ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; QUrl toolControlChannel(const ControlChannelHint &) const override; + Tasking::ExecutableItem portsGatheringRecipe( + const Tasking::Storage &output) const override; ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override; QSettings *avdSettings() const; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 94baa513daf..0ac286d7dbf 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -83,6 +83,7 @@ * Creates an identical copy of a device object. */ +using namespace Tasking; using namespace Utils; namespace ProjectExplorer { @@ -439,6 +440,24 @@ const QList IDevice::deviceActions() const return d->deviceActions; } +ExecutableItem IDevice::portsGatheringRecipe(const Storage &output) const +{ + const Storage input; + + const auto onSetup = [this, input] { + const CommandLine cmd = filePath("/proc/net").isReadableDir() + ? CommandLine{filePath("/bin/sh"), {"-c", "cat /proc/net/tcp*"}} + : CommandLine{filePath("netstat"), {"-a", "-n"}}; + *input = {freePorts(), cmd}; + }; + + return Group { + input, + onGroupSetup(onSetup), + portsFromProcessRecipe(input, output) + }; +} + PortsGatheringMethod IDevice::portsGatheringMethod() const { return {[this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine { @@ -757,8 +776,6 @@ void DeviceProcessSignalOperation::setDebuggerCommand(const FilePath &cmd) DeviceProcessSignalOperation::DeviceProcessSignalOperation() = default; -using namespace Tasking; - void DeviceProcessKiller::start() { m_signalOperation.reset(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index fb1fd2b1196..d672b8222d3 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -140,6 +141,8 @@ public: void addDeviceAction(const DeviceAction &deviceAction); const QList deviceActions() const; + virtual Tasking::ExecutableItem portsGatheringRecipe( + const Tasking::Storage &output) const; virtual PortsGatheringMethod portsGatheringMethod() const; virtual bool canCreateProcessModel() const { return false; } virtual bool hasDeviceTester() const { return false; } From 2f66842206cefdbb7e215b45880a7f9e263f66b2 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 18 Nov 2024 15:37:37 +0100 Subject: [PATCH 216/989] QRCodeGen: Exclude unused library from build The QR Code Generator is only used by design studio so we can save some cycles during compile time by only activating it when building DesignStudio. Change-Id: I248c72e7c2e9ca536026d1647630b6dc9a5f80a0 Reviewed-by: Burak Hancerli Reviewed-by: Eike Ziller --- src/libs/3rdparty/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/3rdparty/CMakeLists.txt b/src/libs/3rdparty/CMakeLists.txt index 364c9a425eb..4a9ec9d4904 100644 --- a/src/libs/3rdparty/CMakeLists.txt +++ b/src/libs/3rdparty/CMakeLists.txt @@ -2,7 +2,6 @@ add_subdirectory(cplusplus) add_subdirectory(syntax-highlighting) add_subdirectory(libvterm) add_subdirectory(libptyqt) -add_subdirectory(qrcodegen) add_subdirectory(qtkeychain) add_subdirectory(lua) add_subdirectory(sol2) @@ -10,3 +9,7 @@ add_subdirectory(sol2) if(WIN32) add_subdirectory(winpty) endif() + +if (BUILD_DESIGNSTUDIO) + add_subdirectory(qrcodegen) +endif() From 62f563dcf9a83815ebd7b2e8339fc5c66f3fd7c5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 14:40:24 +0100 Subject: [PATCH 217/989] Qnx: Inline QnxAttachDebugSupport Task-number: QTCREATORBUG-29168 Change-Id: Ife073a09dfbcc165407e7c2f86829a08db5424f4 Reviewed-by: hjk --- src/plugins/qnx/qnxdebugsupport.cpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index aeffc7e5982..8f40390bf13 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -183,23 +183,6 @@ public: } }; -class QnxAttachDebugSupport : public Debugger::DebuggerRunTool -{ -public: - explicit QnxAttachDebugSupport(ProjectExplorer::RunControl *runControl) - : DebuggerRunTool(runControl) - { - setId("QnxAttachDebugSupport"); - setUsePortsGatherer(isCppDebugging(), isQmlDebugging()); - setUseCtrlCStub(true); - - if (isCppDebugging()) { - auto pdebugRunner = new PDebugRunner(runControl, this); - addStartDependency(pdebugRunner); - } - } -}; - void showAttachToProcessDialog() { auto kitChooser = new KitChooser; @@ -230,7 +213,15 @@ void showAttachToProcessDialog() auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); runControl->copyDataFromRunConfiguration(runConfig); - auto debugger = new QnxAttachDebugSupport(runControl); + auto debugger = new DebuggerRunTool(runControl); + debugger->setId("QnxAttachDebugSupport"); + debugger->setupPortsGatherer(); + debugger->setUseCtrlCStub(true); + if (debugger->isCppDebugging()) { + auto pdebugRunner = new PDebugRunner(runControl, debugger); + debugger->addStartDependency(pdebugRunner); + } + debugger->setStartMode(AttachToRemoteServer); debugger->setCloseMode(DetachAtClose); debugger->setSymbolFile(localExecutable); From 250ef7a04e9ad3aee8a56f8536d7834f4675bfd1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 14:45:28 +0100 Subject: [PATCH 218/989] Qnx: Inline PDebugRunner Task-number: QTCREATORBUG-29168 Change-Id: Idfd9ec47a1cc33642e752983055c013588e46f70 Reviewed-by: hjk --- src/plugins/qnx/qnxdebugsupport.cpp | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index 8f40390bf13..feb51ea51ab 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -165,24 +165,6 @@ private: PathChooser *m_localExecutable; }; - -// QnxAttachDebugSupport - -class PDebugRunner : public ProjectExplorer::SimpleTargetRunner -{ -public: - PDebugRunner(RunControl *runControl, DebuggerRunTool *debugger) - : SimpleTargetRunner(runControl) - { - setId("PDebugRunner"); - - setStartModifier([this, debugger] { - const int pdebugPort = debugger->debugChannel().port(); - setCommandLine({QNX_DEBUG_EXECUTABLE, {QString::number(pdebugPort)}}); - }); - } -}; - void showAttachToProcessDialog() { auto kitChooser = new KitChooser; @@ -218,7 +200,13 @@ void showAttachToProcessDialog() debugger->setupPortsGatherer(); debugger->setUseCtrlCStub(true); if (debugger->isCppDebugging()) { - auto pdebugRunner = new PDebugRunner(runControl, debugger); + auto pdebugRunner = new SimpleTargetRunner(runControl); + pdebugRunner->setId("PDebugRunner"); + pdebugRunner->setStartModifier([pdebugRunner, debugger] { + const int pdebugPort = debugger->debugChannel().port(); + pdebugRunner->setCommandLine({QNX_DEBUG_EXECUTABLE, {QString::number(pdebugPort)}}); + }); + debugger->addStartDependency(pdebugRunner); } From f733754ad6ca46d4bf185a59a8fdb396245336dd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 15:01:19 +0100 Subject: [PATCH 219/989] Qnx: Inline QnxDebuggeeRunner Task-number: QTCREATORBUG-29168 Change-Id: Ica7f34ed72a43995a5940eecb51446cb6156500a Reviewed-by: hjk --- src/plugins/qnx/qnxdebugsupport.cpp | 47 +++++++++++------------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index feb51ea51ab..d9cda7b27dd 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -70,34 +70,6 @@ static QStringList searchPaths(Kit *kit) return searchPaths; } -// QnxDebuggeeRunner - -class QnxDebuggeeRunner : public ProjectExplorer::SimpleTargetRunner -{ -public: - explicit QnxDebuggeeRunner(RunControl *runControl) - : SimpleTargetRunner(runControl) - { - setId("QnxDebuggeeRunner"); - - setStartModifier([this] { - CommandLine cmd = commandLine(); - QStringList arguments; - if (usesDebugChannel()) { - int pdebugPort = debugChannel().port(); - cmd.setExecutable(device()->filePath(QNX_DEBUG_EXECUTABLE)); - arguments.append(QString::number(pdebugPort)); - } - if (usesQmlChannel()) { - arguments.append(qmlDebugTcpArguments(QmlDebuggerServices, qmlChannel())); - } - cmd.setArguments(ProcessArgs::joinArgs(arguments)); - setCommandLine(cmd); - }); - } -}; - - // QnxDebugSupport class QnxDebugSupport : public Debugger::DebuggerRunTool @@ -111,7 +83,24 @@ public: setUsePortsGatherer(isCppDebugging(), isQmlDebugging()); - auto debuggeeRunner = new QnxDebuggeeRunner(runControl); + auto debuggeeRunner = new SimpleTargetRunner(runControl); + debuggeeRunner->setId("QnxDebuggeeRunner"); + + debuggeeRunner->setStartModifier([debuggeeRunner] { + CommandLine cmd = debuggeeRunner->commandLine(); + QStringList arguments; + if (debuggeeRunner->usesDebugChannel()) { + const int pdebugPort = debuggeeRunner->debugChannel().port(); + cmd.setExecutable(debuggeeRunner->device()->filePath(QNX_DEBUG_EXECUTABLE)); + arguments.append(QString::number(pdebugPort)); + } + if (debuggeeRunner->usesQmlChannel()) { + arguments.append(qmlDebugTcpArguments(QmlDebuggerServices, debuggeeRunner->qmlChannel())); + } + cmd.setArguments(ProcessArgs::joinArgs(arguments)); + debuggeeRunner->setCommandLine(cmd); + }); + auto slog2InfoRunner = new Slog2InfoRunner(runControl); debuggeeRunner->addStartDependency(slog2InfoRunner); From 042e670c3c884517dd7b07920a85c9c5996add80 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 15:07:07 +0100 Subject: [PATCH 220/989] Qnx: Inline QnxDebugSupport Task-number: QTCREATORBUG-29168 Change-Id: I571f57d82df81ff019ecb458b38e2a5df8f5d244 Reviewed-by: hjk --- src/plugins/qnx/qnxdebugsupport.cpp | 97 +++++++++++++---------------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index d9cda7b27dd..e949b5b9f38 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -70,57 +70,6 @@ static QStringList searchPaths(Kit *kit) return searchPaths; } -// QnxDebugSupport - -class QnxDebugSupport : public Debugger::DebuggerRunTool -{ -public: - explicit QnxDebugSupport(ProjectExplorer::RunControl *runControl) - : DebuggerRunTool(runControl) - { - setId("QnxDebugSupport"); - appendMessage(Tr::tr("Preparing remote side..."), LogMessageFormat); - - setUsePortsGatherer(isCppDebugging(), isQmlDebugging()); - - auto debuggeeRunner = new SimpleTargetRunner(runControl); - debuggeeRunner->setId("QnxDebuggeeRunner"); - - debuggeeRunner->setStartModifier([debuggeeRunner] { - CommandLine cmd = debuggeeRunner->commandLine(); - QStringList arguments; - if (debuggeeRunner->usesDebugChannel()) { - const int pdebugPort = debuggeeRunner->debugChannel().port(); - cmd.setExecutable(debuggeeRunner->device()->filePath(QNX_DEBUG_EXECUTABLE)); - arguments.append(QString::number(pdebugPort)); - } - if (debuggeeRunner->usesQmlChannel()) { - arguments.append(qmlDebugTcpArguments(QmlDebuggerServices, debuggeeRunner->qmlChannel())); - } - cmd.setArguments(ProcessArgs::joinArgs(arguments)); - debuggeeRunner->setCommandLine(cmd); - }); - - - auto slog2InfoRunner = new Slog2InfoRunner(runControl); - debuggeeRunner->addStartDependency(slog2InfoRunner); - - addStartDependency(debuggeeRunner); - - Kit *k = runControl->kit(); - - setStartMode(AttachToRemoteServer); - setCloseMode(KillAtClose); - setUseCtrlCStub(true); - setSolibSearchPath(FileUtils::toFilePathList(searchPaths(k))); - if (auto qtVersion = dynamic_cast(QtSupport::QtKitAspect::qtVersion(k))) { - setSysRoot(qtVersion->qnxTarget()); - modifyDebuggerEnvironment(qtVersion->environment()); - } - } -}; - - // QnxAttachDebugDialog class QnxAttachDebugDialog : public DeviceProcessesDialog @@ -220,7 +169,51 @@ class QnxDebugWorkerFactory final : public RunWorkerFactory public: QnxDebugWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto debugger = new DebuggerRunTool(runControl); + + debugger->setId("QnxDebugSupport"); + debugger->appendMessage(Tr::tr("Preparing remote side..."), LogMessageFormat); + + debugger->setupPortsGatherer(); + + auto debuggeeRunner = new SimpleTargetRunner(runControl); + debuggeeRunner->setId("QnxDebuggeeRunner"); + + debuggeeRunner->setStartModifier([debuggeeRunner] { + CommandLine cmd = debuggeeRunner->commandLine(); + QStringList arguments; + if (debuggeeRunner->usesDebugChannel()) { + const int pdebugPort = debuggeeRunner->debugChannel().port(); + cmd.setExecutable(debuggeeRunner->device()->filePath(QNX_DEBUG_EXECUTABLE)); + arguments.append(QString::number(pdebugPort)); + } + if (debuggeeRunner->usesQmlChannel()) { + arguments.append(qmlDebugTcpArguments(QmlDebuggerServices, debuggeeRunner->qmlChannel())); + } + cmd.setArguments(ProcessArgs::joinArgs(arguments)); + debuggeeRunner->setCommandLine(cmd); + }); + + + auto slog2InfoRunner = new Slog2InfoRunner(runControl); + debuggeeRunner->addStartDependency(slog2InfoRunner); + + debugger->addStartDependency(debuggeeRunner); + + Kit *k = runControl->kit(); + + debugger->setStartMode(AttachToRemoteServer); + debugger->setCloseMode(KillAtClose); + debugger->setUseCtrlCStub(true); + debugger->setSolibSearchPath(FileUtils::toFilePathList(searchPaths(k))); + if (auto qtVersion = dynamic_cast(QtSupport::QtKitAspect::qtVersion(k))) { + debugger->setSysRoot(qtVersion->qnxTarget()); + debugger->modifyDebuggerEnvironment(qtVersion->environment()); + } + + return debugger; + }); addSupportedRunMode(ProjectExplorer::Constants::DEBUG_RUN_MODE); addSupportedRunConfig(Constants::QNX_RUNCONFIG_ID); } From de5485aba9a7e35e594abea1d9056521374e459b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 15:16:42 +0100 Subject: [PATCH 221/989] RemoteLinux: Reuse IDevice::portsGatheringRecipe() Instead of DeviceUsedPortsGatherer. Change-Id: I3b2250bdc1d5b6ed0455c643671a80bd0bb32c05 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/linuxdevicetester.cpp | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 36153409cde..b430efedb4d 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -5,9 +5,7 @@ #include "linuxdevice.h" #include "remotelinuxtr.h" -#include "utils/async.h" -#include #include #include @@ -161,28 +159,33 @@ GroupItem GenericLinuxDeviceTesterPrivate::unameTask() const GroupItem GenericLinuxDeviceTesterPrivate::gathererTask() const { - const auto onSetup = [this](DeviceUsedPortsGatherer &gatherer) { + const Storage portsStorage; + + const auto onSetup = [this] { emit q->progressMessage(Tr::tr("Checking if specified ports are available...")); - gatherer.setDevice(m_device); }; - const auto onDone = [this](const DeviceUsedPortsGatherer &gatherer, DoneWith result) { - if (result != DoneWith::Success) { - emit q->errorMessage(Tr::tr("Error gathering ports: %1").arg(gatherer.errorString()) + '\n' + const auto onDone = [this, portsStorage] { + const auto ports = *portsStorage; + if (!ports) { + emit q->errorMessage(Tr::tr("Error gathering ports: %1").arg(ports.error()) + '\n' + Tr::tr("Some tools will not work out of the box.\n")); - } else if (gatherer.usedPorts().isEmpty()) { + } else if (ports->isEmpty()) { emit q->progressMessage(Tr::tr("All specified ports are available.") + '\n'); } else { - const QString portList = transform(gatherer.usedPorts(), [](const Port &port) { + const QString portList = transform(*ports, [](const Port &port) { return QString::number(port.number()); }).join(", "); emit q->errorMessage(Tr::tr("The following specified ports are currently in use: %1") .arg(portList) + '\n'); } + return true; }; return Group { - finishAllAndSuccess, - DeviceUsedPortsGathererTask(onSetup, onDone) + portsStorage, + onGroupSetup(onSetup), + m_device->portsGatheringRecipe(portsStorage), + onGroupDone(onDone) }; } From 063fd3dcf8d46b5ecc0a0b1657f49a0f35ef825f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 19 Nov 2024 15:33:30 +0100 Subject: [PATCH 222/989] Android: Remove serverUrl arg from qmlServerReady() signal Amends e66ae4ac76c6caf995a29d9b98fe7323dec648a4 Change-Id: Ia670acc4d1aaccb2fb44712e973e6a4d7d2b6508 Reviewed-by: hjk --- src/libs/qmldebug/qmloutputparser.h | 2 +- src/plugins/android/androidrunner.cpp | 15 +-------------- src/plugins/android/androidrunner.h | 4 +--- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/libs/qmldebug/qmloutputparser.h b/src/libs/qmldebug/qmloutputparser.h index d875ea59183..486dc9002fc 100644 --- a/src/libs/qmldebug/qmloutputparser.h +++ b/src/libs/qmldebug/qmloutputparser.h @@ -20,7 +20,7 @@ public: void processOutput(const QString &output); signals: - void waitingForConnectionOnPort(Utils::Port port); + void waitingForConnectionOnPort(Utils::Port port); // TODO: Unused port arg. void connectionEstablishedMessage(); void connectingToSocketMessage(); void errorMessage(const QString &detailedError); diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 6b8150ec037..f8395f30c07 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -45,7 +45,7 @@ AndroidRunner::AndroidRunner(RunControl *runControl) Q_UNUSED(metaTypes) connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, - this, &AndroidRunner::qmlServerPortReady); + this, &AndroidRunner::qmlServerReady); } void AndroidRunner::start() @@ -116,19 +116,6 @@ void AndroidRunner::stop() emit canceled(); } -void AndroidRunner::qmlServerPortReady(Port port) -{ - // FIXME: Note that the passed is nonsense, as the port is on the - // device side. It only happens to work since we redirect - // host port n to target port n via adb. - QUrl serverUrl; - serverUrl.setHost(QHostAddress(QHostAddress::LocalHost).toString()); - serverUrl.setPort(port.number()); - serverUrl.setScheme(urlTcpScheme()); - qCDebug(androidRunnerLog) << "Qml Server port ready"<< serverUrl; - emit qmlServerReady(serverUrl); -} - void AndroidRunner::remoteStarted(const Port &debugServerPort, qint64 pid) { m_pid = ProcessHandle(pid); diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index bf77bc32848..c4833f44559 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -26,12 +26,10 @@ public: signals: void canceled(); - void qmlServerReady(const QUrl &serverUrl); + void qmlServerReady(); void avdDetected(); private: - void qmlServerPortReady(Utils::Port port); - void remoteStarted(const Utils::Port &debugServerPort, qint64 pid); void remoteFinished(const QString &errString); void remoteStdOut(const QString &output); From 97ac8ea219023d82fbc9bddf2633e9c170c9ed1a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 15:52:37 +0100 Subject: [PATCH 223/989] QmlPreview: Inline LocalQmlPreviewSupport Task-number: QTCREATORBUG-29168 Change-Id: I93f17e165a714018375b3ec43b633d1a397c34dc Reviewed-by: hjk --- .../qmlpreview/qmlpreviewruncontrol.cpp | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp index 9b5001a27c3..bef05103e36 100644 --- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp +++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp @@ -174,13 +174,12 @@ QmlPreviewRunWorkerFactory::QmlPreviewRunWorkerFactory(QmlPreviewPlugin *plugin, addSupportedRunMode(Constants::QML_PREVIEW_RUNNER); } -class LocalQmlPreviewSupport final : public SimpleTargetRunner +LocalQmlPreviewSupportFactory::LocalQmlPreviewSupportFactory() { -public: - LocalQmlPreviewSupport(RunControl *runControl) - : SimpleTargetRunner(runControl) - { - setId("LocalQmlPreviewSupport"); + setId(ProjectExplorer::Constants::QML_PREVIEW_RUN_FACTORY); + setProducer([](RunControl *runControl) { + auto worker = new SimpleTargetRunner(runControl); + worker->setId("LocalQmlPreviewSupport"); runControl->setQmlChannel(Utils::urlFromLocalSocket()); @@ -188,11 +187,11 @@ public: RunWorker *preview = runControl->createWorker(ProjectExplorer::Constants::QML_PREVIEW_RUNNER); - addStopDependency(preview); - addStartDependency(preview); + worker->addStopDependency(preview); + worker->addStartDependency(preview); - setStartModifier([this, runControl] { - CommandLine cmd = commandLine(); + worker->setStartModifier([worker, runControl] { + CommandLine cmd = worker->commandLine(); if (const auto aspect = runControl->aspectData()) { const auto qmlBuildSystem = qobject_cast( @@ -214,17 +213,11 @@ public: } cmd.addArg(qmlDebugLocalArguments(QmlPreviewServices, runControl->qmlChannel().path())); - setCommandLine(cmd); - - forceRunOnHost(); + worker->setCommandLine(cmd); + worker->forceRunOnHost(); }); - } -}; - -LocalQmlPreviewSupportFactory::LocalQmlPreviewSupportFactory() -{ - setId(ProjectExplorer::Constants::QML_PREVIEW_RUN_FACTORY); - setProduct(); + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE); addSupportedDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE); From fc35bab3af690621a9b43e6c167e3f791f31859c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 16:03:50 +0100 Subject: [PATCH 224/989] WebAssembly: Inline class EmrunRunWorker Task-number: QTCREATORBUG-29168 Change-Id: I2ee076c06cf62370ff2aeaffbc4bbd0318cbf617 Reviewed-by: hjk --- .../webassemblyrunconfiguration.cpp | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/plugins/webassembly/webassemblyrunconfiguration.cpp b/src/plugins/webassembly/webassemblyrunconfiguration.cpp index 62d96ae5f6d..def5b1c54c5 100644 --- a/src/plugins/webassembly/webassemblyrunconfiguration.cpp +++ b/src/plugins/webassembly/webassemblyrunconfiguration.cpp @@ -199,26 +199,6 @@ private: StringAspect effectiveEmrunCall{this}; }; -class EmrunRunWorker : public SimpleTargetRunner -{ -public: - EmrunRunWorker(RunControl *runControl) - : SimpleTargetRunner(runControl) - { - runControl->requestWorkerChannel(); - - setStartModifier([this, runControl] { - const QString browserId = - runControl->aspectData()->currentBrowser; - setCommandLine(emrunCommand(runControl->target(), - runControl->buildKey(), - browserId, - QString::number(runControl->workerChannel().port()))); - setEnvironment(runControl->buildEnvironment()); - }); - } -}; - // Factories class EmrunRunConfigurationFactory final : public ProjectExplorer::RunConfigurationFactory @@ -236,7 +216,20 @@ class EmrunRunWorkerFactory final : public ProjectExplorer::RunWorkerFactory public: EmrunRunWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new SimpleTargetRunner(runControl); + runControl->requestWorkerChannel(); + + worker->setStartModifier([worker, runControl] { + const QString browserId = + runControl->aspectData()->currentBrowser; + worker->setCommandLine(emrunCommand(runControl->target(), runControl->buildKey(), + browserId, QString::number(runControl->workerChannel().port()))); + worker->setEnvironment(runControl->buildEnvironment()); + }); + + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); addSupportedRunConfig(Constants::WEBASSEMBLY_RUNCONFIGURATION_EMRUN); } From 45a5ab85529efbb0c2db6d332fc3e1603e16319f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 16:07:35 +0100 Subject: [PATCH 225/989] Boot2Qt: Inline QdbDeviceRunSupport Task-number: QTCREATORBUG-29168 Change-Id: I4b2bcc5901fbe84ab3e39d3acfe14459f4f71c99 Reviewed-by: hjk --- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index af046c9b679..41db814387b 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -110,26 +110,6 @@ private: Process m_launcher; }; -// QdbDeviceRunSupport - -class QdbDeviceRunSupport : public SimpleTargetRunner -{ -public: - QdbDeviceRunSupport(RunControl *runControl) - : SimpleTargetRunner(runControl) - { - setStartModifier([this] { - const CommandLine remoteCommand = commandLine(); - const FilePath remoteExe = remoteCommand.executable(); - CommandLine cmd{remoteExe.withNewPath(Constants::AppcontrollerFilepath)}; - cmd.addArg(remoteExe.nativePath()); - cmd.addArgs(remoteCommand.arguments(), CommandLine::Raw); - setCommandLine(cmd); - }); - } -}; - - // QdbDeviceDebugSupport class QdbDeviceDebugSupport final : public Debugger::DebuggerRunTool @@ -230,7 +210,18 @@ class QdbRunWorkerFactory final : public RunWorkerFactory public: QdbRunWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new SimpleTargetRunner(runControl); + worker->setStartModifier([worker] { + const CommandLine remoteCommand = worker->commandLine(); + const FilePath remoteExe = remoteCommand.executable(); + CommandLine cmd{remoteExe.withNewPath(Constants::AppcontrollerFilepath)}; + cmd.addArg(remoteExe.nativePath()); + cmd.addArgs(remoteCommand.arguments(), CommandLine::Raw); + worker->setCommandLine(cmd); + }); + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); addSupportedRunConfig(Constants::QdbRunConfigurationId); addSupportedRunConfig(QmlProjectManager::Constants::QML_RUNCONFIG_ID); From c6ff6d8a8f23a8aa9fbcec6eda01c1799223cc4f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 18 Nov 2024 14:48:15 +0100 Subject: [PATCH 226/989] Boot2Qt: Dismantle QdbDevicePerfProfilerSupport Task-number: QTCREATORBUG-29168 Change-Id: I3a48576599df40af324db1796c3a754b6859e2b0 Reviewed-by: hjk --- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index 41db814387b..45a36158a74 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -184,25 +184,6 @@ QdbDeviceQmlToolingSupport::QdbDeviceQmlToolingSupport(RunControl *runControl) addStopDependency(worker); } -// QdbDevicePerfProfilerSupport - -class QdbDevicePerfProfilerSupport final : public RunWorker -{ -public: - explicit QdbDevicePerfProfilerSupport(RunControl *runControl); -}; - -QdbDevicePerfProfilerSupport::QdbDevicePerfProfilerSupport(RunControl *runControl) - : RunWorker(runControl) -{ - setId("QdbDevicePerfProfilerSupport"); - - runControl->requestPerfChannel(); - auto profilee = new QdbDeviceInferiorRunner(runControl, NoQmlDebugServices); - addStartDependency(profilee); - addStopDependency(profilee); -} - // Factories class QdbRunWorkerFactory final : public RunWorkerFactory @@ -261,7 +242,11 @@ class QdbPerfProfilerWorkerFactory final : public RunWorkerFactory public: QdbPerfProfilerWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + runControl->requestPerfChannel(); + auto worker = new QdbDeviceInferiorRunner(runControl, NoQmlDebugServices); + return worker; + }); addSupportedRunMode("PerfRecorder"); addSupportedDeviceType(Qdb::Constants::QdbLinuxOsType); addSupportedRunConfig(Constants::QdbRunConfigurationId); From 490a859ee90e79df3fde471d05a88df1b443fc40 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 16:14:54 +0100 Subject: [PATCH 227/989] AppMan: Inline AppManInferiorRunner Change-Id: I3e67d39de10f88b6b98fbf8ea0856bd0562de687 Reviewed-by: hjk --- .../appmanagerruncontrol.cpp | 131 +++++++++--------- 1 file changed, 62 insertions(+), 69 deletions(-) diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 812206c8243..ad920797856 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -92,79 +92,72 @@ public: } }; - -// AppManInferiorRunner - -class AppManInferiorRunner : public SimpleTargetRunner +static RunWorker *createInferiorRunner(RunControl *runControl, QmlDebugServicesPreset qmlServices) { -public: - AppManInferiorRunner(RunControl *runControl, QmlDebugServicesPreset qmlServices) - : SimpleTargetRunner(runControl) - { - setId(AppManager::Constants::DEBUG_LAUNCHER_ID); - setEssential(true); + auto worker = new SimpleTargetRunner(runControl); + worker->setId(AppManager::Constants::DEBUG_LAUNCHER_ID); + worker->setEssential(true); - if (usesPerfChannel()) { - suppressDefaultStdOutHandling(); - runControl->setProperty("PerfProcess", QVariant::fromValue(process())); + if (worker->usesPerfChannel()) { + worker->suppressDefaultStdOutHandling(); + runControl->setProperty("PerfProcess", QVariant::fromValue(worker->process())); + } + + worker->setStartModifier([worker, runControl, qmlServices] { + FilePath controller = runControl->aspectData()->filePath; + QString appId = runControl->aspectData()->value; + QString instanceId = runControl->aspectData()->value; + QString documentUrl = runControl->aspectData()->value; + bool restartIfRunning = runControl->aspectData()->value; + QStringList envVars; + if (auto envAspect = runControl->aspectData()) + envVars = envAspect->environment.toStringList(); + envVars.replaceInStrings(" ", "\\ "); + + CommandLine cmd{controller}; + if (!instanceId.isEmpty()) + cmd.addArgs({"--instance-id", instanceId}); + + cmd.addArg("debug-application"); + + if (worker->usesDebugChannel() || worker->usesQmlChannel()) { + QStringList debugArgs; + debugArgs.append(envVars.join(' ')); + if (worker->usesDebugChannel()) + debugArgs.append(QString("gdbserver :%1").arg(worker->debugChannel().port())); + if (worker->usesQmlChannel()) { + const QString qmlArgs = qmlDebugCommandLineArguments(qmlServices, + QString("port:%1").arg(worker->qmlChannel().port()), true); + debugArgs.append(QString("%program% %1 %arguments%") .arg(qmlArgs)); + } + cmd.addArg(debugArgs.join(' ')); + } + if (worker->usesPerfChannel()) { + const Store perfArgs = runControl->settingsData(PerfProfiler::Constants::PerfSettingsId); + const QString recordArgs = perfArgs[PerfProfiler::Constants::PerfRecordArgsId].toString(); + cmd.addArg(QString("perf record %1 -o - --").arg(recordArgs)); } - setStartModifier([this, runControl, qmlServices] { - FilePath controller = runControl->aspectData()->filePath; - QString appId = runControl->aspectData()->value; - QString instanceId = runControl->aspectData()->value; - QString documentUrl = runControl->aspectData()->value; - bool restartIfRunning = runControl->aspectData()->value; - QStringList envVars; - if (auto envAspect = runControl->aspectData()) - envVars = envAspect->environment.toStringList(); - envVars.replaceInStrings(" ", "\\ "); + cmd.addArg("-eio"); + if (restartIfRunning) + cmd.addArg("--restart"); + cmd.addArg(appId); - CommandLine cmd{controller}; - if (!instanceId.isEmpty()) - cmd.addArgs({"--instance-id", instanceId}); + if (!documentUrl.isEmpty()) + cmd.addArg(documentUrl); - cmd.addArg("debug-application"); - - if (usesDebugChannel() || usesQmlChannel()) { - QStringList debugArgs; - debugArgs.append(envVars.join(' ')); - if (usesDebugChannel()) - debugArgs.append(QString("gdbserver :%1").arg(debugChannel().port())); - if (usesQmlChannel()) { - const QString qmlArgs = qmlDebugCommandLineArguments(qmlServices, - QString("port:%1").arg(qmlChannel().port()), true); - debugArgs.append(QString("%program% %1 %arguments%") .arg(qmlArgs)); - } - cmd.addArg(debugArgs.join(' ')); - } - if (usesPerfChannel()) { - const Store perfArgs = runControl->settingsData(PerfProfiler::Constants::PerfSettingsId); - const QString recordArgs = perfArgs[PerfProfiler::Constants::PerfRecordArgsId].toString(); - cmd.addArg(QString("perf record %1 -o - --").arg(recordArgs)); - } - - cmd.addArg("-eio"); - if (restartIfRunning) - cmd.addArg("--restart"); - cmd.addArg(appId); - - if (!documentUrl.isEmpty()) - cmd.addArg(documentUrl); - - // Always use the default environment to start the appman-controller in - // The env variables from the EnvironmentAspect are set through the controller - setEnvironment({}); - // Prevent the write channel to be closed, otherwise the appman-controller will exit - setProcessMode(ProcessMode::Writer); - setCommandLine(cmd); - - appendMessage(Tr::tr("Starting Application Manager debugging..."), NormalMessageFormat); - appendMessage(Tr::tr("Using: %1.").arg(cmd.toUserOutput()), NormalMessageFormat); - }); - } -}; + // Always use the default environment to start the appman-controller in + // The env variables from the EnvironmentAspect are set through the controller + worker->setEnvironment({}); + // Prevent the write channel to be closed, otherwise the appman-controller will exit + worker->setProcessMode(ProcessMode::Writer); + worker->setCommandLine(cmd); + worker->appendMessage(Tr::tr("Starting Application Manager debugging..."), NormalMessageFormat); + worker->appendMessage(Tr::tr("Using: %1.").arg(cmd.toUserOutput()), NormalMessageFormat); + }); + return worker; +} // AppManagerDebugSupport @@ -181,7 +174,7 @@ public: if (isQmlDebugging()) runControl->requestQmlChannel(); - auto debuggee = new AppManInferiorRunner(runControl, QmlDebuggerServices); + auto debuggee = createInferiorRunner(runControl, QmlDebuggerServices); addStartDependency(debuggee); addStopDependency(debuggee); @@ -260,7 +253,7 @@ public: runControl->requestQmlChannel(); QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); - auto runner = new AppManInferiorRunner(runControl, services); + auto runner = createInferiorRunner(runControl, services); addStartDependency(runner); addStopDependency(runner); @@ -284,7 +277,7 @@ public: setId("AppManagerPerfProfilerSupport"); runControl->requestPerfChannel(); - auto profilee = new AppManInferiorRunner(runControl, NoQmlDebugServices); + auto profilee = createInferiorRunner(runControl, NoQmlDebugServices); addStartDependency(profilee); addStopDependency(profilee); } From 7da684f1f1e63cf0eb268d9721c78a16ea9da0b1 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 20 Nov 2024 16:49:34 +0100 Subject: [PATCH 228/989] Coco: Tiny code simplification Change-Id: I56a4b1b0789f24108b203ca90c3e764678f30d46 Reviewed-by: Jarek Kobus --- src/plugins/coco/cocoplugin.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index 6a1ceff67eb..c157033ef21 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -108,15 +108,13 @@ public: void addEntryToProjectSettings(); private: - static void addBuildStep(ProjectExplorer::Target *target); - QMakeStepFactory m_qmakeStepFactory; CMakeStepFactory m_cmakeStepFactory; CocoLanguageClient *m_client = nullptr; }; -void CocoPlugin::addBuildStep(Target *target) +static void addBuildStep(Target *target) { for (BuildConfiguration *config : target->buildConfigurations()) { if (BuildSettings::supportsBuildConfig(*config)) { From 73c5d4e5e5fc14a832f98fd690741a17cadbcc25 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 20 Nov 2024 16:36:27 +0100 Subject: [PATCH 229/989] Coco: Use the simpler IPlugin::initializer overload Change-Id: I97103dd65f81bb40bd47a55f7c827c8e98e3f19a Reviewed-by: Jarek Kobus --- src/plugins/coco/cocoplugin.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index c157033ef21..0f453d3372c 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -104,7 +104,7 @@ public: } } - bool initialize(const QStringList &arguments, QString *errorString); + void initialize() final; void addEntryToProjectSettings(); private: @@ -128,11 +128,8 @@ static void addBuildStep(Target *target) } } -bool CocoPlugin::initialize(const QStringList &arguments, QString *errorString) +void CocoPlugin::initialize() { - Q_UNUSED(arguments) - Q_UNUSED(errorString) - IOptionsPage::registerCategory( "I.Coco", QCoreApplication::translate("Coco", "Coco"), @@ -152,8 +149,6 @@ bool CocoPlugin::initialize(const QStringList &arguments, QString *errorString) }); initLanguageServer(); - - return true; } void CocoPlugin::addEntryToProjectSettings() From cb23332ae5024358922a28bd1d06eafe4b84a363 Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Wed, 6 Nov 2024 16:48:11 +0100 Subject: [PATCH 230/989] Debugger: pmr containers Added support for visualization of for `std::pmr` containers (and more broadly containers with custom non-empty allocators). The gotcha with pmr allocators in particular is that unlike most allocators these are non-empty classes: they contain a pointer to a memory resource. Tested locally with CDB and GDB (MinGW). Task number: QTCREATORBUG-30224 Change-Id: If0ceb8a46905151a98f27d3e3ff11386406a9737 Reviewed-by: hjk Reviewed-by: David Schulz --- share/qtcreator/debugger/libcpp_stdtypes.py | 23 +- share/qtcreator/debugger/stdtypes.py | 98 ++++-- src/plugins/debugger/simplifytype.cpp | 344 +++++++++++--------- tests/auto/debugger/tst_dumpers.cpp | 92 +++++- 4 files changed, 385 insertions(+), 172 deletions(-) diff --git a/share/qtcreator/debugger/libcpp_stdtypes.py b/share/qtcreator/debugger/libcpp_stdtypes.py index 6c3e051261d..899a5be663d 100644 --- a/share/qtcreator/debugger/libcpp_stdtypes.py +++ b/share/qtcreator/debugger/libcpp_stdtypes.py @@ -53,7 +53,28 @@ def qdump__std____1__list(d, value): def qdump__std____1__set(d, value): - (proxy, head, size) = value.split("ppp") + # Looking up the allocator template type is potentially an expensive operation. + # A better alternative would be finding out the allocator type through accessing a class member. + # However due to different implementations doing things very differently + # it is deemed acceptable. + # Specifically: + # * GCC's `_Rb_tree_impl` basically inherits from the allocator, the comparator + # and the sentinel node + # * Clang packs the allocator and the sentinel node into a compressed pair, + # so depending on whether the allocator is sized or not, + # there may or may not be a member to access + # * MSVC goes even one step further and stores the allocator and the sentinel node together + # in a compressed pair, which in turn is stored together with the comparator inside + # another compressed pair + alloc_type = value.type[2] + alloc_size = alloc_type.size() + # size of empty allocators (which are the majority) is reported as 1 + # in theory there can be allocators whose size is truly 1 byte, + # in which case this will cause issues, but in practice they should be rather rare + if alloc_size > 1: + (proxy, head, alloc, size) = value.split(f'pp{{{alloc_type.name}}}p') + else: + (proxy, head, size) = value.split("ppp") d.check(0 <= size and size <= 100 * 1000 * 1000) d.putItemCount(size) diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index f7acc264ac2..6f913fb1be2 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -1,6 +1,25 @@ # Copyright (C) 2016 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +# Disclaimers: +# 1. Looking up the allocator template type is potentially an expensive operation. +# A better alternative would be finding out the allocator type +# through accessing a class member. +# However due to different implementations doing things very differently +# it is deemed acceptable. +# Specifically: +# * GCC's `_Rb_tree_impl` basically inherits from the allocator, the comparator +# and the sentinel node +# * Clang packs the allocator and the sentinel node into a compressed pair, +# so depending on whether the allocator is sized or not, +# there may or may not be a member to access +# * MSVC goes even one step further and stores the allocator and the sentinel node together +# in a compressed pair, which in turn is stored together with the comparator inside +# another compressed pair +# 2. `size` on an empty type, which the majority of the allocators are of, +# for whatever reason reports 1. In theory there can be allocators whose type is truly 1 byte, +# in which case we will have issues, but in practice they should be rather rare. + from utils import DisplayFormat from dumper import Children, SubItem, DumperBase @@ -94,7 +113,13 @@ def qdumpHelper__std__deque__libstdcxx(d, value): pcur = pfirst def qdumpHelper__std__deque__libcxx(d, value): - mptr, mfirst, mbegin, mend, start, size = value.split("pppptt") + alloc_type = value.type[1] # see disclaimer #1 + alloc_size = alloc_type.size() + # see disclaimer #2 + if alloc_size > 1: + mptr, mfirst, mbegin, mend, alloc, start, size = value.split(f'pppp{{{alloc_type.name}}}tt') + else: + mptr, mfirst, mbegin, mend, start, size = value.split("pppptt") d.check(0 <= size and size <= 1000 * 1000 * 1000) d.putItemCount(size) if d.isExpanded(): @@ -160,7 +185,11 @@ def qdumpHelper__std__deque__msvc(d, value): else: bufsize = 1 - (proxy, map, mapsize, myoff, mysize) = value.split("ppppp") + alloc_size = value.type[1].size() # see disclaimer #1 + # see disclaimer #2 + offset = alloc_size if alloc_size > 1 else 0 + core = d.createValue(value.address() + offset, value.type) + (proxy, map, mapsize, myoff, mysize) = core.split("ppppp") d.check(0 <= mapsize and mapsize <= 1000 * 1000 * 1000) d.putItemCount(mysize) @@ -221,10 +250,14 @@ def qdump__std__list__QNX(d, value): d.isDebugBuild = True except Exception: d.isDebugBuild = False + + alloc_size = value.type[1].size() # see disclaimer #1 + # see disclaimer #2 + offset = alloc_size if alloc_size > 1 else 0 if d.isDebugBuild: - (proxy, head, size) = value.split("ppp") - else: - (head, size) = value.split("pp") + offset += d.ptrSize() # _Myval2.Myproxy + core = d.createValue(value.address() + offset, value.type) + (head, size) = core.split("pp") d.putItemCount(size, 1000) @@ -331,10 +364,13 @@ def qdump_std__map__helper(d, value): d.isDebugBuild = True except Exception: d.isDebugBuild = False + alloc_size = value.type[3].size() # see disclaimer #1 + # see disclaimer #2 + offset = alloc_size if alloc_size > 1 else 0 if d.isDebugBuild: - (proxy, head, size) = value.split("ppp") - else: - (head, size) = value.split("pp") + offset += d.ptrSize() # _Myval2.Myproxy + core = d.createValue(value.address() + offset, value.type) + (head, size) = core.split("pp") d.check(0 <= size and size <= 100 * 1000 * 1000) d.putItemCount(size) if d.isExpanded(): @@ -559,10 +595,14 @@ def qdump__std__set__QNX(d, value): d.isDebugBuild = True except Exception: d.isDebugBuild = False + + alloc_size = value.type[2].size() # see disclaimer #1 + # see disclaimer #2 + offset = alloc_size if alloc_size > 1 else 0 if d.isDebugBuild: - (proxy, head, size) = value.split("ppp") - else: - (head, size) = value.split("pp") + offset += d.ptrSize() # _Myval2.Myproxy + core = d.createValue(value.address() + offset, value.type) + (head, size) = core.split("pp") d.check(0 <= size and size <= 100 * 1000 * 1000) d.putItemCount(size) if d.isExpanded(): @@ -840,10 +880,14 @@ def qdump__std__unordered_map(d, value): d.isDebugBuild = True except Exception: d.isDebugBuild = False + + alloc_size = value.type[4].size() # see disclaimer #1 + # see disclaimer #2 + offset = alloc_size if alloc_size > 1 else 0 if d.isDebugBuild: - (_, start, size) = _list.split("ppp") - else: - (start, size) = _list.split("pp") + offset += d.ptrSize() # _Myval2.Myproxy + core = d.createValue(_list.address() + offset, _list.type) + (start, size) = core.split("pp") else: try: # gcc ~= 4.7 @@ -1083,12 +1127,16 @@ def qdumpHelper__std__vector__msvc(d, value): d.isDebugBuild = True except RuntimeError: d.isDebugBuild = False + + alloc_size = value.type[1].size() # see disclaimer #1 + # see disclaimer #2 + offset = alloc_size if alloc_size > 1 else 0 if d.isDebugBuild: - proxy1, proxy2, start, finish, alloc, size = value.split("pppppi") - else: - start, finish, alloc, size = value.split("pppi") + offset += 2 * d.ptrSize() # _Myproxy and _MyVal2._Myproxy + core = d.createValue(value.address() + offset, value.type) + first, last, end, size = core.split("pppi") d.check(0 <= size and size <= 1000 * 1000 * 1000) - qdumpHelper__std__vector__bool(d, start, size, inner_type) + qdumpHelper__std__vector__bool(d, first, size, inner_type) else: if d.isDebugBuild is None: try: @@ -1096,13 +1144,17 @@ def qdumpHelper__std__vector__msvc(d, value): d.isDebugBuild = True except RuntimeError: d.isDebugBuild = False + + alloc_size = value.type[1].size() # see disclaimer #1 + # see disclaimer #2 + offset = alloc_size if alloc_size > 1 else 0 if d.isDebugBuild: - proxy, start, finish, alloc = value.split("pppp") - else: - start, finish, alloc = value.split("ppp") - size = (finish - start) // inner_type.size() + offset += d.ptrSize() # _MyVal2._Myproxy + core = d.createValue(value.address() + offset, value.type) + first, last, end = core.split(f'ppp') + size = (last - first) // inner_type.size() d.check(0 <= size and size <= 1000 * 1000 * 1000) - qdumpHelper__std__vector__nonbool(d, start, finish, alloc, inner_type) + qdumpHelper__std__vector__nonbool(d, first, last, end, inner_type) def qform__std____debug__vector(): diff --git a/src/plugins/debugger/simplifytype.cpp b/src/plugins/debugger/simplifytype.cpp index 56e79ea0433..3d59e5a0929 100644 --- a/src/plugins/debugger/simplifytype.cpp +++ b/src/plugins/debugger/simplifytype.cpp @@ -87,6 +87,199 @@ static inline QString fixNestedTemplates(QString s) return s; } +static void simplifyAllocator( + const QString &typeIn, + const QString &allocatorTemplateHead, + const QString &containerTypePrefix, + const bool isLibCpp, + QString &type) +{ + const int allocatorTemplateHeadLength = allocatorTemplateHead.length(); + int start = type.indexOf(allocatorTemplateHead); + if (start != -1) { + // search for matching '>' + int pos; + int level = 0; + for (pos = start + allocatorTemplateHeadLength - 1; pos < type.size(); ++pos) { + int c = type.at(pos).unicode(); + if (c == '<') { + ++level; + } else if (c == '>') { + --level; + if (level == 0) + break; + } + } + const QString alloc = fixNestedTemplates(type.mid(start, pos + 1 - start).trimmed()); + const QString inner = fixNestedTemplates( + alloc.mid(allocatorTemplateHeadLength, alloc.size() - allocatorTemplateHeadLength - 1) + .trimmed()); + + const QString allocEsc = QRegularExpression::escape(alloc); + const QString innerEsc = QRegularExpression::escape(inner); + if (inner == "char") { // std::string + simplifyStdString("char", "string", &type); + } else if (inner == "wchar_t") { // std::wstring + simplifyStdString("wchar_t", "wstring", &type); + } else if (inner == "unsigned short") { // std::wstring/MSVC + simplifyStdString("unsigned short", "wstring", &type); + } + // std::vector, std::deque, std::list + QRegularExpression re1(QString::fromLatin1("(vector|(forward_)?list|deque)<%1, ?%2\\s*>") + .arg(innerEsc, allocEsc)); + QTC_ASSERT(re1.isValid(), return); + QRegularExpressionMatch match = re1.match(type); + if (match.hasMatch()) + type.replace( + match.captured(), + QString::fromLatin1("%1%2<%3>").arg(containerTypePrefix, match.captured(1), inner)); + + // std::stack + QRegularExpression stackRE( + QString::fromLatin1("stack<%1, ?std::deque<%2> >").arg(innerEsc, innerEsc)); + QTC_ASSERT(stackRE.isValid(), return); + match = stackRE.match(type); + if (match.hasMatch()) + type.replace( + match.captured(), + QString::fromLatin1("%1stack<%2>").arg(containerTypePrefix, inner)); + + // std::hash + QRegularExpression hashCharRE( + QString::fromLatin1("hash, ?%1\\s*?>").arg(allocEsc)); + QTC_ASSERT(hashCharRE.isValid(), return); + match = hashCharRE.match(type); + if (match.hasMatch()) + type.replace(match.captured(), QString::fromLatin1("hash")); + + // std::set + QRegularExpression setRE(QString::fromLatin1("(multi)?set<%1, ?std::less<%2>, ?%3\\s*?>") + .arg(innerEsc, innerEsc, allocEsc)); + QTC_ASSERT(setRE.isValid(), return); + match = setRE.match(type); + if (match.hasMatch()) + type.replace( + match.captured(), + QString::fromLatin1("%1%2set<%3>") + .arg(containerTypePrefix, match.captured(1), inner)); + + // std::unordered_set + QRegularExpression unorderedSetRE( + QString::fromLatin1( + "unordered_(multi)?set<%1, ?std::hash<%2>, ?std::equal_to<%3>, ?%4\\s*?>") + .arg(innerEsc, innerEsc, innerEsc, allocEsc)); + QTC_ASSERT(unorderedSetRE.isValid(), return); + match = unorderedSetRE.match(type); + if (match.hasMatch()) + type.replace( + match.captured(), + QString::fromLatin1("%1unordered_%2set<%3>") + .arg(containerTypePrefix, match.captured(1), inner)); + + // boost::unordered_set + QRegularExpression boostUnorderedSetRE( + QString::fromLatin1("unordered_set<%1, ?boost::hash<%2>, ?std::equal_to<%3>, ?%4\\s*?>") + .arg(innerEsc, innerEsc, innerEsc, allocEsc)); + QTC_ASSERT(boostUnorderedSetRE.isValid(), return); + match = boostUnorderedSetRE.match(type); + if (match.hasMatch()) + type.replace(match.captured(), QString::fromLatin1("unordered_set<%1>").arg(inner)); + + // std::map + if (inner.startsWith("std::pair<")) { + // search for outermost ',', split key and value + int pos; + int level = 0; + for (pos = 10; pos < inner.size(); ++pos) { + int c = inner.at(pos).unicode(); + if (c == '<') + ++level; + else if (c == '>') + --level; + else if (c == ',' && level == 0) + break; + } + const QString key = chopConst(inner.mid(10, pos - 10)); + const QString keyEsc = QRegularExpression::escape(key); + // Get value: MSVC: 'pair', gcc: 'pair' + if (inner.at(++pos) == ' ') + pos++; + const QString value = inner.mid(pos, inner.size() - pos - 1).trimmed(); + const QString valueEsc = QRegularExpression::escape(value); + QRegularExpression mapRE1( + QString::fromLatin1("(multi)?map<%1, ?%2, ?std::less<%3 ?>, ?%4\\s*?>") + .arg(keyEsc, valueEsc, keyEsc, allocEsc)); + QTC_ASSERT(mapRE1.isValid(), return); + match = mapRE1.match(type); + if (match.hasMatch()) { + type.replace( + match.captured(), + QString::fromLatin1("%1%2map<%3, %4>") + .arg(containerTypePrefix, match.captured(1), key, value)); + } else { + QRegularExpression mapRE2( + QString::fromLatin1( + "(multi)?map, ?%4\\s*?>") + .arg(keyEsc, valueEsc, keyEsc, allocEsc)); + match = mapRE2.match(type); + if (match.hasMatch()) + type.replace( + match.captured(), + QString::fromLatin1("%1%2map") + .arg(containerTypePrefix, match.captured(1), key, value)); + } + } + + // std::unordered_map + if (inner.startsWith("std::pair<")) { + // search for outermost ',', split key and value + int pos; + int level = 0; + for (pos = 10; pos < inner.size(); ++pos) { + int c = inner.at(pos).unicode(); + if (c == '<') + ++level; + else if (c == '>') + --level; + else if (c == ',' && level == 0) + break; + } + const QString key = chopConst(inner.mid(10, pos - 10)); + const QString keyEsc = QRegularExpression::escape(key); + // Get value: MSVC: 'pair', gcc: 'pair' + if (inner.at(++pos) == ' ') + pos++; + const QString value = inner.mid(pos, inner.size() - pos - 1).trimmed(); + const QString valueEsc = QRegularExpression::escape(value); + QRegularExpression mapRE1( + QString::fromLatin1("unordered_(multi)?map<%1, ?%2, ?std::hash<%3 ?>, " + "?std::equal_to<%4 ?>, ?%5\\s*?>") + .arg(keyEsc, valueEsc, keyEsc, keyEsc, allocEsc)); + QTC_ASSERT(mapRE1.isValid(), return); + match = mapRE1.match(type); + if (match.hasMatch()) + type.replace( + match.captured(), + QString::fromLatin1("%1unordered_%2map<%3, %4>") + .arg(containerTypePrefix, match.captured(1), key, value)); + + if (isLibCpp) { + QRegularExpression mapRE2( + QString::fromLatin1("unordered_(multi)?map, ?std::equal_to, ?%2\\s*?>") + .arg(valueEsc, allocEsc)); + QTC_ASSERT(mapRE2.isValid(), return); + match = mapRE2.match(type); + if (match.hasMatch()) + type.replace( + match.captured(), + QString::fromLatin1("%1unordered_%2map") + .arg(containerTypePrefix, match.captured(1), value)); + } + } + } +} + QString simplifyType(const QString &typeIn) { QString type = typeIn; @@ -140,153 +333,10 @@ QString simplifyType(const QString &typeIn) type.replace(match.captured(), match.captured(1)); } - // Anything with a std::allocator - int start = type.indexOf("std::allocator<"); - if (start != -1) { - // search for matching '>' - int pos; - int level = 0; - for (pos = start + 12; pos < type.size(); ++pos) { - int c = type.at(pos).unicode(); - if (c == '<') { - ++level; - } else if (c == '>') { - --level; - if (level == 0) - break; - } - } - const QString alloc = fixNestedTemplates(type.mid(start, pos + 1 - start).trimmed()); - const QString inner = fixNestedTemplates(alloc.mid(15, alloc.size() - 16).trimmed()); - - const QString allocEsc = QRegularExpression::escape(alloc); - const QString innerEsc = QRegularExpression::escape(inner); - if (inner == "char") { // std::string - simplifyStdString("char", "string", &type); - } else if (inner == "wchar_t") { // std::wstring - simplifyStdString("wchar_t", "wstring", &type); - } else if (inner == "unsigned short") { // std::wstring/MSVC - simplifyStdString("unsigned short", "wstring", &type); - } - // std::vector, std::deque, std::list - QRegularExpression re1(QString::fromLatin1("(vector|list|deque)<%1, ?%2\\s*>").arg(innerEsc, allocEsc)); - QTC_ASSERT(re1.isValid(), return typeIn); - QRegularExpressionMatch match = re1.match(type); - if (match.hasMatch()) - type.replace(match.captured(), QString::fromLatin1("%1<%2>").arg(match.captured(1), inner)); - - // std::stack - QRegularExpression stackRE(QString::fromLatin1("stack<%1, ?std::deque<%2> >").arg(innerEsc, innerEsc)); - QTC_ASSERT(stackRE.isValid(), return typeIn); - match = stackRE.match(type); - if (match.hasMatch()) - type.replace(match.captured(), QString::fromLatin1("stack<%1>").arg(inner)); - - // std::hash - QRegularExpression hashCharRE(QString::fromLatin1("hash, ?%1\\s*?>").arg(allocEsc)); - QTC_ASSERT(hashCharRE.isValid(), return typeIn); - match = hashCharRE.match(type); - if (match.hasMatch()) - type.replace(match.captured(), QString::fromLatin1("hash")); - - // std::set - QRegularExpression setRE(QString::fromLatin1("set<%1, ?std::less<%2>, ?%3\\s*?>").arg(innerEsc, innerEsc, allocEsc)); - QTC_ASSERT(setRE.isValid(), return typeIn); - match = setRE.match(type); - if (match.hasMatch()) - type.replace(match.captured(), QString::fromLatin1("set<%1>").arg(inner)); - - // std::unordered_set - QRegularExpression unorderedSetRE(QString::fromLatin1("unordered_(multi)?set<%1, ?std::hash<%2>, ?std::equal_to<%3>, ?%4\\s*?>") - .arg(innerEsc, innerEsc, innerEsc, allocEsc)); - QTC_ASSERT(unorderedSetRE.isValid(), return typeIn); - match = unorderedSetRE.match(type); - if (match.hasMatch()) - type.replace(match.captured(), QString::fromLatin1("unordered_%1set<%2>").arg(match.captured(1), inner)); - - // boost::unordered_set - QRegularExpression boostUnorderedSetRE(QString::fromLatin1("unordered_set<%1, ?boost::hash<%2>, ?std::equal_to<%3>, ?%4\\s*?>") - .arg(innerEsc, innerEsc, innerEsc, allocEsc)); - QTC_ASSERT(boostUnorderedSetRE.isValid(), return typeIn); - match = boostUnorderedSetRE.match(type); - if (match.hasMatch()) - type.replace(match.captured(), QString::fromLatin1("unordered_set<%1>").arg(inner)); - - // std::map - if (inner.startsWith("std::pair<")) { - // search for outermost ',', split key and value - int pos; - int level = 0; - for (pos = 10; pos < inner.size(); ++pos) { - int c = inner.at(pos).unicode(); - if (c == '<') - ++level; - else if (c == '>') - --level; - else if (c == ',' && level == 0) - break; - } - const QString key = chopConst(inner.mid(10, pos - 10)); - const QString keyEsc = QRegularExpression::escape(key); - // Get value: MSVC: 'pair', gcc: 'pair' - if (inner.at(++pos) == ' ') - pos++; - const QString value = inner.mid(pos, inner.size() - pos - 1).trimmed(); - const QString valueEsc = QRegularExpression::escape(value); - QRegularExpression mapRE1(QString::fromLatin1("map<%1, ?%2, ?std::less<%3 ?>, ?%4\\s*?>") - .arg(keyEsc, valueEsc, keyEsc, allocEsc)); - QTC_ASSERT(mapRE1.isValid(), return typeIn); - match = mapRE1.match(type); - if (match.hasMatch()) { - type.replace(match.captured(), QString::fromLatin1("map<%1, %2>").arg(key, value)); - } else { - QRegularExpression mapRE2(QString::fromLatin1("map, ?%4\\s*?>") - .arg(keyEsc, valueEsc, keyEsc, allocEsc)); - match = mapRE2.match(type); - if (match.hasMatch()) - type.replace(match.captured(), QString::fromLatin1("map").arg(key, value)); - } - } - - // std::unordered_map - if (inner.startsWith("std::pair<")) { - // search for outermost ',', split key and value - int pos; - int level = 0; - for (pos = 10; pos < inner.size(); ++pos) { - int c = inner.at(pos).unicode(); - if (c == '<') - ++level; - else if (c == '>') - --level; - else if (c == ',' && level == 0) - break; - } - const QString key = chopConst(inner.mid(10, pos - 10)); - const QString keyEsc = QRegularExpression::escape(key); - // Get value: MSVC: 'pair', gcc: 'pair' - if (inner.at(++pos) == ' ') - pos++; - const QString value = inner.mid(pos, inner.size() - pos - 1).trimmed(); - const QString valueEsc = QRegularExpression::escape(value); - QRegularExpression mapRE1(QString::fromLatin1("unordered_(multi)?map<%1, ?%2, ?std::hash<%3 ?>, ?std::equal_to<%4 ?>, ?%5\\s*?>") - .arg(keyEsc, valueEsc, keyEsc, keyEsc, allocEsc)); - QTC_ASSERT(mapRE1.isValid(), return typeIn); - match = mapRE1.match(type); - if (match.hasMatch()) - type.replace(match.captured(), QString::fromLatin1("unordered_%1map<%2, %3>").arg(match.captured(1), key, value)); - - if (isLibCpp) { - QRegularExpression mapRE2(QString::fromLatin1("unordered_map, ?std::equal_to, ?%2\\s*?>") - .arg(valueEsc, allocEsc)); - QTC_ASSERT(mapRE2.isValid(), return typeIn); - match = mapRE2.match(type); - if (match.hasMatch()) - type.replace(match.captured(), QString::fromLatin1("unordered_map").arg(value)); - } - } - } // with std::allocator + // Fix e.g. `std::vector> -> std::vector` + simplifyAllocator(typeIn, "std::allocator<", "", isLibCpp, type); + // Fix e.g. `std::vector> -> std::pmr::vector` + simplifyAllocator(typeIn, "std::pmr::polymorphic_allocator<", "pmr::", isLibCpp, type); } type.replace('@', " *"); type.replace(" >", ">"); diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 45e91af5657..987a8c21ec7 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -4838,7 +4838,7 @@ void tst_Dumpers::dumper_data() "};\n\n" "std::deque deq;\n" - "for (int i = 0; i < 100; ++i)\n" + "for (uint16_t i = 0; i < 100; ++i)\n" " deq.push_back({i, i});\n", "&deq") @@ -8684,6 +8684,96 @@ void tst_Dumpers::dumper_data() + Check{"err_class", "Unexpected", "tl::expected"} + Check{"err_class.inner.m_x", "10", "int"}; // clang-format on + + // clang-format off + QTest::newRow("QTCREATORBUG-30224-StdLibPmrContainers") << Data{ + R"( + #include + #include + #include + #include + #include + #include + #include + #include + #include + )", + R"( + std::pmr::deque d; + std::pmr::forward_list fl; + std::pmr::list l; + std::pmr::set s; + std::pmr::multiset ms; + std::pmr::unordered_set us; + std::pmr::unordered_multiset ums; + std::pmr::map m; + std::pmr::multimap mm; + std::pmr::unordered_map um; + std::pmr::unordered_multimap umm; + std::pmr::vector v; + + constexpr auto count = 10; + for (auto i = 0; i < count; ++i) + { + if (i < count / 2) { + d.push_back(i); + } + else { + d.push_front(i); + } + + fl.push_front(i); + + l.push_back(i); + + s.insert(i); + ms.insert(i); + us.insert(i); + ums.insert(i); + + m.emplace(i, i); + mm.emplace(i, i); + um.emplace(i, i); + umm.emplace(i, i); + + v.push_back(i); + } + )", + "&d, &fl, &l, &s, &ms, &us, &ums, &m, &mm, &um, &umm, &v" + } + + Check{"d", "<10 items>", "std::pmr::deque"} % NoGdbEngine + + Check{"d", "<10 items>", "std::pmr::deque"} % GdbEngine + + Check{"d.1", "[1]", "8", "int"} + + Check{"fl", "<10 items>", "std::pmr::forward_list"} % NoGdbEngine + + Check{"fl", "<10 items>", "std::pmr::forward_list"} % GdbEngine + + Check{"fl.2", "[2]", "7", "int"} + + Check{"l", "<10 items>", "std::pmr::list"} % NoGdbEngine + + Check{"l", "<10 items>", "std::pmr::list"} % GdbEngine + + Check{"l.3", "[3]", "3", "int"} + + Check{"s", "<10 items>", "std::pmr::set"} % NoGdbEngine + + Check{"s", "<10 items>", "std::pmr::set"} % GdbEngine + + Check{"s.4", "[4]", "4", "int"} + + Check{"ms", "<10 items>", "std::pmr::multiset"} % NoGdbEngine + + Check{"ms", "<10 items>", "std::pmr::multiset"} % GdbEngine + + Check{"ms.4", "[4]", "4", "int"} + + Check{"us", "<10 items>", "std::pmr::unordered_set"} % NoGdbEngine + + Check{"us", "<10 items>", "std::pmr::unordered_set"} % GdbEngine + + Check{"ums", "<10 items>", "std::pmr::unordered_multiset"} % NoGdbEngine + + Check{"ums", "<10 items>", "std::pmr::unordered_multiset"} % GdbEngine + + Check{"m", "<10 items>", "std::pmr::map"} % NoGdbEngine + + Check{"m", "<10 items>", "std::pmr::map"} % GdbEngine + + Check{"m.5", "[5] 5", "5", ""} + + Check{"mm", "<10 items>", "std::pmr::multimap"} % NoGdbEngine + + Check{"mm", "<10 items>", "std::pmr::multimap"} % GdbEngine + + Check{"mm.5", "[5] 5", "5", ""} + + Check{"um", "<10 items>", "std::pmr::unordered_map"} % NoGdbEngine + + Check{"um", "<10 items>", "std::pmr::unordered_map"} % GdbEngine + + Check{"umm", "<10 items>", "std::pmr::unordered_multimap"} % NoGdbEngine + + Check{"umm", "<10 items>", "std::pmr::unordered_multimap"} % GdbEngine + + Check{"v", "<10 items>", "std::pmr::vector"} % NoGdbEngine + + Check{"v", "<10 items>", "std::pmr::vector"} % GdbEngine + + Check{"v.6", "[6]", "6", "int"}; + // clang-format on } int main(int argc, char *argv[]) From 7d858ff8aae97be4a39cfb9bca2cf123877991e4 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 20 Nov 2024 12:16:17 +0100 Subject: [PATCH 231/989] ProjectExplorer: Support changing the run environment ... in EnvironmentKitAspect. Fixes: QTCREATORBUG-31906 Change-Id: I11faf955ca6f7a7e01563cbf408bcfd9b2319e0a Reviewed-by: hjk --- src/libs/utils/environmentdialog.cpp | 8 +- src/libs/utils/environmentdialog.h | 10 +- src/plugins/mcusupport/mcukitmanager.cpp | 2 +- .../projectexplorer/environmentaspect.cpp | 8 +- .../projectexplorer/environmentkitaspect.cpp | 165 ++++++++++++------ .../projectexplorer/environmentkitaspect.h | 8 +- src/plugins/projectexplorer/extracompiler.cpp | 2 +- src/plugins/qnx/qnxsettingspage.cpp | 2 +- 8 files changed, 141 insertions(+), 64 deletions(-) diff --git a/src/libs/utils/environmentdialog.cpp b/src/libs/utils/environmentdialog.cpp index 82cc998e372..ee569fea9a4 100644 --- a/src/libs/utils/environmentdialog.cpp +++ b/src/libs/utils/environmentdialog.cpp @@ -8,14 +8,18 @@ namespace Utils { std::optional EnvironmentDialog::getEnvironmentItems( - QWidget *parent, const EnvironmentItems &initial, const QString &placeholderText, Polisher polisher) + QWidget *parent, + const EnvironmentItems &initial, + const QString &placeholderText, + Polisher polisher, + const QString &dialogTitle) { return getNameValueItems( parent, initial, placeholderText, polisher, - Tr::tr("Edit Environment")); + dialogTitle.isEmpty() ? Tr::tr("Edit Environment") : dialogTitle); } } // namespace Utils diff --git a/src/libs/utils/environmentdialog.h b/src/libs/utils/environmentdialog.h index 335ba7ffe58..69340e6a951 100644 --- a/src/libs/utils/environmentdialog.h +++ b/src/libs/utils/environmentdialog.h @@ -13,10 +13,12 @@ namespace Utils { class QTCREATOR_UTILS_EXPORT EnvironmentDialog : public NameValuesDialog { public: - static std::optional getEnvironmentItems(QWidget *parent = nullptr, - const EnvironmentItems &initial = {}, - const QString &placeholderText = {}, - Polisher polish = {}); + static std::optional getEnvironmentItems( + QWidget *parent = nullptr, + const EnvironmentItems &initial = {}, + const QString &placeholderText = {}, + Polisher polish = {}, + const QString &dialogTitle = {}); }; } // namespace Utils diff --git a/src/plugins/mcusupport/mcukitmanager.cpp b/src/plugins/mcusupport/mcukitmanager.cpp index 194c5efd840..a50f1d0135a 100644 --- a/src/plugins/mcusupport/mcukitmanager.cpp +++ b/src/plugins/mcusupport/mcukitmanager.cpp @@ -247,7 +247,7 @@ public: if (McuSupportOptions::kitsNeedQtVersion()) changes.append({QLatin1String("LD_LIBRARY_PATH"), "%{Qt:QT_INSTALL_LIBS}"}); - EnvironmentKitAspect::setEnvironmentChanges(k, changes); + EnvironmentKitAspect::setBuildEnvChanges(k, changes); } static void setKitCMakeOptions(Kit *k, diff --git a/src/plugins/projectexplorer/environmentaspect.cpp b/src/plugins/projectexplorer/environmentaspect.cpp index 43107b6141d..5b2295d8132 100644 --- a/src/plugins/projectexplorer/environmentaspect.cpp +++ b/src/plugins/projectexplorer/environmentaspect.cpp @@ -5,6 +5,7 @@ #include "buildconfiguration.h" #include "environmentaspectwidget.h" +#include "environmentkitaspect.h" #include "kit.h" #include "projectexplorer.h" #include "projectexplorersettings.h" @@ -30,8 +31,11 @@ EnvironmentAspect::EnvironmentAspect(AspectContainer *container) setId("EnvironmentAspect"); setConfigWidgetCreator([this] { return new EnvironmentAspectWidget(this); }); addDataExtractor(this, &EnvironmentAspect::environment, &Data::environment); - if (qobject_cast(container)) { - addModifier([](Environment &env) { env.modify(projectExplorerSettings().appEnvChanges); }); + if (const auto runConfig = qobject_cast(container)) { + addModifier([runConfig](Environment &env) { + env.modify(projectExplorerSettings().appEnvChanges); + env.modify(EnvironmentKitAspect::runEnvChanges(runConfig->kit())); + }); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, this, &EnvironmentAspect::environmentChanged); } diff --git a/src/plugins/projectexplorer/environmentkitaspect.cpp b/src/plugins/projectexplorer/environmentkitaspect.cpp index 19b56be9cc0..1d33e7e6b3b 100644 --- a/src/plugins/projectexplorer/environmentkitaspect.cpp +++ b/src/plugins/projectexplorer/environmentkitaspect.cpp @@ -10,7 +10,6 @@ #include "toolchain.h" #include -#include #include #include #include @@ -23,8 +22,8 @@ #include #include +#include #include -#include using namespace Utils; @@ -41,57 +40,76 @@ static bool enforcesMSVCEnglish(const EnvironmentItems &changes) return changes.contains(forceMSVCEnglishItem()); } +static Id buildEnvId() { return "PE.Profile.Environment"; } +static Id runEnvId() { return "PE.Profile.RunEnvironment"; } + namespace Internal { class EnvironmentKitAspectImpl final : public KitAspect { public: EnvironmentKitAspectImpl(Kit *workingCopy, const KitAspectFactory *factory) : KitAspect(workingCopy, factory), - m_summaryLabel(createSubWidget()), - m_manageButton(createSubWidget()), - m_mainWidget(createSubWidget()) + m_mainWidget(createSubWidget()), + m_buildEnvButton(createSubWidget()), + m_runEnvButton(createSubWidget()) { - auto *layout = new QVBoxLayout; - layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(m_summaryLabel); + addMutableAction(m_mainWidget); if (HostOsInfo::isWindowsHost()) - initMSVCOutputSwitch(layout); - m_mainWidget->setLayout(layout); + initMSVCOutputSwitch(); refresh(); - m_manageButton->setText(Tr::tr("Change...")); - connect(m_manageButton, &QAbstractButton::clicked, - this, &EnvironmentKitAspectImpl::editEnvironmentChanges); + m_buildEnvButton->setText(Tr::tr("Edit Build Environment...")); + m_buildEnvButton->setIcon({}); + m_runEnvButton->setText(Tr::tr("Edit Run Environment...")); + connect(m_buildEnvButton, &QAbstractButton::clicked, + this, &EnvironmentKitAspectImpl::editBuildEnvironmentChanges); + connect(m_runEnvButton, &QAbstractButton::clicked, + this, &EnvironmentKitAspectImpl::editRunEnvironmentChanges); } private: void addToInnerLayout(Layouting::Layout &layout) override { - addMutableAction(m_mainWidget); + Layouting::Layout box(new QHBoxLayout); + box.setContentsMargins(0, 0, 0, 0); + box.attachTo(m_mainWidget); + if (m_vslangCheckbox) + box.addItem(m_vslangCheckbox); + box.addItems({m_buildEnvButton, m_runEnvButton}); + box.addItem(Layouting::Stretch(1)); layout.addItem(m_mainWidget); - layout.addItem(m_manageButton); } - void makeReadOnly() override { m_manageButton->setEnabled(false); } + void makeReadOnly() override + { + if (m_vslangCheckbox) + m_vslangCheckbox->setEnabled(false); + m_buildEnvButton->setEnabled(false); + m_runEnvButton->setEnabled(false); + } void refresh() override { - const EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(kit()); - const QString shortSummary = EnvironmentItem::toStringList(changes).join("; "); - m_summaryLabel->setText(shortSummary.isEmpty() ? Tr::tr("No changes to apply.") : shortSummary); + const auto toString = [](const EnvironmentItems &changes) { + return EnvironmentItem::toStringList(changes).join("\n"); + }; + m_buildEnvButton->setToolTip(toString(EnvironmentKitAspect::buildEnvChanges(kit()))); + m_runEnvButton->setToolTip(toString(EnvironmentKitAspect::runEnvChanges(kit()))); + + // TODO: Set an icon on the button representing whether there are changes or not. } - void editEnvironmentChanges() + void editBuildEnvironmentChanges() { - MacroExpander *expander = kit()->macroExpander(); - EnvironmentDialog::Polisher polisher = [expander](QWidget *w) { - VariableChooser::addSupportForChildWidgets(w, expander); - }; auto changes = EnvironmentDialog::getEnvironmentItems( - m_summaryLabel, EnvironmentKitAspect::environmentChanges(kit()), QString(), polisher); + m_mainWidget, + EnvironmentKitAspect::buildEnvChanges(kit()), + QString(), + polisher(), + Tr::tr("Edit Build Environment")); if (!changes) return; - if (HostOsInfo::isWindowsHost()) { + if (m_vslangCheckbox) { // re-add what envWithoutMSVCEnglishEnforcement removed // or update vslang checkbox if user added it manually if (m_vslangCheckbox->isChecked() && !enforcesMSVCEnglish(*changes)) @@ -99,33 +117,51 @@ private: else if (enforcesMSVCEnglish(*changes)) m_vslangCheckbox->setChecked(true); } - EnvironmentKitAspect::setEnvironmentChanges(kit(), *changes); + EnvironmentKitAspect::setBuildEnvChanges(kit(), *changes); } - void initMSVCOutputSwitch(QVBoxLayout *layout) + void editRunEnvironmentChanges() { - m_vslangCheckbox = new QCheckBox(Tr::tr("Force UTF-8 MSVC compiler output")); - layout->addWidget(m_vslangCheckbox); + if (const auto changes = EnvironmentDialog::getEnvironmentItems( + m_mainWidget, + EnvironmentKitAspect::runEnvChanges(kit()), + QString(), + polisher(), + Tr::tr("Edit Run Environment"))) { + EnvironmentKitAspect::setRunEnvChanges(kit(), *changes); + } + } + + EnvironmentDialog::Polisher polisher() const + { + return [expander = kit()->macroExpander()](QWidget *w) { + VariableChooser::addSupportForChildWidgets(w, expander); + }; + } + + void initMSVCOutputSwitch() + { + m_vslangCheckbox = new QCheckBox(Tr::tr("Force UTF-8 MSVC output")); 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).")); m_vslangCheckbox->setChecked( - enforcesMSVCEnglish(EnvironmentKitAspect::environmentChanges(kit()))); + enforcesMSVCEnglish(EnvironmentKitAspect::buildEnvChanges(kit()))); connect(m_vslangCheckbox, &QCheckBox::clicked, this, [this](bool checked) { - EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(kit()); + EnvironmentItems changes = EnvironmentKitAspect::buildEnvChanges(kit()); const bool hasVsLangEntry = enforcesMSVCEnglish(changes); if (checked && !hasVsLangEntry) changes.append(forceMSVCEnglishItem()); else if (!checked && hasVsLangEntry) changes.removeAll(forceMSVCEnglishItem()); - EnvironmentKitAspect::setEnvironmentChanges(kit(), changes); + EnvironmentKitAspect::setBuildEnvChanges(kit(), changes); }); } - ElidingLabel *m_summaryLabel; - QPushButton *m_manageButton; - QCheckBox *m_vslangCheckbox; - QWidget *m_mainWidget; + QWidget * const m_mainWidget; + QPushButton * const m_buildEnvButton; + QPushButton * const m_runEnvButton; + QCheckBox *m_vslangCheckbox = nullptr; }; class EnvironmentKitAspectFactory : public KitAspectFactory @@ -157,7 +193,7 @@ Tasks EnvironmentKitAspectFactory::validate(const Kit *k) const Tasks result; QTC_ASSERT(k, return result); - const QVariant variant = k->value(EnvironmentKitAspect::id()); + const QVariant variant = k->value(buildEnvId()); if (!variant.isNull() && !variant.canConvert(QMetaType(QMetaType::QVariantList))) result << BuildSystemTask(Task::Error, Tr::tr("The environment setting value is invalid.")); @@ -168,24 +204,32 @@ void EnvironmentKitAspectFactory::fix(Kit *k) { QTC_ASSERT(k, return); - const QVariant variant = k->value(EnvironmentKitAspect::id()); - if (!variant.isNull() && !variant.canConvert(QMetaType(QMetaType::QVariantList))) { - qWarning("Kit \"%s\" has a wrong environment value set.", qPrintable(k->displayName())); - EnvironmentKitAspect::setEnvironmentChanges(k, EnvironmentItems()); + if (const QVariant variant = k->value(buildEnvId()); + !variant.isNull() && !variant.canConvert(QMetaType(QMetaType::QVariantList))) { + qWarning("Kit \"%s\" has a wrong build environment value set.", qPrintable(k->displayName())); + EnvironmentKitAspect::setBuildEnvChanges(k, EnvironmentItems()); + } + if (const QVariant variant = k->value(runEnvId()); + !variant.isNull() && !variant.canConvert(QMetaType(QMetaType::QVariantList))) { + qWarning("Kit \"%s\" has a wrong run environment value set.", qPrintable(k->displayName())); + EnvironmentKitAspect::setRunEnvChanges(k, EnvironmentItems()); } } void EnvironmentKitAspectFactory::addToBuildEnvironment(const Kit *k, Environment &env) const { const QStringList values - = transform(EnvironmentItem::toStringList(EnvironmentKitAspect::environmentChanges(k)), + = transform(EnvironmentItem::toStringList(EnvironmentKitAspect::buildEnvChanges(k)), [k](const QString &v) { return k->macroExpander()->expand(v); }); env.modify(EnvironmentItem::fromStringList(values)); } void EnvironmentKitAspectFactory::addToRunEnvironment(const Kit *k, Environment &env) const { - addToBuildEnvironment(k, env); + const QStringList values + = transform(EnvironmentItem::toStringList(EnvironmentKitAspect::runEnvChanges(k)), + [k](const QString &v) { return k->macroExpander()->expand(v); }); + env.modify(EnvironmentItem::fromStringList(values)); } KitAspect *EnvironmentKitAspectFactory::createKitAspect(Kit *k) const @@ -196,8 +240,14 @@ KitAspect *EnvironmentKitAspectFactory::createKitAspect(Kit *k) const KitAspectFactory::ItemList EnvironmentKitAspectFactory::toUserOutput(const Kit *k) const { - return {{Tr::tr("Environment"), - EnvironmentItem::toStringList(EnvironmentKitAspect::environmentChanges(k)).join("
    ")}}; + ItemList list; + const auto addIfNotEmpty = [&](const QString &displayName, const EnvironmentItems &changes) { + if (!changes.isEmpty()) + list.emplaceBack(displayName, EnvironmentItem::toStringList(changes).join("
    ")); + }; + addIfNotEmpty(Tr::tr("Build Environment"), EnvironmentKitAspect::buildEnvChanges(k)); + addIfNotEmpty(Tr::tr("Run Environment"), EnvironmentKitAspect::runEnvChanges(k)); + return list; } const EnvironmentKitAspectFactory theEnvironmentKitAspectFactory; @@ -206,20 +256,33 @@ const EnvironmentKitAspectFactory theEnvironmentKitAspectFactory; Id EnvironmentKitAspect::id() { - return "PE.Profile.Environment"; + return buildEnvId(); } -EnvironmentItems EnvironmentKitAspect::environmentChanges(const Kit *k) +EnvironmentItems EnvironmentKitAspect::buildEnvChanges(const Kit *k) { if (k) - return EnvironmentItem::fromStringList(k->value(EnvironmentKitAspect::id()).toStringList()); + return EnvironmentItem::fromStringList(k->value(buildEnvId()).toStringList()); return {}; } -void EnvironmentKitAspect::setEnvironmentChanges(Kit *k, const EnvironmentItems &changes) +void EnvironmentKitAspect::setBuildEnvChanges(Kit *k, const EnvironmentItems &changes) { if (k) - k->setValue(EnvironmentKitAspect::id(), EnvironmentItem::toStringList(changes)); + k->setValue(buildEnvId(), EnvironmentItem::toStringList(changes)); +} + +EnvironmentItems EnvironmentKitAspect::runEnvChanges(const Kit *k) +{ + if (k) + return EnvironmentItem::fromStringList(k->value(runEnvId()).toStringList()); + return {}; +} + +void EnvironmentKitAspect::setRunEnvChanges(Kit *k, const Utils::EnvironmentItems &changes) +{ + if (k) + k->setValue(runEnvId(), EnvironmentItem::toStringList(changes)); } } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/environmentkitaspect.h b/src/plugins/projectexplorer/environmentkitaspect.h index b7ebc155576..5985c08ac28 100644 --- a/src/plugins/projectexplorer/environmentkitaspect.h +++ b/src/plugins/projectexplorer/environmentkitaspect.h @@ -16,8 +16,12 @@ class PROJECTEXPLORER_EXPORT EnvironmentKitAspect { public: static Utils::Id id(); - static Utils::EnvironmentItems environmentChanges(const Kit *k); - static void setEnvironmentChanges(Kit *k, const Utils::EnvironmentItems &changes); + + static Utils::EnvironmentItems buildEnvChanges(const Kit *k); + static void setBuildEnvChanges(Kit *k, const Utils::EnvironmentItems &changes); + + static Utils::EnvironmentItems runEnvChanges(const Kit *k); + static void setRunEnvChanges(Kit *k, const Utils::EnvironmentItems &changes); }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index e72ce3772dd..c11e3c4bc64 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -277,7 +277,7 @@ Environment ExtraCompiler::buildEnvironment() const if (BuildConfiguration *bc = target->activeBuildConfiguration()) return bc->environment(); - const EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(target->kit()); + const EnvironmentItems changes = EnvironmentKitAspect::buildEnvChanges(target->kit()); Environment env = Environment::systemEnvironment(); env.modify(changes); return env; diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index a5db2b60423..bc1ee131ef9 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -283,7 +283,7 @@ void QnxConfiguration::createKit(const QnxTarget &target) k->setSticky(DebuggerKitAspect::id(), true); k->setSticky(QmakeProjectManager::Constants::KIT_INFORMATION_ID, true); - EnvironmentKitAspect::setEnvironmentChanges(k, qnxEnvironmentItems()); + EnvironmentKitAspect::setBuildEnvChanges(k, qnxEnvironmentItems()); }; // add kit with device and qt version not sticky From cf8d10877376b930e57a6a3b056446a4c9de99a6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 16:00:58 +0100 Subject: [PATCH 232/989] RunControl: Reuse portsGatheringRecipe() Change-Id: I20383f556b3488528758fdf886929afd3ee38a16 Reviewed-by: hjk Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/runcontrol.cpp | 67 +++++++++++----------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 6fef5669272..b89db25d147 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -8,7 +8,6 @@ #include "customparser.h" #include "devicesupport/devicekitaspects.h" #include "devicesupport/devicemanager.h" -#include "devicesupport/deviceusedportsgatherer.h" #include "devicesupport/idevice.h" #include "devicesupport/idevicefactory.h" #include "devicesupport/sshparameters.h" @@ -357,14 +356,14 @@ public: void startTaskTree(); void checkAutoDeleteAndEmitStopped(); - void enablePortsGatherer(); + bool isPortsGatherer() const + { return useDebugChannel || useQmlChannel || usePerfChannel || useWorkerChannel; } QUrl getNextChannel(PortList *portList, const QList &usedPorts); RunControl *q; Id runMode; TaskTreeRunner m_taskTreeRunner; - - std::unique_ptr portsGatherer; + TaskTreeRunner m_portsGathererRunner; }; } // Internal @@ -592,41 +591,43 @@ void RunControlPrivate::initiateReStart() void RunControlPrivate::startPortsGathererIfNeededAndContinueStart() { - if (!portsGatherer) { + if (!isPortsGatherer()) { continueStart(); return; } - connect(portsGatherer.get(), &DeviceUsedPortsGatherer::done, this, [this](bool success) { - if (success) { - PortList portList = device->freePorts(); - const QList usedPorts = portsGatherer->usedPorts(); - q->appendMessage(Tr::tr("Found %n free ports.", nullptr, portList.count()) + '\n', - NormalMessageFormat); - if (useDebugChannel) - debugChannel = getNextChannel(&portList, usedPorts); - if (useQmlChannel) - qmlChannel = getNextChannel(&portList, usedPorts); - if (usePerfChannel) - perfChannel = getNextChannel(&portList, usedPorts); - if (useWorkerChannel) - workerChannel = getNextChannel(&portList, usedPorts); + const Storage portsStorage; - continueStart(); - } else { - onWorkerFailed(nullptr, portsGatherer->errorString()); + const auto onDone = [this, portsStorage] { + const auto ports = *portsStorage; + if (!ports) { + onWorkerFailed(nullptr, ports.error()); + return; } - }); + PortList portList = device->freePorts(); + const QList usedPorts = *ports; + q->appendMessage(Tr::tr("Found %n free ports.", nullptr, portList.count()) + '\n', + NormalMessageFormat); + if (useDebugChannel) + debugChannel = getNextChannel(&portList, usedPorts); + if (useQmlChannel) + qmlChannel = getNextChannel(&portList, usedPorts); + if (usePerfChannel) + perfChannel = getNextChannel(&portList, usedPorts); + if (useWorkerChannel) + workerChannel = getNextChannel(&portList, usedPorts); + + continueStart(); + }; + + const Group recipe { + portsStorage, + device->portsGatheringRecipe(portsStorage), + onGroupDone(onDone) + }; q->appendMessage(Tr::tr("Checking available ports...") + '\n', NormalMessageFormat); - portsGatherer->setDevice(device); - portsGatherer->start(); -} - -void RunControlPrivate::enablePortsGatherer() -{ - if (!portsGatherer) - portsGatherer = std::make_unique(); + m_portsGathererRunner.start(recipe); } QUrl RunControlPrivate::getNextChannel(PortList *portList, const QList &usedPorts) @@ -643,7 +644,6 @@ QUrl RunControlPrivate::getNextChannel(PortList *portList, const QList &us void RunControl::requestDebugChannel() { - d->enablePortsGatherer(); d->useDebugChannel = true; } @@ -659,7 +659,6 @@ QUrl RunControl::debugChannel() const void RunControl::requestQmlChannel() { - d->enablePortsGatherer(); d->useQmlChannel = true; } @@ -680,7 +679,6 @@ void RunControl::setQmlChannel(const QUrl &channel) void RunControl::requestPerfChannel() { - d->enablePortsGatherer(); d->usePerfChannel = true; } @@ -696,7 +694,6 @@ QUrl RunControl::perfChannel() const void RunControl::requestWorkerChannel() { - d->enablePortsGatherer(); d->useWorkerChannel = true; } From a729f82858cc636409aed58722eb9da1235c1375 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 16:21:39 +0100 Subject: [PATCH 233/989] AppMan: Inline AppManagerRunner Task-number: QTCREATORBUG-29168 Change-Id: I6961f8acd19be0c2538aacc2bb43598a03986634 Reviewed-by: hjk --- .../appmanagerruncontrol.cpp | 97 +++++++++---------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index ad920797856..36c84e6c67a 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -41,57 +41,6 @@ using namespace Utils; namespace AppManager::Internal { -// AppManagerRunner - -class AppManagerRunner final : public SimpleTargetRunner -{ -public: - AppManagerRunner(RunControl *runControl) - : SimpleTargetRunner(runControl) - { - setId("ApplicationManagerPlugin.Run.TargetRunner"); - connect(this, &RunWorker::stopped, this, [this, runControl] { - appendMessage(Tr::tr("%1 exited.").arg(runControl->runnable().command.toUserOutput()), - OutputFormat::NormalMessageFormat); - }); - - setStartModifier([this, runControl] { - FilePath controller = runControl->aspectData()->filePath; - QString appId = runControl->aspectData()->value; - QString instanceId = runControl->aspectData()->value; - QString documentUrl = runControl->aspectData()->value; - bool restartIfRunning = runControl->aspectData()->value; - QStringList envVars; - if (auto envAspect = runControl->aspectData()) - envVars = envAspect->environment.toStringList(); - envVars.replaceInStrings(" ", "\\ "); - - // Always use the default environment to start the appman-controller in - // The env variables from the EnvironmentAspect are set through the controller - setEnvironment({}); - // Prevent the write channel to be closed, otherwise the appman-controller will exit - setProcessMode(ProcessMode::Writer); - CommandLine cmd{controller}; - if (!instanceId.isEmpty()) - cmd.addArgs({"--instance-id", instanceId}); - - if (envVars.isEmpty()) - cmd.addArgs({"start-application", "-eio"}); - else - cmd.addArgs({"debug-application", "-eio"}); - - if (restartIfRunning) - cmd.addArg("--restart"); - if (!envVars.isEmpty()) - cmd.addArg(envVars.join(' ')); - cmd.addArg(appId); - if (!documentUrl.isEmpty()) - cmd.addArg(documentUrl); - setCommandLine(cmd); - }); - } -}; - static RunWorker *createInferiorRunner(RunControl *runControl, QmlDebugServicesPreset qmlServices) { auto worker = new SimpleTargetRunner(runControl); @@ -290,7 +239,51 @@ class AppManagerRunWorkerFactory final : public RunWorkerFactory public: AppManagerRunWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new SimpleTargetRunner(runControl); + worker->setId("ApplicationManagerPlugin.Run.TargetRunner"); + QObject::connect(worker, &RunWorker::stopped, worker, [worker, runControl] { + worker->appendMessage( + Tr::tr("%1 exited.").arg(runControl->runnable().command.toUserOutput()), + OutputFormat::NormalMessageFormat); + }); + + worker->setStartModifier([worker, runControl] { + FilePath controller = runControl->aspectData()->filePath; + QString appId = runControl->aspectData()->value; + QString instanceId = runControl->aspectData()->value; + QString documentUrl = runControl->aspectData()->value; + bool restartIfRunning = runControl->aspectData()->value; + QStringList envVars; + if (auto envAspect = runControl->aspectData()) + envVars = envAspect->environment.toStringList(); + envVars.replaceInStrings(" ", "\\ "); + + // Always use the default environment to start the appman-controller in + // The env variables from the EnvironmentAspect are set through the controller + worker->setEnvironment({}); + // Prevent the write channel to be closed, otherwise the appman-controller will exit + worker->setProcessMode(ProcessMode::Writer); + CommandLine cmd{controller}; + if (!instanceId.isEmpty()) + cmd.addArgs({"--instance-id", instanceId}); + + if (envVars.isEmpty()) + cmd.addArgs({"start-application", "-eio"}); + else + cmd.addArgs({"debug-application", "-eio"}); + + if (restartIfRunning) + cmd.addArg("--restart"); + if (!envVars.isEmpty()) + cmd.addArg(envVars.join(' ')); + cmd.addArg(appId); + if (!documentUrl.isEmpty()) + cmd.addArg(documentUrl); + worker->setCommandLine(cmd); + }); + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); addSupportedRunConfig(Constants::RUNCONFIGURATION_ID); addSupportedRunConfig(Constants::RUNANDDEBUGCONFIGURATION_ID); From afba6d2a78089d78e7ac9c854a54cbce8d7a7023 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 17:29:53 +0100 Subject: [PATCH 234/989] BareMetal: Inline GdbServerProviderRunner Task-number: QTCREATORBUG-29168 Change-Id: I417051e09ba2490b5cf2d57881737559477fd804 Reviewed-by: hjk --- .../debugservers/gdb/gdbserverprovider.cpp | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp index cf2bbe915ca..f510428e97e 100644 --- a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp @@ -33,21 +33,6 @@ const char initCommandsKeyC[] = "InitCommands"; const char resetCommandsKeyC[] = "ResetCommands"; const char useExtendedRemoteKeyC[] = "UseExtendedRemote"; -class GdbServerProviderRunner final : public SimpleTargetRunner -{ -public: - GdbServerProviderRunner(RunControl *runControl, const CommandLine &commandLine) - : SimpleTargetRunner(runControl) - { - setId("BareMetalGdbServer"); - // Baremetal's GDB servers are launched on the host, not on the target. - setStartModifier([this, commandLine] { - setCommandLine(commandLine); - forceRunOnHost(); - }); - } -}; - // GdbServerProvider GdbServerProvider::GdbServerProvider(const QString &id) @@ -187,7 +172,14 @@ RunWorker *GdbServerProvider::targetRunner(RunControl *runControl) const // Command arguments are in host OS style as the bare metal's GDB servers are launched // on the host, not on that target. - return new GdbServerProviderRunner(runControl, command()); + auto worker = new SimpleTargetRunner(runControl); + worker->setId("BareMetalGdbServer"); + // Baremetal's GDB servers are launched on the host, not on the target. + worker->setStartModifier([worker, cmd = command()] { + worker->setCommandLine(cmd); + worker->forceRunOnHost(); + }); + return worker; } void GdbServerProvider::fromMap(const Store &data) From 11aed5528e81cb84fc38ff8dd173763d25ba2dda Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 17:34:29 +0100 Subject: [PATCH 235/989] Qnx: Inline QnxQmlProfilerSupport Task-number: QTCREATORBUG-29168 Change-Id: I54aba4ec9ad4b830c990cbdf6a54336bef852113 Reviewed-by: hjk --- src/plugins/qnx/qnxanalyzesupport.cpp | 50 +++++++++++---------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index f0aa20d88d6..fae9ff9252a 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -11,45 +11,37 @@ #include #include -#include - using namespace ProjectExplorer; using namespace Utils; namespace Qnx::Internal { -class QnxQmlProfilerSupport final : public SimpleTargetRunner -{ -public: - explicit QnxQmlProfilerSupport(RunControl *runControl) - : SimpleTargetRunner(runControl) - { - setId("QnxQmlProfilerSupport"); - appendMessage(Tr::tr("Preparing remote side..."), LogMessageFormat); - - runControl->requestQmlChannel(); - - auto slog2InfoRunner = new Slog2InfoRunner(runControl); - addStartDependency(slog2InfoRunner); - - auto profiler = runControl->createWorker(ProjectExplorer::Constants::QML_PROFILER_RUNNER); - profiler->addStartDependency(this); - addStopDependency(profiler); - - setStartModifier([this] { - CommandLine cmd = commandLine(); - cmd.addArg(qmlDebugTcpArguments(QmlProfilerServices, qmlChannel())); - setCommandLine(cmd); - }); - } -}; - class QnxQmlProfilerWorkerFactory final : public RunWorkerFactory { public: QnxQmlProfilerWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new SimpleTargetRunner(runControl); + worker->setId("QnxQmlProfilerSupport"); + worker->appendMessage(Tr::tr("Preparing remote side..."), LogMessageFormat); + + runControl->requestQmlChannel(); + + auto slog2InfoRunner = new Slog2InfoRunner(runControl); + worker->addStartDependency(slog2InfoRunner); + + auto profiler = runControl->createWorker(ProjectExplorer::Constants::QML_PROFILER_RUNNER); + profiler->addStartDependency(worker); + worker->addStopDependency(profiler); + + worker->setStartModifier([worker] { + CommandLine cmd = worker->commandLine(); + cmd.addArg(qmlDebugTcpArguments(QmlProfilerServices, worker->qmlChannel())); + worker->setCommandLine(cmd); + }); + return worker; + }); // FIXME: Shouldn't this use the run mode id somehow? addSupportedRunConfig(Constants::QNX_RUNCONFIG_ID); } From 3cd0f3b2d089731c1d6a67255201eeb17a8255f1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 18:32:37 +0100 Subject: [PATCH 236/989] McuSupport: Inline FlashAndRunWorker Task-number: QTCREATORBUG-29168 Change-Id: I4faa4e4b9611d3df0cba135f7525af5bfb6c6939 Reviewed-by: hjk --- .../mcusupport/mcusupportrunconfiguration.cpp | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp index 260b908c854..781b27e9740 100644 --- a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp +++ b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp @@ -73,31 +73,6 @@ public: bool FlashAndRunConfiguration::disabled = false; -class FlashAndRunWorker : public SimpleTargetRunner -{ -public: - FlashAndRunWorker(RunControl *runControl) - : SimpleTargetRunner(runControl) - { - setStartModifier([this, runControl] { - const Target *target = runControl->target(); - setCommandLine({cmakeFilePath(target), runControl->aspectData()->value, - CommandLine::Raw}); - setWorkingDirectory(target->activeBuildConfiguration()->buildDirectory()); - setEnvironment(target->activeBuildConfiguration()->environment()); - }); - - connect(runControl, &RunControl::started, []() { - FlashAndRunConfiguration::disabled = true; - ProjectExplorerPlugin::updateRunActions(); - }); - connect(runControl, &RunControl::stopped, []() { - FlashAndRunConfiguration::disabled = false; - ProjectExplorerPlugin::updateRunActions(); - }); - } -}; - // Factories McuSupportRunConfigurationFactory::McuSupportRunConfigurationFactory() @@ -108,7 +83,27 @@ McuSupportRunConfigurationFactory::McuSupportRunConfigurationFactory() FlashRunWorkerFactory::FlashRunWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new SimpleTargetRunner(runControl); + worker->setStartModifier([worker, runControl] { + const Target *target = runControl->target(); + worker->setCommandLine({cmakeFilePath(target), + runControl->aspectData()->value, CommandLine::Raw}); + worker->setWorkingDirectory(target->activeBuildConfiguration()->buildDirectory()); + worker->setEnvironment(target->activeBuildConfiguration()->environment()); + }); + + QObject::connect(runControl, &RunControl::started, runControl, [] { + FlashAndRunConfiguration::disabled = true; + ProjectExplorerPlugin::updateRunActions(); + }); + QObject::connect(runControl, &RunControl::stopped, runControl, [] { + FlashAndRunConfiguration::disabled = false; + ProjectExplorerPlugin::updateRunActions(); + }); + + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); addSupportedRunConfig(Constants::RUNCONFIGURATION); } From 183ed4e4905efbc572adc595d68ebdd1856c08f7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 21:23:29 +0100 Subject: [PATCH 237/989] Ios: Remove unused field Task-number: QTCREATORBUG-29168 Change-Id: I84c4f5482b35dbe311a37dd1564f0c12569940bb Reviewed-by: hjk --- src/plugins/ios/iosrunner.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index 287210da4c7..9102390b3d2 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -751,7 +751,6 @@ public: private: void start() override; - const QString m_dumperLib; IosRunner *m_runner; }; From cca652bced780207ed777be66af8319e5710cb1b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 18:42:08 +0100 Subject: [PATCH 238/989] ProjectExplorer: Remove unused SimpleTargetRunner::setExtraData() Task-number: QTCREATORBUG-29168 Change-Id: Ia62bbff8dab91e400e97cad4efeb279da83bf214 Reviewed-by: hjk --- src/plugins/projectexplorer/runcontrol.cpp | 11 +---------- src/plugins/projectexplorer/runcontrol.h | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index b89db25d147..ea5d5efccd6 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1400,7 +1400,6 @@ public: Utils::CommandLine m_command; Utils::FilePath m_workingDirectory; Utils::Environment m_environment; - QVariantHash m_extraData; ProcessResultData m_resultData; @@ -1565,7 +1564,7 @@ void SimpleTargetRunnerPrivate::start() m_stopRequested = false; - QVariantHash extraData = m_extraData; + QVariantHash extraData = q->runControl()->extraData(); extraData[TERMINAL_SHELL_NAME] = m_command.executable().fileName(); m_process.setCommand(cmdLine); @@ -1584,7 +1583,6 @@ void SimpleTargetRunnerPrivate::start() m_process.start(); } - /*! \class ProjectExplorer::SimpleTargetRunner @@ -1596,7 +1594,6 @@ void SimpleTargetRunnerPrivate::start() \sa Utils::Process */ - SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl) : RunWorker(runControl), d(new Internal::SimpleTargetRunnerPrivate(this)) { @@ -1644,7 +1641,6 @@ void SimpleTargetRunner::start() d->m_command = runControl()->commandLine(); d->m_workingDirectory = runControl()->workingDirectory(); d->m_environment = runControl()->environment(); - d->m_extraData = runControl()->extraData(); if (d->m_startModifier) d->m_startModifier(); @@ -1740,11 +1736,6 @@ void SimpleTargetRunner::forceRunOnHost() } } -void SimpleTargetRunner::addExtraData(const QString &key, const QVariant &value) -{ - d->m_extraData[key] = value; -} - // RunWorkerPrivate RunWorkerPrivate::RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl) diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 326660bb03a..efc772302ab 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -299,7 +299,6 @@ public: void suppressDefaultStdOutHandling(); void forceRunOnHost(); - void addExtraData(const QString &key, const QVariant &value); private: void start() final; From 7a0c13b46b092f265b77009735589ea0357b0d8f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 18:57:23 +0100 Subject: [PATCH 239/989] Android: Drop AndroidDebugSupport::stop() overload It's not much useful. Task-number: QTCREATORBUG-29168 Change-Id: I01b0b2defb03c7bce1c2722f6a67a5422312b539 Reviewed-by: hjk --- src/plugins/android/androiddebugsupport.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index 8170bb89d2d..2d432a6b643 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -92,7 +92,6 @@ public: } void start() override; - void stop() override; private: AndroidRunner *m_runner = nullptr; @@ -190,12 +189,6 @@ void AndroidDebugSupport::start() DebuggerRunTool::start(); } -void AndroidDebugSupport::stop() -{ - qCDebug(androidDebugSupportLog) << "Stop"; - DebuggerRunTool::stop(); -} - // AndroidDebugWorkerFactory class AndroidDebugWorkerFactory final : public RunWorkerFactory From 99f89999e83087da5d1d79f56d46facc2353b192 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 21 Nov 2024 09:13:40 +0100 Subject: [PATCH 240/989] Utils: Remove EnvironmentDialog class It was only wrapping a single static function. Change-Id: I97031510ceb2cdc339181d79eae9228705493a67 Reviewed-by: Jarek Kobus --- src/libs/utils/environmentdialog.cpp | 6 ++--- src/libs/utils/environmentdialog.h | 8 ++----- .../coreplugin/dialogs/externaltoolconfig.cpp | 5 ++--- src/plugins/coreplugin/systemsettings.cpp | 3 +-- .../projectexplorer/environmentkitaspect.cpp | 22 ++++++++++--------- .../projectexplorersettings.cpp | 4 ++-- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/libs/utils/environmentdialog.cpp b/src/libs/utils/environmentdialog.cpp index ee569fea9a4..021c5e7467c 100644 --- a/src/libs/utils/environmentdialog.cpp +++ b/src/libs/utils/environmentdialog.cpp @@ -7,14 +7,14 @@ namespace Utils { -std::optional EnvironmentDialog::getEnvironmentItems( +std::optional runEnvironmentItemsDialog( QWidget *parent, const EnvironmentItems &initial, const QString &placeholderText, - Polisher polisher, + NameValuesDialog::Polisher polisher, const QString &dialogTitle) { - return getNameValueItems( + return NameValuesDialog::getNameValueItems( parent, initial, placeholderText, diff --git a/src/libs/utils/environmentdialog.h b/src/libs/utils/environmentdialog.h index 69340e6a951..aab03ec6c33 100644 --- a/src/libs/utils/environmentdialog.h +++ b/src/libs/utils/environmentdialog.h @@ -10,15 +10,11 @@ namespace Utils { -class QTCREATOR_UTILS_EXPORT EnvironmentDialog : public NameValuesDialog -{ -public: - static std::optional getEnvironmentItems( +QTCREATOR_UTILS_EXPORT std::optional runEnvironmentItemsDialog( QWidget *parent = nullptr, const EnvironmentItems &initial = {}, const QString &placeholderText = {}, - Polisher polish = {}, + NameValuesDialog::Polisher polish = {}, const QString &dialogTitle = {}); -}; } // namespace Utils diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp index 5f57b5719cf..e19f7dbe305 100644 --- a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp +++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp @@ -937,9 +937,8 @@ void ExternalToolConfig::editEnvironmentChanges() const QString placeholderText = HostOsInfo::isWindowsHost() ? Tr::tr("PATH=C:\\dev\\bin;${PATH}") : Tr::tr("PATH=/opt/bin:${PATH}"); - const auto newItems = EnvironmentDialog::getEnvironmentItems(m_environmentLabel, - m_environment, - placeholderText); + const std::optional newItems = + runEnvironmentItemsDialog(m_environmentLabel, m_environment, placeholderText); if (newItems) { m_environment = *newItems; updateEnvironmentLabel(); diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index b89734d7567..ed3cb5cd45e 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -352,8 +352,7 @@ public: updateEnvironmentChangesLabel(); connect(environmentButton, &QPushButton::clicked, this, [this, environmentButton] { std::optional changes - = Utils::EnvironmentDialog::getEnvironmentItems(environmentButton, - m_environmentChanges); + = runEnvironmentItemsDialog(environmentButton, m_environmentChanges); if (!changes) return; m_environmentChanges = *changes; diff --git a/src/plugins/projectexplorer/environmentkitaspect.cpp b/src/plugins/projectexplorer/environmentkitaspect.cpp index 1d33e7e6b3b..556fa224f05 100644 --- a/src/plugins/projectexplorer/environmentkitaspect.cpp +++ b/src/plugins/projectexplorer/environmentkitaspect.cpp @@ -100,12 +100,13 @@ private: void editBuildEnvironmentChanges() { - auto changes = EnvironmentDialog::getEnvironmentItems( - m_mainWidget, - EnvironmentKitAspect::buildEnvChanges(kit()), - QString(), - polisher(), - Tr::tr("Edit Build Environment")); + std::optional changes = + runEnvironmentItemsDialog( + m_mainWidget, + EnvironmentKitAspect::buildEnvChanges(kit()), + QString(), + polisher(), + Tr::tr("Edit Build Environment")); if (!changes) return; @@ -122,17 +123,18 @@ private: void editRunEnvironmentChanges() { - if (const auto changes = EnvironmentDialog::getEnvironmentItems( + const std::optional changes = + runEnvironmentItemsDialog( m_mainWidget, EnvironmentKitAspect::runEnvChanges(kit()), QString(), polisher(), - Tr::tr("Edit Run Environment"))) { + Tr::tr("Edit Run Environment")); + if (changes) EnvironmentKitAspect::setRunEnvChanges(kit(), *changes); - } } - EnvironmentDialog::Polisher polisher() const + NameValuesDialog::Polisher polisher() const { return [expander = kit()->macroExpander()](QWidget *w) { VariableChooser::addSupportForChildWidgets(w, expander); diff --git a/src/plugins/projectexplorer/projectexplorersettings.cpp b/src/plugins/projectexplorer/projectexplorersettings.cpp index 5d023a711f9..f940b8d1a5f 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.cpp +++ b/src/plugins/projectexplorer/projectexplorersettings.cpp @@ -384,8 +384,8 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget() appEnvButton->setSizePolicy(QSizePolicy::Fixed, appEnvButton->sizePolicy().verticalPolicy()); appEnvButton->setToolTip(appEnvToolTip); connect(appEnvButton, &QPushButton::clicked, this, [appEnvButton, this] { - std::optional changes - = EnvironmentDialog::getEnvironmentItems(appEnvButton, m_appEnvChanges); + const std::optional changes = + runEnvironmentItemsDialog(appEnvButton, m_appEnvChanges); if (!changes) return; m_appEnvChanges = *changes; From da8850e1f6d251410f329bc7d2b278242e36e0ff Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Thu, 21 Nov 2024 09:09:48 +0100 Subject: [PATCH 241/989] Debugger: remove unused function parameter Amends: cb23332ae5024358922a28bd1d06eafe4b84a363 Change-Id: I6f52381e41439b4e46b16366cd4a62278ec7006a Reviewed-by: Christian Kandeler --- src/plugins/debugger/simplifytype.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/simplifytype.cpp b/src/plugins/debugger/simplifytype.cpp index 3d59e5a0929..406ce6f5b62 100644 --- a/src/plugins/debugger/simplifytype.cpp +++ b/src/plugins/debugger/simplifytype.cpp @@ -88,7 +88,6 @@ static inline QString fixNestedTemplates(QString s) } static void simplifyAllocator( - const QString &typeIn, const QString &allocatorTemplateHead, const QString &containerTypePrefix, const bool isLibCpp, @@ -334,9 +333,9 @@ QString simplifyType(const QString &typeIn) } // Fix e.g. `std::vector> -> std::vector` - simplifyAllocator(typeIn, "std::allocator<", "", isLibCpp, type); + simplifyAllocator("std::allocator<", "", isLibCpp, type); // Fix e.g. `std::vector> -> std::pmr::vector` - simplifyAllocator(typeIn, "std::pmr::polymorphic_allocator<", "pmr::", isLibCpp, type); + simplifyAllocator("std::pmr::polymorphic_allocator<", "pmr::", isLibCpp, type); } type.replace('@', " *"); type.replace(" >", ">"); From df61ee100326134b3f6d44e57c3f2c967b28c8a9 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 21 Nov 2024 11:07:52 +0100 Subject: [PATCH 242/989] Android: Drop qml port parsing from application output We define the port in advance now. After that, AndroidRunner's start() and stop() are not special anymore, so drop them, too. Task-number: QTCREATORBUG-29168 Change-Id: I9accf6518bb4b6d6474fd16862caef7e61d532f3 Reviewed-by: Jarek Kobus --- src/plugins/android/androidqmltoolingsupport.cpp | 6 ------ src/plugins/android/androidrunner.cpp | 3 --- src/plugins/android/androidrunner.h | 1 - 3 files changed, 10 deletions(-) diff --git a/src/plugins/android/androidqmltoolingsupport.cpp b/src/plugins/android/androidqmltoolingsupport.cpp index 6c14f30c3fc..8070dbb57a5 100644 --- a/src/plugins/android/androidqmltoolingsupport.cpp +++ b/src/plugins/android/androidqmltoolingsupport.cpp @@ -25,13 +25,7 @@ public: auto worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); worker->addStartDependency(this); - - connect(runner, &AndroidRunner::qmlServerReady, this, &RunWorker::reportStarted); } - -private: - void start() override {} - void stop() override { reportStopped(); } }; class AndroidQmlToolingSupportFactory final : public RunWorkerFactory diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index f8395f30c07..07a4f079368 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -43,9 +43,6 @@ AndroidRunner::AndroidRunner(RunControl *runControl) qRegisterMetaType("Android::AndroidDeviceInfo") }; Q_UNUSED(metaTypes) - - connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, - this, &AndroidRunner::qmlServerReady); } void AndroidRunner::start() diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index c4833f44559..2739fbf87ae 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -26,7 +26,6 @@ public: signals: void canceled(); - void qmlServerReady(); void avdDetected(); private: From c9700fef0cddfb71a54c0c82d721110566fc9389 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 16:08:45 +0100 Subject: [PATCH 243/989] ProjectExplorer: Get rid of DeviceUsedPortsGatherer Change-Id: I4dfd53715abfa4d69a66674e02cc1e0ac40c25fd Reviewed-by: hjk --- src/plugins/debugger/debuggerruncontrol.h | 2 +- src/plugins/projectexplorer/CMakeLists.txt | 1 - .../devicesupport/deviceusedportsgatherer.cpp | 112 ------------------ .../devicesupport/deviceusedportsgatherer.h | 55 --------- .../projectexplorer/projectexplorer.qbs | 1 - src/plugins/qnx/qnxanalyzesupport.cpp | 1 - src/plugins/qnx/qnxdebugsupport.cpp | 1 - src/plugins/valgrind/memchecktool.cpp | 4 +- src/plugins/valgrind/xmlprotocol/parser.h | 1 + .../webassemblyrunconfiguration.cpp | 1 - 10 files changed, 4 insertions(+), 175 deletions(-) delete mode 100644 src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp delete mode 100644 src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index 1e7c92b29b5..2f056666ee7 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index c98db1a5cad..bcd866cb5d3 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -58,7 +58,6 @@ add_qtc_plugin(ProjectExplorer devicesupport/deviceprocessesdialog.cpp devicesupport/deviceprocessesdialog.h devicesupport/devicesettingspage.cpp devicesupport/devicesettingspage.h devicesupport/devicetestdialog.cpp devicesupport/devicetestdialog.h - devicesupport/deviceusedportsgatherer.cpp devicesupport/deviceusedportsgatherer.h devicesupport/filetransfer.cpp devicesupport/filetransfer.h devicesupport/filetransferinterface.h devicesupport/idevice.cpp devicesupport/idevice.h diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp deleted file mode 100644 index a6557c10c94..00000000000 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "deviceusedportsgatherer.h" - -#include "idevice.h" -#include "sshparameters.h" -#include "../projectexplorertr.h" - -#include - -#include -#include -#include -#include -#include -#include - -using namespace Utils; - -namespace ProjectExplorer { -namespace Internal { - -class DeviceUsedPortsGathererPrivate -{ -public: - std::unique_ptr process; - QList usedPorts; - IDevice::ConstPtr device; - PortsGatheringMethod portsGatheringMethod; - QString m_errorString; -}; - -} // namespace Internal - -DeviceUsedPortsGatherer::DeviceUsedPortsGatherer(QObject *parent) - : QObject(parent) - , d(new Internal::DeviceUsedPortsGathererPrivate) -{} - -DeviceUsedPortsGatherer::~DeviceUsedPortsGatherer() -{ - stop(); - delete d; -} - -void DeviceUsedPortsGatherer::start() -{ - const auto emitError = [this](const QString &errorString) { - d->m_errorString = errorString; - emit done(false); - }; - - d->usedPorts.clear(); - d->m_errorString.clear(); - QTC_ASSERT(d->device, emitError("No device given"); return); - - d->portsGatheringMethod = d->device->portsGatheringMethod(); - QTC_ASSERT(d->portsGatheringMethod.commandLine, emitError("Not implemented"); return); - QTC_ASSERT(d->portsGatheringMethod.parsePorts, emitError("Not implemented"); return); - - const QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::AnyIPProtocol; - - d->process.reset(new Process); - d->process->setCommand(d->portsGatheringMethod.commandLine(protocol)); - - connect(d->process.get(), &Process::done, this, [this, emitError] { - if (d->process->result() == ProcessResult::FinishedWithSuccess) { - d->usedPorts.clear(); - const QList usedPorts = d->portsGatheringMethod.parsePorts( - d->process->rawStdOut()); - for (const Port port : usedPorts) { - if (d->device->freePorts().contains(port)) - d->usedPorts << port; - } - emit done(true); - } else { - const QString errorString = d->process->errorString(); - const QString stdErr = d->process->readAllStandardError(); - const QString outputString - = stdErr.isEmpty() ? stdErr : Tr::tr("Remote error output was: %1").arg(stdErr); - emitError(Utils::joinStrings({errorString, outputString}, '\n')); - } - stop(); - }); - d->process->start(); -} - -void DeviceUsedPortsGatherer::stop() -{ - if (d->process) { - d->process->disconnect(); - d->process.release()->deleteLater(); - } -} - -void DeviceUsedPortsGatherer::setDevice(const IDeviceConstPtr &device) -{ - d->device = device; -} - -QList DeviceUsedPortsGatherer::usedPorts() const -{ - return d->usedPorts; -} - -QString DeviceUsedPortsGatherer::errorString() const -{ - return d->m_errorString; -} - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h deleted file mode 100644 index 6d22610d187..00000000000 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "idevicefwd.h" - -#include - -#include - -#include - -using namespace Tasking; - -namespace ProjectExplorer { - -namespace Internal { class DeviceUsedPortsGathererPrivate; } - -class PROJECTEXPLORER_EXPORT DeviceUsedPortsGatherer : public QObject -{ - Q_OBJECT - -public: - DeviceUsedPortsGatherer(QObject *parent = nullptr); - ~DeviceUsedPortsGatherer() override; - - void start(); - void stop(); - void setDevice(const IDeviceConstPtr &device); - QList usedPorts() const; - QString errorString() const; - -signals: - void done(bool success); - -private: - Internal::DeviceUsedPortsGathererPrivate * const d; -}; - -class PROJECTEXPLORER_EXPORT DeviceUsedPortsGathererTaskAdapter - : public TaskAdapter -{ -public: - DeviceUsedPortsGathererTaskAdapter() { - connect(task(), &DeviceUsedPortsGatherer::done, this, [this](bool success) { - emit done(toDoneResult(success)); - }); - } - void start() final { task()->start(); } -}; - -using DeviceUsedPortsGathererTask = CustomTask; - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 8ce76b16010..fa2c8dea645 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -216,7 +216,6 @@ QtcPlugin { "deviceprocessesdialog.cpp", "deviceprocessesdialog.h", "devicesettingspage.cpp", "devicesettingspage.h", "devicetestdialog.cpp", "devicetestdialog.h", - "deviceusedportsgatherer.cpp", "deviceusedportsgatherer.h", "filetransfer.cpp", "filetransfer.h", "filetransferinterface.h", "idevice.cpp", "idevice.h", diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index fae9ff9252a..923c00af4de 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -7,7 +7,6 @@ #include "qnxtr.h" #include "slog2inforunner.h" -#include #include #include diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index e949b5b9f38..c9fc71ef42d 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index b7430ca8eb7..a1807697da8 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -1021,8 +1021,8 @@ void MemcheckTool::loadXmlLogFile(const QString &filePath) m_logParser.reset(new Parser); connect(m_logParser.get(), &Parser::error, this, &MemcheckTool::parserError); - connect(m_logParser.get(), &Parser::done, this, [this](DoneResult result, const QString &err) { - if (result == DoneResult::Error) + connect(m_logParser.get(), &Parser::done, this, [this](Tasking::DoneResult result, const QString &err) { + if (result == Tasking::DoneResult::Error) internalParserError(err); loadingExternalXmlLogFileFinished(); m_logParser.release()->deleteLater(); diff --git a/src/plugins/valgrind/xmlprotocol/parser.h b/src/plugins/valgrind/xmlprotocol/parser.h index f53609ccf66..41c6aa502fa 100644 --- a/src/plugins/valgrind/xmlprotocol/parser.h +++ b/src/plugins/valgrind/xmlprotocol/parser.h @@ -45,6 +45,7 @@ signals: void errorCount(qint64 unique, qint64 count); void suppressionCount(const QString &name, qint64 count); void announceThread(const AnnounceThread &announceThread); + // TODO: Replace with Utils::Result void done(Tasking::DoneResult result, const QString &errorString); private: diff --git a/src/plugins/webassembly/webassemblyrunconfiguration.cpp b/src/plugins/webassembly/webassemblyrunconfiguration.cpp index def5b1c54c5..8783150a55d 100644 --- a/src/plugins/webassembly/webassemblyrunconfiguration.cpp +++ b/src/plugins/webassembly/webassemblyrunconfiguration.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From b007db06d50db5c3a7a23b3b4cfc820512e10d6c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 16:11:08 +0100 Subject: [PATCH 244/989] ProjectExplorer: Get rid of PortsGatheringMethod Remove the associated virtual method of IDevice. The replacements is IDevice::portsGatheringRecipe(). Change-Id: I8496b2a12fe5c136204811a8d2afa340591ce9da Reviewed-by: hjk --- src/plugins/android/androiddevice.cpp | 14 ------------- src/plugins/android/androiddevice.h | 1 - .../projectexplorer/devicesupport/idevice.cpp | 21 ------------------- .../projectexplorer/devicesupport/idevice.h | 8 ------- 4 files changed, 44 deletions(-) diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 0d5fb804c73..663cfe57470 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -655,20 +655,6 @@ ExecutableItem AndroidDevice::portsGatheringRecipe(const Storage CommandLine { - Q_UNUSED(protocol); - return {AndroidConfig::adbToolPath(), { - adbSelector(serialNumber()), "shell" , "netstat", "-a", "-n" - }}; - }, - &Port::parseFromCommandOutput - }; -} - QUrl AndroidDevice::toolControlChannel(const ControlChannelHint &) const { QUrl url; diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index eca0fb7d09b..975ec932362 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -60,7 +60,6 @@ private: QUrl toolControlChannel(const ControlChannelHint &) const override; Tasking::ExecutableItem portsGatheringRecipe( const Tasking::Storage &output) const override; - ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override; QSettings *avdSettings() const; void initAvdSettings(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 0ac286d7dbf..96b9c2e0ca6 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -458,27 +458,6 @@ ExecutableItem IDevice::portsGatheringRecipe(const Storage &out }; } -PortsGatheringMethod IDevice::portsGatheringMethod() const -{ - return {[this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine { - // We might encounter the situation that protocol is given IPv6 - // but the consumer of the free port information decides to open - // an IPv4(only) port. As a result the next IPv6 scan will - // report the port again as open (in IPv6 namespace), while the - // same port in IPv4 namespace might still be blocked, and - // re-use of this port fails. - // GDBserver behaves exactly like this. - - Q_UNUSED(protocol) - - if (filePath("/proc/net").isReadableDir()) - return {filePath("/bin/sh"), {"-c", "cat /proc/net/tcp*"}}; - - return {filePath("netstat"), {"-a", "-n"}}; - }, - &Port::parseFromCommandOutput}; -} - DeviceTester *IDevice::createDeviceTester() { QTC_ASSERT(false, qDebug("This should not have been called...")); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index d672b8222d3..ec6220d30b1 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -76,13 +76,6 @@ protected: QString m_errorMessage; }; -class PROJECTEXPLORER_EXPORT PortsGatheringMethod final -{ -public: - std::function commandLine; - std::function(const QByteArray &commandOutput)> parsePorts; -}; - // See cpp file for documentation. class PROJECTEXPLORER_EXPORT IDevice : public Utils::AspectContainer, public std::enable_shared_from_this @@ -143,7 +136,6 @@ public: virtual Tasking::ExecutableItem portsGatheringRecipe( const Tasking::Storage &output) const; - virtual PortsGatheringMethod portsGatheringMethod() const; virtual bool canCreateProcessModel() const { return false; } virtual bool hasDeviceTester() const { return false; } virtual DeviceTester *createDeviceTester(); From 9343de20f3097412dede16fd1d0614679efa838a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 15 Nov 2024 16:41:21 +0100 Subject: [PATCH 245/989] Valgrind: Replace Parser::done() args with Utils::Result Change-Id: Iaed1f47d2dfc5195c83c3ef8c5141af1a1f17832 Reviewed-by: hjk --- src/plugins/valgrind/memchecktool.cpp | 6 +++--- src/plugins/valgrind/xmlprotocol/parser.cpp | 10 +++++----- src/plugins/valgrind/xmlprotocol/parser.h | 14 ++++++++++---- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index a1807697da8..5323e45e547 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -1021,9 +1021,9 @@ void MemcheckTool::loadXmlLogFile(const QString &filePath) m_logParser.reset(new Parser); connect(m_logParser.get(), &Parser::error, this, &MemcheckTool::parserError); - connect(m_logParser.get(), &Parser::done, this, [this](Tasking::DoneResult result, const QString &err) { - if (result == Tasking::DoneResult::Error) - internalParserError(err); + connect(m_logParser.get(), &Parser::done, this, [this](const Result &result) { + if (!result) + internalParserError(result.error()); loadingExternalXmlLogFileFinished(); m_logParser.release()->deleteLater(); }); diff --git a/src/plugins/valgrind/xmlprotocol/parser.cpp b/src/plugins/valgrind/xmlprotocol/parser.cpp index 550a021a87c..9c8009a0822 100644 --- a/src/plugins/valgrind/xmlprotocol/parser.cpp +++ b/src/plugins/valgrind/xmlprotocol/parser.cpp @@ -709,7 +709,7 @@ public: m_errorString = data.m_internalError; }); QObject::connect(m_watcher.get(), &QFutureWatcherBase::finished, q, [this] { - emit q->done(toDoneResult(!m_errorString), m_errorString.value_or(QString())); + emit q->done({!m_errorString, m_errorString.value_or(QString())}); m_watcher.release()->deleteLater(); m_thread.reset(); m_socket.reset(); @@ -780,13 +780,13 @@ bool Parser::isRunning() const return d->m_watcher.get(); } -bool Parser::runBlocking() +Result Parser::runBlocking() { - bool ok = false; + Result ok(Result::Ok); QEventLoop loop; - const auto finalize = [&loop, &ok](DoneResult result) { - ok = result == DoneResult::Success; + const auto finalize = [&loop, &ok](const Result &result) { + ok = result; // Refer to the QObject::deleteLater() docs. QMetaObject::invokeMethod(&loop, [&loop] { loop.quit(); }, Qt::QueuedConnection); }; diff --git a/src/plugins/valgrind/xmlprotocol/parser.h b/src/plugins/valgrind/xmlprotocol/parser.h index 41c6aa502fa..94218ee606a 100644 --- a/src/plugins/valgrind/xmlprotocol/parser.h +++ b/src/plugins/valgrind/xmlprotocol/parser.h @@ -3,6 +3,8 @@ #pragma once +#include + #include #include @@ -37,7 +39,7 @@ public: void start(); bool isRunning() const; - bool runBlocking(); + Utils::Result runBlocking(); signals: void status(const Status &status); @@ -45,8 +47,7 @@ signals: void errorCount(qint64 unique, qint64 count); void suppressionCount(const QString &name, qint64 count); void announceThread(const AnnounceThread &announceThread); - // TODO: Replace with Utils::Result - void done(Tasking::DoneResult result, const QString &errorString); + void done(const Utils::Result &result); private: std::unique_ptr d; @@ -55,7 +56,12 @@ private: class ParserTaskAdapter final : public Tasking::TaskAdapter { public: - ParserTaskAdapter() { connect(task(), &Parser::done, this, &Tasking::TaskInterface::done); } + ParserTaskAdapter() + { + connect(task(), &Parser::done, this, [this](const Utils::Result &result) { + emit done(Tasking::toDoneResult(result == Utils::Result::Ok)); + }); + } void start() final { task()->start(); } }; From 2dd900cec40baab5f545c393343fa28ef94be068 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 21 Nov 2024 08:41:48 +0100 Subject: [PATCH 246/989] Utils: Tweak MarkdownBrowser Some preparations for re-using it from the Axivion plugin. Change-Id: I4107152f4571c79e027e9f1d680e1378175a7b84 Reviewed-by: Marcus Tillmanns --- src/libs/utils/markdownbrowser.cpp | 52 +++++++++++++++++++++++------- src/libs/utils/markdownbrowser.h | 11 ++++++- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/libs/utils/markdownbrowser.cpp b/src/libs/utils/markdownbrowser.cpp index e15323058cb..aaffc4b020d 100644 --- a/src/libs/utils/markdownbrowser.cpp +++ b/src/libs/utils/markdownbrowser.cpp @@ -234,6 +234,8 @@ public: m_redraw(); } + void setMaximumCacheSize(qsizetype maxSize) { m_entries.setMaxCost(maxSize); } + private: std::function m_redraw; std::function m_scheduleLoad; @@ -281,8 +283,8 @@ public: || (url.isRelative() && isBaseHttp); }; - QList remoteUrls = Utils::filtered(m_urlsToLoad, isRemoteUrl); - QList localUrls = Utils::filtered(m_urlsToLoad, std::not_fn(isRemoteUrl)); + QSet remoteUrls = Utils::filtered(m_urlsToLoad, isRemoteUrl); + QSet localUrls = Utils::filtered(m_urlsToLoad, std::not_fn(isRemoteUrl)); if (m_basePath.isEmpty()) localUrls.clear(); @@ -290,27 +292,32 @@ public: if (!m_loadRemoteImages) remoteUrls.clear(); - const LoopList remoteIterator(remoteUrls); - const LoopList localIterator(localUrls); + const LoopList remoteIterator(Utils::toList(remoteUrls)); + const LoopList localIterator(Utils::toList(localUrls)); - auto onQuerySetup = [remoteIterator, base = m_basePath.toUrl()](NetworkQuery &query) { + auto onQuerySetup = [this, remoteIterator, base = m_basePath.toUrl()](NetworkQuery &query) { QUrl url = *remoteIterator; if (url.isRelative()) url = base.resolved(url); - query.setRequest(QNetworkRequest(*remoteIterator)); - query.setNetworkAccessManager(NetworkAccessManager::instance()); + QNetworkRequest request(url); + if (m_requestHook) + m_requestHook(&request); + + query.setRequest(request); + query.setNetworkAccessManager(m_networkAccessManager); + query.setProperty("originalName", *remoteIterator); }; auto onQueryDone = [this](const NetworkQuery &query, DoneWith result) { if (result == DoneWith::Cancel) return; - m_urlsToLoad.removeOne(query.reply()->url()); + m_urlsToLoad.remove(query.reply()->url()); if (result == DoneWith::Success) - m_imageHandler.set(query.reply()->url().toString(), query.reply()->readAll()); + m_imageHandler.set(query.property("originalName").toString(), query.reply()->readAll()); else - m_imageHandler.set(query.reply()->url().toString(), QByteArray{}); + m_imageHandler.set(query.property("originalName").toString(), QByteArray{}); markContentsDirty(0, this->characterCount()); }; @@ -354,20 +361,26 @@ public: void scheduleLoad(const QUrl &url) { - m_urlsToLoad.append(url); + m_urlsToLoad.insert(url); m_needsToRestartLoading = true; } void setBasePath(const FilePath &filePath) { m_basePath = filePath; } void setAllowRemoteImages(bool allow) { m_loadRemoteImages = allow; } + void setNetworkAccessManager(QNetworkAccessManager *nam) { m_networkAccessManager = nam;} + void setRequestHook(const MarkdownBrowser::RequestHook &hook) { m_requestHook = hook; } + void setMaximumCacheSize(qsizetype maxSize) { m_imageHandler.setMaximumCacheSize(maxSize); } + private: AnimatedImageHandler m_imageHandler; - QList m_urlsToLoad; + QSet m_urlsToLoad; bool m_needsToRestartLoading = false; bool m_loadRemoteImages = false; Tasking::TaskTreeRunner m_imageLoaderTree; FilePath m_basePath; + std::function m_requestHook; + QNetworkAccessManager *m_networkAccessManager = NetworkAccessManager::instance(); }; MarkdownBrowser::MarkdownBrowser(QWidget *parent) @@ -404,6 +417,21 @@ void MarkdownBrowser::setAllowRemoteImages(bool allow) static_cast(document())->setAllowRemoteImages(allow); } +void MarkdownBrowser::setNetworkAccessManager(QNetworkAccessManager *nam) +{ + static_cast(document())->setNetworkAccessManager(nam); +} + +void MarkdownBrowser::setRequestHook(const RequestHook &hook) +{ + static_cast(document())->setRequestHook(hook); +} + +void MarkdownBrowser::setMaximumCacheSize(qsizetype maxSize) +{ + static_cast(document())->setMaximumCacheSize(maxSize); +} + void MarkdownBrowser::setBasePath(const FilePath &filePath) { static_cast(document())->setBasePath(filePath); diff --git a/src/libs/utils/markdownbrowser.h b/src/libs/utils/markdownbrowser.h index 63de9e29f3a..a8fe2662f9f 100644 --- a/src/libs/utils/markdownbrowser.h +++ b/src/libs/utils/markdownbrowser.h @@ -9,18 +9,27 @@ #include +QT_BEGIN_NAMESPACE +class QNetworkAccessManager; +class QNetworkRequest; +QT_END_NAMESPACE + namespace Utils { class QTCREATOR_UTILS_EXPORT MarkdownBrowser : public QTextBrowser { Q_OBJECT - public: + using RequestHook = std::function; + MarkdownBrowser(QWidget *parent = nullptr); void setMarkdown(const QString &markdown); void setBasePath(const FilePath &filePath); void setAllowRemoteImages(bool allow); + void setNetworkAccessManager(QNetworkAccessManager *nam); + void setRequestHook(const RequestHook &hook); + void setMaximumCacheSize(qsizetype maxSize); QSize sizeHint() const override; QSize minimumSizeHint() const override; From f2d5dc6f49b8138320a106c2b089e351cb2e6765 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 21 Nov 2024 12:08:38 +0100 Subject: [PATCH 247/989] Qnx: Avoid capturing by reference Capture a pointer instead. Otherwise we might crash. Change-Id: I3d841299e44634e298d78ad8f5acb6e9588846f4 Reviewed-by: hjk --- src/plugins/qnx/slog2inforunner.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index 4cb635f0d2e..2346bc8caa4 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -52,11 +52,11 @@ void Slog2InfoRunner::start() const auto onLogSetup = [this](Process &process) { process.setCommand({device()->filePath("slog2info"), {"-w"}}); - connect(&process, &Process::readyReadStandardOutput, this, [&] { - processLogInput(QString::fromLatin1(process.readAllRawStandardOutput())); + connect(&process, &Process::readyReadStandardOutput, this, [this, processPtr = &process] { + processLogInput(QString::fromLatin1(processPtr->readAllRawStandardOutput())); }); - connect(&process, &Process::readyReadStandardError, this, [&] { - appendMessage(QString::fromLatin1(process.readAllRawStandardError()), StdErrFormat); + connect(&process, &Process::readyReadStandardError, this, [this, processPtr = &process] { + appendMessage(QString::fromLatin1(processPtr->readAllRawStandardError()), StdErrFormat); }); }; const auto onLogError = [this](const Process &process) { From 1d0e0a881530a5c0ef9b8e84497835a59c929088 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 21 Nov 2024 11:55:42 +0100 Subject: [PATCH 248/989] AppMan: Reuse setupPortsGatherer() Change-Id: I6f3d0d0f1c442aaae595db97f59569a999dc219e Reviewed-by: hjk --- src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 36c84e6c67a..95125318bbd 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -118,10 +118,7 @@ public: { setId("ApplicationManagerPlugin.Debug.Support"); - if (isCppDebugging()) - runControl->requestDebugChannel(); - if (isQmlDebugging()) - runControl->requestQmlChannel(); + setupPortsGatherer(); auto debuggee = createInferiorRunner(runControl, QmlDebuggerServices); From 0316d92b4779bf2ee454616b668905c9f71c7d8d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 18:26:57 +0100 Subject: [PATCH 249/989] RemoteLinux: Inline RemoteLinuxQmlToolingSupport Task-number: QTCREATORBUG-29168 Change-Id: I3d4665e8cc8846c762b9378536066b4d59221389 Reviewed-by: hjk --- .../remotelinux/remotelinuxdebugsupport.cpp | 46 ++++++++----------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp index 3a92ec267b7..69dec931378 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp @@ -18,32 +18,6 @@ using namespace Utils; namespace RemoteLinux::Internal { -class RemoteLinuxQmlToolingSupport final : public SimpleTargetRunner -{ -public: - explicit RemoteLinuxQmlToolingSupport(RunControl *runControl) - : SimpleTargetRunner(runControl) - { - setId("RemoteLinuxQmlToolingSupport"); - - runControl->requestQmlChannel(); - - auto runworker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); - runworker->addStartDependency(this); - addStopDependency(runworker); - - setStartModifier([this, runControl] { - QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); - - CommandLine cmd = commandLine(); - cmd.addArg(qmlDebugTcpArguments(services, qmlChannel())); - setCommandLine(cmd); - }); - } -}; - -// Factories - static const QList supportedRunConfigs() { return { @@ -99,7 +73,25 @@ class RemoteLinuxQmlToolingWorkerFactory final : public ProjectExplorer::RunWork public: RemoteLinuxQmlToolingWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + runControl->requestQmlChannel(); + + auto worker = new SimpleTargetRunner(runControl); + worker->setId("RemoteLinuxQmlToolingSupport"); + + auto runworker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); + runworker->addStartDependency(worker); + worker->addStopDependency(runworker); + + worker->setStartModifier([worker, runControl] { + QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); + + CommandLine cmd = worker->commandLine(); + cmd.addArg(qmlDebugTcpArguments(services, worker->qmlChannel())); + worker->setCommandLine(cmd); + }); + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); addSupportedRunMode(ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE); addSupportedDeviceType(Constants::GenericLinuxOsType); From 2092b7d80c39d29049d284b42ffe06130cc0ce9a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 17:59:19 +0100 Subject: [PATCH 250/989] QmlProfiler: Inline LocalQmlProfilerSupport Task-number: QTCREATORBUG-29168 Change-Id: I991529d42bbe5b75b3a0bc13baf7c64005d9e1bb Reviewed-by: hjk --- .../qmlprofiler/qmlprofilerruncontrol.cpp | 51 +++++-------------- .../qmlprofiler/qmlprofilerruncontrol.h | 11 +--- .../tests/localqmlprofilerrunner_test.cpp | 25 ++------- 3 files changed, 19 insertions(+), 68 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index 43666ab5ff1..ec416eb38d1 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -142,45 +142,20 @@ void QmlProfilerRunner::profilerStateChanged() } } -// -// LocalQmlProfilerSupport -// - -static QUrl localServerUrl(RunControl *runControl) +RunWorker *createLocalQmlProfilerWorker(RunControl *runControl) { - QUrl serverUrl; - Kit *kit = runControl->kit(); - const QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(kit); - if (version) { - if (version->qtVersion() >= QVersionNumber(5, 6, 0)) - serverUrl = Utils::urlFromLocalSocket(); - else - serverUrl = Utils::urlFromLocalHostAndFreePort(); - } else { - qWarning("Running QML profiler on Kit without Qt version?"); - serverUrl = Utils::urlFromLocalHostAndFreePort(); - } - return serverUrl; -} + auto worker = new SimpleTargetRunner(runControl); -LocalQmlProfilerSupport::LocalQmlProfilerSupport(RunControl *runControl) - : LocalQmlProfilerSupport(runControl, localServerUrl(runControl)) -{ -} - -LocalQmlProfilerSupport::LocalQmlProfilerSupport(RunControl *runControl, const QUrl &serverUrl) - : SimpleTargetRunner(runControl) -{ - setId("LocalQmlProfilerSupport"); + worker->setId("LocalQmlProfilerSupport"); auto profiler = new QmlProfilerRunner(runControl); - addStopDependency(profiler); + worker->addStopDependency(profiler); // We need to open the local server before the application tries to connect. // In the TCP case, it doesn't hurt either to start the profiler before. - addStartDependency(profiler); + worker->addStartDependency(profiler); - setStartModifier([this, runControl, serverUrl] { + worker->setStartModifier([worker, runControl] { QUrl serverUrl = runControl->qmlChannel(); QString code; @@ -192,16 +167,17 @@ LocalQmlProfilerSupport::LocalQmlProfilerSupport(RunControl *runControl, const Q QTC_CHECK(false); QString arguments = Utils::ProcessArgs::quoteArg( - qmlDebugCommandLineArguments(QmlProfilerServices, code, true)); + qmlDebugCommandLineArguments(QmlProfilerServices, code, true)); - Utils::CommandLine cmd = commandLine(); + Utils::CommandLine cmd = worker->commandLine(); const QString oldArgs = cmd.arguments(); cmd.setArguments(arguments); cmd.addArgs(oldArgs, Utils::CommandLine::Raw); - setCommandLine(cmd); - - forceRunOnHost(); + worker->setCommandLine(cmd); + worker->forceRunOnHost(); }); + + return worker; } // Factories @@ -224,7 +200,7 @@ public: LocalQmlProfilerRunWorkerFactory() { setId(ProjectExplorer::Constants::QML_PROFILER_RUN_FACTORY); - setProduct(); + setProducer(&createLocalQmlProfilerWorker); addSupportedRunMode(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); addSupportedDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE); @@ -238,5 +214,4 @@ void setupQmlProfilerRunning() static LocalQmlProfilerRunWorkerFactory theLocalQmlProfilerRunWorkerFactory; } - } // QmlProfiler::Internal diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h index 424d8e1afc4..dcc374c9892 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h @@ -37,16 +37,7 @@ private: QmlProfilerRunnerPrivate *d; }; -class LocalQmlProfilerSupport : public ProjectExplorer::SimpleTargetRunner -{ - Q_OBJECT - -public: - LocalQmlProfilerSupport(ProjectExplorer::RunControl *runControl); - LocalQmlProfilerSupport(ProjectExplorer::RunControl *runControl, - const QUrl &serverUrl); -}; - +ProjectExplorer::RunWorker *createLocalQmlProfilerWorker(ProjectExplorer::RunControl *runControl); void setupQmlProfilerRunning(); } // QmlProfiler::Internal diff --git a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp index a417775dbf6..94ea38a8fe7 100644 --- a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp +++ b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp @@ -29,8 +29,7 @@ LocalQmlProfilerRunnerTest::LocalQmlProfilerRunnerTest(QObject *parent) : QObjec void LocalQmlProfilerRunnerTest::testRunner() { QPointer runControl; - QPointer profiler; - QUrl serverUrl; + QPointer profiler; bool running = false; bool started = false; @@ -38,14 +37,10 @@ void LocalQmlProfilerRunnerTest::testRunner() int runCount = 0; int stopCount = 0; - // should not be used anywhere but cannot be empty - serverUrl.setScheme(Utils::urlSocketScheme()); - serverUrl.setPath("invalid"); - runControl = new RunControl(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); runControl->setCommandLine(CommandLine{"\\-/|\\-/"}); - profiler = new LocalQmlProfilerSupport(runControl, serverUrl); + profiler = createLocalQmlProfilerWorker(runControl); auto connectRunner = [&]() { connect(runControl, &RunControl::aboutToStart, this, [&] { @@ -85,13 +80,12 @@ void LocalQmlProfilerRunnerTest::testRunner() QTRY_VERIFY(runControl.isNull()); QVERIFY(profiler.isNull()); - serverUrl = Utils::urlFromLocalSocket(); // comma is used to specify a test function. In this case, an invalid one. runControl = new RunControl(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); const FilePath app = FilePath::fromString(QCoreApplication::applicationFilePath()); runControl->setCommandLine({app, {"-test", "QmlProfiler,"}}); - profiler = new LocalQmlProfilerSupport(runControl, serverUrl); + profiler = createLocalQmlProfilerWorker(runControl); connectRunner(); runControl->initiateStart(); @@ -106,11 +100,9 @@ void LocalQmlProfilerRunnerTest::testRunner() QTRY_VERIFY(runControl.isNull()); QVERIFY(profiler.isNull()); - serverUrl.clear(); - serverUrl = Utils::urlFromLocalHostAndFreePort(); runControl = new RunControl(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); runControl->setCommandLine(CommandLine{app}); - profiler = new LocalQmlProfilerSupport(runControl, serverUrl); + profiler = createLocalQmlProfilerWorker(runControl); connectRunner(); runControl->initiateStart(); @@ -126,16 +118,9 @@ void LocalQmlProfilerRunnerTest::testRunner() QTRY_VERIFY(runControl.isNull()); QVERIFY(profiler.isNull()); - serverUrl.setScheme(Utils::urlSocketScheme()); - { - Utils::TemporaryFile file("file with spaces"); - if (file.open()) - serverUrl.setPath(file.fileName()); - } - runControl = new RunControl(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); runControl->setCommandLine({app, {"-test", "QmlProfiler,"}}); - profiler = new LocalQmlProfilerSupport(runControl, serverUrl); + profiler = createLocalQmlProfilerWorker(runControl); connectRunner(); runControl->initiateStart(); From 5738d3c9f24294c9a3ec3d6b8e383ecce7d33ed8 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 20 Nov 2024 18:06:59 +0100 Subject: [PATCH 251/989] ProjectExplorer: Remove unused member from OutputParserTester It was never set and always compared against the empty string. Change-Id: I258b04f19d99eda40acaab0c7d884b257ea8325c Reviewed-by: Christian Stenger --- src/plugins/baremetal/iarewparser.cpp | 45 ++-- src/plugins/baremetal/keilparser.cpp | 69 ++---- src/plugins/baremetal/sdccparser.cpp | 45 ++-- .../cmakeautogenparser.cpp | 21 +- .../cmakeprojectmanager/cmakeoutputparser.cpp | 47 ++--- .../nim/project/nimoutputtaskparser.cpp | 18 +- src/plugins/projectexplorer/clangparser.cpp | 33 +-- src/plugins/projectexplorer/customparser.cpp | 71 ++----- src/plugins/projectexplorer/gccparser.cpp | 199 ++++++------------ src/plugins/projectexplorer/gnumakeparser.cpp | 23 +- .../projectexplorer/linuxiccparser.cpp | 27 +-- src/plugins/projectexplorer/msvcparser.cpp | 85 +++----- .../projectexplorer/outputparser_test.cpp | 10 +- .../projectexplorer/outputparser_test.h | 4 +- .../projectexplorer/sanitizerparser.cpp | 2 +- .../projectexplorer/xcodebuildparser.cpp | 19 +- .../qmakeprojectmanager/qmakeparser.cpp | 31 +-- src/plugins/qtsupport/qtparser.cpp | 47 ++--- src/plugins/qtsupport/qttestparser.cpp | 2 +- 19 files changed, 242 insertions(+), 556 deletions(-) diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp index 0cc4117d012..ed548692593 100644 --- a/src/plugins/baremetal/iarewparser.cpp +++ b/src/plugins/baremetal/iarewparser.cpp @@ -247,18 +247,15 @@ void IarParserTest::testIarOutputParsers_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT << "Sometext\n" << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR << QString() << "Sometext\n" - << Tasks() - << QString(); + << Tasks(); // For std out. QTest::newRow("Error in command line") @@ -267,8 +264,7 @@ void IarParserTest::testIarOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "Error in command line: Some error")) - << QString(); + "Error in command line: Some error")); QTest::newRow("Linker error") << QString::fromLatin1("Error[e46]: Some error") @@ -276,8 +272,7 @@ void IarParserTest::testIarOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "[e46]: Some error")) - << QString(); + "[e46]: Some error")); // For std error. QTest::newRow("No details warning") @@ -289,8 +284,7 @@ void IarParserTest::testIarOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "[Pe223]: Some warning \"foo\" bar", Utils::FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("Details warning") << QString::fromLatin1(" some_detail;\n" @@ -305,8 +299,7 @@ void IarParserTest::testIarOutputParsers_data() " some_detail;\n" " ^", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("No details split-description warning") << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n" @@ -318,8 +311,7 @@ void IarParserTest::testIarOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "[Pe223]: Some warning, split", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("No details error") << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n" @@ -330,8 +322,7 @@ void IarParserTest::testIarOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "[Pe223]: Some error", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("Details error") << QString::fromLatin1(" some_detail;\n" @@ -346,8 +337,7 @@ void IarParserTest::testIarOutputParsers_data() " some_detail;\n" " ^", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("No details split-description error") << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n" @@ -359,8 +349,7 @@ void IarParserTest::testIarOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "[Pe223]: Some error, split", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("No definition for") << QString::fromLatin1("Error[Li005]: Some error \"foo\" [referenced from c:\\fo\n" @@ -372,8 +361,7 @@ void IarParserTest::testIarOutputParsers_data() << QString() << (Tasks() << CompileTask(Task::Error, "[Li005]: Some error \"foo\"", - FilePath::fromUserInput("c:\\foo\\bar\\main.c.o"))) - << QString(); + FilePath::fromUserInput("c:\\foo\\bar\\main.c.o"))); QTest::newRow("More than one source file specified") << QString::fromLatin1("Fatal error[Su011]: Some error:\n" @@ -386,8 +374,7 @@ void IarParserTest::testIarOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "[Su011]: Some error:\n" " c:\\foo.c\n" - " c:\\bar.c")) - << QString(); + " c:\\bar.c")); QTest::newRow("At end of source") << QString::fromLatin1("At end of source Error[Pe040]: Some error \";\"") @@ -395,8 +382,7 @@ void IarParserTest::testIarOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "[Pe040]: Some error \";\"")) - << QString(); + "[Pe040]: Some error \";\"")); } void IarParserTest::testIarOutputParsers() @@ -408,11 +394,8 @@ void IarParserTest::testIarOutputParsers() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } QObject *createIarParserTest() diff --git a/src/plugins/baremetal/keilparser.cpp b/src/plugins/baremetal/keilparser.cpp index 5a5df91ccc7..8f962a205c0 100644 --- a/src/plugins/baremetal/keilparser.cpp +++ b/src/plugins/baremetal/keilparser.cpp @@ -269,18 +269,15 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT << "Sometext\n" << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR << QString() << "Sometext\n" - << Tasks() - << QString(); + << Tasks(); // ARM compiler specific patterns. @@ -292,8 +289,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "#1234: Some warning", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("ARM: Details warning") << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning\n" @@ -307,8 +303,7 @@ void KeilParserTest::testKeilOutputParsers_data() " int f;\n" " ^", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("ARM: No details error") << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error") @@ -318,8 +313,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "#1234: Some error", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("ARM: No details error with column") << QString::fromLatin1("\"flash.sct\", line 51 (column 20): Error: L1234: Some error") @@ -329,8 +323,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "L1234: Some error", FilePath::fromUserInput("flash.sct"), - 51)) - << QString(); + 51)); QTest::newRow("ARM: Details error") << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error\n" @@ -344,8 +337,7 @@ void KeilParserTest::testKeilOutputParsers_data() " int f;\n" " ^", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("ARM: At end of source") << QString::fromLatin1("\"c:\\foo\\main.c\", line 71: Error: At end of source: #40: Some error") @@ -355,8 +347,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "#40: Some error", FilePath::fromUserInput("c:\\foo\\main.c"), - 71)) - << QString(); + 71)); QTest::newRow("ARM: Starts with error") << QString::fromLatin1("Error: L6226E: Some error.") @@ -364,8 +355,7 @@ void KeilParserTest::testKeilOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "L6226E: Some error.")) - << QString(); + "L6226E: Some error.")); // MCS51 compiler specific patterns. @@ -378,8 +368,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "#A9: Some warning", FilePath::fromUserInput("c:\\foo\\dscr.a51"), - 15)) - << QString(); + 15)); QTest::newRow("MCS51: Assembler simple error") << QString::fromLatin1("*** ERROR #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some error") @@ -389,8 +378,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "#A9: Some error", FilePath::fromUserInput("c:\\foo\\dscr.a51"), - 15)) - << QString(); + 15)); QTest::newRow("MCS51: Assembler fatal error") << QString::fromLatin1("A51 FATAL ERROR -\n" @@ -402,8 +390,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "Assembler fatal error\n" " Some detail 1\n" - " Some detail N")) - << QString(); + " Some detail N")); QTest::newRow("MCS51: Assembler details error") << QString::fromLatin1("01AF Some detail\n" @@ -417,8 +404,7 @@ void KeilParserTest::testKeilOutputParsers_data() " Some detail\n" " ___^", FilePath::fromUserInput("d:\\foo.a51"), - 28)) - << QString(); + 28)); // Compiler messages. QTest::newRow("MCS51: Compiler simple warning") @@ -429,8 +415,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "C123: Some warning", FilePath::fromUserInput("c:\\foo.c"), - 13)) - << QString(); + 13)); QTest::newRow("MCS51: Compiler extended warning") << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning : 'extended text'") @@ -440,8 +425,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "C123: Some warning : 'extended text'", FilePath::fromUserInput("c:\\foo.c"), - 13)) - << QString(); + 13)); QTest::newRow("MCS51: Compiler simple error") << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error") @@ -451,8 +435,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "C123: Some error", FilePath::fromUserInput("c:\\foo.c"), - 13)) - << QString(); + 13)); QTest::newRow("MCS51: Compiler extended error") << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error : 'extended text'") @@ -462,8 +445,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "C123: Some error : 'extended text'", FilePath::fromUserInput("c:\\foo.c"), - 13)) - << QString(); + 13)); QTest::newRow("MCS51: Compiler fatal error") << QString::fromLatin1("C51 FATAL-ERROR -\n" @@ -475,8 +457,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "Compiler fatal error\n" " Some detail 1\n" - " Some detail N")) - << QString(); + " Some detail N")); // Linker messages. QTest::newRow("MCS51: Linker warning") @@ -487,8 +468,7 @@ void KeilParserTest::testKeilOutputParsers_data() << QString() << (Tasks() << CompileTask(Task::Warning, "L16: Some warning\n" - " Some detail 1")) - << QString(); + " Some detail 1")); QTest::newRow("MCS51: Linker simple fatal error") << QString::fromLatin1("*** FATAL ERROR L456: Some error") @@ -496,8 +476,7 @@ void KeilParserTest::testKeilOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "L456: Some error")) - << QString(); + "L456: Some error")); QTest::newRow("MCS51: Linker extended fatal error") << QString::fromLatin1("*** FATAL ERROR L456: Some error\n" @@ -509,8 +488,7 @@ void KeilParserTest::testKeilOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "L456: Some error\n" " Some detail 1\n" - " Some detail N")) - << QString(); + " Some detail N")); } void KeilParserTest::testKeilOutputParsers() @@ -522,11 +500,8 @@ void KeilParserTest::testKeilOutputParsers() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } QObject *createKeilParserTest() diff --git a/src/plugins/baremetal/sdccparser.cpp b/src/plugins/baremetal/sdccparser.cpp index 517f051390b..37a020a800d 100644 --- a/src/plugins/baremetal/sdccparser.cpp +++ b/src/plugins/baremetal/sdccparser.cpp @@ -162,18 +162,15 @@ void SdccParserTest::testSdccOutputParsers_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT << "Sometext\n" << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR << QString() << "Sometext\n" - << Tasks() - << QString(); + << Tasks(); // Compiler messages. @@ -185,8 +182,7 @@ void SdccParserTest::testSdccOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "Some error", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("Compiler single line warning") << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning") @@ -196,8 +192,7 @@ void SdccParserTest::testSdccOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "Some warning", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("Compiler multi line warning") << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning\n" @@ -211,8 +206,7 @@ void SdccParserTest::testSdccOutputParsers_data() "details #1\n" " details #2", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("Compiler simple single line error") << QString::fromLatin1("c:\\foo\\main.c:63: error: Some error") @@ -222,8 +216,7 @@ void SdccParserTest::testSdccOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "Some error", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("Compiler single line error") << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error") @@ -233,8 +226,7 @@ void SdccParserTest::testSdccOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "Some error", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("Compiler multi line error") << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error\n" @@ -248,8 +240,7 @@ void SdccParserTest::testSdccOutputParsers_data() "details #1\n" " details #2", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("Compiler syntax error") << QString::fromLatin1("c:\\foo\\main.c:63: syntax error: Some error") @@ -259,8 +250,7 @@ void SdccParserTest::testSdccOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "Some error", FilePath::fromUserInput("c:\\foo\\main.c"), - 63)) - << QString(); + 63)); QTest::newRow("Compiler bad option error") << QString::fromLatin1("at 1: error 123: Some error") @@ -268,8 +258,7 @@ void SdccParserTest::testSdccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "Some error")) - << QString(); + "Some error")); QTest::newRow("Compiler bad option warning") << QString::fromLatin1("at 1: warning 123: Some warning") @@ -277,8 +266,7 @@ void SdccParserTest::testSdccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Warning, - "Some warning")) - << QString(); + "Some warning")); QTest::newRow("Linker warning") << QString::fromLatin1("?ASlink-Warning-Couldn't find library 'foo.lib'") @@ -286,8 +274,7 @@ void SdccParserTest::testSdccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Warning, - "Couldn't find library 'foo.lib'")) - << QString(); + "Couldn't find library 'foo.lib'")); QTest::newRow("Linker error") << QString::fromLatin1("?ASlink-Error- : \"foo.rel\"") @@ -295,8 +282,7 @@ void SdccParserTest::testSdccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - " : \"foo.rel\"")) - << QString(); + " : \"foo.rel\"")); } void SdccParserTest::testSdccOutputParsers() @@ -308,11 +294,8 @@ void SdccParserTest::testSdccOutputParsers() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } QObject *createSdccParserTest() diff --git a/src/plugins/cmakeprojectmanager/cmakeautogenparser.cpp b/src/plugins/cmakeprojectmanager/cmakeautogenparser.cpp index 2d5d97f5f7b..2211432449b 100644 --- a/src/plugins/cmakeprojectmanager/cmakeautogenparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeautogenparser.cpp @@ -119,15 +119,14 @@ void CMakeAutogenParserTest::testCMakeAutogenParser_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); // negative tests QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() << Tasks() << QString(); + << QString::fromLatin1("Sometext\n") << QString() << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() - << QString::fromLatin1("Sometext\n") << Tasks() << QString(); + << QString::fromLatin1("Sometext\n") << Tasks(); // positive tests QTest::newRow("AutoMoc error") << R"(AutoMoc error @@ -145,8 +144,7 @@ Consider to contains a "Q_OBJECT" macro, but does not include "main.moc"! Consider to - add #include "main.moc" - - enable SKIP_AUTOMOC for this file)")) - << QString(); + - enable SKIP_AUTOMOC for this file)")); QTest::newRow("AutoMoc subprocess error") << R"(AutoMoc subprocess error ------------------------ @@ -167,7 +165,7 @@ into "BIN:/src/quickcontrols/basic/impl/qtquickcontrols2basicstyleimplplugin_autogen/include/qtquickcontrols2basicstyleimplplugin_QtQuickControls2BasicStyleImplPlugin.moc" included by "BIN:/src/quickcontrols/basic/impl/qtquickcontrols2basicstyleimplplugin_QtQuickControls2BasicStyleImplPlugin.cpp" -Process failed with return value 1)")) << QString(); +Process failed with return value 1)")); QTest::newRow("AUTOMOC: warning:") << R"(AUTOMOC: warning: /home/alex/src/CMake/tests/solid.orig/solid/solid/device.cpp: The file @@ -183,7 +181,7 @@ CMAKE_AUTOMOC_RELAXED_MODE).)" << OutputParserTester::STDERR includes the moc file "device_p.moc" instead of "moc_device_p.cpp". Running moc on "/home/alex/src/CMake/tests/solid.orig/solid/solid/device_p.h" ! Include "moc_device_p.cpp" for compatibility with strict mode (see -CMAKE_AUTOMOC_RELAXED_MODE).)")) << QString(); +CMAKE_AUTOMOC_RELAXED_MODE).)")); QTest::newRow("AutoMoc warning") << R"(AutoMoc warning --------------- @@ -194,8 +192,7 @@ includes the moc file "main.moc", but does not contain a Q_OBJECT, Q_GADGET, Q_N Task::Warning, R"(AutoMoc warning "SRC:/src/main.cpp" -includes the moc file "main.moc", but does not contain a Q_OBJECT, Q_GADGET, Q_NAMESPACE, Q_NAMESPACE_EXPORT, Q_GADGET_EXPORT, Q_ENUM_NS, K_PLUGIN_FACTORY, K_PLUGIN_CLASS, K_PLUGIN_FACTORY_WITH_JSON or K_PLUGIN_CLASS_WITH_JSON macro.)")) - << QString(); +includes the moc file "main.moc", but does not contain a Q_OBJECT, Q_GADGET, Q_NAMESPACE, Q_NAMESPACE_EXPORT, Q_GADGET_EXPORT, Q_ENUM_NS, K_PLUGIN_FACTORY, K_PLUGIN_CLASS, K_PLUGIN_FACTORY_WITH_JSON or K_PLUGIN_CLASS_WITH_JSON macro.)")); QTest::newRow("AutoUic error") << R"(AutoUic error ------------- @@ -212,7 +209,7 @@ could not be found in the following directories includes the uic file "ui_global.h", but the user interface file "global.ui" could not be found in the following directories - "SRC:/monitor/ui")")) << QString(); + "SRC:/monitor/ui")")); } void CMakeAutogenParserTest::testCMakeAutogenParser() @@ -224,10 +221,8 @@ void CMakeAutogenParserTest::testCMakeAutogenParser() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench - .testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines, outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } QObject *createCMakeAutogenParserTest() diff --git a/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp b/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp index e8865fc9f80..63cd8ae8f0a 100644 --- a/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp @@ -276,19 +276,16 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); // negative tests QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString::fromLatin1("Sometext\n") << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString::fromLatin1("Sometext\n") - << Tasks() - << QString(); + << Tasks(); // positive tests QTest::newRow("add custom target") @@ -317,8 +314,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() "Tried extensions " ".c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp\n" ".hxx .in .txx", - FilePath::fromUserInput("src/1/app/CMakeLists.txt"), -1)) - << QString(); + FilePath::fromUserInput("src/1/app/CMakeLists.txt"), -1)); QTest::newRow("add subdirectory") << QString::fromLatin1("CMake Error at src/1/CMakeLists.txt:8 (add_subdirectory):\n" @@ -328,8 +324,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << (Tasks() << BuildSystemTask(Task::Error, "add_subdirectory given source \"app1\" which is not an existing directory.", - FilePath::fromUserInput("src/1/CMakeLists.txt"), 8)) - << QString(); + FilePath::fromUserInput("src/1/CMakeLists.txt"), 8)); QTest::newRow("unknown command") << QString::fromLatin1("CMake Error at src/1/CMakeLists.txt:8 (i_am_wrong_command):\n" @@ -339,8 +334,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << (Tasks() << BuildSystemTask(Task::Error, "Unknown CMake command \"i_am_wrong_command\".", - FilePath::fromUserInput("src/1/CMakeLists.txt"), 8)) - << QString(); + FilePath::fromUserInput("src/1/CMakeLists.txt"), 8)); QTest::newRow("incorrect arguments") << QString::fromLatin1("CMake Error at src/1/CMakeLists.txt:8 (message):\n" @@ -350,8 +344,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << (Tasks() << BuildSystemTask(Task::Error, "message called with incorrect number of arguments", - FilePath::fromUserInput("src/1/CMakeLists.txt"), 8)) - << QString(); + FilePath::fromUserInput("src/1/CMakeLists.txt"), 8)); QTest::newRow("cmake error") << QString::fromLatin1("CMake Error: Error in cmake code at\n" @@ -363,8 +356,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << (Tasks() << BuildSystemTask(Task::Error, "Parse error. Expected \"(\", got newline with text \"\n\".", - FilePath::fromUserInput("/test/path/CMakeLists.txt"), 9)) - << QString(); + FilePath::fromUserInput("/test/path/CMakeLists.txt"), 9)); QTest::newRow("cmake error2") << QString::fromLatin1("CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.\n" @@ -375,8 +367,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << (Tasks() << BuildSystemTask(Task::Error, "Error required internal CMake variable not set, " - "cmake may be not be built correctly.")) - << QString(); + "cmake may be not be built correctly.")); QTest::newRow("cmake error at") << QString::fromLatin1("CMake Error at CMakeLists.txt:4:\n" @@ -390,8 +381,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() "Parse error. Expected \"(\", got newline with text \"\n" "\n" "\".", - FilePath::fromUserInput("CMakeLists.txt"), 4)) - << QString(); + FilePath::fromUserInput("CMakeLists.txt"), 4)); QTest::newRow("cmake syntax warning") << QString::fromLatin1("Syntax Warning in cmake code at\n" @@ -402,8 +392,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << (Tasks() << BuildSystemTask(Task::Warning, "Argument not separated from preceding token by whitespace.", - FilePath::fromUserInput("/test/path/CMakeLists.txt"), 9)) - << QString(); + FilePath::fromUserInput("/test/path/CMakeLists.txt"), 9)); QTest::newRow("cmake warning") << QString::fromLatin1("CMake Warning at CMakeLists.txt:13 (message):\n" @@ -413,8 +402,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << (Tasks() << BuildSystemTask(Task::Warning, "this is a warning", - FilePath::fromUserInput("CMakeLists.txt"), 13)) - << QString(); + FilePath::fromUserInput("CMakeLists.txt"), 13)); QTest::newRow("cmake author warning") << QString::fromLatin1("CMake Warning (dev) at CMakeLists.txt:15 (message):\n" @@ -424,13 +412,12 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << (Tasks() << BuildSystemTask(Task::Warning, "this is an author warning", - FilePath::fromUserInput("CMakeLists.txt"), 15)) - << QString(); + FilePath::fromUserInput("CMakeLists.txt"), 15)); QTest::newRow("eat normal CMake output") << QString::fromLatin1("-- Qt5 install prefix: /usr/lib\n" " * Plugin componentsplugin, with CONDITION TARGET QmlDesigner") - << OutputParserTester::STDERR << QString() << QString() << (Tasks()) << QString(); + << OutputParserTester::STDERR << QString() << QString() << (Tasks()); QTest::newRow("cmake call-stack") << QString::fromLatin1( @@ -471,8 +458,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() " /Qt/6.5.3/mingw_64/lib/cmake/Qt6Core/Qt6CoreMacros.cmake:588 " "(add_executable)", FilePath::fromUserInput("/Projects/Test-Project/CMakeLists.txt"), - 13)) - << QString(); + 13)); } void CMakeOutputParserTest::testCMakeOutputParser() @@ -484,11 +470,8 @@ void CMakeOutputParserTest::testCMakeOutputParser() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } QObject *createCMakeOutputParserTest() diff --git a/src/plugins/nim/project/nimoutputtaskparser.cpp b/src/plugins/nim/project/nimoutputtaskparser.cpp index 1fde71d3c21..90fb0009752 100644 --- a/src/plugins/nim/project/nimoutputtaskparser.cpp +++ b/src/plugins/nim/project/nimoutputtaskparser.cpp @@ -61,19 +61,16 @@ void NimParserTest::testNimParser_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); // negative tests QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT << "Sometext\n" << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR << QString() << "Sometext\n" - << Tasks() - << QString(); + << Tasks(); // positive tests QTest::newRow("Parse error string") @@ -82,8 +79,7 @@ void NimParserTest::testNimParser_data() << QString() << QString() << Tasks({CompileTask(Task::Error, "Error: undeclared identifier: 'x'", - FilePath::fromUserInput("main.nim"), 23)}) - << QString(); + FilePath::fromUserInput("main.nim"), 23)}); QTest::newRow("Parse warning string") << QString::fromLatin1("lib/pure/parseopt.nim(56, 34) Warning: quoteIfContainsWhite is deprecated [Deprecated]") @@ -91,8 +87,7 @@ void NimParserTest::testNimParser_data() << QString() << QString() << Tasks({CompileTask(Task::Warning, "Warning: quoteIfContainsWhite is deprecated [Deprecated]", - FilePath::fromUserInput("lib/pure/parseopt.nim"), 56)}) - << QString(); + FilePath::fromUserInput("lib/pure/parseopt.nim"), 56)}); } void NimParserTest::testNimParser() @@ -104,11 +99,8 @@ void NimParserTest::testNimParser() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } } // Nim diff --git a/src/plugins/projectexplorer/clangparser.cpp b/src/plugins/projectexplorer/clangparser.cpp index 05bcc3e0aa2..98fd61f5f91 100644 --- a/src/plugins/projectexplorer/clangparser.cpp +++ b/src/plugins/projectexplorer/clangparser.cpp @@ -129,7 +129,6 @@ void ProjectExplorerTest::testClangOutputParser_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); auto compileTask = [](Task::TaskType type, const QString &description, @@ -154,14 +153,12 @@ void ProjectExplorerTest::testClangOutputParser_data() QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString::fromLatin1("Sometext\n") << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString::fromLatin1("Sometext\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("clang++ warning") << QString::fromLatin1("clang++: warning: argument unused during compilation: '-mthreads'") @@ -169,8 +166,7 @@ void ProjectExplorerTest::testClangOutputParser_data() << QString() << QString() << (Tasks() << CompileTask(Task::Warning, - "argument unused during compilation: '-mthreads'")) - << QString(); + "argument unused during compilation: '-mthreads'")); QTest::newRow("clang++ error") << QString::fromLatin1("clang++: error: no input files [err_drv_no_input_files]") @@ -178,8 +174,7 @@ void ProjectExplorerTest::testClangOutputParser_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "no input files [err_drv_no_input_files]")) - << QString(); + "no input files [err_drv_no_input_files]")); QTest::newRow("complex warning") << QString::fromLatin1("In file included from ..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qnamespace.h:45:\n" @@ -198,8 +193,7 @@ void ProjectExplorerTest::testClangOutputParser_data() FilePath::fromUserInput("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h"), 1425, 0, QVector() - << formatRange(61, 278))} - << QString(); + << formatRange(61, 278))}; QTest::newRow("note") << QString::fromLatin1("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h:1289:27: note: instantiated from:\n" @@ -216,8 +210,7 @@ void ProjectExplorerTest::testClangOutputParser_data() FilePath::fromUserInput("..\\..\\..\\QtSDK1.1\\Desktop\\Qt\\4.7.3\\mingw\\include/QtCore/qglobal.h"), 1289, 27, QVector() - << formatRange(19, 167))) - << QString(); + << formatRange(19, 167))); QTest::newRow("fatal error") << QString::fromLatin1("/usr/include/c++/4.6/utility:68:10: fatal error: 'bits/c++config.h' file not found\n" @@ -236,8 +229,7 @@ void ProjectExplorerTest::testClangOutputParser_data() QVector() << formatRange(34, 0) << formatRange(34, 28, "olpfile:///usr/include/c++/4.6/utility::68::10") - << formatRange(62, 93))) - << QString(); + << formatRange(62, 93))); QTest::newRow("line confusion") << QString::fromLatin1("/home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp:567:51: warning: ?: has lower precedence than +; + will be evaluated first [-Wparentheses]\n" @@ -256,8 +248,7 @@ void ProjectExplorerTest::testClangOutputParser_data() QVector() << formatRange(74, 0) << formatRange(74, 64, "olpfile:///home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp::567::51") - << formatRange(138, 202))) - << QString(); + << formatRange(138, 202))); QTest::newRow("code sign error") << QString::fromLatin1("Check dependencies\n" @@ -269,8 +260,7 @@ void ProjectExplorerTest::testClangOutputParser_data() << CompileTask(Task::Error, "No matching provisioning profiles found: No provisioning profiles with a valid signing identity (i.e. certificate and private key pair) were found.") << CompileTask(Task::Error, - "code signing is required for product type 'Application' in SDK 'iOS 7.0'")) - << QString(); + "code signing is required for product type 'Application' in SDK 'iOS 7.0'")); } void ProjectExplorerTest::testClangOutputParser() @@ -282,11 +272,8 @@ void ProjectExplorerTest::testClangOutputParser() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } } // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp index 0e2a360af11..1a245c6b454 100644 --- a/src/plugins/projectexplorer/customparser.cpp +++ b/src/plugins/projectexplorer/customparser.cpp @@ -389,8 +389,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << QString() << 1 << 2 << 3 << QString() << 1 << 2 << 3 << QString::fromLatin1("Sometext\n") << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") @@ -400,8 +399,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern << 1 << 2 << 3 << QString() << 1 << 2 << 3 << QString::fromLatin1("Sometext\n") << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") @@ -411,8 +409,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern << 1 << 2 << 3 << QString() << 1 << 2 << 3 << QString() << QString::fromLatin1("Sometext\n") - << Tasks() - << QString(); + << Tasks(); const QString simpleError = "main.c:9: error: `sfasdf' undeclared (first use this function)"; const QString simpleErrorPassThrough = simpleError + '\n'; @@ -426,8 +423,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 << QString() << QString() - << Tasks({CompileTask(Task::Error, message, fileName, 9)}) - << QString(); + << Tasks({CompileTask(Task::Error, message, fileName, 9)}); const QString pathPattern = "^([a-z\\./]+):(\\d+): error: ([^\\s].+)$"; QString workingDir = "/home/src/project"; @@ -441,8 +437,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << pathPattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 << QString() << QString() - << Tasks({CompileTask(Task::Error, message, expandedFileName, 9)}) - << QString(); + << Tasks({CompileTask(Task::Error, message, expandedFileName, 9)}); expandedFileName = "/home/src/project/subdir/main.c"; QTest::newRow("simple error with subdir path") @@ -453,8 +448,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << pathPattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 << QString() << QString() - << Tasks({CompileTask(Task::Error, message, expandedFileName, 9)}) - << QString(); + << Tasks({CompileTask(Task::Error, message, expandedFileName, 9)}); workingDir = "/home/src/build-project"; QTest::newRow("simple error with buildir path") @@ -465,8 +459,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << pathPattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 << QString() << QString() - << Tasks({CompileTask(Task::Error, message, expandedFileName, 9)}) - << QString(); + << Tasks({CompileTask(Task::Error, message, expandedFileName, 9)}); QTest::newRow("simple error on wrong channel") << simpleError @@ -476,8 +469,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 << simpleErrorPassThrough << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("simple error on other wrong channel") << simpleError @@ -487,8 +479,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 << QString() << simpleErrorPassThrough - << Tasks() - << QString(); + << Tasks(); const QString simpleError2 = "Error: Line 19 in main.c: `sfasdf' undeclared (first use this function)"; const QString simplePattern2 = "^Error: Line (\\d+) in ([a-z]+\\.[a-z]+): ([^\\s].+)$"; @@ -502,8 +493,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern2 << 2 << 1 << 3 << QString() << 1 << 2 << 3 << QString() << QString() - << Tasks({CompileTask(Task::Error, message, fileName, lineNumber2)}) - << QString(); + << Tasks({CompileTask(Task::Error, message, fileName, lineNumber2)}); QTest::newRow("another simple error on stdout") << simpleError2 @@ -513,8 +503,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern2 << 2 << 1 << 3 << QString() << 1 << 2 << 3 << QString() << QString() - << Tasks({CompileTask(Task::Error, message, fileName, lineNumber2)}) - << QString(); + << Tasks({CompileTask(Task::Error, message, fileName, lineNumber2)}); const QString simpleWarningPattern = "^([a-z]+\\.[a-z]+):(\\d+): warning: ([^\\s].+)$"; const QString simpleWarning = "main.c:1234: warning: `helloWorld' declared but not used"; @@ -528,8 +517,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << QString() << 1 << 2 << 3 << simpleWarningPattern << 1 << 2 << 3 << QString() << QString() - << Tasks({CompileTask(Task::Warning, warningMessage, fileName, 1234)}) - << QString(); + << Tasks({CompileTask(Task::Warning, warningMessage, fileName, 1234)}); const QString simpleWarning2 = "Warning: `helloWorld' declared but not used (main.c:19)"; const QString simpleWarningPassThrough2 = simpleWarning2 + '\n'; @@ -543,8 +531,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern2 << 1 << 2 << 3 << simpleWarningPattern2 << 2 << 3 << 1 << QString() << QString() - << Tasks({CompileTask(Task::Warning, warningMessage, fileName, lineNumber2)}) - << QString(); + << Tasks({CompileTask(Task::Warning, warningMessage, fileName, lineNumber2)}); QTest::newRow("warning on wrong channel") << simpleWarning2 @@ -554,8 +541,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << QString() << 1 << 2 << 3 << simpleWarningPattern2 << 2 << 3 << 1 << simpleWarningPassThrough2 << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("warning on other wrong channel") << simpleWarning2 @@ -565,8 +551,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << QString() << 1 << 2 << 3 << simpleWarningPattern2 << 2 << 3 << 1 << QString() << simpleWarningPassThrough2 - << Tasks() - << QString(); + << Tasks(); QTest::newRow("error and *warning*") << simpleWarning @@ -576,8 +561,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern << 1 << 2 << 3 << simpleWarningPattern << 1 << 2 << 3 << QString() << QString() - << Tasks({CompileTask(Task::Warning, warningMessage, fileName, 1234)}) - << QString(); + << Tasks({CompileTask(Task::Warning, warningMessage, fileName, 1234)}); QTest::newRow("*error* when equal pattern") << simpleError @@ -587,8 +571,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << simplePattern << 1 << 2 << 3 << simplePattern << 1 << 2 << 3 << QString() << QString() - << Tasks({CompileTask(Task::Error, message, fileName, 9)}) - << QString(); + << Tasks({CompileTask(Task::Error, message, fileName, 9)}); const QString unitTestError = "../LedDriver/LedDriverTest.c:63: FAIL: Expected 0x0080 Was 0xffff"; const FilePath unitTestFileName = FilePath::fromUserInput("../LedDriver/LedDriverTest.c"); @@ -604,8 +587,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << unitTestPattern << 1 << 2 << 3 << QString() << 1 << 2 << 3 << QString() << QString() - << Tasks({CompileTask(Task::Error, unitTestMessage, unitTestFileName, unitTestLineNumber)}) - << QString(); + << Tasks({CompileTask(Task::Error, unitTestMessage, unitTestFileName, unitTestLineNumber)}); const QString leadingSpacesPattern = "^ MESSAGE:(.+)"; const QString leadingSpacesMessage = " MESSAGE:Error"; @@ -619,8 +601,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << leadingSpacesPattern << 2 << 3 << 1 << QString() << 1 << 2 << 3 << QString() << QString() - << Tasks({CompileTask(Task::Error, "Error", {}, -1)}) - << QString(); + << Tasks({CompileTask(Task::Error, "Error", {}, -1)}); QTest::newRow("leading spaces: no match") << noLeadingSpacesMessage << QString() @@ -630,8 +611,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << leadingSpacesPattern << 2 << 3 << 1 << QString() << 1 << 2 << 3 << (noLeadingSpacesMessage + '\n') << QString() - << Tasks() - << QString(); + << Tasks(); const QString noLeadingSpacesPattern = "^MESSAGE:(.+)"; QTest::newRow("no leading spaces: match") << noLeadingSpacesMessage @@ -642,8 +622,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << noLeadingSpacesPattern << 2 << 3 << 1 << QString() << 1 << 2 << 3 << QString() << QString() - << Tasks({CompileTask(Task::Error, "Error", {}, -1)}) - << QString(); + << Tasks({CompileTask(Task::Error, "Error", {}, -1)}); QTest::newRow("no leading spaces: no match") << leadingSpacesMessage << QString() @@ -653,8 +632,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << noLeadingSpacesPattern << 3 << 2 << 1 << QString() << 1 << 2 << 3 << (leadingSpacesMessage + '\n') << QString() - << Tasks() - << QString(); + << Tasks(); } void ProjectExplorerTest::testCustomOutputParsers() @@ -675,7 +653,6 @@ void ProjectExplorerTest::testCustomOutputParsers() QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); QFETCH(Tasks, tasks); - QFETCH(QString, outputLines); CustomParserSettings settings; settings.error.setPattern(errorPattern); @@ -696,9 +673,7 @@ void ProjectExplorerTest::testCustomOutputParsers() OutputParserTester testbench; testbench.addLineParser(parser); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } #endif diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp index 7c9825df192..15ef7a8a54b 100644 --- a/src/plugins/projectexplorer/gccparser.cpp +++ b/src/plugins/projectexplorer/gccparser.cpp @@ -295,7 +295,6 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); auto compileTask = [](Task::TaskType type, const QString &description, @@ -320,20 +319,17 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString::fromLatin1("Sometext\n") << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString::fromLatin1("Sometext\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("ar output") << QString::fromLatin1("../../../../x86/i686-unknown-linux-gnu/bin/i686-unknown-linux-gnu-ar: creating lib/libSkyView.a") << OutputParserTester::STDERR << QString() << QString::fromLatin1("../../../../x86/i686-unknown-linux-gnu/bin/i686-unknown-linux-gnu-ar: creating lib/libSkyView.a\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("GCCE error") << QString::fromLatin1("/temp/test/untitled8/main.cpp: In function `int main(int, char**)':\n" @@ -357,8 +353,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Error, "(Each undeclared identifier is reported only once for each function it appears in.)", FilePath::fromUserInput("/temp/test/untitled8/main.cpp"), - 9, 0)) - << QString(); + 9, 0)); QTest::newRow("GCCE warning") << QString::fromLatin1("/src/corelib/global/qglobal.h:1635: warning: inline function `QDebug qDebug()' used but never defined") @@ -368,8 +363,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Warning, "inline function `QDebug qDebug()' used but never defined", FilePath::fromUserInput("/src/corelib/global/qglobal.h"), - 1635, 0)) - << QString(); + 1635, 0)); QTest::newRow("warning") << QString::fromLatin1("main.cpp:7:2: warning: Some warning") @@ -379,8 +373,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Warning, "Some warning", FilePath::fromUserInput("main.cpp"), - 7, 2)) - << QString(); + 7, 2)); QTest::newRow("GCCE #error") << QString::fromLatin1("C:\\temp\\test\\untitled8\\main.cpp:7: #error Symbian error") @@ -390,8 +383,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Error, "#error Symbian error", FilePath::fromUserInput("C:\\temp\\test\\untitled8\\main.cpp"), - 7, 0)) - << QString(); + 7, 0)); // Symbian reports #warning(s) twice (using different syntax). QTest::newRow("GCCE #warning1") @@ -402,8 +394,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Warning, "#warning Symbian warning", FilePath::fromUserInput("C:\\temp\\test\\untitled8\\main.cpp"), - 8, 0)) - << QString(); + 8, 0)); QTest::newRow("GCCE #warning2") << QString::fromLatin1("/temp/test/untitled8/main.cpp:8:2: warning: #warning Symbian warning") @@ -413,8 +404,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Warning, "#warning Symbian warning", FilePath::fromUserInput("/temp/test/untitled8/main.cpp"), - 8, 2)) - << QString(); + 8, 2)); QVector formatRanges; if (HostOsInfo::isWindowsHost()) { @@ -438,8 +428,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("C:\\temp\\test\\untitled8/main.cpp"), 8, 0, formatRanges) - << CompileTask(Task::Error, "collect2: ld returned 1 exit status")) - << QString(); + << CompileTask(Task::Error, "collect2: ld returned 1 exit status")); formatRanges.clear(); if (HostOsInfo::isWindowsHost()) { @@ -463,8 +452,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("C:\\temp\\test\\untitled8/main.cpp"), -1, 0, formatRanges) - << CompileTask(Task::Error, "collect2: ld returned 1 exit status")) - << QString(); + << CompileTask(Task::Error, "collect2: ld returned 1 exit status")); QTest::newRow("linker: dll format not recognized") << QString::fromLatin1("c:\\Qt\\4.6\\lib/QtGuid4.dll: file not recognized: File format not recognized") @@ -473,8 +461,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "file not recognized: File format not recognized", - FilePath::fromUserInput("c:\\Qt\\4.6\\lib/QtGuid4.dll"))) - << QString(); + FilePath::fromUserInput("c:\\Qt\\4.6\\lib/QtGuid4.dll"))); QTest::newRow("Invalid rpath") << QString::fromLatin1("g++: /usr/local/lib: No such file or directory") @@ -482,8 +469,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "/usr/local/lib: No such file or directory")) - << QString(); + "/usr/local/lib: No such file or directory")); QTest::newRow("unused variable") << QString::fromLatin1("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp: In member function 'void Debugger::Internal::GdbEngine::handleBreakInsert2(const Debugger::Internal::GdbResponse&)':\n" @@ -503,8 +489,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Warning, "unused variable 'handler'", FilePath::fromUserInput("../../../../master/src/plugins/debugger/gdb/gdbengine.cpp"), - 2115, 0)) - << QString(); + 2115, 0)); QTest::newRow("gnumakeparser.cpp errors") << QString::fromLatin1("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp: In member function 'void ProjectExplorer::ProjectExplorerPlugin::testGnuMakeParserTaskMangling_data()':\n" @@ -528,8 +513,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Error, "expected ';' before ':' token", FilePath::fromUserInput("/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp"), - 264, 0)) - << QString(); + 264, 0)); QTest::newRow("distcc error(QTCREATORBUG-904)") << QString::fromLatin1("distcc[73168] (dcc_get_hostlist) Warning: no hostlist is set; can't distribute work\n" @@ -537,8 +521,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << OutputParserTester::STDERR << QString() << QString::fromLatin1("distcc[73168] (dcc_get_hostlist) Warning: no hostlist is set; can't distribute work\n" "distcc[73168] (dcc_build_somewhere) Warning: failed to distribute, running locally instead\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("ld warning (QTCREATORBUG-905)") << QString::fromLatin1("ld: warning: Core::IEditor* QVariant::value() const has different visibility (hidden) in .obj/debug-shared/openeditorsview.o and (default) in .obj/debug-shared/editormanager.o") @@ -546,8 +529,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Warning, - "Core::IEditor* QVariant::value() const has different visibility (hidden) in .obj/debug-shared/openeditorsview.o and (default) in .obj/debug-shared/editormanager.o")) - << QString(); + "Core::IEditor* QVariant::value() const has different visibility (hidden) in .obj/debug-shared/openeditorsview.o and (default) in .obj/debug-shared/editormanager.o")); QTest::newRow("ld fatal") << QString::fromLatin1("ld: fatal: Symbol referencing errors. No output written to testproject") @@ -555,15 +537,13 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "Symbol referencing errors. No output written to testproject")) - << QString(); + "Symbol referencing errors. No output written to testproject")); QTest::newRow("Teambuilder issues") << QString::fromLatin1("TeamBuilder Client:: error: could not find Scheduler, running Job locally...") << OutputParserTester::STDERR << QString() << QString::fromLatin1("TeamBuilder Client:: error: could not find Scheduler, running Job locally...\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("note") << QString::fromLatin1("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here") @@ -573,8 +553,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Unknown, "initialized from here", FilePath::fromUserInput("/home/dev/creator/share/qtcreator/debugger/dumper.cpp"), - 1079)) - << QString(); + 1079)); QTest::newRow("static member function") << QString::fromLatin1("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c: In static member function 'static std::_Rb_tree_node_base* std::_Rb_global<_Dummy>::_Rebalance_for_erase(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&)':\n" @@ -593,15 +572,13 @@ void ProjectExplorerTest::testGccOutputParsers_data() << formatRange(50, 67, "olpfile:///Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c::0::0") << formatRange(117, 216) << formatRange(333, 67, "olpfile:///Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c::194::0") - << formatRange(400, 64))) - << QString(); + << formatRange(400, 64))); QTest::newRow("rm false positive") << QString::fromLatin1("rm: cannot remove `release/moc_mainwindow.cpp': No such file or directory") << OutputParserTester::STDERR << QString() << QString::fromLatin1("rm: cannot remove `release/moc_mainwindow.cpp': No such file or directory\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("ld: missing library") << QString::fromLatin1("/usr/bin/ld: cannot find -ldoesnotexist") @@ -609,8 +586,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, - "cannot find -ldoesnotexist")) - << QString(); + "cannot find -ldoesnotexist")); QTest::newRow("In function") << QString::fromLatin1("../../scriptbug/main.cpp: In function void foo(i) [with i = double]:\n" @@ -630,8 +606,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Warning, "unused variable c", FilePath::fromUserInput("../../scriptbug/main.cpp"), - 8)) - << QString(); + 8)); QTest::newRow("instantiated from here") << QString::fromLatin1("main.cpp:10: instantiated from here ") @@ -641,8 +616,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Unknown, "instantiated from here", FilePath::fromUserInput("main.cpp"), - 10)) - << QString(); + 10)); QTest::newRow("In constructor") << QString::fromLatin1("/dev/creator/src/plugins/find/basetextfind.h: In constructor 'Find::BaseTextFind::BaseTextFind(QTextEdit*)':") @@ -651,8 +625,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << (Tasks() << CompileTask(Task::Unknown, "In constructor 'Find::BaseTextFind::BaseTextFind(QTextEdit*)':", - FilePath::fromUserInput("/dev/creator/src/plugins/find/basetextfind.h"))) - << QString(); + FilePath::fromUserInput("/dev/creator/src/plugins/find/basetextfind.h"))); QTest::newRow("At global scope") << QString::fromLatin1("../../scriptbug/main.cpp: At global scope:\n" @@ -679,8 +652,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Warning, "unused parameter v", FilePath::fromUserInput("../../scriptbug/main.cpp"), - 5)) - << QString(); + 5)); QTest::newRow("gcc 4.5 fatal error") << QString::fromLatin1("/home/code/test.cpp:54:38: fatal error: test.moc: No such file or directory") @@ -690,8 +662,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Error, "test.moc: No such file or directory", FilePath::fromUserInput("/home/code/test.cpp"), - 54, 38)) - << QString(); + 54, 38)); formatRanges.clear(); if (HostOsInfo::isWindowsHost()) { @@ -721,8 +692,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("M:\\Development\\x64\\QtPlot/qplotaxis.cpp"), 26) << CompileTask(Task::Error, - "collect2: ld returned 1 exit status")) - << QString(); + "collect2: ld returned 1 exit status")); QTest::newRow("instantiated from here should not be an error") << QString::fromLatin1("../stl/main.cpp: In member function typename _Vector_base<_Tp, _Alloc>::_Tp_alloc_type::const_reference Vector<_Tp, _Alloc>::at(int) [with _Tp = Point, _Alloc = Allocator]:\n" @@ -751,8 +721,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("../stl/main.cpp"), 31, 0, QVector() - << formatRange(23, 85))) - << QString(); + << formatRange(23, 85))); formatRanges.clear(); if (HostOsInfo::isWindowsHost()) { @@ -783,8 +752,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "C:/Symbian_SDK/epoc32/include/e32cmn.inl:7094: warning: returning reference to temporary", FilePath::fromUserInput("C:/Symbian_SDK/epoc32/include/e32cmn.inl"), 7094, 0, - formatRanges)} - << QString(); + formatRanges)}; QTest::newRow("In constructor 2") << QString::fromUtf8("perfattributes.cpp: In constructor ‘PerfEventAttributes::PerfEventAttributes()’:\n" "perfattributes.cpp:28:48: warning: ‘void* memset(void*, int, size_t)’ clearing an object of non-trivial type ‘class PerfEventAttributes’; use assignment or value-initialization instead [-Wclass-memaccess]\n" @@ -801,8 +769,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("perfattributes.cpp"), 28, 48, QVector() - << formatRange(170, 400))} - << QString(); + << formatRange(170, 400))}; QTest::newRow("QTCREATORBUG-2206") << QString::fromLatin1("../../../src/XmlUg/targetdelete.c: At top level:") << OutputParserTester::STDERR @@ -810,8 +777,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << (Tasks() << CompileTask(Task::Unknown, "At top level:", - FilePath::fromUserInput("../../../src/XmlUg/targetdelete.c"))) - << QString(); + FilePath::fromUserInput("../../../src/XmlUg/targetdelete.c"))); QTest::newRow("GCCE 4: commandline, includes") << QString::fromLatin1("In file included from /Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h:15,\n" @@ -832,8 +798,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << formatRange(48, 39, "olpfile:///Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h::15::0") << formatRange(87, 46) << formatRange(133, 50, "olpfile:///Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh::1134::26") - << formatRange(183, 44))} - << QString(); + << formatRange(183, 44))}; QTest::newRow("Linker fail (release build)") << QString::fromLatin1("release/main.o:main.cpp:(.text+0x42): undefined reference to `MainWindow::doSomething()'") @@ -842,8 +807,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "undefined reference to `MainWindow::doSomething()'", - FilePath::fromUserInput("main.cpp"))) - << QString(); + FilePath::fromUserInput("main.cpp"))); QTest::newRow("enumeration warning") << QString::fromLatin1("../../../src/shared/proparser/profileevaluator.cpp: In member function 'ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(const ProString&, const ProStringList&)':\n" @@ -858,8 +822,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("../../../src/shared/proparser/profileevaluator.cpp"), 2817, 9, QVector() - << formatRange(76, 351))) - << QString(); + << formatRange(76, 351))); QTest::newRow("include with line:column info") << QString::fromLatin1("In file included from :0:0:\n" @@ -874,8 +837,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("./mw.h"), 4, 0, QVector() - << formatRange(26, 88))} - << QString(); + << formatRange(26, 88))}; QTest::newRow("instantiation with line:column info") << QString::fromLatin1("file.h: In function 'void UnitTest::CheckEqual(UnitTest::TestResults&, const Expected&, const Actual&, const UnitTest::TestDetails&) [with Expected = unsigned int, Actual = int]':\n" @@ -895,8 +857,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << CompileTask(Task::Warning, "comparison between signed and unsigned integer expressions [-Wsign-compare]", FilePath::fromUserInput("file.h"), - 21, 5)) - << QString(); + 21, 5)); QTest::newRow("linker error") // QTCREATORBUG-3107 << QString::fromLatin1("cns5k_ins_parser_tests.cpp:(.text._ZN20CNS5kINSParserEngine21DropBytesUntilStartedEP14CircularBufferIhE[CNS5kINSParserEngine::DropBytesUntilStarted(CircularBuffer*)]+0x6d): undefined reference to `CNS5kINSPacket::SOH_BYTE'") @@ -905,8 +866,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "undefined reference to `CNS5kINSPacket::SOH_BYTE'", - FilePath::fromUserInput("cns5k_ins_parser_tests.cpp"))) - << QString(); + FilePath::fromUserInput("cns5k_ins_parser_tests.cpp"))); QTest::newRow("libimf warning") << QString::fromLatin1("libimf.so: warning: warning: feupdateenv is not implemented and will always fail") @@ -915,8 +875,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "warning: feupdateenv is not implemented and will always fail", - FilePath::fromUserInput("libimf.so"))) - << QString(); + FilePath::fromUserInput("libimf.so"))); QTest::newRow("gcc 4.8") << QString::fromLatin1("In file included from /home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp:31:0:\n" @@ -937,8 +896,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QVector() << formatRange(41, 22) << formatRange(63, 67, "olpfile:///home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp::31::0") - << formatRange(130, 146))} - << QString(); + << formatRange(130, 146))}; QTest::newRow("qtcreatorbug-9195") << QString::fromLatin1("In file included from /usr/include/qt4/QtCore/QString:1:0,\n" @@ -965,8 +923,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << formatRange(136, 33, "olpfile:///usr/include/qt4/QtCore/qstring.h::0::0") << formatRange(169, 28) << formatRange(197, 33, "olpfile:///usr/include/qt4/QtCore/qstring.h::597::5") - << formatRange(230, 99))} - << QString(); + << formatRange(230, 99))}; QTest::newRow("ld: Multiple definition error") << QString::fromLatin1("foo.o: In function `foo()':\n" @@ -991,8 +948,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("/home/user/test/bar.cpp"), 4) << CompileTask(Task::Error, - "collect2: error: ld returned 1 exit status")) - << QString(); + "collect2: error: ld returned 1 exit status")); QTest::newRow("ld: .data section") << QString::fromLatin1("foo.o:(.data+0x0): multiple definition of `foo'\n" @@ -1008,9 +964,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "first defined here", FilePath::fromUserInput("bar.o"), -1) << CompileTask(Task::Error, - "collect2: error: ld returned 1 exit status")) - << QString(); - + "collect2: error: ld returned 1 exit status")); QTest::newRow("Undefined symbol (Apple ld)") << "Undefined symbols for architecture x86_64:\n" @@ -1023,8 +977,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "Undefined symbols for architecture x86_64:\n" " \"SvgLayoutTest()\", referenced from:\n" " _main in main.cpp.o", - "main.cpp.o")}) - << QString(); + "main.cpp.o")}); QTest::newRow("ld: undefined member function reference") << "obj/gtest-clang-printing.o:gtest-clang-printing.cpp:llvm::VerifyDisableABIBreakingChecks: error: undefined reference to 'llvm::DisableABIBreakingChecks'" @@ -1033,8 +986,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "error: undefined reference to 'llvm::DisableABIBreakingChecks'", - "gtest-clang-printing.cpp")) - << QString(); + "gtest-clang-printing.cpp")); const auto task = [](Task::TaskType type, const QString &msg, const QString &file = {}, int line = -1) { @@ -1056,8 +1008,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() errorTask("ld.lld: error: undefined symbol: func()"), unknownTask("referenced by test.cpp:5", "test.cpp", 5), unknownTask("/tmp/ccg8pzRr.o:(main)", "/tmp/ccg8pzRr.o"), - errorTask("collect2: error: ld returned 1 exit status")}) - << QString(); + errorTask("collect2: error: ld returned 1 exit status")}); QTest::newRow("lld: undefined reference with debug info (more verbose format)") << "ld.lld: error: undefined symbol: someFunc()\n" @@ -1071,8 +1022,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() unknownTask("referenced by main.cpp:10 (/tmp/untitled4/main.cpp:10)", "/tmp/untitled4/main.cpp", 10), unknownTask("/tmp/Debug4/untitled4.5abe06ac/3a52ce780950d4d9/main.cpp.o:(main)", - "/tmp/Debug4/untitled4.5abe06ac/3a52ce780950d4d9/main.cpp.o")} - << QString(); + "/tmp/Debug4/untitled4.5abe06ac/3a52ce780950d4d9/main.cpp.o")}; QTest::newRow("lld: undefined reference without debug info") << "ld.lld: error: undefined symbol: func()\n" @@ -1084,8 +1034,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() errorTask("ld.lld: error: undefined symbol: func()"), unknownTask("referenced by test.cpp", "test.cpp"), unknownTask("/tmp/ccvjyJph.o:(main)", "/tmp/ccvjyJph.o"), - errorTask("collect2: error: ld returned 1 exit status")} - << QString(); + errorTask("collect2: error: ld returned 1 exit status")}; if (HostOsInfo::isWindowsHost()) { QTest::newRow("lld: undefined reference with mingw") @@ -1097,8 +1046,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() errorTask("lld-link: error: undefined symbol: __Z4funcv"), unknownTask("referenced by C:\\Users\\orgads\\AppData\\Local\\Temp\\cccApKoz.o:(.text)", "C:/Users/orgads/AppData/Local/Temp/cccApKoz.o"), - errorTask("collect2.exe: error: ld returned 1 exit status")} - << QString(); + errorTask("collect2.exe: error: ld returned 1 exit status")}; } QTest::newRow("lld: multiple definitions with debug info") @@ -1115,8 +1063,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() unknownTask("test1.o:(func())", "test1.o"), unknownTask("defined at test1.cpp:1", "test1.cpp", 1), unknownTask("test1.o:(.text+0x0)", "test1.o"), - errorTask("collect2: error: ld returned 1 exit status")} - << QString(); + errorTask("collect2: error: ld returned 1 exit status")}; QTest::newRow("lld: multiple definitions with debug info (more verbose format)") << "ld.lld: error: duplicate symbol: theFunc()\n" @@ -1136,8 +1083,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "/tmp/untitled3/main.cpp", 5), unknownTask("/tmp/Debug/untitled3.dade828b/3a52ce780950d4d9/main.cpp.o:(.text+0x0)", "/tmp/Debug/untitled3.dade828b/3a52ce780950d4d9/main.cpp.o"), - errorTask("collect2: error: ld returned 1 exit status")} - << QString(); + errorTask("collect2: error: ld returned 1 exit status")}; QTest::newRow("lld: multiple definitions without debug info") << "ld.lld: error: duplicate symbol: func()\n" @@ -1153,8 +1099,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() unknownTask("test1.o:(func())", "test1.o"), unknownTask("defined at test1.cpp", "test1.cpp"), unknownTask("test1.o:(.text+0x0)", "test1.o"), - errorTask("collect2: error: ld returned 1 exit status")} - << QString(); + errorTask("collect2: error: ld returned 1 exit status")}; if (HostOsInfo::isWindowsHost()) { QTest::newRow("lld: multiple definitions with mingw") @@ -1163,8 +1108,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << OutputParserTester::STDERR << QString() << QString() << Tasks{ errorTask("lld-link: error: duplicate symbol: __Z4funcv in test1.o and in test2.o"), - errorTask("collect2.exe: error: ld returned 1 exit status", {})} - << QString(); + errorTask("collect2.exe: error: ld returned 1 exit status", {})}; } QTest::newRow("Mac: ranlib warning") @@ -1173,8 +1117,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Warning, - "file: lib/libtest.a(Test0.cpp.o) has no symbols")) - << QString(); + "file: lib/libtest.a(Test0.cpp.o) has no symbols")); QTest::newRow("Mac: ranlib warning2") << QString::fromLatin1("/path/to/XCode/and/ranlib: file: lib/libtest.a(Test0.cpp.o) has no symbols") @@ -1182,8 +1125,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString() << QString() << (Tasks() << CompileTask(Task::Warning, - "file: lib/libtest.a(Test0.cpp.o) has no symbols")) - << QString(); + "file: lib/libtest.a(Test0.cpp.o) has no symbols")); QTest::newRow("GCC 9 output") << QString("In file included from /usr/include/qt/QtCore/qlocale.h:43,\n" @@ -1294,8 +1236,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("param-type-mismatch.c"), 5, 24, QVector() - << formatRange(92, 519))} - << QString(); + << formatRange(92, 519))}; QTest::newRow(R"("inlined from")") << QString("In file included from smallstringvector.h:30,\n" @@ -1327,8 +1268,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("smallstring.h"), 465, 21, QVector() - << formatRange(62, 805))} - << QString(); + << formatRange(62, 805))}; QTest::newRow(R"("required from")") << QString( @@ -1369,8 +1309,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("moc_helpindexfilter.cpp"), 105, 1, QVector() - << formatRange(46, 1458))} - << QString(); + << formatRange(46, 1458))}; QTest::newRow(R"("requested here")") << QString( @@ -1403,8 +1342,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "/usr/include/qt/QtTest/qtestcase.h:88:17: note: expanded from macro 'QCOMPARE'\n" " if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\\\n" " ^", - FilePath::fromUserInput("tst_addresscache.cpp"), 79, 13, {})} - << QString(); + FilePath::fromUserInput("tst_addresscache.cpp"), 79, 13, {})}; QTest::newRow(R"("note: here")") << QString( @@ -1436,8 +1374,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "qmlprofilerstatisticsmodel.cpp:365:5: note: here\n" " 365 | default:\n" " | ^~~~~~~", - FilePath::fromUserInput("qmlprofilerstatisticsmodel.cpp"), 365, 5, {})} - << QString(); + FilePath::fromUserInput("qmlprofilerstatisticsmodel.cpp"), 365, 5, {})}; QTest::newRow("cc1plus") << QString( @@ -1452,16 +1389,14 @@ void ProjectExplorerTest::testGccOutputParsers_data() CompileTask(Task::Error, "one or more PCH files were found, but they were invalid"), CompileTask(Task::Error, "use -Winvalid-pch for more information"), CompileTask(Task::Error, ".pch/Qt6Core5Compat: No such file or directory", ".pch/Qt6Core5Compat"), - CompileTask(Task::Warning, "-Wformat-security ignored without -Wformat [-Wformat-security]")} - << QString(); + CompileTask(Task::Warning, "-Wformat-security ignored without -Wformat [-Wformat-security]")}; QTest::newRow("clean path") << QString("/home/tim/path/to/sources/./and/more.h:15:22: error: blubb") << OutputParserTester::STDERR << QString() << QString() << Tasks{CompileTask(Task::Error, "blubb", "/home/tim/path/to/sources/and/more.h", - 15, 22)} - << QString(); + 15, 22)}; QTest::newRow("no line number") << QString::fromUtf8("In file included from /data/dev/creator/src/libs/utils/aspects.cpp:12:\n" @@ -1491,8 +1426,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() formatRange(378, 44, "olpfile:///data/dev/creator/src/libs/utils/aspects.cpp::3454::13"), formatRange(422, 31), formatRange(453, 48, "olpfile:///data/dev/creator/src/libs/utils/layoutbuilder.h::79::51"), - formatRange(501, 228)})}) - << QString(); + formatRange(501, 228)})}); } void ProjectExplorerTest::testGccOutputParsers() @@ -1504,11 +1438,8 @@ void ProjectExplorerTest::testGccOutputParsers() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } } // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/gnumakeparser.cpp b/src/plugins/projectexplorer/gnumakeparser.cpp index d8f877fd325..ace90641dd5 100644 --- a/src/plugins/projectexplorer/gnumakeparser.cpp +++ b/src/plugins/projectexplorer/gnumakeparser.cpp @@ -161,7 +161,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); QTest::addColumn("additionalSearchDirs"); QTest::newRow("pass-through stdout") @@ -169,14 +168,12 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString::fromLatin1("Sometext\n") << QString() << Tasks() - << QString() << QStringList(); QTest::newRow("pass-through stderr") << QStringList() << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString::fromLatin1("Sometext\n") << Tasks() - << QString() << QStringList(); QTest::newRow("pass-through gcc infos") << QStringList() @@ -193,7 +190,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() "../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]\n" "../../scriptbug/main.cpp:22: instantiated from here\n") << Tasks() - << QString() << QStringList(); // make sure adding directories works (once;-) @@ -204,7 +200,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << OutputParserTester::STDOUT << QString() << QString() << Tasks() - << QString() << QStringList({"/home/code/build/qt/examples/opengl/grabber", "/home/code/build/qt/examples/opengl/grabber", "/test/dir"}); QTest::newRow("leaving directory") @@ -213,7 +208,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << OutputParserTester::STDOUT << QString() << QString() << Tasks() - << QString() << QStringList("/test/dir"); QTest::newRow("make error") @@ -224,7 +218,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << (Tasks() << BuildSystemTask(Task::Error, "No rule to make target `hello.c', needed by `hello.o'. Stop.")) - << QString() << QStringList(); QTest::newRow("multiple fatals") @@ -237,7 +230,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << (Tasks() << BuildSystemTask(Task::Error, "[.obj/debug-shared/gnumakeparser.o] Error 1")) - << QString() << QStringList(); QTest::newRow("Makefile error") @@ -249,7 +241,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << BuildSystemTask(Task::Error, "missing separator (did you mean TAB instead of 8 spaces?). Stop.", Utils::FilePath::fromUserInput("Makefile"), 360)) - << QString() << QStringList(); QTest::newRow("mingw32-make error") @@ -261,7 +252,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << (Tasks() << BuildSystemTask(Task::Error, "[debug/qplotaxis.o] Error 1")) - << QString() << QStringList(); QTest::newRow("mingw64-make error") @@ -272,7 +262,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << (Tasks() << BuildSystemTask(Task::Error, "[dynlib.inst] Error -1073741819")) - << QString() << QStringList(); QTest::newRow("make warning") @@ -283,7 +272,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << (Tasks() << BuildSystemTask(Task::Warning, "jobserver unavailable: using -j1. Add `+' to parent make rule.")) - << QString() << QStringList(); QTest::newRow("pass-trough note") @@ -292,7 +280,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << OutputParserTester::STDERR << QString() << QString::fromLatin1("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here\n") << Tasks() - << QString() << QStringList(); QTest::newRow("Full path make exe") @@ -303,7 +290,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << (Tasks() << BuildSystemTask(Task::Error, "[sis] Error 2")) - << QString() << QStringList(); QTest::newRow("missing g++") @@ -314,7 +300,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << (Tasks() << BuildSystemTask(Task::Error, "g++: Command not found")) - << QString() << QStringList(); QTest::newRow("warning in Makefile") @@ -326,7 +311,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << BuildSystemTask(Task::Warning, "overriding commands for target `xxxx.app/Contents/Info.plist'", "Makefile", 794)) - << QString() << QStringList(); } @@ -345,7 +329,6 @@ void ProjectExplorerTest::testGnuMakeParserParsing() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); QFETCH(QStringList, additionalSearchDirs); FilePaths searchDirs = childParser->searchDirectories(); @@ -354,9 +337,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing() for (const QString &dir : std::as_const(extraSearchDirs)) testbench.addSearchDir(FilePath::fromString(dir)); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); // make sure we still have all the original dirs FilePaths newSearchDirs = tester->directories; @@ -393,7 +374,7 @@ void ProjectExplorerTest::testGnuMakeParserTaskMangling() {BuildSystemTask(Task::Error, "missing separator (did you mean TAB instead of 8 spaces?). Stop.", FilePath::fromString(theMakeFile.fileName()), 360)}, - QString(), QString(), QString()); + QString(), QString()); } } // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/linuxiccparser.cpp b/src/plugins/projectexplorer/linuxiccparser.cpp index 6e625b240a5..255fb575126 100644 --- a/src/plugins/projectexplorer/linuxiccparser.cpp +++ b/src/plugins/projectexplorer/linuxiccparser.cpp @@ -108,25 +108,21 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString::fromLatin1("Sometext\n") << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString::fromLatin1("Sometext\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pch creation") << QString::fromLatin1("\".pch/Qt5Core.pchi.cpp\": creating precompiled header file \".pch/Qt5Core.pchi\"") << OutputParserTester::STDERR << QString() << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("undeclared function") << QString::fromLatin1("main.cpp(13): error: identifier \"f\" is undefined\n" @@ -140,8 +136,7 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() "identifier \"f\" is undefined\n" "main.cpp(13): error: identifier \"f\" is undefined\n" " f(0);", - FilePath::fromUserInput(QLatin1String("main.cpp")), 13)) - << QString(); + FilePath::fromUserInput(QLatin1String("main.cpp")), 13)); // same, with PCH remark QTest::newRow("pch use+undeclared function") @@ -157,8 +152,7 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() "identifier \"f\" is undefined\n" "main.cpp(13): error: identifier \"f\" is undefined\n" " f(0);", - FilePath::fromUserInput("main.cpp"), 13)) - << QString(); + FilePath::fromUserInput("main.cpp"), 13)); QTest::newRow("private function") @@ -173,8 +167,7 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() "function \"AClass::privatefunc\" (declared at line 4 of \"main.h\") is inaccessible\n" "main.cpp(53): error #308: function \"AClass::privatefunc\" (declared at line 4 of \"main.h\") is inaccessible\n" " b.privatefunc();", - FilePath::fromUserInput("main.cpp"), 53)) - << QString(); + FilePath::fromUserInput("main.cpp"), 53)); QTest::newRow("simple warning") << QString::fromLatin1("main.cpp(41): warning #187: use of \"=\" where \"==\" may have been intended\n" @@ -188,8 +181,7 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() "use of \"=\" where \"==\" may have been intended\n" "main.cpp(41): warning #187: use of \"=\" where \"==\" may have been intended\n" " while (a = true)", - FilePath::fromUserInput("main.cpp"), 41)) - << QString(); + FilePath::fromUserInput("main.cpp"), 41)); } void ProjectExplorerTest::testLinuxIccOutputParsers() @@ -201,11 +193,8 @@ void ProjectExplorerTest::testLinuxIccOutputParsers() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } } // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp index 17710cb13c3..1be62b953c9 100644 --- a/src/plugins/projectexplorer/msvcparser.cpp +++ b/src/plugins/projectexplorer/msvcparser.cpp @@ -263,7 +263,6 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); auto compileTask = [](Task::TaskType type, const QString &description, @@ -287,13 +286,11 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT << "Sometext\n" << "" - << Tasks() - << ""; + << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR << "" << "Sometext\n" - << Tasks() - << ""; + << Tasks(); QTest::newRow("labeled error") << "qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value" @@ -302,8 +299,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "C4716: 'findUnresolvedModule' : must return a value", - FilePath::fromUserInput("qmlstandalone\\main.cpp"), 54)) - << ""; + FilePath::fromUserInput("qmlstandalone\\main.cpp"), 54)); QTest::newRow("labeled error-2015") << "qmlstandalone\\main.cpp(54): error C4716: 'findUnresolvedModule' : must return a value" @@ -312,8 +308,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "C4716: 'findUnresolvedModule' : must return a value", - FilePath::fromUserInput("qmlstandalone\\main.cpp"), 54)) - << ""; + FilePath::fromUserInput("qmlstandalone\\main.cpp"), 54)); QTest::newRow("labeled error with number prefix") << "1>qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value" @@ -322,8 +317,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "C4716: 'findUnresolvedModule' : must return a value", - FilePath::fromUserInput("qmlstandalone\\main.cpp"), 54)) - << ""; + FilePath::fromUserInput("qmlstandalone\\main.cpp"), 54)); QTest::newRow("labeled warning") << "x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter" @@ -332,9 +326,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "C4100: 'something' : unreferenced formal parameter", - FilePath::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69)) - << ""; - + FilePath::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69)); QTest::newRow("labeled warning with number prefix") << "1>x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter" @@ -343,8 +335,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << (Tasks() << CompileTask(Task::Warning, "C4100: 'something' : unreferenced formal parameter", - FilePath::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69)) - << ""; + FilePath::fromUserInput("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69)); QTest::newRow("labeled chained warning") << "x:\\src\\libs\\narf\\stringutils.cpp(155): warning C4996: " @@ -361,8 +352,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() " header (containing std::codecvt_mode, std::codecvt_utf8, " "std::codecvt_utf16, and std::codecvt_utf8_utf16) are deprecated in " "C++17. more blabla", - FilePath::fromUserInput("x:\\src\\libs\\narf\\stringutils.cpp"), 155)) - << ""; + FilePath::fromUserInput("x:\\src\\libs\\narf\\stringutils.cpp"), 155)); QTest::newRow("additional information") << "x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n" @@ -375,8 +365,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50) << CompileTask(Task::Unknown, "see declaration of 'TextEditor::CompletionItem'", - FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39)) - << ""; + FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39)); QTest::newRow("additional information with prefix") << "2>x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n" @@ -389,8 +378,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50) << CompileTask(Task::Unknown, "see declaration of 'TextEditor::CompletionItem'", - FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39)) - << ""; + FilePath::fromUserInput("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39)); QTest::newRow("fatal linker error") << "LINK : fatal error LNK1146: no argument specified with option '/LIBPATH:'" @@ -398,8 +386,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << "" << "" << (Tasks() << CompileTask(Task::Error, - "LNK1146: no argument specified with option '/LIBPATH:'")) - << ""; + "LNK1146: no argument specified with option '/LIBPATH:'")); // This actually comes through stderr! QTest::newRow("command line warning") @@ -408,8 +395,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << "" << "" << (Tasks() << CompileTask(Task::Warning, - "D9002 : ignoring unknown option '-fopenmp'")) - << ""; + "D9002 : ignoring unknown option '-fopenmp'")); QTest::newRow("complex error") << "..\\untitled\\main.cpp(19) : error C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n" @@ -432,8 +418,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() FilePath::fromUserInput("..\\untitled\\main.cpp"), 19, QVector() - << formatRange(85, 365))) - << ""; + << formatRange(85, 365))); QTest::newRow("Linker error 1") << "main.obj : error LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main" @@ -442,8 +427,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main", - FilePath::fromUserInput("main.obj"), -1)) - << ""; + FilePath::fromUserInput("main.obj"), -1)); QTest::newRow("Linker error 2") << "debug\\Experimentation.exe : fatal error LNK1120: 1 unresolved externals" @@ -452,8 +436,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << (Tasks() << CompileTask(Task::Error, "LNK1120: 1 unresolved externals", - FilePath::fromUserInput("debug\\Experimentation.exe"))) - << ""; + FilePath::fromUserInput("debug\\Experimentation.exe"))); QTest::newRow("nmake error") << "Error: dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist." @@ -461,8 +444,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << "" << "" << (Tasks() << CompileTask(Task::Error, - "dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist.")) - << ""; + "dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist.")); QTest::newRow("jom error") << "Error: dependent 'main.cpp' does not exist." @@ -470,8 +452,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << "" << "" << (Tasks() << CompileTask(Task::Error, - "dependent 'main.cpp' does not exist.")) - << ""; + "dependent 'main.cpp' does not exist.")); QTest::newRow("Multiline error") << "c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility(2227) : warning C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'\n" @@ -502,8 +483,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() FilePath::fromUserInput("symbolgroupvalue.cpp"), 2314, QVector() - << formatRange(141, 287))) - << ""; + << formatRange(141, 287))); QTest::newRow("Ambiguous symbol") << "D:\\Project\\file.h(98) : error C2872: 'UINT64' : ambiguous symbol\n" @@ -520,15 +500,13 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() FilePath::fromUserInput("C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\basetsd.h"), 83) << CompileTask(Task::Unknown, "or Types::UINT64", - FilePath::fromUserInput("D:\\Project\\types.h"), 71)) - << ""; + FilePath::fromUserInput("D:\\Project\\types.h"), 71)); QTest::newRow("ignore moc note") << "/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated." << OutputParserTester::STDERR << "" << "/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.\n" - << (Tasks()) - << ""; + << (Tasks()); QTest::newRow("error with note") << "main.cpp(7): error C2733: 'func': second C linkage of overloaded function not allowed\n" @@ -542,8 +520,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() FilePath::fromUserInput("main.cpp"), 7, QVector() - << formatRange(67, 130))} - << ""; + << formatRange(67, 130))}; QTest::newRow("cyrillic warning") // QTCREATORBUG-20297 << QString::fromUtf8("cl: командная строка warning D9025: переопределение \"/MDd\" на \"/MTd\"") @@ -551,8 +528,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << "" << "" << (Tasks() << CompileTask(Task::Warning, - QString::fromUtf8("D9025: переопределение \"/MDd\" на \"/MTd\""))) - << ""; + QString::fromUtf8("D9025: переопределение \"/MDd\" на \"/MTd\""))); } void ProjectExplorerTest::testMsvcOutputParsers() @@ -564,11 +540,8 @@ void ProjectExplorerTest::testMsvcOutputParsers() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } void ProjectExplorerTest::testClangClOutputParsers_data() @@ -578,7 +551,6 @@ void ProjectExplorerTest::testClangClOutputParsers_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); const QString clangClCompilerLog = "In file included from .\\qwindowseglcontext.cpp:40:\n" @@ -636,8 +608,7 @@ void ProjectExplorerTest::testClangClOutputParsers_data() "expected unqualified-id\n" ".\\qwindowsgdinativeinterface.cpp(51,1) : error: expected unqualified-id\n" "void *QWindowsGdiNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs)", - FilePath::fromUserInput(".\\qwindowsgdinativeinterface.cpp"), 51)) - << ""; + FilePath::fromUserInput(".\\qwindowsgdinativeinterface.cpp"), 51)); QTest::newRow("other error") << "C:\\Program Files\\LLVM\\bin\\clang-cl.exe /nologo /c /EHsc /Od -m64 /Zi /MDd " @@ -660,8 +631,7 @@ void ProjectExplorerTest::testClangClOutputParsers_data() "C:\\MyData\\Project_home\\cpp\\TestForError\\main.cpp(3,10): error: expected ';' after return statement\n" "return 0", FilePath::fromUserInput("C:\\MyData\\Project_home\\cpp\\TestForError\\main.cpp"), - 3)} - << ""; + 3)}; } void ProjectExplorerTest::testClangClOutputParsers() @@ -673,11 +643,8 @@ void ProjectExplorerTest::testClangClOutputParsers() QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); QFETCH(Tasks, tasks); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } } // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/outputparser_test.cpp b/src/plugins/projectexplorer/outputparser_test.cpp index 6e5f1bc45f4..ab7e339141a 100644 --- a/src/plugins/projectexplorer/outputparser_test.cpp +++ b/src/plugins/projectexplorer/outputparser_test.cpp @@ -60,8 +60,7 @@ void OutputParserTester::testParsing(const QString &lines, Channel inputChannel, Tasks tasks, const QString &childStdOutLines, - const QString &childStdErrLines, - const QString &outputLines) + const QString &childStdErrLines) { for (Utils::OutputLineParser * const parser : lineParsers()) parser->skipFileExistsCheck(); @@ -81,7 +80,6 @@ void OutputParserTester::testParsing(const QString &lines, emit aboutToDeleteParser(); setLineParsers({}); - QCOMPARE(m_receivedOutput, outputLines); QCOMPARE(m_receivedStdErrChildLine, childStdErrLines); QCOMPARE(m_receivedStdOutChildLine, childStdOutLines); QCOMPARE(m_receivedTasks.size(), tasks.size()); @@ -121,7 +119,6 @@ void OutputParserTester::reset() m_receivedStdErrChildLine.clear(); m_receivedStdOutChildLine.clear(); m_receivedTasks.clear(); - m_receivedOutput.clear(); } class OutputParserTest final : public QObject @@ -139,7 +136,6 @@ void OutputParserTest::testAnsiFilterOutputParser_data() QTest::addColumn("inputChannel"); QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); - QTest::addColumn("outputLines"); QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT @@ -186,9 +182,7 @@ void OutputParserTest::testAnsiFilterOutputParser() QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - testbench.testParsing(input, inputChannel, - Tasks(), childStdOutLines, childStdErrLines, - QString()); + testbench.testParsing(input, inputChannel, Tasks(), childStdOutLines, childStdErrLines); } QObject *createOutputParserTest() diff --git a/src/plugins/projectexplorer/outputparser_test.h b/src/plugins/projectexplorer/outputparser_test.h index 4b3fc0f1b06..a53097262c2 100644 --- a/src/plugins/projectexplorer/outputparser_test.h +++ b/src/plugins/projectexplorer/outputparser_test.h @@ -32,8 +32,7 @@ public: void testParsing(const QString &lines, Channel inputChannel, Tasks tasks, const QString &childStdOutLines, - const QString &childStdErrLines, - const QString &outputLines); + const QString &childStdErrLines); void setDebugEnabled(bool); @@ -48,7 +47,6 @@ private: QString m_receivedStdErrChildLine; QString m_receivedStdOutChildLine; Tasks m_receivedTasks; - QString m_receivedOutput; friend class TestTerminator; }; diff --git a/src/plugins/projectexplorer/sanitizerparser.cpp b/src/plugins/projectexplorer/sanitizerparser.cpp index 546de844485..54c83623e05 100644 --- a/src/plugins/projectexplorer/sanitizerparser.cpp +++ b/src/plugins/projectexplorer/sanitizerparser.cpp @@ -244,7 +244,7 @@ SUMMARY: AddressSanitizer: 19 byte(s) leaked in 1 allocation(s).)"; QFETCH(QString, input); QFETCH(Tasks, tasks); QFETCH(QString, childStdErrLines); - testbench.testParsing(input, OutputParserTester::STDERR, tasks, {}, childStdErrLines, {}); + testbench.testParsing(input, OutputParserTester::STDERR, tasks, {}, childStdErrLines); } }; diff --git a/src/plugins/projectexplorer/xcodebuildparser.cpp b/src/plugins/projectexplorer/xcodebuildparser.cpp index 2037614e043..0cc964e8b57 100644 --- a/src/plugins/projectexplorer/xcodebuildparser.cpp +++ b/src/plugins/projectexplorer/xcodebuildparser.cpp @@ -121,7 +121,6 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); QTest::addColumn("finalStatus"); QTest::newRow("outside pass-through stdout") @@ -129,42 +128,36 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString::fromLatin1("Sometext\n") << QString() << Tasks() - << QString() << XcodebuildParser::OutsideXcodebuild; QTest::newRow("outside pass-through stderr") << XcodebuildParser::OutsideXcodebuild << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString::fromLatin1("Sometext\n") << Tasks() - << QString() << XcodebuildParser::OutsideXcodebuild; QTest::newRow("inside pass stdout to stderr") << XcodebuildParser::InXcodebuild << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString() << QString::fromLatin1("Sometext\n") << Tasks() - << QString() << XcodebuildParser::InXcodebuild; QTest::newRow("inside ignore stderr") << XcodebuildParser::InXcodebuild << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString() << Tasks() - << QString() << XcodebuildParser::InXcodebuild; QTest::newRow("unknown pass stdout to stderr") << XcodebuildParser::UnknownXcodebuildState << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString() << QString::fromLatin1("Sometext\n") << Tasks() - << QString() << XcodebuildParser::UnknownXcodebuildState; QTest::newRow("unknown ignore stderr (change?)") << XcodebuildParser::UnknownXcodebuildState << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString() << Tasks() - << QString() << XcodebuildParser::UnknownXcodebuildState; QTest::newRow("switch outside->in->outside") << XcodebuildParser::OutsideXcodebuild @@ -178,7 +171,6 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() << OutputParserTester::STDOUT << QString::fromLatin1("outside\noutside2\n") << QString::fromLatin1("in xcodebuild\nin xcodebuild2\n") << Tasks() - << QString() << XcodebuildParser::OutsideXcodebuild; QTest::newRow("switch outside->in->outside (new)") << XcodebuildParser::OutsideXcodebuild @@ -191,7 +183,6 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() << OutputParserTester::STDOUT << QString::fromLatin1("outside\noutside2\n") << QString::fromLatin1("in xcodebuild\nin xcodebuild2\n") << Tasks() - << QString() << XcodebuildParser::OutsideXcodebuild; QTest::newRow("switch Unknown->in->outside") << XcodebuildParser::UnknownXcodebuildState @@ -203,7 +194,6 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() << OutputParserTester::STDOUT << QString::fromLatin1("outside\n") << QString::fromLatin1("unknown\nin xcodebuild\n") << Tasks() - << QString() << XcodebuildParser::OutsideXcodebuild; QTest::newRow("switch in->unknown") @@ -215,7 +205,6 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() << QString() << QString() << (Tasks() << CompileTask(Task::Error, Tr::tr("Xcodebuild failed."))) - << QString() << XcodebuildParser::UnknownXcodebuildState; QTest::newRow("switch out->unknown") @@ -227,7 +216,6 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() << QString() << QString::fromLatin1("outErr\n") << (Tasks() << CompileTask(Task::Error, Tr::tr("Xcodebuild failed."))) - << QString() << XcodebuildParser::UnknownXcodebuildState; QTest::newRow("inside catch codesign replace signature") @@ -237,7 +225,6 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() << (Tasks() << CompileTask(Task::Warning, Tr::tr("Replacing signature"), "/somepath/somefile.app")) - << QString() << XcodebuildParser::InXcodebuild; QTest::newRow("outside forward codesign replace signature") @@ -245,7 +232,6 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() << QString::fromLatin1("/somepath/somefile.app: replacing existing signature") << OutputParserTester::STDOUT << QString::fromLatin1("/somepath/somefile.app: replacing existing signature\n") << QString() << Tasks() - << QString() << XcodebuildParser::OutsideXcodebuild; } @@ -265,14 +251,11 @@ void ProjectExplorerTest::testXcodebuildParserParsing() QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); QFETCH(Tasks, tasks); - QFETCH(QString, outputLines); QFETCH(ProjectExplorer::XcodebuildParser::XcodebuildStatus, finalStatus); tester->expectedFinalState = finalStatus; childParser->m_xcodeBuildParserState = initialStatus; - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); delete tester; } diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.cpp b/src/plugins/qmakeprojectmanager/qmakeparser.cpp index 0b0bdc5af08..280bf14944c 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparser.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparser.cpp @@ -94,19 +94,15 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); - QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString::fromLatin1("Sometext\n") << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString::fromLatin1("Sometext\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("qMake error") << QString::fromLatin1("Project ERROR: undefined file") @@ -114,8 +110,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() << QString() << QString() << (Tasks() << BuildSystemTask(Task::Error, - "undefined file")) - << QString(); + "undefined file")); QTest::newRow("qMake Parse Error") << QString::fromLatin1("e:\\project.pro:14: Parse Error ('sth odd')") @@ -125,8 +120,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() << BuildSystemTask(Task::Error, "Parse Error ('sth odd')", FilePath::fromUserInput("e:\\project.pro"), - 14)) - << QString(); + 14)); QTest::newRow("qMake warning") << QString::fromLatin1("Project WARNING: bearer module might require ReadUserData capability") @@ -134,8 +128,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() << QString() << QString() << (Tasks() << BuildSystemTask(Task::Warning, - "bearer module might require ReadUserData capability")) - << QString(); + "bearer module might require ReadUserData capability")); QTest::newRow("qMake warning 2") << QString::fromLatin1("WARNING: Failure to find: blackberrycreatepackagestepconfigwidget.cpp") @@ -143,8 +136,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() << QString() << QString() << (Tasks() << BuildSystemTask(Task::Warning, - "Failure to find: blackberrycreatepackagestepconfigwidget.cpp")) - << QString(); + "Failure to find: blackberrycreatepackagestepconfigwidget.cpp")); QTest::newRow("qMake warning with location") << QString::fromLatin1("WARNING: e:\\QtSDK\\Simulator\\Qt\\msvc2008\\lib\\qtmaind.prl:1: Unescaped backslashes are deprecated.") @@ -153,8 +145,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() << (Tasks() << BuildSystemTask(Task::Warning, "Unescaped backslashes are deprecated.", - FilePath::fromUserInput("e:\\QtSDK\\Simulator\\Qt\\msvc2008\\lib\\qtmaind.prl"), 1)) - << QString(); + FilePath::fromUserInput("e:\\QtSDK\\Simulator\\Qt\\msvc2008\\lib\\qtmaind.prl"), 1)); QTest::newRow("moc note") << QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.") @@ -163,8 +154,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() << (Tasks() << BuildSystemTask(Task::Unknown, "Note: No relevant classes found. No output generated.", - FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), -1)) - << QString(); + FilePath::fromUserInput("/home/qtwebkithelpviewer.h"), -1)); } void QmakeOutputParserTest::testQmakeOutputParsers() @@ -176,11 +166,8 @@ void QmakeOutputParserTest::testQmakeOutputParsers() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, - tasks, childStdOutLines, childStdErrLines, - outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } QObject *createQmakeOutputParserTest() diff --git a/src/plugins/qtsupport/qtparser.cpp b/src/plugins/qtsupport/qtparser.cpp index 93fd16d90a5..28a3d08f3d4 100644 --- a/src/plugins/qtsupport/qtparser.cpp +++ b/src/plugins/qtsupport/qtparser.cpp @@ -132,19 +132,15 @@ void QtOutputParserTest::testQtOutputParser_data() QTest::addColumn("childStdOutLines"); QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); - QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT << QString::fromLatin1("Sometext\n") << QString() - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() << QString::fromLatin1("Sometext\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("pass-through gcc infos") << QString::fromLatin1("/temp/test/untitled8/main.cpp: In function `int main(int, char**)':\n" "../../scriptbug/main.cpp: At global scope:\n" @@ -158,64 +154,56 @@ void QtOutputParserTest::testQtOutputParser_data() "../../scriptbug/main.cpp: In instantiation of void bar(i) [with i = double]:\n" "../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]\n" "../../scriptbug/main.cpp:22: instantiated from here\n") - << Tasks() - << QString(); + << Tasks(); QTest::newRow("qdoc warning") << QString::fromLatin1("/home/user/dev/qt5/qtscript/src/script/api/qscriptengine.cpp:295: warning: Can't create link to 'Object Trees & Ownership'") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Warning, QLatin1String("Can't create link to 'Object Trees & Ownership'"), - Utils::FilePath::fromUserInput(QLatin1String("/home/user/dev/qt5/qtscript/src/script/api/qscriptengine.cpp")), 295)) - << QString(); + Utils::FilePath::fromUserInput(QLatin1String("/home/user/dev/qt5/qtscript/src/script/api/qscriptengine.cpp")), 295)); QTest::newRow("moc warning") << QString::fromLatin1("..\\untitled\\errorfile.h:0: Warning: No relevant classes found. No output generated.") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Warning, QLatin1String("No relevant classes found. No output generated."), - Utils::FilePath::fromUserInput(QLatin1String("..\\untitled\\errorfile.h")), -1)) - << QString(); + Utils::FilePath::fromUserInput(QLatin1String("..\\untitled\\errorfile.h")), -1)); QTest::newRow("moc warning 2") << QString::fromLatin1("c:\\code\\test.h(96): Warning: Property declaration ) has no READ accessor function. The property will be invalid.") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Warning, QLatin1String("Property declaration ) has no READ accessor function. The property will be invalid."), - Utils::FilePath::fromUserInput(QLatin1String("c:\\code\\test.h")), 96)) - << QString(); + Utils::FilePath::fromUserInput(QLatin1String("c:\\code\\test.h")), 96)); QTest::newRow("moc warning (Qt 6/Windows)") << QString::fromLatin1(R"(C:/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h(38:1): error: Plugin Metadata file "QmlProfiler.json" does not exist. Declaration will be ignored)") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Error, R"(Plugin Metadata file "QmlProfiler.json" does not exist. Declaration will be ignored)", - Utils::FilePath::fromUserInput("C:/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h"), 38, 1)) - << QString(); + Utils::FilePath::fromUserInput("C:/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h"), 38, 1)); QTest::newRow("moc warning (Qt 6/Unix)") << QString::fromLatin1(R"(/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h:38:1: error: Plugin Metadata file "QmlProfiler.json" does not exist. Declaration will be ignored)") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Error, R"(Plugin Metadata file "QmlProfiler.json" does not exist. Declaration will be ignored)", - Utils::FilePath::fromUserInput("/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h"), 38, 1)) - << QString(); + Utils::FilePath::fromUserInput("/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h"), 38, 1)); QTest::newRow("moc note") << QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Unknown, QLatin1String("No relevant classes found. No output generated."), - Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), -1)) - << QString(); + Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), -1)); QTest::newRow("ninja with moc") << QString::fromLatin1("E:/sandbox/creator/loaden/src/libs/utils/iwelcomepage.h(54): Error: Undefined interface") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Error, QLatin1String("Undefined interface"), - Utils::FilePath::fromUserInput(QLatin1String("E:/sandbox/creator/loaden/src/libs/utils/iwelcomepage.h")), 54)) - << QString(); + Utils::FilePath::fromUserInput(QLatin1String("E:/sandbox/creator/loaden/src/libs/utils/iwelcomepage.h")), 54)); QTest::newRow("uic warning") << QString::fromLatin1("mainwindow.ui: Warning: The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.") << OutputParserTester::STDERR @@ -223,32 +211,28 @@ void QtOutputParserTest::testQtOutputParser_data() << (Tasks() << CompileTask(Task::Warning, "The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.", - Utils::FilePath::fromUserInput("mainwindow.ui"))) - << QString(); + Utils::FilePath::fromUserInput("mainwindow.ui"))); QTest::newRow("translation") << QString::fromLatin1("Warning: dropping duplicate messages in '/some/place/qtcreator_fr.qm'") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Warning, QLatin1String("dropping duplicate messages"), - Utils::FilePath::fromUserInput(QLatin1String("/some/place/qtcreator_fr.qm")), -1)) - << QString(); + Utils::FilePath::fromUserInput(QLatin1String("/some/place/qtcreator_fr.qm")), -1)); QTest::newRow("qmlsc/qmllint warning") // QTCREATORBUG-28720 << QString::fromLatin1("Warning: Main.qml:4:1: Warnings occurred while importing module " "\"QtQuick.Controls\": [import]\"") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Warning, "Warnings occurred while importing module \"QtQuick.Controls\": [import]\"", - Utils::FilePath::fromUserInput("Main.qml"), 4, 1)) - << QString(); + Utils::FilePath::fromUserInput("Main.qml"), 4, 1)); QTest::newRow("qmlsc/qmllint error") // QTCREATORBUG-28720 << QString::fromLatin1("Error: E:/foo/PerfProfilerFlameGraphView.qml:10:5: " "Could not compile binding for model: Cannot resolve property type for binding on model") << OutputParserTester::STDERR << QString() << QString() << (Tasks() << CompileTask(Task::Error, "Could not compile binding for model: Cannot resolve property type for binding on model", - Utils::FilePath::fromUserInput("E:/foo/PerfProfilerFlameGraphView.qml"), 10, 5)) - << QString(); + Utils::FilePath::fromUserInput("E:/foo/PerfProfilerFlameGraphView.qml"), 10, 5)); } void QtOutputParserTest::testQtOutputParser() @@ -260,9 +244,8 @@ void QtOutputParserTest::testQtOutputParser() QFETCH(Tasks, tasks); QFETCH(QString, childStdOutLines); QFETCH(QString, childStdErrLines); - QFETCH(QString, outputLines); - testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines, outputLines); + testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } QObject *createQtOutputParserTest() diff --git a/src/plugins/qtsupport/qttestparser.cpp b/src/plugins/qtsupport/qttestparser.cpp index a19929b7544..07047c376bb 100644 --- a/src/plugins/qtsupport/qttestparser.cpp +++ b/src/plugins/qtsupport/qttestparser.cpp @@ -121,7 +121,7 @@ void QtTestParserTest::testQtTestOutputParser() " Expected (true) : 1", theFile, 220, Constants::TASK_CATEGORY_AUTOTEST)}; testbench.testParsing(input, OutputParserTester::STDOUT, expectedTasks, expectedChildOutput, - QString(), QString()); + QString()); } QObject *createQtTestParserTest() From 165403f14cb751de959a6d5486dd3d9da1bda15d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 18:37:59 +0100 Subject: [PATCH 252/989] ProjectExplorer: Make SimpleTargetRunner final Task-number: QTCREATORBUG-29168 Change-Id: Ie343e924997fc4956c81e0ab65b5cd70ac355fcc Reviewed-by: hjk --- src/plugins/projectexplorer/runcontrol.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index efc772302ab..3c3cd34ae8d 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -279,10 +279,8 @@ private: * sufficient for running purposes. */ -class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public RunWorker +class PROJECTEXPLORER_EXPORT SimpleTargetRunner final : public RunWorker { - Q_OBJECT - public: explicit SimpleTargetRunner(RunControl *runControl); ~SimpleTargetRunner() override; From 86dc1c6e2528da34167d11da78e09fca80e34bbd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 19:01:03 +0100 Subject: [PATCH 253/989] Boot2Qt: Drop QdbDeviceDebugSupport::stop() overload It's no-op. Task-number: QTCREATORBUG-29168 Change-Id: I616311ee732964058d0394b5312369846ddb227d Reviewed-by: hjk --- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index 45a36158a74..df22296fa7b 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -119,7 +119,6 @@ public: private: void start() override; - void stop() override; }; QdbDeviceDebugSupport::QdbDeviceDebugSupport(RunControl *runControl) @@ -153,13 +152,6 @@ void QdbDeviceDebugSupport::start() DebuggerRunTool::start(); } -void QdbDeviceDebugSupport::stop() -{ - // Do nothing unusual. The launcher will die as result of (gdb) kill. - DebuggerRunTool::stop(); -} - - // QdbDeviceQmlProfilerSupport class QdbDeviceQmlToolingSupport final : public RunWorker From e0743503d1bb81933fedad7f1e4c1eaf5fa3cd1b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 19:12:52 +0100 Subject: [PATCH 254/989] Android: Inline AndroidQmlToolingSupport Task-number: QTCREATORBUG-29168 Change-Id: I6211d9f864247fbcf0f4714ee45879a360b9c74b Reviewed-by: hjk --- .../android/androidqmltoolingsupport.cpp | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/plugins/android/androidqmltoolingsupport.cpp b/src/plugins/android/androidqmltoolingsupport.cpp index 8070dbb57a5..7d37027bf1b 100644 --- a/src/plugins/android/androidqmltoolingsupport.cpp +++ b/src/plugins/android/androidqmltoolingsupport.cpp @@ -13,27 +13,22 @@ using namespace ProjectExplorer; namespace Android::Internal { -class AndroidQmlToolingSupport final : public RunWorker -{ -public: - explicit AndroidQmlToolingSupport(RunControl *runControl) : RunWorker(runControl) - { - setId("AndroidQmlToolingSupport"); - - auto runner = new AndroidRunner(runControl); - addStartDependency(runner); - - auto worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); - worker->addStartDependency(this); - } -}; - class AndroidQmlToolingSupportFactory final : public RunWorkerFactory { public: AndroidQmlToolingSupportFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new RunWorker(runControl); + worker->setId("AndroidQmlToolingSupport"); + + auto runner = new AndroidRunner(runControl); + worker->addStartDependency(runner); + + auto extraWorker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); + extraWorker->addStartDependency(worker); + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); addSupportedRunConfig(Constants::ANDROID_RUNCONFIG_ID); } From e400195ac0c48b05278eefb5c80457c9def2985d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 19:20:15 +0100 Subject: [PATCH 255/989] AppMan: Inline AppManagerPerfProfilerSupport Task-number: QTCREATORBUG-29168 Change-Id: I856ee7d514588c524ccec5835bb51508ca3725de Reviewed-by: hjk --- .../appmanagerruncontrol.cpp | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 95125318bbd..7eef034608a 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -212,25 +212,6 @@ public: } }; -// AppManagerDevicePerfProfilerSupport - -class AppManagerPerfProfilerSupport final : public RunWorker -{ -public: - explicit AppManagerPerfProfilerSupport(RunControl *runControl) - : RunWorker(runControl) - { - setId("AppManagerPerfProfilerSupport"); - - runControl->requestPerfChannel(); - auto profilee = createInferiorRunner(runControl, NoQmlDebugServices); - addStartDependency(profilee); - addStopDependency(profilee); - } -}; - -// Factories - class AppManagerRunWorkerFactory final : public RunWorkerFactory { public: @@ -315,7 +296,16 @@ class AppManagerPerfProfilerWorkerFactory final : public RunWorkerFactory public: AppManagerPerfProfilerWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new RunWorker(runControl); + worker->setId("AppManagerPerfProfilerSupport"); + + runControl->requestPerfChannel(); + auto profilee = createInferiorRunner(runControl, NoQmlDebugServices); + worker->addStartDependency(profilee); + worker->addStopDependency(profilee); + return worker; + }); addSupportedRunMode("PerfRecorder"); addSupportedRunConfig(Constants::RUNANDDEBUGCONFIGURATION_ID); } From ed77787cc3e8555b0ce9d376354fd28e30d9ab7a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 19:23:30 +0100 Subject: [PATCH 256/989] AppMan: Inline AppManagerQmlToolingSupport Task-number: QTCREATORBUG-29168 Change-Id: I7669d3ad685dccbdcea5917ad3b70704e248d29c Reviewed-by: hjk --- .../appmanagerruncontrol.cpp | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 7eef034608a..9066f77d52b 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -187,31 +187,6 @@ private: } }; -// AppManagerQmlToolingSupport - -class AppManagerQmlToolingSupport final : public RunWorker -{ -public: - explicit AppManagerQmlToolingSupport(RunControl *runControl) - : RunWorker(runControl) - { - setId("AppManagerQmlToolingSupport"); - - runControl->requestQmlChannel(); - QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); - auto runner = createInferiorRunner(runControl, services); - addStartDependency(runner); - addStopDependency(runner); - - auto worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); - worker->addStartDependency(this); - addStopDependency(worker); - - // Make sure the QML Profiler is stopped before the appman-controller - runner->addStopDependency(worker); - } -}; - class AppManagerRunWorkerFactory final : public RunWorkerFactory { public: @@ -284,7 +259,24 @@ class AppManagerQmlToolingWorkerFactory final : public RunWorkerFactory public: AppManagerQmlToolingWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new RunWorker(runControl); + worker->setId("AppManagerQmlToolingSupport"); + + runControl->requestQmlChannel(); + QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); + auto runner = createInferiorRunner(runControl, services); + worker->addStartDependency(runner); + worker->addStopDependency(runner); + + auto extraWorker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); + extraWorker->addStartDependency(worker); + worker->addStopDependency(extraWorker); + + // Make sure the QML Profiler is stopped before the appman-controller + runner->addStopDependency(extraWorker); + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); addSupportedRunMode(ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE); addSupportedRunConfig(Constants::RUNANDDEBUGCONFIGURATION_ID); From a63e5b6ce0e025b1c5c99124e5e66aa36635035d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 19:26:01 +0100 Subject: [PATCH 257/989] Boot2Qt: Remove unneeded friend declarations in QdbDeviceInferiorRunner Task-number: QTCREATORBUG-29168 Change-Id: I7ce2831a041e34ac8a5daafd21f1697ecdf298c4 Reviewed-by: hjk --- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index df22296fa7b..8bd52c46c4c 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -101,11 +101,6 @@ public: void stop() override { m_launcher.close(); } private: - friend class QdbDeviceDebugSupport; - friend class QdbDeviceQmlProfilerSupport; - friend class QdbDeviceQmlToolingSupport; - friend class QdbDevicePerfProfilerSupport; - QmlDebugServicesPreset m_qmlServices; Process m_launcher; }; From 7e9c7785ea4efc00e442581016b4d81c81efa362 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 20 Nov 2024 19:35:14 +0100 Subject: [PATCH 258/989] Boot2Qt: Inline QdbDeviceQmlToolingSupport Task-number: QTCREATORBUG-29168 Change-Id: Ib3ca814ffeea004125c0dcbf9bd3fe01c1e632b0 Reviewed-by: hjk --- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 42 +++++++------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index 8bd52c46c4c..665de590702 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -147,32 +147,6 @@ void QdbDeviceDebugSupport::start() DebuggerRunTool::start(); } -// QdbDeviceQmlProfilerSupport - -class QdbDeviceQmlToolingSupport final : public RunWorker -{ -public: - explicit QdbDeviceQmlToolingSupport(RunControl *runControl); -}; - -QdbDeviceQmlToolingSupport::QdbDeviceQmlToolingSupport(RunControl *runControl) - : RunWorker(runControl) -{ - setId("QdbDeviceQmlToolingSupport"); - - runControl->requestQmlChannel(); - QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); - auto runner = new QdbDeviceInferiorRunner(runControl, services); - addStartDependency(runner); - addStopDependency(runner); - - auto worker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); - worker->addStartDependency(this); - addStopDependency(worker); -} - -// Factories - class QdbRunWorkerFactory final : public RunWorkerFactory { public: @@ -215,7 +189,21 @@ class QdbQmlToolingWorkerFactory final : public RunWorkerFactory public: QdbQmlToolingWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new RunWorker(runControl); + worker->setId("QdbDeviceQmlToolingSupport"); + + runControl->requestQmlChannel(); + const QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); + auto runner = new QdbDeviceInferiorRunner(runControl, services); + worker->addStartDependency(runner); + worker->addStopDependency(runner); + + auto extraWorker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); + extraWorker->addStartDependency(worker); + worker->addStopDependency(extraWorker); + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); addSupportedRunMode(ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE); addSupportedRunConfig(Constants::QdbRunConfigurationId); From be434b6a8ec80c49d4a1b801120ca1314b5a5233 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 21 Nov 2024 09:56:17 +0100 Subject: [PATCH 259/989] Boot2Qt: Simplify QdbDeviceDebugSupport Remove setting the remote channel and qml server. This is already done by its superclass, inside: DebuggerRunTool::continueAfterTerminalStart(). Task-number: QTCREATORBUG-29168 Change-Id: I9ed25599d0da920af2eee7908e127cc0e3f46805 Reviewed-by: hjk --- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index 665de590702..a2ca2ce5d3d 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -136,14 +136,9 @@ void QdbDeviceDebugSupport::start() { setStartMode(Debugger::AttachToRemoteServer); setCloseMode(KillAndExitMonitorAtClose); - if (usesDebugChannel()) - setRemoteChannel(debugChannel()); - if (usesQmlChannel()) - setQmlServer(qmlChannel()); setUseContinueInsteadOfRun(true); setContinueAfterAttach(true); addSolibSearchDir("%{sysroot}/system/lib"); - DebuggerRunTool::start(); } From 407b497ca5197e6ad9c1f376ac2d1c8759910fa4 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 21 Nov 2024 15:35:43 +0100 Subject: [PATCH 260/989] Tests: Add new theme include file to manual tests Change-Id: I9209a75641f09748c80918fb918292263c33ddd4 Reviewed-by: Cristian Adam --- tests/manual/widgets/common/themes.qrc | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/manual/widgets/common/themes.qrc b/tests/manual/widgets/common/themes.qrc index bdd8b45efba..698ce420d3d 100644 --- a/tests/manual/widgets/common/themes.qrc +++ b/tests/manual/widgets/common/themes.qrc @@ -12,5 +12,6 @@ ../../../../share/qtcreator/themes/light-2024.creatortheme ../../../../share/qtcreator/themes/light-palette.inc ../../../../share/qtcreator/themes/light.figmatokens + ../../../../share/qtcreator/themes/primitive-colors.inc From 1b9636c8d920e8131e8f3a58e62392b161411c87 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 21 Nov 2024 16:55:34 +0100 Subject: [PATCH 261/989] QtSupport: Don't suggest to run "make install" ...if a Qt version is not properly installed. The command is "make install" for Qt5. For Qt6, it's "ninja install", but only if a Ninja generator is used. Since an error message isn't the right place for a "How to install Qt" document, remove the suggestion altogether. Change-Id: I0b50c97183e2fcd65b4cde236e5489707f1bc708 Reviewed-by: Alexey Edelev --- src/plugins/qtsupport/baseqtversion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 28cc8b9c672..d6d94cac993 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -701,7 +701,7 @@ QString QtVersion::invalidReason() const if (!d->m_qmakeIsExecutable) return Tr::tr("qmake does not exist or is not executable"); if (!d->data().installed) - return Tr::tr("Qt version is not properly installed, please run make install"); + return Tr::tr("Qt version is not properly installed"); if (binPath().isEmpty()) return Tr::tr("Could not determine the path to the binaries of the Qt installation, " "maybe the qmake path is wrong?"); From 2099f5bb98c4b2f79e51720ab2866a32c91d2548 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 5 Nov 2024 14:37:54 +0100 Subject: [PATCH 262/989] Android: avoid scanning mkspecs to detect android abi Use the abi information from the modules/*.json files instead. Those json files are part of a Qt installation since Qt 6.0. Fallback to the old mkspec parsing for older Qt Versions. Fixes: QTCREATORBUG-31068 Change-Id: I18fcea17233eaf2bdc562b9b36718c29eddd1dbe Reviewed-by: Assam Boudjelthia Reviewed-by: Alessandro Portale --- src/plugins/android/androidqtversion.cpp | 13 ++++++---- src/plugins/android/androidqtversion.h | 2 +- src/plugins/projectexplorer/abi.cpp | 30 ++++++++++++++---------- src/plugins/projectexplorer/abi.h | 2 ++ src/plugins/qtsupport/baseqtversion.cpp | 9 ++++--- src/plugins/qtsupport/baseqtversion.h | 1 + 6 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index 2c932ad42c1..2276599faa9 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -82,8 +82,12 @@ bool AndroidQtVersion::supportsMultipleQtAbis() const Abis AndroidQtVersion::detectQtAbis() const { - const bool conf = AndroidConfig::sdkFullyConfigured(); - return conf ? Utils::transform(androidAbis(), &androidAbi2Abi) : Abis(); + Abis result = qtAbisFromJson(); + if (result.isEmpty() && AndroidConfig::sdkFullyConfigured()) { + ensureMkSpecParsed(); + result = Utils::transform(m_androidAbis, &androidAbi2Abi); + } + return result; } void AndroidQtVersion::addToBuildEnvironment(const Kit *k, Utils::Environment &env) const @@ -109,10 +113,9 @@ QString AndroidQtVersion::description() const return Tr::tr("Android"); } -const QStringList &AndroidQtVersion::androidAbis() const +const QStringList AndroidQtVersion::androidAbis() const { - ensureMkSpecParsed(); - return m_androidAbis; + return Utils::transform(detectQtAbis(), &Abi::toAndroidAbi); } int AndroidQtVersion::minimumNDK() const diff --git a/src/plugins/android/androidqtversion.h b/src/plugins/android/androidqtversion.h index ceddb76520f..d96276abb65 100644 --- a/src/plugins/android/androidqtversion.h +++ b/src/plugins/android/androidqtversion.h @@ -25,7 +25,7 @@ public: QSet targetDeviceTypes() const override; QString description() const override; - const QStringList &androidAbis() const; + const QStringList androidAbis() const; int minimumNDK() const; static QString androidDeploymentSettingsFileName(const ProjectExplorer::Target *target); diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 1cde394ec8e..0fa590b7d9f 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -443,18 +443,6 @@ static Abis abiOf(const QByteArray &data) return result; } -static QString androidAbiFromAbi(const Abi &abi) -{ - QString androidAbi; - if (abi.architecture() == Abi::Architecture::ArmArchitecture) - androidAbi = QLatin1String(abi.wordWidth() == 64 ? Constants::ANDROID_ABI_ARM64_V8A - : Constants::ANDROID_ABI_ARMEABI_V7A); - else - androidAbi = QLatin1String(abi.wordWidth() == 64 ? Constants::ANDROID_ABI_X86_64 - : Constants::ANDROID_ABI_X86); - return androidAbi; -} - // -------------------------------------------------------------------------- // Abi // -------------------------------------------------------------------------- @@ -689,6 +677,22 @@ QString Abi::param() const return m_param; } +QString Abi::toAndroidAbi() const +{ + if (architecture() == Abi::Architecture::ArmArchitecture) { + if (wordWidth() == 32) + return Constants::ANDROID_ABI_ARMEABI_V7A; + if (wordWidth() == 64) + return Constants::ANDROID_ABI_ARM64_V8A; + } else if (architecture() == Abi::Architecture::X86Architecture) { + if (wordWidth() == 32) + return Constants::ANDROID_ABI_X86; + if (wordWidth() == 64) + return Constants::ANDROID_ABI_X86_64; + } + return {}; +} + bool Abi::operator != (const Abi &other) const { return !operator ==(other); @@ -936,7 +940,7 @@ Abi Abi::fromString(const QString &abiString) Abi abi(architecture, os, flavor, format, wordWidth); if (abi.os() == LinuxOS && abi.osFlavor() == AndroidLinuxFlavor) - abi.m_param = androidAbiFromAbi(abi); + abi.m_param = abi.toAndroidAbi(); return abi; } diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h index 71f62ad7338..ec06abe4538 100644 --- a/src/plugins/projectexplorer/abi.h +++ b/src/plugins/projectexplorer/abi.h @@ -144,6 +144,8 @@ public: QString toString() const; QString param() const; + QString toAndroidAbi() const; + static QString toString(const Architecture &a); static QString toString(const OS &o); static QString toString(const OSFlavor &of); diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index d6d94cac993..2e19566b983 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -751,14 +751,17 @@ void QtVersion::setQtAbis(const Abis &abis) Abis QtVersion::detectQtAbis() const { qCDebug(abiDetect) << "Detecting ABIs for" << qmakeFilePath(); - if (const Abis abis = qtAbisFromJson(*this, {d->data().archDataPath, d->data().dataPath}); - !abis.isEmpty()) { + if (const Abis abis = qtAbisFromJson(); !abis.isEmpty()) return abis; - } qCDebug(abiDetect) << "Got no ABI from JSON file, falling back to inspecting binaries"; return d->qtAbisFromLibrary(); } +Abis QtVersion::qtAbisFromJson() const +{ + return QtSupport::Internal::qtAbisFromJson(*this, {d->data().archDataPath, d->data().dataPath}); +} + bool QtVersion::hasAbi(ProjectExplorer::Abi::OS os, ProjectExplorer::Abi::OSFlavor flavor) const { const Abis abis = qtAbis(); diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h index d2576b2843d..0fa8032a329 100644 --- a/src/plugins/qtsupport/baseqtversion.h +++ b/src/plugins/qtsupport/baseqtversion.h @@ -203,6 +203,7 @@ protected: const Utils::FilePath &buildDir) const; virtual ProjectExplorer::Abis detectQtAbis() const; + ProjectExplorer::Abis qtAbisFromJson() const; void resetCache() const; From a18e24f94fae2979ebb5d27a5b45c2d280881de9 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 21 Nov 2024 23:33:11 +0100 Subject: [PATCH 263/989] Core: Turn QLabel *tfLabel() into applyTf(QLabel *label) Decorating an existing label is more flexible than creating a decorated one. This turns QLabel *tfLabel(const TextFormat &tf, ...) into applyTf(QLabel *label, const TextFormat &tf, ...) And adapts the current callers, accordingly. Change-Id: Ib42ca5ed1670bba9df11bb28837040537512131f Reviewed-by: hjk --- src/plugins/coreplugin/welcomepagehelper.cpp | 13 +++----- src/plugins/coreplugin/welcomepagehelper.h | 2 +- .../extensionmanagerwidget.cpp | 33 +++++++++++-------- .../extensionmanager/extensionsbrowser.cpp | 25 +++++++++----- src/plugins/welcome/welcomeplugin.cpp | 7 ++-- 5 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 967952e02df..478bb0249e3 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -88,9 +88,8 @@ QWidget *createRule(Qt::Orientation orientation, QWidget *parent) return rule; } -QLabel *tfLabel(const TextFormat &tf, bool singleLine) +void applyTf(QLabel *label, const TextFormat &tf, bool singleLine) { - QLabel *label = singleLine ? new Utils::ElidingLabel : new QLabel; if (singleLine) label->setFixedHeight(tf.lineHeight()); label->setFont(tf.font()); @@ -100,8 +99,6 @@ QLabel *tfLabel(const TextFormat &tf, bool singleLine) QPalette pal = label->palette(); pal.setColor(QPalette::WindowText, tf.color()); label->setPalette(pal); - - return label; } } // namespace WelcomePageHelpers @@ -1271,8 +1268,8 @@ void SectionedGridView::setSearchString(const QString &searchString) static QLabel *createTitleLabel(const QString &text) { constexpr TextFormat headerTitleTF {Theme::Token_Text_Muted, StyleHelper::UiElementH4}; - auto label = tfLabel(headerTitleTF); - label->setText(text); + auto label = new ElidingLabel(text); + applyTf(label, headerTitleTF); label->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); return label; } @@ -1308,8 +1305,8 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListsetText(section.name); + auto sectionNameLabel = new ElidingLabel(section.name); + applyTf(sectionNameLabel, headerTitleTF); QLabel *seeAllLink = createLinkLabel(Tr::tr("Show All") + " >", this); if (gridView->maxRows().has_value()) { diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index 7de554e84a9..8ee3f50b371 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -67,7 +67,7 @@ CORE_EXPORT void drawCardBackground(QPainter *painter, const QRectF &rect, const QBrush &fill, const QPen &pen = QPen(Qt::NoPen), qreal rounding = defaultCardBackgroundRounding); CORE_EXPORT QWidget *createRule(Qt::Orientation orientation, QWidget *parent = nullptr); -CORE_EXPORT QLabel *tfLabel(const TextFormat &tf, bool singleLine = true); +CORE_EXPORT void applyTf(QLabel *label, const TextFormat &tf, bool singleLine = true); } // namespace WelcomePageHelpers diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index a6a284d80fd..2f2fa4131ca 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -67,8 +67,8 @@ constexpr TextFormat h6CapitalTF static QLabel *sectionTitle(const TextFormat &tf, const QString &title) { - QLabel *label = tfLabel(tf, true); - label->setText(title); + auto *label = new ElidingLabel(title); + applyTf(label, tf); return label; }; @@ -134,7 +134,8 @@ public: static const TextFormat detailsTF {titleTF.themeColor, Utils::StyleHelper::UiElementCaption}; - m_title = tfLabel(titleTF); + m_title = new ElidingLabel; + applyTf(m_title, titleTF); m_vendor = new Button({}, Button::SmallLink); m_vendor->setContentsMargins({}); m_divider = new QLabel; @@ -144,9 +145,11 @@ public: const QPixmap dlIcon = Icon({{":/extensionmanager/images/download.png", dlTF.themeColor}}, Icon::Tint).pixmap(); m_dlIcon->setPixmap(dlIcon); - m_dlCount = tfLabel(dlTF); + m_dlCount = new ElidingLabel; + applyTf(m_dlCount, dlTF); m_dlCount->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - m_details = tfLabel(detailsTF); + m_details = new ElidingLabel; + applyTf(m_details, detailsTF); installButton = new Button(Tr::tr("Install..."), Button::MediumPrimary); installButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); installButton->hide(); @@ -428,12 +431,12 @@ static QWidget *descriptionPlaceHolder() static const TextFormat tF { Theme::Token_Text_Muted, UiElement::UiElementH4 }; - auto title = tfLabel(tF); + auto title = new ElidingLabel(Tr::tr("No details to show")); + applyTf(title, tF); title->setAlignment(Qt::AlignCenter); - title->setText(Tr::tr("No details to show")); - auto text = tfLabel(tF, false); + auto text = new QLabel(Tr::tr("Select an extension to see more information about it.")); + applyTf(text, tF, false); text->setAlignment(Qt::AlignCenter); - text->setText(Tr::tr("Select an extension to see more information about it.")); text->setFont({}); using namespace Layouting; // clang-format off @@ -475,15 +478,19 @@ ExtensionManagerWidget::ExtensionManagerWidget() m_description->setMargins({verticalPadding, 0, verticalPadding, 0}); m_dateUpdatedTitle = sectionTitle(h6TF, Tr::tr("Last Update")); - m_dateUpdated = tfLabel(contentTF, false); + m_dateUpdated = new QLabel; + applyTf(m_dateUpdated, contentTF, false); m_tagsTitle = sectionTitle(h6TF, Tr::tr("Tags")); m_tags = new TagList; m_platformsTitle = sectionTitle(h6TF, Tr::tr("Platforms")); - m_platforms = tfLabel(contentTF, false); + m_platforms = new QLabel; + applyTf(m_platforms, contentTF, false); m_dependenciesTitle = sectionTitle(h6TF, Tr::tr("Dependencies")); - m_dependencies = tfLabel(contentTF, false); + m_dependencies = new QLabel; + applyTf(m_dependencies, contentTF, false); m_packExtensionsTitle = sectionTitle(h6TF, Tr::tr("Extensions in pack")); - m_packExtensions = tfLabel(contentTF, false); + m_packExtensions = new QLabel; + applyTf(m_packExtensions, contentTF, false); m_pluginStatus = new PluginStatusWidget; auto secondary = new QWidget; diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index a3e542a9905..420bb0344fb 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -209,20 +209,26 @@ public: m_iconLabel = new QLabel; m_iconLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - m_itemNameLabel = tfLabel(itemNameTF); + m_itemNameLabel = new ElidingLabel; + applyTf(m_itemNameLabel, itemNameTF); m_itemNameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - m_releaseStatus = tfLabel(releaseStatusTF, false); + m_releaseStatus = new QLabel; + applyTf(m_releaseStatus, releaseStatusTF, false); m_releaseStatus->setAlignment(Qt::AlignLeft); m_releaseStatus->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); - m_installStateLabel = tfLabel(stateActiveTF, false); + m_installStateLabel = new QLabel; + applyTf(m_installStateLabel, stateActiveTF, false); m_installStateLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); m_installStateIcon = new QLabel; m_installStateIcon->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - m_vendorLabel = tfLabel(vendorTF); + m_vendorLabel = new ElidingLabel; + applyTf(m_vendorLabel, vendorTF); m_downloadDividerLabel = new QLabel; m_downloadIconLabel = new QLabel; - m_downloadCountLabel = tfLabel(countTF); - m_shortDescriptionLabel = tfLabel(descriptionTF); + m_downloadCountLabel = new QLabel; + applyTf(m_downloadCountLabel, countTF); + m_shortDescriptionLabel = new ElidingLabel; + applyTf(m_shortDescriptionLabel, descriptionTF); using namespace Layouting; Row { @@ -514,7 +520,8 @@ public: static QWidget *extensionViewPlaceHolder() { static const TextFormat tF {Theme::Token_Text_Muted, UiElementH4}; - auto text = tfLabel(tF, false); + auto text = new QLabel; + applyTf(text, tF, false); text->setAlignment(Qt::AlignCenter); text->setText(Tr::tr("No extension found!")); text->setWordWrap(true); @@ -540,8 +547,8 @@ ExtensionsBrowser::ExtensionsBrowser(ExtensionsModel *model, QWidget *parent) static const TextFormat titleTF {Theme::Token_Text_Default, UiElementH2}; - QLabel *titleLabel = tfLabel(titleTF); - titleLabel->setText(Tr::tr("Manage Extensions")); + auto titleLabel = new ElidingLabel(Tr::tr("Manage Extensions")); + applyTf(titleLabel, titleTF); d->searchBox = new SearchBox; d->searchBox->setPlaceholderText(Tr::tr("Search")); diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index 1f5b279dd5d..d364519bd3a 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -75,9 +76,9 @@ public: ideIconLabel->setFixedHeight(lineHeight); } - auto welcomeLabel = tfLabel(welcomeTF); - welcomeLabel->setText(Tr::tr("Welcome to %1") - .arg(QGuiApplication::applicationDisplayName())); + auto welcomeLabel = new ElidingLabel(Tr::tr("Welcome to %1") + .arg(QGuiApplication::applicationDisplayName())); + applyTf(welcomeLabel, welcomeTF); welcomeLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); using namespace Layouting; From bfbe49f81a2dbbc1a3809729f2ebf4e05fd987b5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 21 Nov 2024 13:48:36 +0100 Subject: [PATCH 264/989] Terminal: Add keyboard shortcuts for backspace Adds Keyboard shortcuts to delete a word to the left and the full line to the left. Fixes: QTCREATORBUG-30635 Change-Id: I73681728af9662d104a24d43a73794e33a4a961c Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalconstants.h | 2 ++ src/plugins/terminal/terminalwidget.cpp | 20 ++++++++++++++++++++ src/plugins/terminal/terminalwidget.h | 2 ++ 3 files changed, 24 insertions(+) diff --git a/src/plugins/terminal/terminalconstants.h b/src/plugins/terminal/terminalconstants.h index f53484d28ed..648dba5fe7b 100644 --- a/src/plugins/terminal/terminalconstants.h +++ b/src/plugins/terminal/terminalconstants.h @@ -18,5 +18,7 @@ constexpr char MOVECURSORWORDRIGHT[] = "Terminal.MoveCursorWordRight"; constexpr char CLEAR_TERMINAL[] = "Terminal.ClearTerminal"; constexpr char TOGGLE_KEYBOARD_LOCK[] = "Terminal.ToggleKeyboardLock"; constexpr char SELECTALL[] = "Terminal.SelectAll"; +constexpr char DELETE_WORD_LEFT[] = "Terminal.DeleteWordLeft"; +constexpr char DELETE_LINE_LEFT[] = "Terminal.DeleteLineLeft"; } // namespace Terminal::Constants diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 3ca0cfd8d25..835a0495777 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -313,6 +313,16 @@ void TerminalWidget::setupActions() selectAllAction.addOnTriggered(this, &TerminalWidget::selectAll); m_selectAll = make_registered(selectAllAction); + ActionBuilder deleteWordLeft(this, Constants::DELETE_WORD_LEFT); + deleteWordLeft.setContext(m_context); + deleteWordLeft.addOnTriggered(this, [this]() { writeToPty("\x17"); }); + m_deleteWordLeft = make_registered(deleteWordLeft); + + ActionBuilder deleteLineLeft(this, Constants::DELETE_LINE_LEFT); + deleteLineLeft.setContext(m_context); + deleteLineLeft.addOnTriggered(this, [this]() { writeToPty("\x15"); }); + m_deleteLineLeft = make_registered(deleteLineLeft); + // Ctrl+Q, the default "Quit" shortcut, is a useful key combination in a shell. // It can be used in combination with Ctrl+S to pause a program, and resume it with Ctrl+Q. // So we unlock the EXIT command only for macOS where the default is Cmd+Q to quit. @@ -692,6 +702,16 @@ void TerminalWidget::initActions(QObject *parent) moveCursorWordRightAction.setText(Tr::tr("Move Cursor Word Right")); moveCursorWordRightAction.setContext(context); moveCursorWordRightAction.setDefaultKeySequence({QKeySequence("Alt+Right")}); + + ActionBuilder deleteWordLeft(parent, Constants::DELETE_WORD_LEFT); + deleteWordLeft.setText(Tr::tr("Delete Word Left")); + deleteWordLeft.setContext(context); + deleteWordLeft.setDefaultKeySequence({QKeySequence("Alt+Backspace")}); + + ActionBuilder deleteLineLeft(parent, Constants::DELETE_LINE_LEFT); + deleteLineLeft.setText(Tr::tr("Delete Line Left")); + deleteLineLeft.setContext(context); + deleteLineLeft.setDefaultKeySequence({QKeySequence("Ctrl+Backspace")}); } void TerminalWidget::unlockGlobalAction(const Utils::Id &commandId) diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 351ae457205..473f6bfb0b6 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -107,6 +107,8 @@ private: RegisteredAction m_selectAll; RegisteredAction m_moveCursorWordLeft; RegisteredAction m_moveCursorWordRight; + RegisteredAction m_deleteWordLeft; + RegisteredAction m_deleteLineLeft; Internal::ShortcutMap m_shortcutMap; From 076d6581a9dc1ab592073ec0d32e8c44ba590a33 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 21 Nov 2024 09:22:12 +0100 Subject: [PATCH 265/989] Boot2Qt: Inline QdbDeviceInferiorRunner Task-number: QTCREATORBUG-29168 Change-Id: I92e133106f3fd851088d01e9bed0bb7ee3cf6171 Reviewed-by: hjk --- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 79 +++++++------------ 1 file changed, 29 insertions(+), 50 deletions(-) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index a2ca2ce5d3d..c9032a4922a 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -26,54 +26,38 @@ using namespace Utils; namespace Qdb::Internal { -class QdbDeviceInferiorRunner : public RunWorker +static RunWorker *createQdbDeviceInferiorWorker(RunControl *runControl, + QmlDebugServicesPreset qmlServices) { -public: - QdbDeviceInferiorRunner(RunControl *runControl, QmlDebugServicesPreset qmlServices) - : RunWorker(runControl), - m_qmlServices(qmlServices) - { - setId("QdbDebuggeeRunner"); + auto worker = new SimpleTargetRunner(runControl); + worker->setId("QdbDeviceInferiorWorker"); - connect(&m_launcher, &Process::started, this, &RunWorker::reportStarted); - connect(&m_launcher, &Process::done, this, &RunWorker::reportStopped); + worker->setStartModifier([worker, runControl, qmlServices] { + CommandLine cmd{worker->device()->filePath(Constants::AppcontrollerFilepath)}; - connect(&m_launcher, &Process::readyReadStandardOutput, this, [this] { - appendMessage(m_launcher.readAllStandardOutput(), StdOutFormat); - }); - connect(&m_launcher, &Process::readyReadStandardError, this, [this] { - appendMessage(m_launcher.readAllStandardError(), StdErrFormat); - }); - } - - void start() override - { int lowerPort = 0; int upperPort = 0; - CommandLine cmd; - cmd.setExecutable(device()->filePath(Constants::AppcontrollerFilepath)); - - if (usesDebugChannel()) { + if (worker->usesDebugChannel()) { cmd.addArg("--debug-gdb"); - lowerPort = upperPort = debugChannel().port(); + lowerPort = upperPort = worker->debugChannel().port(); } - if (usesQmlChannel()) { + if (worker->usesQmlChannel()) { cmd.addArg("--debug-qml"); cmd.addArg("--qml-debug-services"); - cmd.addArg(qmlDebugServices(m_qmlServices)); - lowerPort = upperPort = qmlChannel().port(); + cmd.addArg(qmlDebugServices(qmlServices)); + lowerPort = upperPort = worker->qmlChannel().port(); } - if (usesDebugChannel() && usesQmlChannel()) { - lowerPort = debugChannel().port(); - upperPort = qmlChannel().port(); + if (worker->usesDebugChannel() && worker->usesQmlChannel()) { + lowerPort = worker->debugChannel().port(); + upperPort = worker->qmlChannel().port(); if (lowerPort + 1 != upperPort) { - reportFailure("Need adjacent free ports for combined C++/QML debugging"); + worker->reportFailure("Need adjacent free ports for combined C++/QML debugging"); return; } } - if (usesPerfChannel()) { - const Store perfArgs = runControl()->settingsData(PerfProfiler::Constants::PerfSettingsId); + if (worker->usesPerfChannel()) { + const Store perfArgs = runControl->settingsData(PerfProfiler::Constants::PerfSettingsId); // appcontroller is not very clear about this, but it expects a comma-separated list of arguments. // Any literal commas that apper in the args should be escaped by additional commas. // See the source at @@ -86,24 +70,19 @@ public: .join(','); cmd.addArg("--profile-perf"); cmd.addArgs(recordArgs, CommandLine::Raw); - lowerPort = upperPort = perfChannel().port(); + lowerPort = upperPort = worker->perfChannel().port(); } + cmd.addArg("--port-range"); cmd.addArg(QString("%1-%2").arg(lowerPort).arg(upperPort)); - cmd.addCommandLineAsArgs(runControl()->commandLine()); + cmd.addCommandLineAsArgs(runControl->commandLine()); - m_launcher.setCommand(cmd); - m_launcher.setWorkingDirectory(runControl()->workingDirectory()); - m_launcher.setEnvironment(runControl()->environment()); - m_launcher.start(); - } - - void stop() override { m_launcher.close(); } - -private: - QmlDebugServicesPreset m_qmlServices; - Process m_launcher; -}; + worker->setCommandLine(cmd); + worker->setWorkingDirectory(runControl->workingDirectory()); + worker->setEnvironment(runControl->environment()); + }); + return worker; +} // QdbDeviceDebugSupport @@ -126,7 +105,7 @@ QdbDeviceDebugSupport::QdbDeviceDebugSupport(RunControl *runControl) if (isQmlDebugging()) runControl->requestQmlChannel(); - auto debuggee = new QdbDeviceInferiorRunner(runControl, QmlDebuggerServices); + auto debuggee = createQdbDeviceInferiorWorker(runControl, QmlDebuggerServices); addStartDependency(debuggee); debuggee->addStopDependency(this); @@ -190,7 +169,7 @@ public: runControl->requestQmlChannel(); const QmlDebugServicesPreset services = servicesForRunMode(runControl->runMode()); - auto runner = new QdbDeviceInferiorRunner(runControl, services); + auto runner = createQdbDeviceInferiorWorker(runControl, services); worker->addStartDependency(runner); worker->addStopDependency(runner); @@ -214,7 +193,7 @@ public: { setProducer([](RunControl *runControl) { runControl->requestPerfChannel(); - auto worker = new QdbDeviceInferiorRunner(runControl, NoQmlDebugServices); + auto worker = createQdbDeviceInferiorWorker(runControl, NoQmlDebugServices); return worker; }); addSupportedRunMode("PerfRecorder"); From 64c13b44dabf4af9b10a54079aa89a702421668e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 21 Nov 2024 10:01:54 +0100 Subject: [PATCH 266/989] Boot2Qt: Inline QdbDeviceDebugSupport Task-number: QTCREATORBUG-29168 Change-Id: I94432f6b54c05c763ea5c16f3bfc278a995a3ce5 Reviewed-by: hjk --- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 55 ++++++------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index c9032a4922a..5018b45d2fb 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -84,43 +84,6 @@ static RunWorker *createQdbDeviceInferiorWorker(RunControl *runControl, return worker; } -// QdbDeviceDebugSupport - -class QdbDeviceDebugSupport final : public Debugger::DebuggerRunTool -{ -public: - explicit QdbDeviceDebugSupport(RunControl *runControl); - -private: - void start() override; -}; - -QdbDeviceDebugSupport::QdbDeviceDebugSupport(RunControl *runControl) - : Debugger::DebuggerRunTool(runControl) -{ - setId("QdbDeviceDebugSupport"); - - if (isCppDebugging()) - runControl->requestDebugChannel(); - if (isQmlDebugging()) - runControl->requestQmlChannel(); - - auto debuggee = createQdbDeviceInferiorWorker(runControl, QmlDebuggerServices); - addStartDependency(debuggee); - - debuggee->addStopDependency(this); -} - -void QdbDeviceDebugSupport::start() -{ - setStartMode(Debugger::AttachToRemoteServer); - setCloseMode(KillAndExitMonitorAtClose); - setUseContinueInsteadOfRun(true); - setContinueAfterAttach(true); - addSolibSearchDir("%{sysroot}/system/lib"); - DebuggerRunTool::start(); -} - class QdbRunWorkerFactory final : public RunWorkerFactory { public: @@ -150,7 +113,23 @@ class QdbDebugWorkerFactory final : public RunWorkerFactory public: QdbDebugWorkerFactory() { - setProduct(); + setProducer([](RunControl *runControl) { + auto worker = new DebuggerRunTool(runControl); + worker->setId("QdbDeviceDebugSupport"); + + worker->setupPortsGatherer(); + worker->setStartMode(Debugger::AttachToRemoteServer); + worker->setCloseMode(KillAndExitMonitorAtClose); + worker->setUseContinueInsteadOfRun(true); + worker->setContinueAfterAttach(true); + worker->addSolibSearchDir("%{sysroot}/system/lib"); + + auto debuggee = createQdbDeviceInferiorWorker(runControl, QmlDebuggerServices); + worker->addStartDependency(debuggee); + debuggee->addStopDependency(worker); + + return worker; + }); addSupportedRunMode(ProjectExplorer::Constants::DEBUG_RUN_MODE); addSupportedRunConfig(Constants::QdbRunConfigurationId); addSupportedRunConfig(QmlProjectManager::Constants::QML_RUNCONFIG_ID); From 55af0402c8107a4b7c610e950e09fd1b0098b8bf Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 1 Nov 2024 17:58:28 +0100 Subject: [PATCH 267/989] Core: Move system env storage to SystemSettings Less indirections in the code. Change-Id: I61cb9fe100732db62fd01b45cb706ef2d47a2462 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/coreplugin.cpp | 31 +++++------------------ src/plugins/coreplugin/coreplugin.h | 5 ---- src/plugins/coreplugin/systemsettings.cpp | 30 +++++++++++++++++++--- src/plugins/coreplugin/systemsettings.h | 10 ++++++++ 4 files changed, 42 insertions(+), 34 deletions(-) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 73c2079161f..1b5bad97b5b 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -14,6 +14,7 @@ #include "modemanager.h" #include "session.h" #include "settingsdatabase.h" +#include "systemsettings.h" #include "themechooser.h" #include "vcsmanager.h" @@ -31,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -67,11 +69,13 @@ using namespace Utils; static CorePlugin *m_instance = nullptr; const char kWarnCrashReportingSetting[] = "WarnCrashReporting"; -const char kEnvironmentChanges[] = "Core/EnvironmentChanges"; CorePlugin::CorePlugin() - : m_startupSystemEnvironment(Environment::systemEnvironment()) { + // Trigger creation as early as possible before anyone else could + // mess with the systemEnvironment before it is "backed up". + (void) systemSettings(); + qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); @@ -82,10 +86,6 @@ CorePlugin::CorePlugin() qRegisterMetaType(); qRegisterMetaType(); m_instance = this; - - const EnvironmentItems changes = EnvironmentItem::fromStringList( - ICore::settings()->value(kEnvironmentChanges).toStringList()); - setEnvironmentChanges(changes); } CorePlugin::~CorePlugin() @@ -455,25 +455,6 @@ QObject *CorePlugin::remoteCommand(const QStringList & /* options */, return res; } -EnvironmentItems CorePlugin::environmentChanges() -{ - return m_instance->m_environmentChanges; -} - -void CorePlugin::setEnvironmentChanges(const EnvironmentItems &changes) -{ - if (m_instance->m_environmentChanges == changes) - return; - m_instance->m_environmentChanges = changes; - Environment systemEnv = m_instance->m_startupSystemEnvironment; - systemEnv.modify(changes); - Environment::setSystemEnvironment(systemEnv); - ICore::settings()->setValueWithDefault(kEnvironmentChanges, - EnvironmentItem::toStringList(changes)); - if (ICore::instance()) - emit ICore::instance()->systemEnvironmentChanged(); -} - void CorePlugin::fileOpenRequest(const QString &f) { remoteCommand(QStringList(), QString(), QStringList(f)); diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index 45cc8195025..73cf441df1d 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -8,7 +8,6 @@ #include #include -#include namespace Core { @@ -39,8 +38,6 @@ public: const QString &workingDirectory, const QStringList &args) override; - static Utils::EnvironmentItems environmentChanges(); - static void setEnvironmentChanges(const Utils::EnvironmentItems &changes); static QString msgCrashpadInformation(); static void loadMimeFromPlugin(const ExtensionSystem::PluginSpec *plugin); @@ -65,8 +62,6 @@ private: EditMode *m_editMode = nullptr; Locator *m_locator = nullptr; FolderNavigationWidgetFactory *m_folderNavigationWidgetFactory = nullptr; - const Utils::Environment m_startupSystemEnvironment; - Utils::EnvironmentItems m_environmentChanges; }; } // namespace Internal diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index ed3cb5cd45e..1f43e1b4bfb 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -4,13 +4,11 @@ #include "systemsettings.h" #include "coreconstants.h" -#include "coreplugin.h" #include "coreplugintr.h" #include "editormanager/editormanager_p.h" #include "dialogs/ioptionspage.h" #include "fileutils.h" #include "icore.h" -#include "iversioncontrol.h" #include "vcsmanager.h" #include @@ -61,7 +59,12 @@ SystemSettings &systemSettings() } SystemSettings::SystemSettings() + : m_startupSystemEnvironment(Environment::systemEnvironment()) { + const EnvironmentItems changes = EnvironmentItem::fromStringList( + ICore::settings()->value(kEnvironmentChanges).toStringList()); + setEnvironmentChanges(changes); + setAutoApply(false); patchCommand.setSettingsKey("General/PatchCommand"); @@ -348,7 +351,7 @@ public: updatePath(); m_environmentChangesLabel->setElideMode(Qt::ElideRight); - m_environmentChanges = CorePlugin::environmentChanges(); + m_environmentChanges = systemSettings().environmentChanges(); updateEnvironmentChangesLabel(); connect(environmentButton, &QPushButton::clicked, this, [this, environmentButton] { std::optional changes @@ -418,7 +421,7 @@ void SystemSettingsWidget::apply() } } - CorePlugin::setEnvironmentChanges(m_environmentChanges); + systemSettings().setEnvironmentChanges(m_environmentChanges); } void SystemSettingsWidget::resetTerminal() @@ -480,6 +483,25 @@ void SystemSettingsWidget::showHelpForFileBrowser() showHelpDialog(Tr::tr("Variables"), UnixUtils::fileBrowserHelpText()); } +EnvironmentItems SystemSettings::environmentChanges() const +{ + return m_environmentChanges; +} + +void SystemSettings::setEnvironmentChanges(const EnvironmentItems &changes) +{ + if (m_environmentChanges == changes) + return; + m_environmentChanges = changes; + Environment systemEnv = m_startupSystemEnvironment; + systemEnv.modify(changes); + Environment::setSystemEnvironment(systemEnv); + ICore::settings()->setValueWithDefault(kEnvironmentChanges, + EnvironmentItem::toStringList(changes)); + if (ICore::instance()) + emit ICore::instance()->systemEnvironmentChanged(); +} + // SystemSettingsPage class SystemSettingsPage final : public IOptionsPage diff --git a/src/plugins/coreplugin/systemsettings.h b/src/plugins/coreplugin/systemsettings.h index 05c4d152a4f..36bc76129d9 100644 --- a/src/plugins/coreplugin/systemsettings.h +++ b/src/plugins/coreplugin/systemsettings.h @@ -6,9 +6,12 @@ #include "core_global.h" #include +#include namespace Core::Internal { +const char kEnvironmentChanges[] = "Core/EnvironmentChanges"; + class CORE_TEST_EXPORT SystemSettings final : public Utils::AspectContainer { public: @@ -36,6 +39,13 @@ public: #endif Utils::BoolAspect askBeforeExit{this}; + + Utils::EnvironmentItems environmentChanges() const; + void setEnvironmentChanges(const Utils::EnvironmentItems &changes); + +private: + Utils::EnvironmentItems m_environmentChanges; + const Utils::Environment m_startupSystemEnvironment; }; CORE_TEST_EXPORT SystemSettings &systemSettings(); From d4eef825282a4438d19e8b4f45e111cd40fd88cf Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 20 Nov 2024 16:57:57 +0100 Subject: [PATCH 268/989] Coco: Move some build step related code from plugin to cocobuildstep.cpp Closer to the standard pattern. Change-Id: Ibbc34b66353e63009651e1593263c58d97ce917c Reviewed-by: Markus Redeker Reviewed-by: Jarek Kobus --- src/plugins/coco/cocobuildstep.cpp | 81 +++++++++++++++++++++++------- src/plugins/coco/cocobuildstep.h | 14 +----- src/plugins/coco/cocoplugin.cpp | 29 +---------- 3 files changed, 67 insertions(+), 57 deletions(-) diff --git a/src/plugins/coco/cocobuildstep.cpp b/src/plugins/coco/cocobuildstep.cpp index a28497a5618..75c0bb3a7c5 100644 --- a/src/plugins/coco/cocobuildstep.cpp +++ b/src/plugins/coco/cocobuildstep.cpp @@ -8,33 +8,23 @@ #include "cocotr.h" #include + #include -#include -#include +#include +#include + #include +#include + +#include + #include namespace Coco::Internal { using namespace ProjectExplorer; -QMakeStepFactory::QMakeStepFactory() -{ - registerStep(Utils::Id{Constants::COCO_STEP_ID}); - setSupportedProjectType(QmakeProjectManager::Constants::QMAKEPROJECT_ID); - setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); - setRepeatable(false); -} - -CMakeStepFactory::CMakeStepFactory() -{ - registerStep(Utils::Id{Constants::COCO_STEP_ID}); - setSupportedProjectType(CMakeProjectManager::Constants::CMAKE_PROJECT_ID); - setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); - setRepeatable(false); -} - CocoBuildStep *CocoBuildStep::create(BuildConfiguration *buildConfig) { // The "new" command creates a small memory leak which we can tolerate. @@ -122,4 +112,59 @@ Tasking::GroupItem CocoBuildStep::runRecipe() return Tasking::GroupItem({}); } +// Factories + +class QMakeStepFactory final : public BuildStepFactory +{ +public: + QMakeStepFactory() + { + registerStep(Utils::Id{Constants::COCO_STEP_ID}); + setSupportedProjectType(QmakeProjectManager::Constants::QMAKEPROJECT_ID); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); + setRepeatable(false); + } +}; + +class CMakeStepFactory final : public BuildStepFactory +{ +public: + CMakeStepFactory() + { + registerStep(Utils::Id{Constants::COCO_STEP_ID}); + setSupportedProjectType(CMakeProjectManager::Constants::CMAKE_PROJECT_ID); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); + setRepeatable(false); + } +}; + +static void addBuildStep(Target *target) +{ + for (BuildConfiguration *config : target->buildConfigurations()) { + if (BuildSettings::supportsBuildConfig(*config)) { + BuildStepList *steps = config->buildSteps(); + + if (!steps->contains(Constants::COCO_STEP_ID)) + steps->insertStep(0, CocoBuildStep::create(config)); + + steps->firstOfType()->display(config); + } + } +} + +void setupCocoBuildSteps() +{ + static QMakeStepFactory theQmakeStepFactory; + static CMakeStepFactory theCmakeStepFactory; + + QObject::connect(ProjectManager::instance(), &ProjectManager::projectAdded, [&](Project *project) { + if (Target *target = project->activeTarget()) + addBuildStep(target); + + QObject::connect(project, &Project::addedTarget, [](Target *target) { + addBuildStep(target); + }); + }); +} + } // namespace Coco::Internal diff --git a/src/plugins/coco/cocobuildstep.h b/src/plugins/coco/cocobuildstep.h index 15b48565fbc..d87bb0f76b1 100644 --- a/src/plugins/coco/cocobuildstep.h +++ b/src/plugins/coco/cocobuildstep.h @@ -15,18 +15,6 @@ class QPushButton; namespace Coco::Internal { -class QMakeStepFactory: public ProjectExplorer::BuildStepFactory -{ -public: - QMakeStepFactory(); -}; - -class CMakeStepFactory: public ProjectExplorer::BuildStepFactory -{ -public: - CMakeStepFactory(); -}; - class CocoBuildStep : public ProjectExplorer::BuildStep { Q_OBJECT @@ -56,4 +44,6 @@ private: QPushButton *m_reconfigureButton; }; +void setupCocoBuildSteps(); + } // namespace Coco::Internal diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index 0f453d3372c..b838d8c81dc 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -108,28 +107,13 @@ public: void addEntryToProjectSettings(); private: - QMakeStepFactory m_qmakeStepFactory; - CMakeStepFactory m_cmakeStepFactory; - CocoLanguageClient *m_client = nullptr; }; -static void addBuildStep(Target *target) -{ - for (BuildConfiguration *config : target->buildConfigurations()) { - if (BuildSettings::supportsBuildConfig(*config)) { - BuildStepList *steps = config->buildSteps(); - - if (!steps->contains(Constants::COCO_STEP_ID)) - steps->insertStep(0, CocoBuildStep::create(config)); - - steps->firstOfType()->display(config); - } - } -} - void CocoPlugin::initialize() { + setupCocoBuildSteps(); + IOptionsPage::registerCategory( "I.Coco", QCoreApplication::translate("Coco", "Coco"), @@ -139,15 +123,6 @@ void CocoPlugin::initialize() GlobalSettingsPage::instance().widget(); addEntryToProjectSettings(); - connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [&](Project *project) { - if (Target *target = project->activeTarget()) - addBuildStep(target); - - connect(project, &Project::addedTarget, this, [](Target *target) { - addBuildStep(target); - }); - }); - initLanguageServer(); } From 7c7e15cbcee049c23db0bdea95db940cca662d2c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 21 Nov 2024 11:07:50 +0100 Subject: [PATCH 269/989] Android: Move part of start setup into AndroidDebugSupport's c'tor Task-number: QTCREATORBUG-29168 Change-Id: I948c52e8fbd197591ca19e15b928f6a26642ceac Reviewed-by: hjk --- src/plugins/android/androiddebugsupport.cpp | 139 ++++++++++---------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index 2d432a6b643..00f821b3c11 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -89,6 +89,75 @@ public: setLldbPlatform("remote-android"); m_runner = new AndroidRunner(runControl); addStartDependency(m_runner); + + Target *target = runControl->target(); + Kit *kit = target->kit(); + setStartMode(AttachToRemoteServer); + const QString packageName = Internal::packageName(target); + setRunControlName(packageName); + setUseContinueInsteadOfRun(true); + + QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit); + if (!HostOsInfo::isWindowsHost() + && (qtVersion && AndroidConfig::ndkVersion(qtVersion) >= QVersionNumber(11, 0, 0))) { + qCDebug(androidDebugSupportLog) << "UseTargetAsync: " << true; + setUseTargetAsync(true); + } + + if (isCppDebugging()) { + qCDebug(androidDebugSupportLog) << "C++ debugging enabled"; + const ProjectNode *node = target->project()->findNodeForBuildKey(runControl->buildKey()); + FilePaths solibSearchPath = getSoLibSearchPath(node); + if (qtVersion) + solibSearchPath.append(qtVersion->qtSoPaths()); + const FilePaths extraLibs = getExtraLibs(node); + solibSearchPath.append(extraLibs); + + FilePath buildDir = Internal::buildDirectory(target); + const RunConfiguration *activeRunConfig = target->activeRunConfiguration(); + if (activeRunConfig) + solibSearchPath.append(activeRunConfig->buildTargetInfo().workingDirectory); + solibSearchPath.append(buildDir); + const FilePath androidLibsPath = androidBuildDirectory(target) + .pathAppended("libs") + .pathAppended(apkDevicePreferredAbi(target)); + solibSearchPath.append(androidLibsPath); + FilePath::removeDuplicates(solibSearchPath); + setSolibSearchPath(solibSearchPath); + qCDebug(androidDebugSupportLog).noquote() << "SoLibSearchPath: " << solibSearchPath; + setSymbolFile(androidAppProcessDir(target).pathAppended("app_process")); + setSkipExecutableValidation(true); + setUseExtendedRemote(true); + QString devicePreferredAbi = apkDevicePreferredAbi(target); + setAbi(androidAbi2Abi(devicePreferredAbi)); + + auto qt = static_cast(qtVersion); + const int minimumNdk = qt ? qt->minimumNDK() : 0; + + int sdkVersion = qMax(Internal::minimumSDK(kit), minimumNdk); + if (qtVersion) { + const FilePath ndkLocation = AndroidConfig::ndkLocation(qtVersion); + FilePath sysRoot = ndkLocation + / "platforms" + / QString("android-%1").arg(sdkVersion) + / devicePreferredAbi; // Legacy Ndk structure + if (!sysRoot.exists()) + sysRoot = AndroidConfig::toolchainPathFromNdk(ndkLocation) / "sysroot"; + setSysRoot(sysRoot); + qCDebug(androidDebugSupportLog).noquote() << "Sysroot: " << sysRoot.toUserOutput(); + } + } + if (isQmlDebugging()) { + qCDebug(androidDebugSupportLog) << "QML debugging enabled. QML server: " + << qmlChannel().toDisplayString(); + //TODO: Not sure if these are the right paths. + if (qtVersion) + addSearchDirectory(qtVersion->qmlPath()); + } + connect(this, &RunWorker::started, this, [this, packageName] { + qCDebug(androidDebugSupportLog) << "Starting debugger - package name: " << packageName + << ", PID: " << m_runner->pid().pid(); + }); } void start() override; @@ -99,51 +168,10 @@ private: void AndroidDebugSupport::start() { - Target *target = runControl()->target(); - Kit *kit = target->kit(); - - setStartMode(AttachToRemoteServer); - const QString packageName = Internal::packageName(target); - setRunControlName(packageName); - setUseContinueInsteadOfRun(true); setAttachPid(m_runner->pid()); - - QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit); - if (!HostOsInfo::isWindowsHost() - && (qtVersion && AndroidConfig::ndkVersion(qtVersion) >= QVersionNumber(11, 0, 0))) { - qCDebug(androidDebugSupportLog) << "UseTargetAsync: " << true; - setUseTargetAsync(true); - } - if (isCppDebugging()) { - qCDebug(androidDebugSupportLog) << "C++ debugging enabled"; - const ProjectNode *node = target->project()->findNodeForBuildKey(runControl()->buildKey()); - FilePaths solibSearchPath = getSoLibSearchPath(node); - if (qtVersion) - solibSearchPath.append(qtVersion->qtSoPaths()); - const FilePaths extraLibs = getExtraLibs(node); - solibSearchPath.append(extraLibs); - - FilePath buildDir = Internal::buildDirectory(target); - const RunConfiguration *activeRunConfig = target->activeRunConfiguration(); - if (activeRunConfig) - solibSearchPath.append(activeRunConfig->buildTargetInfo().workingDirectory); - solibSearchPath.append(buildDir); - const FilePath androidLibsPath = androidBuildDirectory(target) - .pathAppended("libs") - .pathAppended(apkDevicePreferredAbi(target)); - solibSearchPath.append(androidLibsPath); - FilePath::removeDuplicates(solibSearchPath); - setSolibSearchPath(solibSearchPath); - qCDebug(androidDebugSupportLog).noquote() << "SoLibSearchPath: " << solibSearchPath; - setSymbolFile(androidAppProcessDir(target).pathAppended("app_process")); - setSkipExecutableValidation(true); - setUseExtendedRemote(true); - QString devicePreferredAbi = apkDevicePreferredAbi(target); - setAbi(androidAbi2Abi(devicePreferredAbi)); - if (cppEngineType() == LldbEngineType) { - QString deviceSerialNumber = Internal::deviceSerialNumber(target); + QString deviceSerialNumber = Internal::deviceSerialNumber(runControl()->target()); const int colonPos = deviceSerialNumber.indexOf(QLatin1Char(':')); if (colonPos > 0) { // When wireless debugging is used then the device serial number will include a port number @@ -158,34 +186,9 @@ void AndroidDebugSupport::start() debugServer.setHost(QHostAddress(QHostAddress::LocalHost).toString()); setRemoteChannel(debugServer); } - - auto qt = static_cast(qtVersion); - const int minimumNdk = qt ? qt->minimumNDK() : 0; - - int sdkVersion = qMax(Internal::minimumSDK(kit), minimumNdk); - if (qtVersion) { - const FilePath ndkLocation = AndroidConfig::ndkLocation(qtVersion); - FilePath sysRoot = ndkLocation - / "platforms" - / QString("android-%1").arg(sdkVersion) - / devicePreferredAbi; // Legacy Ndk structure - if (!sysRoot.exists()) - sysRoot = AndroidConfig::toolchainPathFromNdk(ndkLocation) / "sysroot"; - setSysRoot(sysRoot); - qCDebug(androidDebugSupportLog).noquote() << "Sysroot: " << sysRoot.toUserOutput(); - } } - if (isQmlDebugging()) { - qCDebug(androidDebugSupportLog) << "QML debugging enabled. QML server: " - << qmlChannel().toDisplayString(); + if (isQmlDebugging()) setQmlServer(qmlChannel()); - //TODO: Not sure if these are the right paths. - if (qtVersion) - addSearchDirectory(qtVersion->qmlPath()); - } - - qCDebug(androidDebugSupportLog) << "Starting debugger - package name: " << packageName - << ", PID: " << m_runner->pid().pid(); DebuggerRunTool::start(); } From 9c012b0640f35690aa8f3ba9c6c383b12a291348 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 21 Nov 2024 12:25:16 +0100 Subject: [PATCH 270/989] BareMetal: Inline UvscServerProviderRunner Task-number: QTCREATORBUG-29168 Change-Id: Ic8c7d4e2e72510bea2000b17b83e829ee367bb26 Reviewed-by: hjk --- .../debugservers/uvsc/uvscserverprovider.cpp | 46 ++----------------- .../debugservers/uvsc/uvscserverprovider.h | 15 ------ 2 files changed, 5 insertions(+), 56 deletions(-) diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp index 0ae7e91c52f..c71c0d894af 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp @@ -204,13 +204,11 @@ bool UvscServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMess ProjectExplorer::RunWorker *UvscServerProvider::targetRunner(RunControl *runControl) const { - // Get uVision executable path. - const ProcessRunData uv = DebuggerKitAspect::runnable(runControl->kit()); - const CommandLine server{uv.command.executable(), - {"-j0", QStringLiteral("-s%1").arg(m_channel.port())}}; - ProcessRunData r; - r.command = server; - return new UvscServerProviderRunner(runControl, r); + auto worker = new SimpleTargetRunner(runControl); + worker->setId("BareMetalUvscServer"); + worker->setCommandLine({DebuggerKitAspect::runnable(runControl->kit()).command.executable(), + {"-j0", QStringLiteral("-s%1").arg(m_channel.port())}}); + return worker; } void UvscServerProvider::fromMap(const Store &data) @@ -339,38 +337,4 @@ void UvscServerProviderConfigWidget::setFromProvider() m_driverSelector->setSelection(p->driverSelection()); } -// UvscServerProviderRunner - -UvscServerProviderRunner::UvscServerProviderRunner(ProjectExplorer::RunControl *runControl, - const ProcessRunData &runnable) - : RunWorker(runControl) -{ - setId("BareMetalUvscServer"); - - m_process.setCommand(runnable.command); - - connect(&m_process, &Process::started, this, [this] { - ProcessHandle pid(m_process.processId()); - this->runControl()->setApplicationProcessHandle(pid); - reportStarted(); - }); - connect(&m_process, &Process::done, this, [this] { - appendMessage(m_process.exitMessage(), NormalMessageFormat); - reportStopped(); - }); -} - -void UvscServerProviderRunner::start() -{ - const QString msg = Tr::tr("Starting %1...").arg(m_process.commandLine().displayName()); - appendMessage(msg, NormalMessageFormat); - - m_process.start(); -} - -void UvscServerProviderRunner::stop() -{ - m_process.terminate(); -} - } // BareMetal::Internal diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h index 61bbe83f814..4649beab44e 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h @@ -115,20 +115,5 @@ protected: Uv::DriverSelector *m_driverSelector = nullptr; }; -// UvscServerProviderRunner - -class UvscServerProviderRunner final : public ProjectExplorer::RunWorker -{ -public: - explicit UvscServerProviderRunner(ProjectExplorer::RunControl *runControl, - const Utils::ProcessRunData &runnable); - -private: - void start() final; - void stop() final; - - Utils::Process m_process; -}; - } // namespace Internal } // namespace BareMetal From e726a768be61669f16cfe4596964c6cf742d124a Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 6 Nov 2024 09:05:10 +0100 Subject: [PATCH 271/989] Android: Explicit report failed run if connection fails This used to be implicit in the following attach attempt but apparently isn't anymore. Change-Id: I0d8ff3db9c38fc24aed55f1f3b6514cd6315bd4c Reviewed-by: Assam Boudjelthia --- share/qtcreator/debugger/lldbbridge.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 4863a0b3f58..57275c1e9a9 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -986,17 +986,25 @@ class Dumper(DumperBase): and self.platform_ == 'remote-android'): connect_options = lldb.SBPlatformConnectOptions(self.remoteChannel_) - res = self.target.GetPlatform().ConnectRemote(connect_options) + target_platform = self.target.GetPlatform() + + res = target_platform.ConnectRemote(connect_options) + + is_connected = target_platform.IsConnected() + + DumperBase.warn("CONNECT: %s %s target platform: %s connected: %s" + % (res, self.remoteChannel_, target_platform.GetName(), is_connected)) - DumperBase.warn("CONNECT: %s %s platform: %s connected: %s" % (res, - self.remoteChannel_, - self.target.GetPlatform().GetName(), - self.target.GetPlatform().IsConnected())) if not res.Success(): self.report(self.describeError(res)) self.reportState('enginerunfailed') return + if not is_connected: + self.report('Could not connect to debug server') + self.reportState('enginerunfailed') + return + attach_info = lldb.SBAttachInfo(self.attachPid_) self.process = self.target.Attach(attach_info, error) if not error.Success(): From 46856f4869175e5a7a644a29b3d8fda47c576790 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 21 Nov 2024 17:38:58 +0100 Subject: [PATCH 272/989] "2024" themes: Use more Token_* colors ...and less custom #rgb colors Change-Id: I38d4117755cfeb33d0e7e01f3044c3b5ef6a23ce Reviewed-by: Cristian Adam --- share/qtcreator/themes/2024.tokenmapping | 20 ++++++- share/qtcreator/themes/dark-2024.creatortheme | 57 ++++--------------- .../qtcreator/themes/light-2024.creatortheme | 41 ++----------- 3 files changed, 35 insertions(+), 83 deletions(-) diff --git a/share/qtcreator/themes/2024.tokenmapping b/share/qtcreator/themes/2024.tokenmapping index ab1d4a9ba7b..761883e2b05 100644 --- a/share/qtcreator/themes/2024.tokenmapping +++ b/share/qtcreator/themes/2024.tokenmapping @@ -9,10 +9,15 @@ BadgeLabelBackgroundColorChecked=Token_Background_Default BadgeLabelBackgroundColorUnchecked=Token_Foreground_Muted BadgeLabelTextColorChecked=Token_Text_Default BadgeLabelTextColorUnchecked=Token_Text_Default -CodeModel_Error_TextMarkColor=error -CodeModel_Warning_TextMarkColor=warning -CodeModel_Info_TextMarkColor=info +Bookmarks_TextMarkColor=Token_Notification_Neutral_Muted +CodeModel_Error_TextMarkColor=Token_Notification_Danger_Default +CodeModel_Info_TextMarkColor=Token_Notification_Neutral_Default +CodeModel_Warning_TextMarkColor=Token_Notification_Alert_Default ComboBoxTextColor=Token_Text_Muted +Debugger_Breakpoint_TextMarkColor=Token_Notification_Danger_Default +Debugger_WatchItem_ValueChanged=Token_Notification_Danger_Muted +Debugger_WatchItem_ValueInvalid=Token_Background_Subtle +Debugger_WatchItem_ValueNormal=Token_Text_Default DockWidgetResizeHandleColor=Token_Stroke_Subtle EditorPlaceholderColor=Token_Background_Muted FancyTabBarSelectedBackgroundColor=Token_Background_Muted @@ -61,6 +66,7 @@ PaletteAlternateBase=Token_Background_Muted PaletteAlternateBaseDisabled=Token_Background_Subtle PaletteBase=Token_Background_Default PaletteBaseDisabled=Token_Background_Subtle +PaletteBrightText=Token_Notification_Danger_Default PaletteBrightText=Token_Text_Default PaletteBrightTextDisabled=Token_Text_Subtle PaletteButton=Token_Background_Default @@ -115,3 +121,11 @@ TextEditor_CurrentLine_ScrollBarColor=Token_Foreground_Muted TextEditor_SearchResult_ScrollBarColor=Token_Notification_Alert_Default TextEditor_Selection_ScrollBarColor=Token_Foreground_Subtle Timeline_BackgroundColor1=Token_Background_Default +Timeline_BackgroundColor2=Token_Background_Muted +Timeline_DividerColor=Token_Stroke_Subtle +Timeline_HandleColor=Token_Text_Subtle +Timeline_HighlightColor=Token_Text_Default +Timeline_PanelBackgroundColor=Token_Background_Muted +Timeline_PanelHeaderColor=Token_Background_Muted +Timeline_RangeColor=Token_Text_Subtle +Timeline_TextColor=Token_Text_Default diff --git a/share/qtcreator/themes/dark-2024.creatortheme b/share/qtcreator/themes/dark-2024.creatortheme index 459f18e1bdd..f1a9ca352b8 100644 --- a/share/qtcreator/themes/dark-2024.creatortheme +++ b/share/qtcreator/themes/dark-2024.creatortheme @@ -6,20 +6,6 @@ DefaultTextEditorColorScheme=dark-2024.xml DefaultToolbarStyle=Relaxed [Palette] -shadowBackground=ff404142 -text=ffd0d0d0 -textDisabled=60a4a6a8 -textHighlighted=fff0f0f0 -selectedBackground=7a000000 -selectedBackgroundText=ff1d545c -normalBackground=ff2E2F30 -alternateBackground=ff353637 -error=ffdf4f4f -warning=ffecbc1c -splitter=ff06080A -textColorLinkVisited=ffa57aff -backgroundColorDisabled=ff444444 -qmlDesignerButtonColor=ff4c4e50 ;DS Theme Palette START ;greyscale @@ -130,7 +116,7 @@ DSredLight=ffff0401 DSinteraction=highlightBlue DSerrorColor=ffdf3a3a -DSwarningColor=warning +DSwarningColor=ffecbc1c DSdisabledColor=ff707070 DSinteractionHover=ff74cbfc @@ -264,8 +250,8 @@ DStoolTipText=ffdadada DSUnimportedModuleColor=ffe33c2e -DSBackgroundColorAlternate=alternateBackground -DSBackgroundColorNormal=normalBackground +DSBackgroundColorAlternate=ff353637 +DSBackgroundColorNormal=ff2E2F30 DStoolbarBackground=midnightGrey @@ -286,12 +272,12 @@ IconsCodeModelOverlayBackgroundColor=70000000 IconsCodeModelOverlayForegroundColor=ffd0d0d0 TextColorHighlightBackground=7a6f1c -OutputPanes_DebugTextColor=text +OutputPanes_DebugTextColor=Token_Text_Default OutputPanes_ErrorMessageTextColor=ffff6c6c OutputPanes_MessageOutput=ff008787 OutputPanes_NormalMessageTextColor=ff008787 OutputPanes_StdErrTextColor=ffff6666 -OutputPanes_StdOutTextColor=text +OutputPanes_StdOutTextColor=Token_Text_Default OutputPanes_WarningMessageTextColor=fff3c300 OutputPanes_TestPassTextColor=ff00b400 OutputPanes_TestFailTextColor=ffcf4848 @@ -306,46 +292,27 @@ Debugger_LogWindow_LogInput=ff00acac Debugger_LogWindow_LogStatus=ff00875a Debugger_LogWindow_LogTime=ffbf0303 -Debugger_WatchItem_ValueNormal=text -Debugger_WatchItem_ValueInvalid=textDisabled -Debugger_WatchItem_ValueChanged=ffff6666 - -Debugger_Breakpoint_TextMarkColor=ffff4040 - -Timeline_TextColor=text -Timeline_BackgroundColor2=ff444444 -Timeline_DividerColor=ff555555 -Timeline_HighlightColor=ff3099dc -Timeline_PanelBackgroundColor=ff808080 -Timeline_PanelHeaderColor=alternateBackground -Timeline_HandleColor=alternateBackground -Timeline_RangeColor=selectedBackground - -VcsBase_FileStatusUnknown_TextColor=text +VcsBase_FileStatusUnknown_TextColor=Token_Text_Default VcsBase_FileAdded_TextColor=ff00ff00 VcsBase_FileModified_TextColor=ff8ee0ff VcsBase_FileDeleted_TextColor=fffff6c6c VcsBase_FileRenamed_TextColor=ffffa500 VcsBase_FileUnmerged_TextColor=ffff4040 -Bookmarks_TextMarkColor=ff8080ff - -QmlDesigner_BackgroundColor=qmlDesignerButtonColor +QmlDesigner_BackgroundColor=ff4c4e50 QmlDesigner_HighlightColor=ff1d545c QmlDesigner_FormEditorSelectionColor=ff4ba2ff QmlDesigner_FormEditorForegroundColor=ffffffff QmlDesigner_BackgroundColorDarkAlternate=dawnGrey QmlDesigner_BackgroundColorDarker=ff262728 -QmlDesigner_BorderColor=splitter +QmlDesigner_BorderColor=ff06080A QmlDesigner_ButtonColor=ff595b5c -QmlDesigner_TabDark=shadowBackground -QmlDesigner_TabLight=text -QmlDesigner_FormeditorBackgroundColor=qmlDesignerButtonColor -QmlDesigner_AlternateBackgroundColor=qmlDesignerButtonColor +QmlDesigner_TabDark=ff404142 +QmlDesigner_TabLight=Token_Text_Default +QmlDesigner_FormeditorBackgroundColor=ff4c4e50 +QmlDesigner_AlternateBackgroundColor=ff4c4e50 QmlDesigner_ScrollBarHandleColor=ff595b5c -PaletteBrightText=ffff3333 - TerminalForeground=ffffff TerminalSelection=3fd1d1d1 TerminalFindMatch=7fffff00 diff --git a/share/qtcreator/themes/light-2024.creatortheme b/share/qtcreator/themes/light-2024.creatortheme index dacf51d6317..88d3e820674 100644 --- a/share/qtcreator/themes/light-2024.creatortheme +++ b/share/qtcreator/themes/light-2024.creatortheme @@ -6,18 +6,6 @@ DefaultTextEditorColorScheme=light-2024.xml DefaultToolbarStyle=Relaxed [Palette] -shadowBackground=PaletteDark -text=PaletteWindowText -textDisabled=PaletteTextDisabled -selectedBackground=a8ffffff -alternateBackground=PaletteAlternateBase -stop_error=ffec7373 -splitter=ffbdbebf -error=ffdf4f4f -warning=ffecbc1c -textColorLinkVisited=PaletteLinkVisited -backgroundColorDisabled=PaletteWindowDisabled -qmlDesignerButtonColor=fff8f8f8 ;DS Theme Palette START ;greyscale @@ -132,7 +120,7 @@ DSredLight=ffff0401 DSinteraction=highlightBlue DSerrorColor=ffdf3a3a -DSwarningColor=warning +DSwarningColor=ffecbc1c DSdisabledColor=ff8e8e8e DSinteractionHover=highlightHover @@ -285,7 +273,7 @@ IconsCodeModelOverlayBackgroundColor=70ffffff IconsCodeModelOverlayForegroundColor=ff232425 TextColorHighlightBackground=ffef0b -OutputPanes_DebugTextColor=text +OutputPanes_DebugTextColor=Token_Text_Default OutputPanes_ErrorMessageTextColor=ffaa0000 OutputPanes_MessageOutput=ff0000aa OutputPanes_NormalMessageTextColor=ff0000aa @@ -305,21 +293,6 @@ Debugger_LogWindow_LogInput=ff00acac Debugger_LogWindow_LogStatus=ff00875a Debugger_LogWindow_LogTime=ffbf0303 -Debugger_WatchItem_ValueNormal=text -Debugger_WatchItem_ValueInvalid=textDisabled -Debugger_WatchItem_ValueChanged=ffbf0303 - -Debugger_Breakpoint_TextMarkColor=ffff4040 - -Timeline_TextColor=text -Timeline_BackgroundColor2=fff6f6f6 -Timeline_DividerColor=ffd6d6d6 -Timeline_HighlightColor=ff3099dc -Timeline_PanelBackgroundColor=ffd6d6d6 -Timeline_PanelHeaderColor=ff888888 -Timeline_HandleColor=ff888888 -Timeline_RangeColor=selectedBackground - VcsBase_FileStatusUnknown_TextColor=ff000000 VcsBase_FileAdded_TextColor=ff00aa00 VcsBase_FileModified_TextColor=ff0000ee @@ -327,20 +300,18 @@ VcsBase_FileDeleted_TextColor=ff800000 VcsBase_FileRenamed_TextColor=ffd77d00 VcsBase_FileUnmerged_TextColor=ffee0000 -Bookmarks_TextMarkColor=ffa0a0ff - -QmlDesigner_BackgroundColor=qmlDesignerButtonColor +QmlDesigner_BackgroundColor=fff8f8f8 QmlDesigner_HighlightColor=ff46a2da QmlDesigner_FormEditorSelectionColor=ff4ba2ff QmlDesigner_FormEditorForegroundColor=ffffffff QmlDesigner_BackgroundColorDarkAlternate=ffeaeaea QmlDesigner_BackgroundColorDarker=fff5f5f5 -QmlDesigner_BorderColor=splitter +QmlDesigner_BorderColor=ffbdbebf QmlDesigner_ButtonColor=ffcccccc QmlDesigner_TabDark=ff585858 QmlDesigner_TabLight=ffd0d0d0 -QmlDesigner_FormeditorBackgroundColor=qmlDesignerButtonColor -QmlDesigner_AlternateBackgroundColor=qmlDesignerButtonColor +QmlDesigner_FormeditorBackgroundColor=fff8f8f8 +QmlDesigner_AlternateBackgroundColor=fff8f8f8 QmlDesigner_ScrollBarHandleColor=ffcccccc TerminalForeground=ff000000 From 12d55a5636f00280a2afa30da3202b5d3937f3d0 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 14 Nov 2024 13:41:00 +0100 Subject: [PATCH 273/989] Plugins: Change a few usages of PluginSpec::name to ::id First, PluginSpec had only field "name". QtC 15 added "id", which became (a lowercase) copy of "name", and which is the future-proof field to use when identifying a plugin. This change turns usages of PluginSpec::name, which are not exclusively used for user display into PluginSpec::id. In case of id string comparisons, the plugin id string turns to lowercase. Change-Id: Ibae3b06a932158cd6946e1b29192b1db0dd78a40 Reviewed-by: Marcus Tillmanns --- src/app/main.cpp | 4 +-- src/libs/extensionsystem/pluginmanager.cpp | 34 +++++++++---------- .../clangformat/clangformatindenter.cpp | 2 +- src/plugins/coreplugin/coreplugin.cpp | 2 +- src/plugins/cppeditor/cpptoolstestcase.cpp | 2 +- .../componentcore/modelnodeoperations.cpp | 2 +- src/plugins/qmldesigner/dynamiclicensecheck.h | 6 ++-- src/plugins/qmldesigner/qmldesignerplugin.cpp | 2 +- .../qmlpreviewplugin/qmlpreviewplugin.cpp | 2 +- .../tests/qmlpreviewplugin_test.cpp | 2 +- .../buildsystem/qmlbuildsystem.cpp | 2 +- .../qmlmultilanguageaspect.cpp | 12 +++---- .../qmlprojectmanager/qmlprojectplugin.cpp | 2 +- src/plugins/studiowelcome/examplecheckout.cpp | 4 +-- .../pluginmanager/tst_pluginmanager.cpp | 6 ++-- .../pluginspec/testspecs/spec1.json | 3 +- .../pluginspec/tst_pluginspec.cpp | 4 ++- 17 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index 9617037e3e6..6d4ca2f8b1b 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -404,8 +404,8 @@ QStringList lastSessionArgument() { // using insider information here is not particularly beautiful, anyhow const bool hasProjectExplorer = Utils::anyOf(PluginManager::plugins(), - Utils::equal(&PluginSpec::name, - QString("ProjectExplorer"))); + Utils::equal(&PluginSpec::id, + QString("projectexplorer"))); return hasProjectExplorer ? QStringList({"-lastsession"}) : QStringList(); } diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 6f9e0e586ae..a9ee6d60cf2 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -374,7 +374,7 @@ const QStringList PluginManager::allErrors() return Utils::transform(Utils::filtered(plugins(), [](const PluginSpec *spec) { return spec->hasError() && spec->isEffectivelyEnabled(); }), [](const PluginSpec *spec) { - return spec->name().append(": ").append(spec->errorString()); + return spec->id().append(": ").append(spec->errorString()); }); } @@ -444,11 +444,11 @@ QString PluginManager::systemInformation() result += "Plugin information:\n\n"; PluginSpec * const longestSpec = Utils::maxElementOrDefault( d->pluginSpecs, [](const PluginSpec *left, const PluginSpec *right) { - return left->name().size() < right->name().size(); + return left->id().size() < right->id().size(); }); - int size = longestSpec->name().size(); + int size = longestSpec->id().size(); for (const PluginSpec *spec : plugins()) { - result += QLatin1String(spec->isEffectivelyEnabled() ? "+ " : " ") + filled(spec->name(), size) + + result += QLatin1String(spec->isEffectivelyEnabled() ? "+ " : " ") + filled(spec->id(), size) + " " + spec->version() + "\n"; } QString settingspath = QFileInfo(settings()->fileName()).path(); @@ -606,7 +606,7 @@ QString PluginManager::serializedArguments() if (!rc.isEmpty()) rc += separator; rc += QLatin1Char(':'); - rc += ps->name(); + rc += ps->id(); rc += separator; rc += ps->arguments().join(separator); } @@ -660,7 +660,7 @@ void PluginManager::remoteArguments(const QString &serializedArgument, QObject * const QStringList arguments = subList(serializedArguments, QLatin1String(argumentKeywordC)); for (const PluginSpec *ps : plugins()) { if (ps->state() == PluginSpec::Running) { - const QStringList pluginOptions = subList(serializedArguments, QLatin1Char(':') + ps->name()); + const QStringList pluginOptions = subList(serializedArguments, QLatin1Char(':') + ps->id()); if (IPlugin *plugin = ps->plugin()) { QObject *socketParent = plugin->remoteCommand(pluginOptions, workingDirectory, arguments); @@ -815,7 +815,7 @@ void PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, void PluginManager::formatPluginVersions(QTextStream &str) { for (PluginSpec *ps : std::as_const(d->pluginSpecs)) - str << " " << ps->name() << ' ' << ps->version() << ' ' << ps->description() << '\n'; + str << " " << ps->id() << ' ' << ps->version() << ' ' << ps->description() << '\n'; } /*! @@ -969,7 +969,7 @@ void PluginManagerPrivate::startDelayedInitialize() NANOTRACE_SCOPE("ExtensionSystem", "DelayedInitialize"); while (!delayedInitializeQueue.empty()) { PluginSpec *spec = delayedInitializeQueue.front(); - const std::string specName = spec->name().toStdString(); + const std::string specName = spec->id().toStdString(); delayedInitializeQueue.pop(); NANOTRACE_SCOPE(specName, specName + "::delayedInitialized"); profilingReport(">delayedInitialize", spec); @@ -1622,7 +1622,7 @@ public: QDir().mkpath(QFileInfo(m_filePath).absolutePath()); QFile f(m_filePath); if (f.open(QIODevice::WriteOnly)) { - f.write(spec->name().toUtf8()); + f.write(spec->id().toUtf8()); f.write("\n"); f.close(); } else { @@ -1744,11 +1744,11 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt if (enableCrashCheck && destState < PluginSpec::Stopped) lockFile.reset(new LockFile(this, spec)); - const std::string specName = spec->name().toStdString(); + const std::string specId = spec->id().toStdString(); switch (destState) { case PluginSpec::Running: { - NANOTRACE_SCOPE(specName, specName + "::extensionsInitialized"); + NANOTRACE_SCOPE(specId, specId + "::extensionsInitialized"); profilingReport(">initializeExtensions", spec); spec->initializeExtensions(); profilingReport("loadLibrary", spec); spec->loadLibrary(); profilingReport("performanceData().load); break; } case PluginSpec::Initialized: { - NANOTRACE_SCOPE(specName, specName + "::initialize"); + NANOTRACE_SCOPE(specId, specId + "::initialize"); profilingReport(">initializePlugin", spec); spec->initializePlugin(); profilingReport("performanceData().initialize); @@ -1865,7 +1865,7 @@ void PluginManagerPrivate::addPlugins(const PluginSpecs &specs) enableDependenciesIndirectly(); checkForDuplicatePlugins(); // ensure deterministic plugin load order by sorting - Utils::sort(pluginSpecs, &PluginSpec::name); + Utils::sort(pluginSpecs, &PluginSpec::id); emit q->pluginsChanged(); } @@ -1966,14 +1966,14 @@ void PluginManagerPrivate::profilingReport(const char *what, const PluginSpec *s if (m_profilingVerbosity > 0) { qDebug("%-22s %-40s %8lldms (%8lldms)", what, - qPrintable(spec->name()), + qPrintable(spec->id()), absoluteElapsedMS, elapsedMS); } if (target) { QString tc; *target = elapsedMS; - tc = spec->name() + '_'; + tc = spec->id() + '_'; tc += QString::fromUtf8(QByteArray(what + 1)); Utils::Benchmarker::report("loadPlugins", tc, elapsedMS); } @@ -1997,7 +1997,7 @@ QString PluginManagerPrivate::profilingSummary(qint64 *totalOut) const continue; const qint64 t = s->performanceData().total(); summary += QString("%1 %2ms ( %3% ) (%4)\n") - .arg(s->name(), -34) + .arg(s->id(), -34) .arg(t, 8) .arg(100.0 * t / total, 5, 'f', 2) .arg(s->performanceData().summary()); diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index fc213da18ce..1b2d76813f1 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -37,7 +37,7 @@ static bool isBeautifierPluginActivated() return std::find_if(specs.begin(), specs.end(), [](ExtensionSystem::PluginSpec *spec) { - return spec->name() == "Beautifier" && spec->isEffectivelyEnabled(); + return spec->id() == "beautifier" && spec->isEffectivelyEnabled(); }) != specs.end(); } diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 1b5bad97b5b..68b8ed4bd0b 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -140,7 +140,7 @@ void CorePlugin::loadMimeFromPlugin(const ExtensionSystem::PluginSpec *plugin) const QJsonValue mimetypes = metaData.value("Mimetypes"); QString mimetypeString; if (Utils::readMultiLineString(mimetypes, &mimetypeString)) - Utils::addMimeTypes(plugin->name() + ".mimetypes", mimetypeString.trimmed().toUtf8()); + Utils::addMimeTypes(plugin->id() + ".mimetypes", mimetypeString.trimmed().toUtf8()); } static void initProxyAuthDialog() diff --git a/src/plugins/cppeditor/cpptoolstestcase.cpp b/src/plugins/cppeditor/cpptoolstestcase.cpp index 3ac2feeca38..6f9ecfa267c 100644 --- a/src/plugins/cppeditor/cpptoolstestcase.cpp +++ b/src/plugins/cppeditor/cpptoolstestcase.cpp @@ -46,7 +46,7 @@ bool isClangFormatPresent() { using namespace ExtensionSystem; return Utils::contains(PluginManager::plugins(), [](const PluginSpec *plugin) { - return plugin->name() == "ClangFormat" && plugin->isEffectivelyEnabled(); + return plugin->id() == "clangformat" && plugin->isEffectivelyEnabled(); }); }; diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index eaad9eca6f0..88bbb8fc65e 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -1761,7 +1761,7 @@ bool isEffectComposerActivated() { using namespace ExtensionSystem; return Utils::anyOf(PluginManager::plugins(), [](PluginSpec *spec) { - return spec->name() == "EffectComposer" && spec->isEffectivelyEnabled(); + return spec->id() == "effectcomposer" && spec->isEffectivelyEnabled(); }); } diff --git a/src/plugins/qmldesigner/dynamiclicensecheck.h b/src/plugins/qmldesigner/dynamiclicensecheck.h index 35100c8fd91..1a7970ad7ac 100644 --- a/src/plugins/qmldesigner/dynamiclicensecheck.h +++ b/src/plugins/qmldesigner/dynamiclicensecheck.h @@ -26,7 +26,7 @@ inline ExtensionSystem::IPlugin *licenseCheckerPlugin() { const ExtensionSystem::PluginSpec *pluginSpec = Utils::findOrDefault( ExtensionSystem::PluginManager::plugins(), - Utils::equal(&ExtensionSystem::PluginSpec::name, QString("LicenseChecker"))); + Utils::equal(&ExtensionSystem::PluginSpec::id, QString("licensechecker"))); if (pluginSpec) return pluginSpec->plugin(); @@ -37,7 +37,7 @@ inline ExtensionSystem::IPlugin *dsLicenseCheckerPlugin() { const ExtensionSystem::PluginSpec *pluginSpec = Utils::findOrDefault( ExtensionSystem::PluginManager::plugins(), - Utils::equal(&ExtensionSystem::PluginSpec::name, QString("DSLicense"))); + Utils::equal(&ExtensionSystem::PluginSpec::id, QString("dslicense"))); if (pluginSpec) return pluginSpec->plugin(); @@ -48,7 +48,7 @@ inline bool dsLicenseCheckerPluginExists() { const ExtensionSystem::PluginSpec *pluginSpec = Utils::findOrDefault( ExtensionSystem::PluginManager::plugins(), - Utils::equal(&ExtensionSystem::PluginSpec::name, QString("DSLicense"))); + Utils::equal(&ExtensionSystem::PluginSpec::id, QString("dslicense"))); return pluginSpec; } diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 97621d53936..6b3ed8aeefe 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -324,7 +324,7 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString * // uses simplified Telemetry settings page in case of Qt Design Studio ExtensionSystem::PluginSpec *usageStatistic = Utils::findOrDefault(ExtensionSystem::PluginManager::plugins(), [](ExtensionSystem::PluginSpec *p) { - return p->name() == "UsageStatistic"; + return p->id() == "usagestatistic"; }); if (usageStatistic && usageStatistic->plugin()) diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp index 31c6eb05f43..c32848c8c13 100644 --- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp +++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp @@ -170,7 +170,7 @@ QObject *QmlPreviewWidgetPlugin::getPreviewPlugin() const ExtensionSystem::PluginSpecs &specs = ExtensionSystem::PluginManager::plugins(); const auto pluginIt = std::find_if(specs.cbegin(), specs.cend(), [](const ExtensionSystem::PluginSpec *p) { - return p->name() == "QmlPreview"; + return p->id() == "qmlpreview"; }); if (pluginIt != specs.cend()) diff --git a/src/plugins/qmlpreview/tests/qmlpreviewplugin_test.cpp b/src/plugins/qmlpreview/tests/qmlpreviewplugin_test.cpp index 0b005d538f7..07f990e3115 100644 --- a/src/plugins/qmlpreview/tests/qmlpreviewplugin_test.cpp +++ b/src/plugins/qmlpreview/tests/qmlpreviewplugin_test.cpp @@ -31,7 +31,7 @@ static ExtensionSystem::IPlugin *getPlugin() { const ExtensionSystem::PluginSpecs plugins = ExtensionSystem::PluginManager::plugins(); auto it = std::find_if(plugins.begin(), plugins.end(), [](ExtensionSystem::PluginSpec *spec) { - return spec->name() == "QmlPreview"; + return spec->id() == "qmlpreview"; }); return (it == plugins.end()) ? nullptr : (*it)->plugin(); diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp index 2eae7475c83..7d0c3f00a9b 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp @@ -55,7 +55,7 @@ ExtensionSystem::IPlugin *findMcuSupportPlugin() { const ExtensionSystem::PluginSpec *pluginSpec = Utils::findOrDefault( ExtensionSystem::PluginManager::plugins(), - Utils::equal(&ExtensionSystem::PluginSpec::name, QString("McuSupport"))); + Utils::equal(&ExtensionSystem::PluginSpec::id, QString("mcusupport"))); if (pluginSpec) return pluginSpec->plugin(); diff --git a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp index 7b63452c11c..da3a68a1dfe 100644 --- a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp +++ b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp @@ -24,17 +24,17 @@ static bool isMultilanguagePresent() const ExtensionSystem::PluginSpecs &specs = ExtensionSystem::PluginManager::plugins(); return std::find_if(specs.cbegin(), specs.cend(), [](ExtensionSystem::PluginSpec *spec) { - return spec->name() == "MultiLanguage"; + return spec->id() == "multilanguage"; }) != specs.cend(); } -static QObject *getPlugin(const QString &pluginName) +static QObject *getPlugin(const QString &pluginId) { const ExtensionSystem::PluginSpecs &specs = ExtensionSystem::PluginManager::plugins(); const auto pluginIt = std::find_if( - specs.cbegin(), specs.cend(), [pluginName](const ExtensionSystem::PluginSpec *p) { - return p->name() == pluginName; + specs.cbegin(), specs.cend(), [pluginId](const ExtensionSystem::PluginSpec *p) { + return p->id() == pluginId; }); if (pluginIt != specs.cend()) @@ -81,7 +81,7 @@ void QmlMultiLanguageAspect::setCurrentLocale(const QString &locale) if (m_currentLocale == locale) return; m_currentLocale = locale; - if (auto previewPlugin = getPlugin("QmlPreview")) + if (auto previewPlugin = getPlugin("qmlpreview")) previewPlugin->setProperty("localeIsoCode", locale); } @@ -92,7 +92,7 @@ QString QmlMultiLanguageAspect::currentLocale() const Utils::FilePath QmlMultiLanguageAspect::databaseFilePath() const { - if (auto previewPlugin = getPlugin("MultiLanguage")) { + if (auto previewPlugin = getPlugin("multilanguage")) { const auto multilanguageDatabaseFilePath = previewPlugin->property("multilanguageDatabaseFilePath"); return Utils::FilePath::fromString(multilanguageDatabaseFilePath.toString()); } diff --git a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp index b92574bcbab..42d6b5b62df 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp @@ -74,7 +74,7 @@ static bool isQmlDesigner(const ExtensionSystem::PluginSpec *spec) if (!spec) return false; - return spec->name().contains("QmlDesigner"); + return spec->id().contains("qmldesigner"); } static bool qmlDesignerEnabled() diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp index da0c248535d..6f4487e5f86 100644 --- a/src/plugins/studiowelcome/examplecheckout.cpp +++ b/src/plugins/studiowelcome/examplecheckout.cpp @@ -92,8 +92,8 @@ DataModelDownloader::DataModelDownloader(QObject * /* parent */) const ExtensionSystem::PluginSpec *pluginSpec = Utils::findOrDefault(ExtensionSystem::PluginManager::plugins(), - Utils::equal(&ExtensionSystem::PluginSpec::name, - QString("StudioWelcome"))); + Utils::equal(&ExtensionSystem::PluginSpec::id, + QString("studiowelcome"))); if (!pluginSpec) return; diff --git a/tests/auto/extensionsystem/pluginmanager/tst_pluginmanager.cpp b/tests/auto/extensionsystem/pluginmanager/tst_pluginmanager.cpp index 35ed6078139..a0efcaa2e4d 100644 --- a/tests/auto/extensionsystem/pluginmanager/tst_pluginmanager.cpp +++ b/tests/auto/extensionsystem/pluginmanager/tst_pluginmanager.cpp @@ -143,14 +143,14 @@ void tst_PluginManager::circularPlugins() const PluginSpecs plugins = PluginManager::plugins(); QCOMPARE(plugins.count(), 3); for (PluginSpec *spec : plugins) { - if (spec->name() == "plugin1") { + if (spec->id() == "plugin1") { QVERIFY(spec->hasError()); QCOMPARE(spec->state(), PluginSpec::Resolved); QCOMPARE(spec->plugin(), static_cast(0)); - } else if (spec->name() == "plugin2") { + } else if (spec->id() == "plugin2") { QVERIFY2(!spec->hasError(), qPrintable(spec->errorString())); QCOMPARE(spec->state(), PluginSpec::Running); - } else if (spec->name() == "plugin3") { + } else if (spec->id() == "plugin3") { QVERIFY(spec->hasError()); QCOMPARE(spec->state(), PluginSpec::Resolved); QCOMPARE(spec->plugin(), static_cast(0)); diff --git a/tests/auto/extensionsystem/pluginspec/testspecs/spec1.json b/tests/auto/extensionsystem/pluginspec/testspecs/spec1.json index 20d51febac0..21ef3ad70d4 100644 --- a/tests/auto/extensionsystem/pluginspec/testspecs/spec1.json +++ b/tests/auto/extensionsystem/pluginspec/testspecs/spec1.json @@ -2,7 +2,8 @@ "IID" : "plugin", "MetaData" : { "Id": "test", - "Name" : "test", + "Name" : "TestPlugin", + "DisplayName" : "Test Plugin", "Version" : "1.0.1", "CompatVersion" : "1.0.0", "VendorId": "theqtcompanyltd", diff --git a/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp b/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp index a735abf348c..ff75bc039c0 100644 --- a/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp +++ b/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp @@ -92,7 +92,9 @@ void tst_PluginSpec::read() QVERIFY(spec.readMetaData(metaData("testspecs/spec1.json"))); QCOMPARE(spec.errorString(), QString()); QVERIFY(spec.errorString().isEmpty()); - QCOMPARE(spec.name(), QString("test")); + QCOMPARE(spec.id(), QString("test")); + QCOMPARE(spec.name(), QString("TestPlugin")); + QCOMPARE(spec.displayName(), QString("Test Plugin")); QCOMPARE(spec.version(), QString("1.0.1")); QCOMPARE(spec.compatVersion(), QString("1.0.0")); QCOMPARE(spec.isRequired(), false); From 017132a9597a6e3fdc689a41bcd2f6380bd29ae5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 25 Nov 2024 06:50:56 +0100 Subject: [PATCH 274/989] Core: Fix build with old Qt Qt's meta type system needs this include. Change-Id: If465f65b142a952a0be1e440090186a5cb603c8b Reviewed-by: Orgad Shaneh --- src/plugins/coreplugin/systemsettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index 1f43e1b4bfb..2eb2d5677d1 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -9,6 +9,7 @@ #include "dialogs/ioptionspage.h" #include "fileutils.h" #include "icore.h" +#include "iversioncontrol.h" // sic! #include "vcsmanager.h" #include From 6be39b39e64e06cbbf66bc68a3a2e433c1f88820 Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Thu, 21 Nov 2024 13:40:48 +0100 Subject: [PATCH 275/989] Debugger: fix pmr containers test The initial version of the pmr containers dumper test had a couple of shortcomings: * there was an inclusion of `` missing in the test program body * some test setups use compilers that do not use C++17 by default so the correct profile must be specified for the test Disabled a bunch of checks that did not work with libcxx due to incorrect reported size of `std::pmr::polymorphic_allocator>`. Fixed the libcxx dumper for `std::map` (the ordinary, non-pmr, one). As turned out, it was broken due to an incorrect padding calculation for `std::pair`. This has been worked around by using pair's inner types explicitly. Amends: cb23332ae5024358922a28bd1d06eafe4b84a363 Task number: QTCREATORBUG-30224 Change-Id: I937295f88083ee9521a35ac7dbe22303ef52bd53 Reviewed-by: hjk --- share/qtcreator/debugger/libcpp_stdtypes.py | 65 ++++++++++++--------- tests/auto/debugger/tst_dumpers.cpp | 24 +++++--- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/share/qtcreator/debugger/libcpp_stdtypes.py b/share/qtcreator/debugger/libcpp_stdtypes.py index 899a5be663d..d76e7c60a30 100644 --- a/share/qtcreator/debugger/libcpp_stdtypes.py +++ b/share/qtcreator/debugger/libcpp_stdtypes.py @@ -1,6 +1,29 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +# Disclaimers: +# 1. Looking up the allocator template type is potentially an expensive operation. +# A better alternative would be finding out the allocator type +# through accessing a class member. +# However due to different implementations doing things very differently +# it is deemed acceptable. +# Specifically: +# * GCC's `_Rb_tree_impl` basically inherits from the allocator, the comparator +# and the sentinel node +# * Clang packs the allocator and the sentinel node into a compressed pair, +# so depending on whether the allocator is sized or not, +# there may or may not be a member to access +# * MSVC goes even one step further and stores the allocator and the sentinel node together +# in a compressed pair, which in turn is stored together with the comparator inside +# another compressed pair +# 2. `size` on an empty type, which the majority of the allocators are of, +# for whatever reason reports 1. In theory there can be allocators whose type is truly 1 byte, +# in which case we will have issues, but in practice they should be rather rare. +# 3. Note that sometimes the size of `std::pmr::polymorphic_allocator` is bizarrely reported +# as exactly 0, for example this happens with +# `std::__1::pmr::polymorphic_allocator>` from `std::pmr::map`, +# so dumping pmr containers still may still have some breakages for libcxx + from stdtypes import qdump__std__array, qdump__std__complex, qdump__std__once_flag, qdump__std__unique_ptr, qdumpHelper__std__deque__libcxx, qdumpHelper__std__vector__libcxx, qdump__std__forward_list from utils import DisplayFormat from dumper import Children, DumperBase @@ -53,24 +76,10 @@ def qdump__std____1__list(d, value): def qdump__std____1__set(d, value): - # Looking up the allocator template type is potentially an expensive operation. - # A better alternative would be finding out the allocator type through accessing a class member. - # However due to different implementations doing things very differently - # it is deemed acceptable. - # Specifically: - # * GCC's `_Rb_tree_impl` basically inherits from the allocator, the comparator - # and the sentinel node - # * Clang packs the allocator and the sentinel node into a compressed pair, - # so depending on whether the allocator is sized or not, - # there may or may not be a member to access - # * MSVC goes even one step further and stores the allocator and the sentinel node together - # in a compressed pair, which in turn is stored together with the comparator inside - # another compressed pair + # see disclaimer #1 alloc_type = value.type[2] alloc_size = alloc_type.size() - # size of empty allocators (which are the majority) is reported as 1 - # in theory there can be allocators whose size is truly 1 byte, - # in which case this will cause issues, but in practice they should be rather rare + # see disclaimer #2 if alloc_size > 1: (proxy, head, alloc, size) = value.split(f'pp{{{alloc_type.name}}}p') else: @@ -109,30 +118,30 @@ def qform__std____1__map(): def qdump__std____1__map(d, value): - try: - (proxy, head, size) = value.split("ppp") - d.check(0 <= size and size <= 100 * 1000 * 1000) - - # Sometimes there is extra data at the front. Don't know why at the moment. - except RuntimeError: - (junk, proxy, head, size) = value.split("pppp") - d.check(0 <= size and size <= 100 * 1000 * 1000) + alloc_type = value.type[3] # see disclaimer #1 + alloc_size = alloc_type.size() + # see disclaimers #2 and #3 + if alloc_size > 1: + (begin_node_ptr, head, alloc, size) = value.split(f'pp{{{alloc_type.name}}}p') + else: + (begin_node_ptr, head, size) = value.split("ppp") + d.check(0 <= size and size <= 100 * 1000 * 1000) d.putItemCount(size) if d.isExpanded(): keyType = value.type[0] - valueType = value.type[1] - pairType = value.type[3][0] + valType = value.type[1] def in_order_traversal(node): - (left, right, parent, color, pad, pair) = d.split("pppB@{%s}" % (pairType.name), node) + (left, right, parent, color, _pad_1, key, _pad_2, val) = d.split( + f'pppB@{{{keyType.name}}}@{{{valType.name}}}', node) if left: for res in in_order_traversal(left): yield res - yield pair.split("{%s}@{%s}" % (keyType.name, valueType.name))[::2] + yield key, val if right: for res in in_order_traversal(right): diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 987a8c21ec7..5ed89111b4c 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -8693,6 +8693,7 @@ void tst_Dumpers::dumper_data() #include #include #include + #include #include #include #include @@ -8731,16 +8732,17 @@ void tst_Dumpers::dumper_data() us.insert(i); ums.insert(i); - m.emplace(i, i); - mm.emplace(i, i); - um.emplace(i, i); - umm.emplace(i, i); + m.emplace(i, count + i); + mm.emplace(i, count + i); + um.emplace(i, count + i); + umm.emplace(i, count + i); v.push_back(i); } )", "&d, &fl, &l, &s, &ms, &us, &ums, &m, &mm, &um, &umm, &v" } + + Cxx17Profile{} + Check{"d", "<10 items>", "std::pmr::deque"} % NoGdbEngine + Check{"d", "<10 items>", "std::pmr::deque"} % GdbEngine + Check{"d.1", "[1]", "8", "int"} @@ -8760,12 +8762,18 @@ void tst_Dumpers::dumper_data() + Check{"us", "<10 items>", "std::pmr::unordered_set"} % GdbEngine + Check{"ums", "<10 items>", "std::pmr::unordered_multiset"} % NoGdbEngine + Check{"ums", "<10 items>", "std::pmr::unordered_multiset"} % GdbEngine - + Check{"m", "<10 items>", "std::pmr::map"} % NoGdbEngine + + // There is a bizzare interaction of `DumperBase.Type.size` (see Python scripts) and libcxx + // that results in the size of + // `std::__1::pmr::polymorphic_allocator>` + // from `std::pmr::map` being reported as exactly 0 which breaks dumping + + Check{"m", "<10 items>", "std::pmr::map"} % CdbEngine + Check{"m", "<10 items>", "std::pmr::map"} % GdbEngine - + Check{"m.5", "[5] 5", "5", ""} - + Check{"mm", "<10 items>", "std::pmr::multimap"} % NoGdbEngine + + Check{"m.5", "[5] 5", "15", ""} % NoLldbEngine + + Check{"mm", "<10 items>", "std::pmr::multimap"} % CdbEngine + Check{"mm", "<10 items>", "std::pmr::multimap"} % GdbEngine - + Check{"mm.5", "[5] 5", "5", ""} + + Check{"mm.5", "[5] 5", "15", ""} % NoLldbEngine + + Check{"um", "<10 items>", "std::pmr::unordered_map"} % NoGdbEngine + Check{"um", "<10 items>", "std::pmr::unordered_map"} % GdbEngine + Check{"umm", "<10 items>", "std::pmr::unordered_multimap"} % NoGdbEngine From 19398ccbbb7de07d91740249036d264392db9e52 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 25 Nov 2024 09:20:57 +0100 Subject: [PATCH 276/989] Fix build with Crashpad Amends 55af0402c8107a4b7c610e950e09fd1b0098b8bf Change-Id: I1bb0977d2a2f816572e0b14d5885cd51dac55c92 Reviewed-by: Christian Stenger --- src/plugins/coreplugin/systemsettings.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index 2eb2d5677d1..47ededcde1e 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -12,6 +12,10 @@ #include "iversioncontrol.h" // sic! #include "vcsmanager.h" +#ifdef ENABLE_CRASHPAD +#include "coreplugin.h" +#endif + #include #include #include From d7bc681ed9a90d1e58c5bfa8cb6948d74d1f97d2 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Fri, 22 Nov 2024 09:50:09 +0100 Subject: [PATCH 277/989] Android: Fix unnecessary loop in parsePlatforms While the 'targets' value is indeed an array, we only use the first value in practice for Android builds. Simplify the code by removing the loop over 'targets' and use the first value directly. Also, try the next platform if we encounter a problem with the current one. Change-Id: Id00fc595d1a88fa81cb9c90c9ff3343704d781c7 Reviewed-by: Eike Ziller --- src/plugins/android/androidqtversion.cpp | 33 +++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/plugins/android/androidqtversion.cpp b/src/plugins/android/androidqtversion.cpp index 2276599faa9..a1da35cd8c8 100644 --- a/src/plugins/android/androidqtversion.cpp +++ b/src/plugins/android/androidqtversion.cpp @@ -212,24 +212,27 @@ static AndroidQtVersion::BuiltWith parsePlatforms(const QJsonObject &jsonObject, const QJsonObject platform = platformValue.toObject(); if (platform.value("name").toString() != QLatin1String("Android")) continue; - for (const QJsonValue &targetsValue : platform.value("targets").toArray()) { - const QJsonObject target = targetsValue.toObject(); - const QString apiVersionString = target.value("api_version").toString(); - if (apiVersionString.isNull()) - return {}; - bool apiVersionOK = false; - result.apiVersion = versionFromPlatformString(apiVersionString, &apiVersionOK); - if (!apiVersionOK) - return {}; - const QString ndkVersionString = target.value("ndk_version").toString(); - if (ndkVersionString.isNull()) - return {}; - result.ndkVersion = QVersionNumber::fromString(ndkVersionString); + const QJsonArray targets = platform.value("targets").toArray(); + if (targets.isEmpty()) + continue; + const QJsonObject target = targets.first().toObject(); + const QString apiVersionString = target.value("api_version").toString(); + if (apiVersionString.isNull()) + continue; + bool apiVersionOK = false; + result.apiVersion = versionFromPlatformString(apiVersionString, &apiVersionOK); + if (!apiVersionOK) + continue; + const QString ndkVersionString = target.value("ndk_version").toString(); + if (ndkVersionString.isNull()) + continue; + result.ndkVersion = QVersionNumber::fromString(ndkVersionString); + if (result.apiVersion != -1 && !result.ndkVersion.isNull()) { + if (ok) + *ok = true; break; } } - if (ok) - *ok = true; return result; } From b8ce8c146eb594cca917344bdc93eca6ab53c543 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 20 Nov 2024 17:27:26 +0100 Subject: [PATCH 278/989] ProjectExplorer: Use string lists to represent lines ... in the OutputParserTest. All those trailing newlines in particular were enormously confusing. Change-Id: I8b661402f4ae8c648c7d0ec662649e11da977616 Reviewed-by: Christian Stenger --- src/plugins/baremetal/iarewparser.cpp | 58 ++++---- src/plugins/baremetal/keilparser.cpp | 88 +++++------ src/plugins/baremetal/sdccparser.cpp | 58 ++++---- .../cmakeautogenparser.cpp | 24 +-- .../cmakeprojectmanager/cmakeoutputparser.cpp | 38 ++--- .../nim/project/nimoutputtaskparser.cpp | 16 +- src/plugins/projectexplorer/clangparser.cpp | 28 ++-- src/plugins/projectexplorer/customparser.cpp | 57 ++++--- src/plugins/projectexplorer/gccparser.cpp | 140 +++++++++--------- src/plugins/projectexplorer/gnumakeparser.cpp | 54 +++---- .../projectexplorer/linuxiccparser.cpp | 22 +-- src/plugins/projectexplorer/msvcparser.cpp | 71 +++++---- .../projectexplorer/outputparser_test.cpp | 49 +++--- .../projectexplorer/outputparser_test.h | 10 +- .../projectexplorer/sanitizerparser.cpp | 10 +- .../projectexplorer/xcodebuildparser.cpp | 38 ++--- .../qmakeprojectmanager/qmakeparser.cpp | 24 +-- src/plugins/qtsupport/qtparser.cpp | 46 +++--- src/plugins/qtsupport/qttestparser.cpp | 12 +- 19 files changed, 418 insertions(+), 425 deletions(-) diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp index ed548692593..6a02da9641c 100644 --- a/src/plugins/baremetal/iarewparser.cpp +++ b/src/plugins/baremetal/iarewparser.cpp @@ -244,33 +244,33 @@ void IarParserTest::testIarOutputParsers_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); - QTest::addColumn("tasks"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); + QTest::addColumn("tasks"); QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT - << "Sometext\n" << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR - << QString() << "Sometext\n" + << QStringList() << QStringList("Sometext") << Tasks(); // For std out. QTest::newRow("Error in command line") << QString::fromLatin1("Error in command line: Some error") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "Error in command line: Some error")); QTest::newRow("Linker error") << QString::fromLatin1("Error[e46]: Some error") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "[e46]: Some error")); @@ -279,8 +279,8 @@ void IarParserTest::testIarOutputParsers_data() << QString::fromLatin1("\"c:\\foo\\main.c\",63 Warning[Pe223]:\n" " Some warning \"foo\" bar") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "[Pe223]: Some warning \"foo\" bar", Utils::FilePath::fromUserInput("c:\\foo\\main.c"), @@ -292,8 +292,8 @@ void IarParserTest::testIarOutputParsers_data() "\"c:\\foo\\main.c\",63 Warning[Pe223]:\n" " Some warning") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "[Pe223]: Some warning\n" " some_detail;\n" @@ -306,8 +306,8 @@ void IarParserTest::testIarOutputParsers_data() " Some warning\n" " , split") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "[Pe223]: Some warning, split", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -317,8 +317,8 @@ void IarParserTest::testIarOutputParsers_data() << QString::fromLatin1("\"c:\\foo\\main.c\",63 Error[Pe223]:\n" " Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "[Pe223]: Some error", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -330,8 +330,8 @@ void IarParserTest::testIarOutputParsers_data() "\"c:\\foo\\main.c\",63 Error[Pe223]:\n" " Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "[Pe223]: Some error\n" " some_detail;\n" @@ -344,8 +344,8 @@ void IarParserTest::testIarOutputParsers_data() " Some error\n" " , split") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "[Pe223]: Some error, split", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -357,8 +357,8 @@ void IarParserTest::testIarOutputParsers_data() " n.c.o\n" "]") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "[Li005]: Some error \"foo\"", FilePath::fromUserInput("c:\\foo\\bar\\main.c.o"))); @@ -369,8 +369,8 @@ void IarParserTest::testIarOutputParsers_data() " c:\\bar.c\n" "Fatal error detected, aborting.") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "[Su011]: Some error:\n" " c:\\foo.c\n" @@ -379,8 +379,8 @@ void IarParserTest::testIarOutputParsers_data() QTest::newRow("At end of source") << QString::fromLatin1("At end of source Error[Pe040]: Some error \";\"") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "[Pe040]: Some error \";\"")); } @@ -392,8 +392,8 @@ void IarParserTest::testIarOutputParsers() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/baremetal/keilparser.cpp b/src/plugins/baremetal/keilparser.cpp index 8f962a205c0..9e3829610fd 100644 --- a/src/plugins/baremetal/keilparser.cpp +++ b/src/plugins/baremetal/keilparser.cpp @@ -266,17 +266,17 @@ void KeilParserTest::testKeilOutputParsers_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT - << "Sometext\n" << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR - << QString() << "Sometext\n" + << QStringList() << QStringList("Sometext") << Tasks(); // ARM compiler specific patterns. @@ -284,8 +284,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("ARM: No details warning") << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Warning: #1234: Some warning") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "#1234: Some warning", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -296,8 +296,8 @@ void KeilParserTest::testKeilOutputParsers_data() " int f;\n" " ^") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "#1234: Some warning\n" " int f;\n" @@ -308,8 +308,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("ARM: No details error") << QString::fromLatin1("\"c:\\foo\\main.c\", line 63: Error: #1234: Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "#1234: Some error", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -318,8 +318,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("ARM: No details error with column") << QString::fromLatin1("\"flash.sct\", line 51 (column 20): Error: L1234: Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "L1234: Some error", FilePath::fromUserInput("flash.sct"), @@ -330,8 +330,8 @@ void KeilParserTest::testKeilOutputParsers_data() " int f;\n" " ^") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "#1234: Some error\n" " int f;\n" @@ -342,8 +342,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("ARM: At end of source") << QString::fromLatin1("\"c:\\foo\\main.c\", line 71: Error: At end of source: #40: Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "#40: Some error", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -352,8 +352,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("ARM: Starts with error") << QString::fromLatin1("Error: L6226E: Some error.") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "L6226E: Some error.")); @@ -363,8 +363,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("MCS51: Assembler simple warning") << QString::fromLatin1("*** WARNING #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some warning") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "#A9: Some warning", FilePath::fromUserInput("c:\\foo\\dscr.a51"), @@ -373,8 +373,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("MCS51: Assembler simple error") << QString::fromLatin1("*** ERROR #A9 IN 15 (c:\\foo\\dscr.a51, LINE 15): Some error") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "#A9: Some error", FilePath::fromUserInput("c:\\foo\\dscr.a51"), @@ -385,8 +385,8 @@ void KeilParserTest::testKeilOutputParsers_data() " Some detail 1\n" " Some detail N") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "Assembler fatal error\n" " Some detail 1\n" @@ -397,8 +397,8 @@ void KeilParserTest::testKeilOutputParsers_data() "*** ___^\n" "*** ERROR #A45 IN 28 (d:\\foo.a51, LINE 28): Some error") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "#A45: Some error\n" " Some detail\n" @@ -410,8 +410,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("MCS51: Compiler simple warning") << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "C123: Some warning", FilePath::fromUserInput("c:\\foo.c"), @@ -420,8 +420,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("MCS51: Compiler extended warning") << QString::fromLatin1("*** WARNING C123 IN LINE 13 OF c:\\foo.c: Some warning : 'extended text'") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "C123: Some warning : 'extended text'", FilePath::fromUserInput("c:\\foo.c"), @@ -430,8 +430,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("MCS51: Compiler simple error") << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "C123: Some error", FilePath::fromUserInput("c:\\foo.c"), @@ -440,8 +440,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("MCS51: Compiler extended error") << QString::fromLatin1("*** ERROR C123 IN LINE 13 OF c:\\foo.c: Some error : 'extended text'") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "C123: Some error : 'extended text'", FilePath::fromUserInput("c:\\foo.c"), @@ -452,8 +452,8 @@ void KeilParserTest::testKeilOutputParsers_data() " Some detail 1\n" " Some detail N") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "Compiler fatal error\n" " Some detail 1\n" @@ -464,8 +464,8 @@ void KeilParserTest::testKeilOutputParsers_data() << QString::fromLatin1("*** WARNING L16: Some warning\n" " Some detail 1") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "L16: Some warning\n" " Some detail 1")); @@ -473,8 +473,8 @@ void KeilParserTest::testKeilOutputParsers_data() QTest::newRow("MCS51: Linker simple fatal error") << QString::fromLatin1("*** FATAL ERROR L456: Some error") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "L456: Some error")); @@ -483,8 +483,8 @@ void KeilParserTest::testKeilOutputParsers_data() " Some detail 1\n" " Some detail N") << OutputParserTester::STDOUT - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "L456: Some error\n" " Some detail 1\n" @@ -498,8 +498,8 @@ void KeilParserTest::testKeilOutputParsers() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/baremetal/sdccparser.cpp b/src/plugins/baremetal/sdccparser.cpp index 37a020a800d..f2458bad00a 100644 --- a/src/plugins/baremetal/sdccparser.cpp +++ b/src/plugins/baremetal/sdccparser.cpp @@ -159,17 +159,17 @@ void SdccParserTest::testSdccOutputParsers_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); - QTest::addColumn("tasks"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); + QTest::addColumn("tasks"); QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT - << "Sometext\n" << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR - << QString() << "Sometext\n" + << QStringList() << QStringList("Sometext") << Tasks(); // Compiler messages. @@ -177,8 +177,8 @@ void SdccParserTest::testSdccOutputParsers_data() QTest::newRow("Assembler error") << QString::fromLatin1("c:\\foo\\main.c:63: Error: Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "Some error", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -187,8 +187,8 @@ void SdccParserTest::testSdccOutputParsers_data() QTest::newRow("Compiler single line warning") << QString::fromLatin1("c:\\foo\\main.c:63: warning 123: Some warning") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "Some warning", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -199,8 +199,8 @@ void SdccParserTest::testSdccOutputParsers_data() "details #1\n" " details #2") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "Some warning\n" "details #1\n" @@ -211,8 +211,8 @@ void SdccParserTest::testSdccOutputParsers_data() QTest::newRow("Compiler simple single line error") << QString::fromLatin1("c:\\foo\\main.c:63: error: Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "Some error", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -221,8 +221,8 @@ void SdccParserTest::testSdccOutputParsers_data() QTest::newRow("Compiler single line error") << QString::fromLatin1("c:\\foo\\main.c:63: error 123: Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "Some error", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -233,8 +233,8 @@ void SdccParserTest::testSdccOutputParsers_data() "details #1\n" " details #2") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "Some error\n" "details #1\n" @@ -245,8 +245,8 @@ void SdccParserTest::testSdccOutputParsers_data() QTest::newRow("Compiler syntax error") << QString::fromLatin1("c:\\foo\\main.c:63: syntax error: Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "Some error", FilePath::fromUserInput("c:\\foo\\main.c"), @@ -255,32 +255,32 @@ void SdccParserTest::testSdccOutputParsers_data() QTest::newRow("Compiler bad option error") << QString::fromLatin1("at 1: error 123: Some error") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, "Some error")); QTest::newRow("Compiler bad option warning") << QString::fromLatin1("at 1: warning 123: Some warning") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "Some warning")); QTest::newRow("Linker warning") << QString::fromLatin1("?ASlink-Warning-Couldn't find library 'foo.lib'") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Warning, "Couldn't find library 'foo.lib'")); QTest::newRow("Linker error") << QString::fromLatin1("?ASlink-Error- : \"foo.rel\"") << OutputParserTester::STDERR - << QString() - << QString() + << QStringList() + << QStringList() << (Tasks() << CompileTask(Task::Error, " : \"foo.rel\"")); } @@ -292,8 +292,8 @@ void SdccParserTest::testSdccOutputParsers() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/cmakeprojectmanager/cmakeautogenparser.cpp b/src/plugins/cmakeprojectmanager/cmakeautogenparser.cpp index 2211432449b..7c2f2eab63d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeautogenparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeautogenparser.cpp @@ -116,17 +116,17 @@ void CMakeAutogenParserTest::testCMakeAutogenParser_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); // negative tests QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() << Tasks(); + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") - << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QString() - << QString::fromLatin1("Sometext\n") << Tasks(); + << QString::fromLatin1("Sometext") << OutputParserTester::STDERR << QStringList() + << QStringList("Sometext") << Tasks(); // positive tests QTest::newRow("AutoMoc error") << R"(AutoMoc error @@ -136,7 +136,7 @@ contains a "Q_OBJECT" macro, but does not include "main.moc"! Consider to - add #include "main.moc" - enable SKIP_AUTOMOC for this file)" - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << (Tasks() << BuildSystemTask( Task::Error, R"(AutoMoc error @@ -155,7 +155,7 @@ into included by "BIN:/src/quickcontrols/basic/impl/qtquickcontrols2basicstyleimplplugin_QtQuickControls2BasicStyleImplPlugin.cpp" Process failed with return value 1)" << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask( Task::Error, R"(AutoMoc subprocess error @@ -173,7 +173,7 @@ includes the moc file "device_p.moc" instead of "moc_device_p.cpp". Running moc on "/home/alex/src/CMake/tests/solid.orig/solid/solid/device_p.h" ! Include "moc_device_p.cpp" for compatibility with strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).)" << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask( Task::Warning, R"(AUTOMOC: warning: @@ -187,7 +187,7 @@ CMAKE_AUTOMOC_RELAXED_MODE).)")); --------------- "SRC:/src/main.cpp" includes the moc file "main.moc", but does not contain a Q_OBJECT, Q_GADGET, Q_NAMESPACE, Q_NAMESPACE_EXPORT, Q_GADGET_EXPORT, Q_ENUM_NS, K_PLUGIN_FACTORY, K_PLUGIN_CLASS, K_PLUGIN_FACTORY_WITH_JSON or K_PLUGIN_CLASS_WITH_JSON macro.)" - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << (Tasks() << BuildSystemTask( Task::Warning, R"(AutoMoc warning @@ -201,7 +201,7 @@ includes the uic file "ui_global.h", but the user interface file "global.ui" could not be found in the following directories "SRC:/monitor/ui")" << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask( Task::Error, R"(AutoUic error @@ -219,8 +219,8 @@ void CMakeAutogenParserTest::testCMakeAutogenParser() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp b/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp index 63cd8ae8f0a..387a4dfbce6 100644 --- a/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp @@ -273,18 +273,18 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); // negative tests QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks(); // positive tests @@ -300,7 +300,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() " Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp\n" " .hxx .in .txx\n\n") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "Cannot find source file:\n\n" @@ -320,7 +320,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << QString::fromLatin1("CMake Error at src/1/CMakeLists.txt:8 (add_subdirectory):\n" " add_subdirectory given source \"app1\" which is not an existing directory.\n\n") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "add_subdirectory given source \"app1\" which is not an existing directory.", @@ -330,7 +330,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << QString::fromLatin1("CMake Error at src/1/CMakeLists.txt:8 (i_am_wrong_command):\n" " Unknown CMake command \"i_am_wrong_command\".\n\n") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "Unknown CMake command \"i_am_wrong_command\".", @@ -340,7 +340,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << QString::fromLatin1("CMake Error at src/1/CMakeLists.txt:8 (message):\n" " message called with incorrect number of arguments\n\n") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "message called with incorrect number of arguments", @@ -352,7 +352,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() "Parse error. Expected \"(\", got newline with text \"\n" "\".") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "Parse error. Expected \"(\", got newline with text \"\n\".", @@ -361,9 +361,9 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() QTest::newRow("cmake error2") << QString::fromLatin1("CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.\n" "Missing variable is:\n" - "CMAKE_MAKE_PROGRAM\n") + "CMAKE_MAKE_PROGRAM\n\n") // FIXME: Test does not pass without extra newline << OutputParserTester::STDERR - << QString() << QString("Missing variable is:\nCMAKE_MAKE_PROGRAM\n") + << QStringList() << QStringList{"Missing variable is:", "CMAKE_MAKE_PROGRAM"} << (Tasks() << BuildSystemTask(Task::Error, "Error required internal CMake variable not set, " @@ -375,7 +375,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() "\n" " \".\n") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "Parse error. Expected \"(\", got newline with text \"\n" @@ -388,7 +388,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() "/test/path/CMakeLists.txt:9:15\n" "Argument not separated from preceding token by whitespace.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Warning, "Argument not separated from preceding token by whitespace.", @@ -398,7 +398,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << QString::fromLatin1("CMake Warning at CMakeLists.txt:13 (message):\n" " this is a warning\n\n") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Warning, "this is a warning", @@ -408,7 +408,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() << QString::fromLatin1("CMake Warning (dev) at CMakeLists.txt:15 (message):\n" " this is an author warning\n\n") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Warning, "this is an author warning", @@ -417,7 +417,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() QTest::newRow("eat normal CMake output") << QString::fromLatin1("-- Qt5 install prefix: /usr/lib\n" " * Plugin componentsplugin, with CONDITION TARGET QmlDesigner") - << OutputParserTester::STDERR << QString() << QString() << (Tasks()); + << OutputParserTester::STDERR << QStringList() << QStringList() << (Tasks()); QTest::newRow("cmake call-stack") << QString::fromLatin1( @@ -437,7 +437,7 @@ void CMakeOutputParserTest::testCMakeOutputParser_data() " /Qt/6.5.3/mingw_64/lib/cmake/Qt6Core/Qt6CoreMacros.cmake:741 " "(qt6_add_executable)\n" " /Projects/Test-Project/CMakeLists.txt:13 (qt_add_executable)\n") - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << (Tasks() << BuildSystemTask( Task::Error, "\n" @@ -468,8 +468,8 @@ void CMakeOutputParserTest::testCMakeOutputParser() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/nim/project/nimoutputtaskparser.cpp b/src/plugins/nim/project/nimoutputtaskparser.cpp index 90fb0009752..303a17978ba 100644 --- a/src/plugins/nim/project/nimoutputtaskparser.cpp +++ b/src/plugins/nim/project/nimoutputtaskparser.cpp @@ -58,25 +58,25 @@ void NimParserTest::testNimParser_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); // negative tests QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT - << "Sometext\n" << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR - << QString() << "Sometext\n" + << QStringList() << QStringList("Sometext") << Tasks(); // positive tests QTest::newRow("Parse error string") << QString::fromLatin1("main.nim(23, 1) Error: undeclared identifier: 'x'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, "Error: undeclared identifier: 'x'", FilePath::fromUserInput("main.nim"), 23)}); @@ -84,7 +84,7 @@ void NimParserTest::testNimParser_data() QTest::newRow("Parse warning string") << QString::fromLatin1("lib/pure/parseopt.nim(56, 34) Warning: quoteIfContainsWhite is deprecated [Deprecated]") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Warning, "Warning: quoteIfContainsWhite is deprecated [Deprecated]", FilePath::fromUserInput("lib/pure/parseopt.nim"), 56)}); @@ -97,8 +97,8 @@ void NimParserTest::testNimParser() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/projectexplorer/clangparser.cpp b/src/plugins/projectexplorer/clangparser.cpp index 98fd61f5f91..ce461050997 100644 --- a/src/plugins/projectexplorer/clangparser.cpp +++ b/src/plugins/projectexplorer/clangparser.cpp @@ -126,9 +126,9 @@ void ProjectExplorerTest::testClangOutputParser_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); - QTest::addColumn("tasks"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); + QTest::addColumn("tasks"); auto compileTask = [](Task::TaskType type, const QString &description, @@ -152,18 +152,18 @@ void ProjectExplorerTest::testClangOutputParser_data() QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks(); QTest::newRow("clang++ warning") << QString::fromLatin1("clang++: warning: argument unused during compilation: '-mthreads'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "argument unused during compilation: '-mthreads'")); @@ -171,7 +171,7 @@ void ProjectExplorerTest::testClangOutputParser_data() QTest::newRow("clang++ error") << QString::fromLatin1("clang++: error: no input files [err_drv_no_input_files]") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "no input files [err_drv_no_input_files]")); @@ -182,7 +182,7 @@ void ProjectExplorerTest::testClangOutputParser_data() "class Q_CORE_EXPORT QSysInfo {\n" " ^") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask( Task::Warning, "unknown attribute 'dllimport' ignored [-Wunknown-attributes]\n" @@ -200,7 +200,7 @@ void ProjectExplorerTest::testClangOutputParser_data() "# define Q_CORE_EXPORT Q_DECL_IMPORT\n" " ^") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Unknown, "instantiated from:\n" @@ -217,7 +217,7 @@ void ProjectExplorerTest::testClangOutputParser_data() "#include \n" " ^") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Error, "'bits/c++config.h' file not found\n" @@ -236,7 +236,7 @@ void ProjectExplorerTest::testClangOutputParser_data() " int x = option->rect.x() + horizontal ? 2 : 6;\n" " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Warning, "?: has lower precedence than +; + will be evaluated first [-Wparentheses]\n" @@ -255,7 +255,7 @@ void ProjectExplorerTest::testClangOutputParser_data() "Code Sign error: No matching provisioning profiles found: No provisioning profiles with a valid signing identity (i.e. certificate and private key pair) were found.\n" "CodeSign error: code signing is required for product type 'Application' in SDK 'iOS 7.0'") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Check dependencies\n") + << QStringList() << QStringList("Check dependencies") << (Tasks() << CompileTask(Task::Error, "No matching provisioning profiles found: No provisioning profiles with a valid signing identity (i.e. certificate and private key pair) were found.") @@ -270,8 +270,8 @@ void ProjectExplorerTest::testClangOutputParser() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp index 1a245c6b454..ff500afb6a2 100644 --- a/src/plugins/projectexplorer/customparser.cpp +++ b/src/plugins/projectexplorer/customparser.cpp @@ -373,10 +373,9 @@ void ProjectExplorerTest::testCustomOutputParsers_data() QTest::addColumn("warningFileNameCap"); QTest::addColumn("warningLineNumberCap"); QTest::addColumn("warningMessageCap"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); - QTest::addColumn("tasks"); - QTest::addColumn("outputLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); + QTest::addColumn("tasks"); const QString simplePattern = "^([a-z]+\\.[a-z]+):(\\d+): error: ([^\\s].+)$"; const FilePath fileName = FilePath::fromUserInput("main.c"); @@ -388,7 +387,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << QString() << 1 << 2 << 3 << QString() << 1 << 2 << 3 - << QString::fromLatin1("Sometext\n") << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stdout") @@ -398,7 +397,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << simplePattern << 1 << 2 << 3 << QString() << 1 << 2 << 3 - << QString::fromLatin1("Sometext\n") << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") @@ -408,11 +407,10 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << simplePattern << 1 << 2 << 3 << QString() << 1 << 2 << 3 - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks(); const QString simpleError = "main.c:9: error: `sfasdf' undeclared (first use this function)"; - const QString simpleErrorPassThrough = simpleError + '\n'; const QString message = "`sfasdf' undeclared (first use this function)"; QTest::newRow("simple error") @@ -422,7 +420,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << simplePattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, message, fileName, 9)}); const QString pathPattern = "^([a-z\\./]+):(\\d+): error: ([^\\s].+)$"; @@ -436,7 +434,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << pathPattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, message, expandedFileName, 9)}); expandedFileName = "/home/src/project/subdir/main.c"; @@ -447,7 +445,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << pathPattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, message, expandedFileName, 9)}); workingDir = "/home/src/build-project"; @@ -458,7 +456,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << pathPattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, message, expandedFileName, 9)}); QTest::newRow("simple error on wrong channel") @@ -468,7 +466,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseStdErrChannel << CustomParserExpression::ParseBothChannels << simplePattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 - << simpleErrorPassThrough << QString() + << QStringList(simpleError) << QStringList() << Tasks(); QTest::newRow("simple error on other wrong channel") @@ -478,7 +476,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseStdOutChannel << CustomParserExpression::ParseBothChannels << simplePattern << 1 << 2 << 3 << QString() << 0 << 0 << 0 - << QString() << simpleErrorPassThrough + << QStringList() << QStringList(simpleError) << Tasks(); const QString simpleError2 = "Error: Line 19 in main.c: `sfasdf' undeclared (first use this function)"; @@ -492,7 +490,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << simplePattern2 << 2 << 1 << 3 << QString() << 1 << 2 << 3 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, message, fileName, lineNumber2)}); QTest::newRow("another simple error on stdout") @@ -502,7 +500,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << simplePattern2 << 2 << 1 << 3 << QString() << 1 << 2 << 3 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, message, fileName, lineNumber2)}); const QString simpleWarningPattern = "^([a-z]+\\.[a-z]+):(\\d+): warning: ([^\\s].+)$"; @@ -516,11 +514,10 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << QString() << 1 << 2 << 3 << simpleWarningPattern << 1 << 2 << 3 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Warning, warningMessage, fileName, 1234)}); const QString simpleWarning2 = "Warning: `helloWorld' declared but not used (main.c:19)"; - const QString simpleWarningPassThrough2 = simpleWarning2 + '\n'; const QString simpleWarningPattern2 = "^Warning: (.*) \\(([a-z]+\\.[a-z]+):(\\d+)\\)$"; QTest::newRow("another simple warning on stdout") @@ -530,7 +527,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseStdOutChannel << simplePattern2 << 1 << 2 << 3 << simpleWarningPattern2 << 2 << 3 << 1 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Warning, warningMessage, fileName, lineNumber2)}); QTest::newRow("warning on wrong channel") @@ -540,7 +537,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseStdErrChannel << QString() << 1 << 2 << 3 << simpleWarningPattern2 << 2 << 3 << 1 - << simpleWarningPassThrough2 << QString() + << QStringList(simpleWarning2) << QStringList() << Tasks(); QTest::newRow("warning on other wrong channel") @@ -550,7 +547,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseStdOutChannel << QString() << 1 << 2 << 3 << simpleWarningPattern2 << 2 << 3 << 1 - << QString() << simpleWarningPassThrough2 + << QStringList() << QStringList(simpleWarning2) << Tasks(); QTest::newRow("error and *warning*") @@ -560,7 +557,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << simplePattern << 1 << 2 << 3 << simpleWarningPattern << 1 << 2 << 3 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Warning, warningMessage, fileName, 1234)}); QTest::newRow("*error* when equal pattern") @@ -570,7 +567,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << simplePattern << 1 << 2 << 3 << simplePattern << 1 << 2 << 3 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, message, fileName, 9)}); const QString unitTestError = "../LedDriver/LedDriverTest.c:63: FAIL: Expected 0x0080 Was 0xffff"; @@ -586,7 +583,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << CustomParserExpression::ParseBothChannels << unitTestPattern << 1 << 2 << 3 << QString() << 1 << 2 << 3 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, unitTestMessage, unitTestFileName, unitTestLineNumber)}); const QString leadingSpacesPattern = "^ MESSAGE:(.+)"; @@ -600,7 +597,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << leadingSpacesPattern << 2 << 3 << 1 << QString() << 1 << 2 << 3 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, "Error", {}, -1)}); QTest::newRow("leading spaces: no match") << noLeadingSpacesMessage @@ -610,7 +607,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << leadingSpacesPattern << 2 << 3 << 1 << QString() << 1 << 2 << 3 - << (noLeadingSpacesMessage + '\n') << QString() + << QStringList(noLeadingSpacesMessage) << QStringList() << Tasks(); const QString noLeadingSpacesPattern = "^MESSAGE:(.+)"; QTest::newRow("no leading spaces: match") @@ -621,7 +618,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << noLeadingSpacesPattern << 2 << 3 << 1 << QString() << 1 << 2 << 3 - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, "Error", {}, -1)}); QTest::newRow("no leading spaces: no match") << leadingSpacesMessage @@ -631,7 +628,7 @@ void ProjectExplorerTest::testCustomOutputParsers_data() << CustomParserExpression::ParseBothChannels << noLeadingSpacesPattern << 3 << 2 << 1 << QString() << 1 << 2 << 3 - << (leadingSpacesMessage + '\n') << QString() + << QStringList(leadingSpacesMessage) << QStringList() << Tasks(); } @@ -650,8 +647,8 @@ void ProjectExplorerTest::testCustomOutputParsers() QFETCH(int, warningFileNameCap); QFETCH(int, warningLineNumberCap); QFETCH(int, warningMessageCap); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); QFETCH(Tasks, tasks); CustomParserSettings settings; diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp index 15ef7a8a54b..6b162d33268 100644 --- a/src/plugins/projectexplorer/gccparser.cpp +++ b/src/plugins/projectexplorer/gccparser.cpp @@ -292,8 +292,8 @@ void ProjectExplorerTest::testGccOutputParsers_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); auto compileTask = [](Task::TaskType type, @@ -318,17 +318,17 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks(); QTest::newRow("ar output") << QString::fromLatin1("../../../../x86/i686-unknown-linux-gnu/bin/i686-unknown-linux-gnu-ar: creating lib/libSkyView.a") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("../../../../x86/i686-unknown-linux-gnu/bin/i686-unknown-linux-gnu-ar: creating lib/libSkyView.a\n") + << QStringList() << QStringList("../../../../x86/i686-unknown-linux-gnu/bin/i686-unknown-linux-gnu-ar: creating lib/libSkyView.a") << Tasks(); QTest::newRow("GCCE error") @@ -336,7 +336,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "/temp/test/untitled8/main.cpp:9: error: `sfasdf' undeclared (first use this function)\n" "/temp/test/untitled8/main.cpp:9: error: (Each undeclared identifier is reported only once for each function it appears in.)") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Error, "`sfasdf' undeclared (first use this function)\n" @@ -358,7 +358,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("GCCE warning") << QString::fromLatin1("/src/corelib/global/qglobal.h:1635: warning: inline function `QDebug qDebug()' used but never defined") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "inline function `QDebug qDebug()' used but never defined", @@ -368,7 +368,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("warning") << QString::fromLatin1("main.cpp:7:2: warning: Some warning") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "Some warning", @@ -378,7 +378,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("GCCE #error") << QString::fromLatin1("C:\\temp\\test\\untitled8\\main.cpp:7: #error Symbian error") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "#error Symbian error", @@ -389,7 +389,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("GCCE #warning1") << QString::fromLatin1("C:\\temp\\test\\untitled8\\main.cpp:8: warning: #warning Symbian warning") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "#warning Symbian warning", @@ -399,7 +399,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("GCCE #warning2") << QString::fromLatin1("/temp/test/untitled8/main.cpp:8:2: warning: #warning Symbian warning") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "#warning Symbian warning", @@ -419,7 +419,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "C:\\temp\\test\\untitled8/main.cpp:8: undefined reference to `MainWindow::doSomething()'\n" "collect2: ld returned 1 exit status") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Error, "undefined reference to `MainWindow::doSomething()'\n" @@ -443,7 +443,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "C:\\temp\\test\\untitled8/main.cpp:(.text+0x40): undefined reference to `MainWindow::doSomething()'\n" "collect2: ld returned 1 exit status") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Error, "undefined reference to `MainWindow::doSomething()'\n" @@ -457,7 +457,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("linker: dll format not recognized") << QString::fromLatin1("c:\\Qt\\4.6\\lib/QtGuid4.dll: file not recognized: File format not recognized") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "file not recognized: File format not recognized", @@ -466,7 +466,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("Invalid rpath") << QString::fromLatin1("g++: /usr/local/lib: No such file or directory") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "/usr/local/lib: No such file or directory")); @@ -476,7 +476,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "../../../../master/src/plugins/debugger/gdb/gdbengine.cpp:2114: warning: unused variable 'index'\n" "../../../../master/src/plugins/debugger/gdb/gdbengine.cpp:2115: warning: unused variable 'handler'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Warning, "unused variable 'index'\n" @@ -496,7 +496,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp:264: error: expected primary-expression before ':' token\n" "/home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp:264: error: expected ';' before ':' token") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Error, "expected primary-expression before ':' token\n" @@ -519,14 +519,14 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString::fromLatin1("distcc[73168] (dcc_get_hostlist) Warning: no hostlist is set; can't distribute work\n" "distcc[73168] (dcc_build_somewhere) Warning: failed to distribute, running locally instead") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("distcc[73168] (dcc_get_hostlist) Warning: no hostlist is set; can't distribute work\n" - "distcc[73168] (dcc_build_somewhere) Warning: failed to distribute, running locally instead\n") + << QStringList() << QStringList{"distcc[73168] (dcc_get_hostlist) Warning: no hostlist is set; can't distribute work", + "distcc[73168] (dcc_build_somewhere) Warning: failed to distribute, running locally instead"} << Tasks(); QTest::newRow("ld warning (QTCREATORBUG-905)") << QString::fromLatin1("ld: warning: Core::IEditor* QVariant::value() const has different visibility (hidden) in .obj/debug-shared/openeditorsview.o and (default) in .obj/debug-shared/editormanager.o") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "Core::IEditor* QVariant::value() const has different visibility (hidden) in .obj/debug-shared/openeditorsview.o and (default) in .obj/debug-shared/editormanager.o")); @@ -534,7 +534,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("ld fatal") << QString::fromLatin1("ld: fatal: Symbol referencing errors. No output written to testproject") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "Symbol referencing errors. No output written to testproject")); @@ -542,13 +542,13 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("Teambuilder issues") << QString::fromLatin1("TeamBuilder Client:: error: could not find Scheduler, running Job locally...") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("TeamBuilder Client:: error: could not find Scheduler, running Job locally...\n") + << QStringList() << QStringList("TeamBuilder Client:: error: could not find Scheduler, running Job locally...") << Tasks(); QTest::newRow("note") << QString::fromLatin1("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Unknown, "initialized from here", @@ -559,7 +559,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString::fromLatin1("/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c: In static member function 'static std::_Rb_tree_node_base* std::_Rb_global<_Dummy>::_Rebalance_for_erase(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&, std::_Rb_tree_node_base*&)':\n" "/Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c:194: warning: suggest explicit braces to avoid ambiguous 'else'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Warning, "suggest explicit braces to avoid ambiguous 'else'\n" @@ -577,13 +577,13 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("rm false positive") << QString::fromLatin1("rm: cannot remove `release/moc_mainwindow.cpp': No such file or directory") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("rm: cannot remove `release/moc_mainwindow.cpp': No such file or directory\n") + << QStringList() << QStringList("rm: cannot remove `release/moc_mainwindow.cpp': No such file or directory") << Tasks(); QTest::newRow("ld: missing library") << QString::fromLatin1("/usr/bin/ld: cannot find -ldoesnotexist") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "cannot find -ldoesnotexist")); @@ -593,7 +593,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "../../scriptbug/main.cpp:22: instantiated from here\n" "../../scriptbug/main.cpp:8: warning: unused variable c") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Unknown, "In function void foo(i) [with i = double]:\n" @@ -611,7 +611,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("instantiated from here") << QString::fromLatin1("main.cpp:10: instantiated from here ") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Unknown, "instantiated from here", @@ -621,7 +621,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("In constructor") << QString::fromLatin1("/dev/creator/src/plugins/find/basetextfind.h: In constructor 'Find::BaseTextFind::BaseTextFind(QTextEdit*)':") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Unknown, "In constructor 'Find::BaseTextFind::BaseTextFind(QTextEdit*)':", @@ -634,7 +634,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "../../scriptbug/main.cpp:22: instantiated from here\n" "../../scriptbug/main.cpp:5: warning: unused parameter v") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Unknown, "At global scope:\n" @@ -657,7 +657,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("gcc 4.5 fatal error") << QString::fromLatin1("/home/code/test.cpp:54:38: fatal error: test.moc: No such file or directory") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "test.moc: No such file or directory", @@ -678,7 +678,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "M:\\Development\\x64\\QtPlot/qplotaxis.cpp:26: undefined reference to `vtable for QPlotAxis'\n" "collect2: ld returned 1 exit status") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Error, "undefined reference to `vtable for QPlotAxis'\n" @@ -701,7 +701,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "../stl/main.cpp: At global scope:\n" "../stl/main.cpp:31: warning: unused parameter index") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Unknown, "In member function typename _Vector_base<_Tp, _Alloc>::_Tp_alloc_type::const_reference Vector<_Tp, _Alloc>::at(int) [with _Tp = Point, _Alloc = Allocator]:\n" @@ -743,7 +743,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "C:/Symbian_SDK/epoc32/include/e32cmn.inl: In member function 'SSecureId::operator const TSecureId&() const':\n" "C:/Symbian_SDK/epoc32/include/e32cmn.inl:7094: warning: returning reference to temporary") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask(Task::Warning, "returning reference to temporary\n" "In file included from C:/Symbian_SDK/epoc32/include/e32cmn.h:6792,\n" @@ -759,7 +759,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " 28 | memset(this, 0, sizeof(PerfEventAttributes));\n" " | ^") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask(Task::Warning, "‘void* memset(void*, int, size_t)’ clearing an object of non-trivial type ‘class PerfEventAttributes’; use assignment or value-initialization instead [-Wclass-memaccess]\n" "perfattributes.cpp: In constructor ‘PerfEventAttributes::PerfEventAttributes()’:\n" @@ -773,7 +773,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("QTCREATORBUG-2206") << QString::fromLatin1("../../../src/XmlUg/targetdelete.c: At top level:") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Unknown, "At top level:", @@ -784,7 +784,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " from :26:\n" "/Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh:1134:26: warning: no newline at end of file") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask( Task::Warning, "no newline at end of file\n" @@ -803,7 +803,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("Linker fail (release build)") << QString::fromLatin1("release/main.o:main.cpp:(.text+0x42): undefined reference to `MainWindow::doSomething()'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "undefined reference to `MainWindow::doSomething()'", @@ -813,7 +813,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString::fromLatin1("../../../src/shared/proparser/profileevaluator.cpp: In member function 'ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(const ProString&, const ProStringList&)':\n" "../../../src/shared/proparser/profileevaluator.cpp:2817:9: warning: case value '0' not in enumerated type 'ProFileEvaluator::Private::TestFunc'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Warning, "case value '0' not in enumerated type 'ProFileEvaluator::Private::TestFunc'\n" @@ -828,7 +828,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << QString::fromLatin1("In file included from :0:0:\n" "./mw.h:4:0: warning: \"STUPID_DEFINE\" redefined") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask( Task::Warning, "\"STUPID_DEFINE\" redefined\n" @@ -844,7 +844,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "file.cpp:87:10: instantiated from here\n" "file.h:21:5: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Unknown, "In function 'void UnitTest::CheckEqual(UnitTest::TestResults&, const Expected&, const Actual&, const UnitTest::TestDetails&) [with Expected = unsigned int, Actual = int]':\n" @@ -862,7 +862,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("linker error") // QTCREATORBUG-3107 << QString::fromLatin1("cns5k_ins_parser_tests.cpp:(.text._ZN20CNS5kINSParserEngine21DropBytesUntilStartedEP14CircularBufferIhE[CNS5kINSParserEngine::DropBytesUntilStarted(CircularBuffer*)]+0x6d): undefined reference to `CNS5kINSPacket::SOH_BYTE'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "undefined reference to `CNS5kINSPacket::SOH_BYTE'", @@ -871,7 +871,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("libimf warning") << QString::fromLatin1("libimf.so: warning: warning: feupdateenv is not implemented and will always fail") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "warning: feupdateenv is not implemented and will always fail", @@ -883,7 +883,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " #include \n" " ^") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask( Task::Error, "QtGui/QAction: No such file or directory\n" @@ -905,7 +905,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "/usr/include/qt4/QtCore/qstring.h:597:5: error: 'QString::QString(const char*)' is private\n" "main.cpp:7:22: error: within this context") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask( Task::Error, "'QString::QString(const char*)' is private\n" @@ -931,7 +931,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "bar.o:/home/user/test/bar.cpp:4: first defined here\n" "collect2: error: ld returned 1 exit status") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Error, "multiple definition of `foo()'\n" @@ -955,7 +955,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "bar.o:(.data+0x0): first defined here\n" "collect2: error: ld returned 1 exit status") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "multiple definition of `foo'", @@ -971,7 +971,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " \"SvgLayoutTest()\", referenced from:\n" " _main in main.cpp.o" << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks({CompileTask(Task::Error, "Undefined symbols for architecture x86_64:\n" "Undefined symbols for architecture x86_64:\n" @@ -982,7 +982,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("ld: undefined member function reference") << "obj/gtest-clang-printing.o:gtest-clang-printing.cpp:llvm::VerifyDisableABIBreakingChecks: error: undefined reference to 'llvm::DisableABIBreakingChecks'" << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "error: undefined reference to 'llvm::DisableABIBreakingChecks'", @@ -1003,7 +1003,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() ">>> referenced by test.cpp:5\n" ">>> /tmp/ccg8pzRr.o:(main)\n" "collect2: error: ld returned 1 exit status" - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << Tasks({ errorTask("ld.lld: error: undefined symbol: func()"), unknownTask("referenced by test.cpp:5", "test.cpp", 5), @@ -1015,8 +1015,8 @@ void ProjectExplorerTest::testGccOutputParsers_data() ">>> referenced by main.cpp:10 (/tmp/untitled4/main.cpp:10)\n" ">>> /tmp/Debug4/untitled4.5abe06ac/3a52ce780950d4d9/main.cpp.o:(main)\n" "clang-8: error: linker command failed with exit code 1 (use -v to see invocation)" - << OutputParserTester::STDERR << QString() - << QString("clang-8: error: linker command failed with exit code 1 (use -v to see invocation)\n") + << OutputParserTester::STDERR << QStringList() + << QStringList("clang-8: error: linker command failed with exit code 1 (use -v to see invocation)") << Tasks{ errorTask("ld.lld: error: undefined symbol: someFunc()"), unknownTask("referenced by main.cpp:10 (/tmp/untitled4/main.cpp:10)", @@ -1029,7 +1029,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() ">>> referenced by test.cpp\n" ">>> /tmp/ccvjyJph.o:(main)\n" "collect2: error: ld returned 1 exit status" - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << Tasks{ errorTask("ld.lld: error: undefined symbol: func()"), unknownTask("referenced by test.cpp", "test.cpp"), @@ -1041,7 +1041,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() << "lld-link: error: undefined symbol: __Z4funcv\n" ">>> referenced by C:\\Users\\orgads\\AppData\\Local\\Temp\\cccApKoz.o:(.text)\n" "collect2.exe: error: ld returned 1 exit status" - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << Tasks{ errorTask("lld-link: error: undefined symbol: __Z4funcv"), unknownTask("referenced by C:\\Users\\orgads\\AppData\\Local\\Temp\\cccApKoz.o:(.text)", @@ -1056,7 +1056,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() ">>> defined at test1.cpp:1\n" ">>> test1.o:(.text+0x0)\n" "collect2: error: ld returned 1 exit status" - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << Tasks{ errorTask("ld.lld: error: duplicate symbol: func()"), unknownTask("defined at test1.cpp:1", "test1.cpp", 1), @@ -1072,7 +1072,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() ">>> defined at main.cpp:5 (/tmp/untitled3/main.cpp:5)\n" ">>> /tmp/Debug/untitled3.dade828b/3a52ce780950d4d9/main.cpp.o:(.text+0x0)\n" "collect2: error: ld returned 1 exit status" - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << Tasks{ errorTask("ld.lld: error: duplicate symbol: theFunc()"), unknownTask("defined at file.cpp:1 (/tmp/untitled3/file.cpp:1)", @@ -1092,7 +1092,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() ">>> defined at test1.cpp\n" ">>> test1.o:(.text+0x0)\n" "collect2: error: ld returned 1 exit status" - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << Tasks{ errorTask("ld.lld: error: duplicate symbol: func()"), unknownTask("defined at test1.cpp", "test1.cpp"), @@ -1105,7 +1105,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("lld: multiple definitions with mingw") << "lld-link: error: duplicate symbol: __Z4funcv in test1.o and in test2.o\n" "collect2.exe: error: ld returned 1 exit status" - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << Tasks{ errorTask("lld-link: error: duplicate symbol: __Z4funcv in test1.o and in test2.o"), errorTask("collect2.exe: error: ld returned 1 exit status", {})}; @@ -1114,7 +1114,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("Mac: ranlib warning") << QString::fromLatin1("ranlib: file: lib/libtest.a(Test0.cpp.o) has no symbols") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "file: lib/libtest.a(Test0.cpp.o) has no symbols")); @@ -1122,7 +1122,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("Mac: ranlib warning2") << QString::fromLatin1("/path/to/XCode/and/ranlib: file: lib/libtest.a(Test0.cpp.o) has no symbols") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "file: lib/libtest.a(Test0.cpp.o) has no symbols")); @@ -1165,7 +1165,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " | ~~~~~~~~~~~~^~~" ) << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask(Task::Warning, "implicitly-declared ‘constexpr QVariant::Private& QVariant::Private::operator=(const QVariant::Private&)’ is deprecated [-Wdeprecated-copy]\n" "In file included from /usr/include/qt/QtCore/qlocale.h:43,\n" @@ -1251,7 +1251,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " 465 | at(newSize) = 0;\n" " | ~~~~~~~~~~~~^~~") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask(Task::Warning, "writing 1 byte into a region of size 0 [-Wstringop-overflow=]\n" "In file included from smallstringvector.h:30,\n" @@ -1288,7 +1288,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " 110 | T value;\n" " | ^~~~~") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask(Task::Error, "‘QMapNode::value’ has incomplete type\n" "In file included from qmap.h:1,\n" @@ -1327,7 +1327,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " ^\n" "1 warning generated.") << OutputParserTester::STDERR - << QString() << QString("1 warning generated.\n") + << QStringList() << QStringList("1 warning generated.") << Tasks{compileTask(Task::Warning, "comparison of integers of different signs: 'const unsigned long long' and 'const int' [-Wsign-compare]\n" "In file included from tst_addresscache.cpp:21:\n" @@ -1359,7 +1359,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " 365 | default:\n" " | ^~~~~~~") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{compileTask(Task::Warning, "this statement may fall through [-Wimplicit-fallthrough=]\n" "In file included from qmlprofilerstatisticsmodel.h:31,\n" @@ -1384,7 +1384,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() "cc1plus: warning: -Wformat-security ignored without -Wformat [-Wformat-security]\n" "compilation terminated.") << OutputParserTester::STDERR - << QString() << QString("compilation terminated.\n") + << QStringList() << QStringList("compilation terminated.") << Tasks{ CompileTask(Task::Error, "one or more PCH files were found, but they were invalid"), CompileTask(Task::Error, "use -Winvalid-pch for more information"), @@ -1394,7 +1394,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() QTest::newRow("clean path") << QString("/home/tim/path/to/sources/./and/more.h:15:22: error: blubb") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks{CompileTask(Task::Error, "blubb", "/home/tim/path/to/sources/and/more.h", 15, 22)}; @@ -1406,7 +1406,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() " 79 | apply = [p](XInterface *x) { doit_nest(x, p); };\n" " | ~~~~~~~~^~~~~") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks{compileTask( Task::Error, "use of deleted function ‘Utils::BaseAspect::BaseAspect(const Utils::BaseAspect&)’\n" @@ -1436,8 +1436,8 @@ void ProjectExplorerTest::testGccOutputParsers() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/projectexplorer/gnumakeparser.cpp b/src/plugins/projectexplorer/gnumakeparser.cpp index ace90641dd5..5ef31748a12 100644 --- a/src/plugins/projectexplorer/gnumakeparser.cpp +++ b/src/plugins/projectexplorer/gnumakeparser.cpp @@ -158,21 +158,21 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() QTest::addColumn("extraSearchDirs"); QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); - QTest::addColumn("tasks"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); + QTest::addColumn("tasks"); QTest::addColumn("additionalSearchDirs"); QTest::newRow("pass-through stdout") << QStringList() << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() + << QStringList("Sometext") << QStringList() << Tasks() << QStringList(); QTest::newRow("pass-through stderr") << QStringList() << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks() << QStringList(); QTest::newRow("pass-through gcc infos") @@ -183,12 +183,12 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() "../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]\n" "../../scriptbug/main.cpp:22: instantiated from here") << OutputParserTester::STDERR - << QString() - << QString::fromLatin1("/temp/test/untitled8/main.cpp: In function `int main(int, char**)':\n" - "../../scriptbug/main.cpp: At global scope:\n" - "../../scriptbug/main.cpp: In instantiation of void bar(i) [with i = double]:\n" - "../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]\n" - "../../scriptbug/main.cpp:22: instantiated from here\n") + << QStringList() + << QStringList{"/temp/test/untitled8/main.cpp: In function `int main(int, char**)':", + "../../scriptbug/main.cpp: At global scope:", + "../../scriptbug/main.cpp: In instantiation of void bar(i) [with i = double]:", + "../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]", + "../../scriptbug/main.cpp:22: instantiated from here"} << Tasks() << QStringList(); @@ -198,7 +198,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QString::fromLatin1("make[4]: Entering directory `/home/code/build/qt/examples/opengl/grabber'\n" "make[4]: Entering directory `/home/code/build/qt/examples/opengl/grabber'") << OutputParserTester::STDOUT - << QString() << QString() + << QStringList() << QStringList() << Tasks() << QStringList({"/home/code/build/qt/examples/opengl/grabber", "/home/code/build/qt/examples/opengl/grabber", "/test/dir"}); @@ -206,7 +206,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QStringList({"/home/code/build/qt/examples/opengl/grabber", "/test/dir"}) << QString::fromLatin1("make[4]: Leaving directory `/home/code/build/qt/examples/opengl/grabber'") << OutputParserTester::STDOUT - << QString() << QString() + << QStringList() << QStringList() << Tasks() << QStringList("/test/dir"); @@ -214,7 +214,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QStringList() << QString::fromLatin1("make: *** No rule to make target `hello.c', needed by `hello.o'. Stop.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "No rule to make target `hello.c', needed by `hello.o'. Stop.")) @@ -226,7 +226,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() "make[3]: *** Waiting for unfinished jobs....\n" "make[2]: *** [sub-projectexplorer-make_default] Error 2") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "[.obj/debug-shared/gnumakeparser.o] Error 1")) @@ -236,7 +236,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QStringList() << QString::fromLatin1("Makefile:360: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "missing separator (did you mean TAB instead of 8 spaces?). Stop.", @@ -248,7 +248,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QString::fromLatin1("mingw32-make[1]: *** [debug/qplotaxis.o] Error 1\n" "mingw32-make: *** [debug] Error 2") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "[debug/qplotaxis.o] Error 1")) @@ -258,7 +258,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QStringList() << QString::fromLatin1("mingw64-make.exe[1]: *** [dynlib.inst] Error -1073741819") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "[dynlib.inst] Error -1073741819")) @@ -268,17 +268,17 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QStringList() << QString::fromLatin1("make[2]: warning: jobserver unavailable: using -j1. Add `+' to parent make rule.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Warning, "jobserver unavailable: using -j1. Add `+' to parent make rule.")) << QStringList(); - QTest::newRow("pass-trough note") + QTest::newRow("pass-through note") << QStringList() << QString::fromLatin1("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here\n") + << QStringList() << QStringList("/home/dev/creator/share/qtcreator/debugger/dumper.cpp:1079: note: initialized from here") << Tasks() << QStringList(); @@ -286,7 +286,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QStringList() << QString::fromLatin1("C:\\Qt\\4.6.2-Symbian\\s60sdk\\epoc32\\tools\\make.exe: *** [sis] Error 2") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "[sis] Error 2")) @@ -296,7 +296,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QStringList() << QString::fromLatin1("make: g++: Command not found") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "g++: Command not found")) @@ -306,7 +306,7 @@ void ProjectExplorerTest::testGnuMakeParserParsing_data() << QStringList() << QString::fromLatin1("Makefile:794: warning: overriding commands for target `xxxx.app/Contents/Info.plist'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Warning, "overriding commands for target `xxxx.app/Contents/Info.plist'", @@ -327,8 +327,8 @@ void ProjectExplorerTest::testGnuMakeParserParsing() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); QFETCH(QStringList, additionalSearchDirs); FilePaths searchDirs = childParser->searchDirectories(); @@ -374,7 +374,7 @@ void ProjectExplorerTest::testGnuMakeParserTaskMangling() {BuildSystemTask(Task::Error, "missing separator (did you mean TAB instead of 8 spaces?). Stop.", FilePath::fromString(theMakeFile.fileName()), 360)}, - QString(), QString()); + {}, {}); } } // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/linuxiccparser.cpp b/src/plugins/projectexplorer/linuxiccparser.cpp index 255fb575126..d612ed2c984 100644 --- a/src/plugins/projectexplorer/linuxiccparser.cpp +++ b/src/plugins/projectexplorer/linuxiccparser.cpp @@ -105,23 +105,23 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks(); QTest::newRow("pch creation") << QString::fromLatin1("\".pch/Qt5Core.pchi.cpp\": creating precompiled header file \".pch/Qt5Core.pchi\"") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks(); QTest::newRow("undeclared function") @@ -130,7 +130,7 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() " ^\n" "\n") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("\n") + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "identifier \"f\" is undefined\n" @@ -146,7 +146,7 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() " ^\n" "\n") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("\n") + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "identifier \"f\" is undefined\n" @@ -161,7 +161,7 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() " ^\n" "\n") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("\n") + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "function \"AClass::privatefunc\" (declared at line 4 of \"main.h\") is inaccessible\n" @@ -175,7 +175,7 @@ void ProjectExplorerTest::testLinuxIccOutputParsers_data() " ^\n" "\n") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("\n") + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "use of \"=\" where \"==\" may have been intended\n" @@ -191,8 +191,8 @@ void ProjectExplorerTest::testLinuxIccOutputParsers() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp index 1be62b953c9..26ad3d3cb59 100644 --- a/src/plugins/projectexplorer/msvcparser.cpp +++ b/src/plugins/projectexplorer/msvcparser.cpp @@ -260,8 +260,8 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); auto compileTask = [](Task::TaskType type, @@ -285,17 +285,17 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("pass-through stdout") << "Sometext" << OutputParserTester::STDOUT - << "Sometext\n" << "" + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << "Sometext" << OutputParserTester::STDERR - << "" << "Sometext\n" + << QStringList() << QStringList("Sometext") << Tasks(); QTest::newRow("labeled error") << "qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "C4716: 'findUnresolvedModule' : must return a value", @@ -304,7 +304,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("labeled error-2015") << "qmlstandalone\\main.cpp(54): error C4716: 'findUnresolvedModule' : must return a value" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "C4716: 'findUnresolvedModule' : must return a value", @@ -313,7 +313,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("labeled error with number prefix") << "1>qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "C4716: 'findUnresolvedModule' : must return a value", @@ -322,7 +322,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("labeled warning") << "x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "C4100: 'something' : unreferenced formal parameter", @@ -331,7 +331,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("labeled warning with number prefix") << "1>x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "C4100: 'something' : unreferenced formal parameter", @@ -345,7 +345,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() "header (containing std::codecvt_mode, std::codecvt_utf8, std::codecvt_utf16, and " "std::codecvt_utf8_utf16) are deprecated in C++17. more blabla" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "STL4017: std::wbuffer_convert, std::wstring_convert, and the " @@ -358,7 +358,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << "x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n" " x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'", @@ -371,7 +371,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() << "2>x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n" " x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'", @@ -383,7 +383,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("fatal linker error") << "LINK : fatal error LNK1146: no argument specified with option '/LIBPATH:'" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "LNK1146: no argument specified with option '/LIBPATH:'")); @@ -392,7 +392,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("command line warning") << "cl : Command line warning D9002 : ignoring unknown option '-fopenmp'" << OutputParserTester::STDERR - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "D9002 : ignoring unknown option '-fopenmp'")); @@ -405,7 +405,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() " ]\n" " No constructor could take the source type, or constructor overload resolution was ambiguous" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << compileTask(Task::Error, "C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n" @@ -423,7 +423,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("Linker error 1") << "main.obj : error LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main", @@ -432,7 +432,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("Linker error 2") << "debug\\Experimentation.exe : fatal error LNK1120: 1 unresolved externals" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "LNK1120: 1 unresolved externals", @@ -441,7 +441,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("nmake error") << "Error: dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist." << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "dependent '..\\..\\..\\..\\creator-2.5\\src\\plugins\\coreplugin\\ifile.h' does not exist.")); @@ -449,7 +449,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("jom error") << "Error: dependent 'main.cpp' does not exist." << OutputParserTester::STDERR - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "dependent 'main.cpp' does not exist.")); @@ -464,7 +464,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() " _InIt=const unsigned char *\n" " ]" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'", @@ -490,7 +490,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() " could be 'C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\basetsd.h(83) : unsigned __int64 UINT64'\n" " or 'D:\\Project\\types.h(71) : Types::UINT64'" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "C2872: 'UINT64' : ambiguous symbol", @@ -505,14 +505,14 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("ignore moc note") << "/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated." << OutputParserTester::STDERR - << "" << "/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.\n" + << QStringList() << QStringList("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.") << (Tasks()); QTest::newRow("error with note") << "main.cpp(7): error C2733: 'func': second C linkage of overloaded function not allowed\n" "main.cpp(6): note: see declaration of 'func'" << OutputParserTester::STDOUT - << "" << "" + << QStringList() << QStringList() << Tasks{compileTask(Task::Error, "C2733: 'func': second C linkage of overloaded function not allowed\n" "main.cpp(7): error C2733: 'func': second C linkage of overloaded function not allowed\n" @@ -525,7 +525,7 @@ void ProjectExplorerTest::testMsvcOutputParsers_data() QTest::newRow("cyrillic warning") // QTCREATORBUG-20297 << QString::fromUtf8("cl: командная строка warning D9025: переопределение \"/MDd\" на \"/MTd\"") << OutputParserTester::STDERR - << "" << "" + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, QString::fromUtf8("D9025: переопределение \"/MDd\" на \"/MTd\""))); @@ -538,8 +538,8 @@ void ProjectExplorerTest::testMsvcOutputParsers() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } @@ -548,8 +548,8 @@ void ProjectExplorerTest::testClangClOutputParsers_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); const QString clangClCompilerLog = @@ -577,12 +577,12 @@ void ProjectExplorerTest::testClangClOutputParsers_data() "Stop."; const QString input = clangClCompilerLog + ignoredStderr; - const QString expectedStderr = ignoredStderr + '\n'; + const QStringList expectedStderr = ignoredStderr.split('\n'); QTest::newRow("error") << input << OutputParserTester::STDERR - << "" << expectedStderr + << QStringList() << expectedStderr << (Tasks() << CompileTask(Task::Warning, "private field 'm_version' is not used [-Wunused-private-field]\n" @@ -620,12 +620,11 @@ void ProjectExplorerTest::testClangClOutputParsers_data() " ^\r\n" " ;" << OutputParserTester::STDERR - << "" - << "C:\\Program Files\\LLVM\\bin\\clang-cl.exe /nologo /c /EHsc /Od -m64 /Zi /MDd " + << QStringList() + << QStringList{"C:\\Program Files\\LLVM\\bin\\clang-cl.exe /nologo /c /EHsc /Od -m64 /Zi /MDd " "/DUNICODE /D_UNICODE /DWIN32 /FdTestForError.cl.pdb " "/FoC:\\MyData\\Project_home\\cpp\build-TestForError-msvc_2017_clang-Debug\\Debug_msvc_201_47eca974c876c8b3\\TestForError.b6dd39ae\\3a52ce780950d4d9\\main.cpp.obj " - "C:\\MyData\\Project_home\\cpp\\TestForError\\main.cpp /TP\n" - " ;\n" + "C:\\MyData\\Project_home\\cpp\\TestForError\\main.cpp /TP", " ;"} << Tasks{CompileTask(Task::Error, "expected ';' after return statement\n" "C:\\MyData\\Project_home\\cpp\\TestForError\\main.cpp(3,10): error: expected ';' after return statement\n" @@ -640,8 +639,8 @@ void ProjectExplorerTest::testClangClOutputParsers() testbench.addLineParser(new ClangClParser); QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); QFETCH(Tasks, tasks); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); diff --git a/src/plugins/projectexplorer/outputparser_test.cpp b/src/plugins/projectexplorer/outputparser_test.cpp index ab7e339141a..30efe4bbcb6 100644 --- a/src/plugins/projectexplorer/outputparser_test.cpp +++ b/src/plugins/projectexplorer/outputparser_test.cpp @@ -28,9 +28,9 @@ private: Result handleLine(const QString &line, Utils::OutputFormat type) final { if (type == Utils::StdOutFormat) - m_tester->m_receivedStdOutChildLine.append(line + '\n'); + m_tester->m_receivedStdOutChildLines << line; else - m_tester->m_receivedStdErrChildLine.append(line + '\n'); + m_tester->m_receivedStdErrChildLines << line; return Status::Done; } @@ -56,11 +56,11 @@ OutputParserTester::~OutputParserTester() taskHub().disconnect(this); } -void OutputParserTester::testParsing(const QString &lines, +void OutputParserTester::testParsing(const QString &input, Channel inputChannel, Tasks tasks, - const QString &childStdOutLines, - const QString &childStdErrLines) + const QStringList &childStdOutLines, + const QStringList &childStdErrLines) { for (Utils::OutputLineParser * const parser : lineParsers()) parser->skipFileExistsCheck(); @@ -70,18 +70,15 @@ void OutputParserTester::testParsing(const QString &lines, addLineParser(terminator); reset(); - if (inputChannel == STDOUT) - appendMessage(lines + '\n', Utils::StdOutFormat); - else - appendMessage(lines + '\n', Utils::StdErrFormat); + appendMessage(input, inputChannel == STDOUT ? Utils::StdOutFormat : Utils::StdErrFormat); flush(); // delete the parser(s) to test emit aboutToDeleteParser(); setLineParsers({}); - QCOMPARE(m_receivedStdErrChildLine, childStdErrLines); - QCOMPARE(m_receivedStdOutChildLine, childStdOutLines); + QCOMPARE(m_receivedStdErrChildLines, childStdErrLines); + QCOMPARE(m_receivedStdOutChildLines, childStdOutLines); QCOMPARE(m_receivedTasks.size(), tasks.size()); if (m_receivedTasks.size() == tasks.size()) { for (int i = 0; i < tasks.size(); ++i) { @@ -116,8 +113,8 @@ void OutputParserTester::setDebugEnabled(bool debug) void OutputParserTester::reset() { - m_receivedStdErrChildLine.clear(); - m_receivedStdOutChildLine.clear(); + m_receivedStdErrChildLines.clear(); + m_receivedStdOutChildLines.clear(); m_receivedTasks.clear(); } @@ -134,44 +131,44 @@ void OutputParserTest::testAnsiFilterOutputParser_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString(); + << QStringList("Sometext") << QStringList(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Sometext\n"); + << QStringList() << QStringList("Sometext"); QString input = QString::fromLatin1("te") + QChar(27) + QString::fromLatin1("Nst"); QTest::newRow("ANSI: ESC-N") << input << OutputParserTester::STDOUT - << QString::fromLatin1("test\n") << QString(); + << QStringList("test") << QStringList(); input = QString::fromLatin1("te") + QChar(27) + QLatin1String("^ignored") + QChar(27) + QLatin1String("\\st"); QTest::newRow("ANSI: ESC-^ignoredESC-\\") << input << OutputParserTester::STDOUT - << QString::fromLatin1("test\n") << QString(); + << QStringList("test") << QStringList(); input = QString::fromLatin1("te") + QChar(27) + QLatin1String("]0;ignored") + QChar(7) + QLatin1String("st"); QTest::newRow("ANSI: window title change") << input << OutputParserTester::STDOUT - << QString::fromLatin1("test\n") << QString(); + << QStringList("test") << QStringList(); input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[Ast"); QTest::newRow("ANSI: cursor up") << input << OutputParserTester::STDOUT - << QString::fromLatin1("test\n") << QString(); + << QStringList("test") << QStringList(); input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2Ast"); QTest::newRow("ANSI: cursor up (with int parameter)") << input << OutputParserTester::STDOUT - << QString::fromLatin1("test\n") << QString(); + << QStringList("test") << QStringList(); input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[2;3Hst"); QTest::newRow("ANSI: position cursor") << input << OutputParserTester::STDOUT - << QString::fromLatin1("test\n") << QString(); + << QStringList("test") << QStringList(); input = QString::fromLatin1("te") + QChar(27) + QLatin1String("[31;1mst"); QTest::newRow("ANSI: bold red") << input << OutputParserTester::STDOUT - << QString::fromLatin1("test\n") << QString(); + << QStringList("test") << QStringList(); } void OutputParserTest::testAnsiFilterOutputParser() @@ -179,8 +176,8 @@ void OutputParserTest::testAnsiFilterOutputParser() OutputParserTester testbench; QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, Tasks(), childStdOutLines, childStdErrLines); } diff --git a/src/plugins/projectexplorer/outputparser_test.h b/src/plugins/projectexplorer/outputparser_test.h index a53097262c2..a61f3e2b812 100644 --- a/src/plugins/projectexplorer/outputparser_test.h +++ b/src/plugins/projectexplorer/outputparser_test.h @@ -29,10 +29,10 @@ public: ~OutputParserTester(); // test functions: - void testParsing(const QString &lines, Channel inputChannel, + void testParsing(const QString &input, Channel inputChannel, Tasks tasks, - const QString &childStdOutLines, - const QString &childStdErrLines); + const QStringList &childStdOutLines, + const QStringList &childStdErrLines); void setDebugEnabled(bool); @@ -44,8 +44,8 @@ private: bool m_debug = false; - QString m_receivedStdErrChildLine; - QString m_receivedStdOutChildLine; + QStringList m_receivedStdErrChildLines; + QStringList m_receivedStdOutChildLines; Tasks m_receivedTasks; friend class TestTerminator; diff --git a/src/plugins/projectexplorer/sanitizerparser.cpp b/src/plugins/projectexplorer/sanitizerparser.cpp index 54c83623e05..955620c6dab 100644 --- a/src/plugins/projectexplorer/sanitizerparser.cpp +++ b/src/plugins/projectexplorer/sanitizerparser.cpp @@ -167,8 +167,8 @@ private slots: void testParser_data() { QTest::addColumn("input"); - QTest::addColumn("tasks"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("tasks"); + QTest::addColumn("childStdErrLines"); const QString odrInput = R"(================================================================= ==3792966==ERROR: AddressSanitizer: odr-violation (0x55f0cfaeddc0): @@ -216,7 +216,7 @@ SUMMARY: AddressSanitizer: odr-violation: global 'lre_id_continue_table_ascii' a QTest::newRow("odr violation") << odrInput << QList{odrTask} - << (odrNonMatchedLines.join('\n') + "\n"); + << odrNonMatchedLines; const QString leakInput = R"( ==61167==ERROR: LeakSanitizer: detected memory leaks @@ -230,7 +230,7 @@ Direct leak of 19 byte(s) in 1 object(s) allocated from: #5 0x7eff1ea1c041 in __libc_start_main ../csu/libc-start.c:308 SUMMARY: AddressSanitizer: 19 byte(s) leaked in 1 allocation(s).)"; - const QString leakNonMatchedLines = "\n"; + const QStringList leakNonMatchedLines{QString()}; const Task leakTask(Task::Error, QString("AddressSanitizer: 19 byte(s) leaked in 1 allocation(s).") + leakInput, {}, -1, Constants::TASK_CATEGORY_SANITIZER); @@ -243,7 +243,7 @@ SUMMARY: AddressSanitizer: 19 byte(s) leaked in 1 allocation(s).)"; testbench.setLineParsers({new SanitizerParser}); QFETCH(QString, input); QFETCH(Tasks, tasks); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, OutputParserTester::STDERR, tasks, {}, childStdErrLines); } }; diff --git a/src/plugins/projectexplorer/xcodebuildparser.cpp b/src/plugins/projectexplorer/xcodebuildparser.cpp index 0cc964e8b57..1488b1f745b 100644 --- a/src/plugins/projectexplorer/xcodebuildparser.cpp +++ b/src/plugins/projectexplorer/xcodebuildparser.cpp @@ -118,45 +118,45 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() QTest::addColumn("initialStatus"); QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); - QTest::addColumn("tasks"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); + QTest::addColumn("tasks"); QTest::addColumn("finalStatus"); QTest::newRow("outside pass-through stdout") << XcodebuildParser::OutsideXcodebuild - << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() + << QString("Sometext") << OutputParserTester::STDOUT + << QStringList("Sometext") << QStringList() << Tasks() << XcodebuildParser::OutsideXcodebuild; QTest::newRow("outside pass-through stderr") << XcodebuildParser::OutsideXcodebuild << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks() << XcodebuildParser::OutsideXcodebuild; QTest::newRow("inside pass stdout to stderr") << XcodebuildParser::InXcodebuild << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks() << XcodebuildParser::InXcodebuild; QTest::newRow("inside ignore stderr") << XcodebuildParser::InXcodebuild << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks() << XcodebuildParser::InXcodebuild; QTest::newRow("unknown pass stdout to stderr") << XcodebuildParser::UnknownXcodebuildState << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks() << XcodebuildParser::UnknownXcodebuildState; QTest::newRow("unknown ignore stderr (change?)") << XcodebuildParser::UnknownXcodebuildState << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << Tasks() << XcodebuildParser::UnknownXcodebuildState; QTest::newRow("switch outside->in->outside") @@ -169,7 +169,7 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() "** BUILD SUCCEEDED **\n" "outside2") << OutputParserTester::STDOUT - << QString::fromLatin1("outside\noutside2\n") << QString::fromLatin1("in xcodebuild\nin xcodebuild2\n") + << QStringList{"outside","outside2"} << QStringList{"in xcodebuild", "in xcodebuild2"} << Tasks() << XcodebuildParser::OutsideXcodebuild; QTest::newRow("switch outside->in->outside (new)") @@ -181,7 +181,7 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() "** BUILD SUCCEEDED **\n" "outside2") << OutputParserTester::STDOUT - << QString::fromLatin1("outside\noutside2\n") << QString::fromLatin1("in xcodebuild\nin xcodebuild2\n") + << QStringList{"outside", "outside2"} << QStringList{"in xcodebuild", "in xcodebuild2"} << Tasks() << XcodebuildParser::OutsideXcodebuild; QTest::newRow("switch Unknown->in->outside") @@ -192,7 +192,7 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() "** BUILD SUCCEEDED **\n" "outside") << OutputParserTester::STDOUT - << QString::fromLatin1("outside\n") << QString::fromLatin1("unknown\nin xcodebuild\n") + << QStringList("outside") << QStringList{"unknown", "in xcodebuild"} << Tasks() << XcodebuildParser::OutsideXcodebuild; @@ -202,7 +202,7 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() "** BUILD FAILED **\n" "unknownErr") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, Tr::tr("Xcodebuild failed."))) << XcodebuildParser::UnknownXcodebuildState; @@ -213,7 +213,7 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() "** BUILD FAILED **\n" "unknownErr") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("outErr\n") + << QStringList() << QStringList("outErr") << (Tasks() << CompileTask(Task::Error, Tr::tr("Xcodebuild failed."))) << XcodebuildParser::UnknownXcodebuildState; @@ -221,7 +221,7 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() QTest::newRow("inside catch codesign replace signature") << XcodebuildParser::InXcodebuild << QString::fromLatin1("/somepath/somefile.app: replacing existing signature") << OutputParserTester::STDOUT - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, Tr::tr("Replacing signature"), "/somepath/somefile.app")) @@ -230,7 +230,7 @@ void ProjectExplorerTest::testXcodebuildParserParsing_data() QTest::newRow("outside forward codesign replace signature") << XcodebuildParser::OutsideXcodebuild << QString::fromLatin1("/somepath/somefile.app: replacing existing signature") << OutputParserTester::STDOUT - << QString::fromLatin1("/somepath/somefile.app: replacing existing signature\n") << QString() + << QStringList("/somepath/somefile.app: replacing existing signature") << QStringList() << Tasks() << XcodebuildParser::OutsideXcodebuild; } @@ -248,8 +248,8 @@ void ProjectExplorerTest::testXcodebuildParserParsing() QFETCH(ProjectExplorer::XcodebuildParser::XcodebuildStatus, initialStatus); QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); QFETCH(Tasks, tasks); QFETCH(ProjectExplorer::XcodebuildParser::XcodebuildStatus, finalStatus); diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.cpp b/src/plugins/qmakeprojectmanager/qmakeparser.cpp index 280bf14944c..568c54033b4 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparser.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparser.cpp @@ -91,23 +91,23 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); QTest::addColumn("tasks"); QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() + << QStringList("Sometext") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext") << Tasks(); QTest::newRow("qMake error") << QString::fromLatin1("Project ERROR: undefined file") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "undefined file")); @@ -115,7 +115,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() QTest::newRow("qMake Parse Error") << QString::fromLatin1("e:\\project.pro:14: Parse Error ('sth odd')") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Error, "Parse Error ('sth odd')", @@ -125,7 +125,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() QTest::newRow("qMake warning") << QString::fromLatin1("Project WARNING: bearer module might require ReadUserData capability") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Warning, "bearer module might require ReadUserData capability")); @@ -133,7 +133,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() QTest::newRow("qMake warning 2") << QString::fromLatin1("WARNING: Failure to find: blackberrycreatepackagestepconfigwidget.cpp") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Warning, "Failure to find: blackberrycreatepackagestepconfigwidget.cpp")); @@ -141,7 +141,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() QTest::newRow("qMake warning with location") << QString::fromLatin1("WARNING: e:\\QtSDK\\Simulator\\Qt\\msvc2008\\lib\\qtmaind.prl:1: Unescaped backslashes are deprecated.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Warning, "Unescaped backslashes are deprecated.", @@ -150,7 +150,7 @@ void QmakeOutputParserTest::testQmakeOutputParsers_data() QTest::newRow("moc note") << QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << BuildSystemTask(Task::Unknown, "Note: No relevant classes found. No output generated.", @@ -164,8 +164,8 @@ void QmakeOutputParserTest::testQmakeOutputParsers() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/qtsupport/qtparser.cpp b/src/plugins/qtsupport/qtparser.cpp index 28a3d08f3d4..2217448285b 100644 --- a/src/plugins/qtsupport/qtparser.cpp +++ b/src/plugins/qtsupport/qtparser.cpp @@ -129,17 +129,17 @@ void QtOutputParserTest::testQtOutputParser_data() { QTest::addColumn("input"); QTest::addColumn("inputChannel"); - QTest::addColumn("childStdOutLines"); - QTest::addColumn("childStdErrLines"); - QTest::addColumn("tasks"); + QTest::addColumn("childStdOutLines"); + QTest::addColumn("childStdErrLines"); + QTest::addColumn("tasks"); QTest::newRow("pass-through stdout") << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT - << QString::fromLatin1("Sometext\n") << QString() + << QStringList("Sometext\n") << QStringList() << Tasks(); QTest::newRow("pass-through stderr") << QString::fromLatin1("Sometext") << OutputParserTester::STDERR - << QString() << QString::fromLatin1("Sometext\n") + << QStringList() << QStringList("Sometext\n") << Tasks(); QTest::newRow("pass-through gcc infos") << QString::fromLatin1("/temp/test/untitled8/main.cpp: In function `int main(int, char**)':\n" @@ -148,66 +148,66 @@ void QtOutputParserTest::testQtOutputParser_data() "../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]\n" "../../scriptbug/main.cpp:22: instantiated from here") << OutputParserTester::STDERR - << QString() - << QString::fromLatin1("/temp/test/untitled8/main.cpp: In function `int main(int, char**)':\n" - "../../scriptbug/main.cpp: At global scope:\n" - "../../scriptbug/main.cpp: In instantiation of void bar(i) [with i = double]:\n" - "../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]\n" - "../../scriptbug/main.cpp:22: instantiated from here\n") + << QStringList() + << QStringList{"/temp/test/untitled8/main.cpp: In function `int main(int, char**)':", + "../../scriptbug/main.cpp: At global scope:", + "../../scriptbug/main.cpp: In instantiation of void bar(i) [with i = double]:", + "../../scriptbug/main.cpp:8: instantiated from void foo(i) [with i = double]", + "../../scriptbug/main.cpp:22: instantiated from here\n"} << Tasks(); QTest::newRow("qdoc warning") << QString::fromLatin1("/home/user/dev/qt5/qtscript/src/script/api/qscriptengine.cpp:295: warning: Can't create link to 'Object Trees & Ownership'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, QLatin1String("Can't create link to 'Object Trees & Ownership'"), Utils::FilePath::fromUserInput(QLatin1String("/home/user/dev/qt5/qtscript/src/script/api/qscriptengine.cpp")), 295)); QTest::newRow("moc warning") << QString::fromLatin1("..\\untitled\\errorfile.h:0: Warning: No relevant classes found. No output generated.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, QLatin1String("No relevant classes found. No output generated."), Utils::FilePath::fromUserInput(QLatin1String("..\\untitled\\errorfile.h")), -1)); QTest::newRow("moc warning 2") << QString::fromLatin1("c:\\code\\test.h(96): Warning: Property declaration ) has no READ accessor function. The property will be invalid.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, QLatin1String("Property declaration ) has no READ accessor function. The property will be invalid."), Utils::FilePath::fromUserInput(QLatin1String("c:\\code\\test.h")), 96)); QTest::newRow("moc warning (Qt 6/Windows)") << QString::fromLatin1(R"(C:/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h(38:1): error: Plugin Metadata file "QmlProfiler.json" does not exist. Declaration will be ignored)") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, R"(Plugin Metadata file "QmlProfiler.json" does not exist. Declaration will be ignored)", Utils::FilePath::fromUserInput("C:/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h"), 38, 1)); QTest::newRow("moc warning (Qt 6/Unix)") << QString::fromLatin1(R"(/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h:38:1: error: Plugin Metadata file "QmlProfiler.json" does not exist. Declaration will be ignored)") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, R"(Plugin Metadata file "QmlProfiler.json" does not exist. Declaration will be ignored)", Utils::FilePath::fromUserInput("/Users/alportal/dev/qt-creator-qt6/src/plugins/qmlprofiler/qmlprofilerplugin.h"), 38, 1)); QTest::newRow("moc note") << QString::fromLatin1("/home/qtwebkithelpviewer.h:0: Note: No relevant classes found. No output generated.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Unknown, QLatin1String("No relevant classes found. No output generated."), Utils::FilePath::fromUserInput(QLatin1String("/home/qtwebkithelpviewer.h")), -1)); QTest::newRow("ninja with moc") << QString::fromLatin1("E:/sandbox/creator/loaden/src/libs/utils/iwelcomepage.h(54): Error: Undefined interface") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, QLatin1String("Undefined interface"), Utils::FilePath::fromUserInput(QLatin1String("E:/sandbox/creator/loaden/src/libs/utils/iwelcomepage.h")), 54)); QTest::newRow("uic warning") << QString::fromLatin1("mainwindow.ui: Warning: The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, "The name 'pushButton' (QPushButton) is already in use, defaulting to 'pushButton1'.", @@ -215,7 +215,7 @@ void QtOutputParserTest::testQtOutputParser_data() QTest::newRow("translation") << QString::fromLatin1("Warning: dropping duplicate messages in '/some/place/qtcreator_fr.qm'") << OutputParserTester::STDERR - << QString() << QString() + << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Warning, QLatin1String("dropping duplicate messages"), Utils::FilePath::fromUserInput(QLatin1String("/some/place/qtcreator_fr.qm")), -1)); @@ -229,7 +229,7 @@ void QtOutputParserTest::testQtOutputParser_data() QTest::newRow("qmlsc/qmllint error") // QTCREATORBUG-28720 << QString::fromLatin1("Error: E:/foo/PerfProfilerFlameGraphView.qml:10:5: " "Could not compile binding for model: Cannot resolve property type for binding on model") - << OutputParserTester::STDERR << QString() << QString() + << OutputParserTester::STDERR << QStringList() << QStringList() << (Tasks() << CompileTask(Task::Error, "Could not compile binding for model: Cannot resolve property type for binding on model", Utils::FilePath::fromUserInput("E:/foo/PerfProfilerFlameGraphView.qml"), 10, 5)); @@ -242,8 +242,8 @@ void QtOutputParserTest::testQtOutputParser() QFETCH(QString, input); QFETCH(OutputParserTester::Channel, inputChannel); QFETCH(Tasks, tasks); - QFETCH(QString, childStdOutLines); - QFETCH(QString, childStdErrLines); + QFETCH(QStringList, childStdOutLines); + QFETCH(QStringList, childStdErrLines); testbench.testParsing(input, inputChannel, tasks, childStdOutLines, childStdErrLines); } diff --git a/src/plugins/qtsupport/qttestparser.cpp b/src/plugins/qtsupport/qttestparser.cpp index 07047c376bb..73c1fc45775 100644 --- a/src/plugins/qtsupport/qttestparser.cpp +++ b/src/plugins/qtsupport/qttestparser.cpp @@ -105,11 +105,11 @@ void QtTestParserTest::testQtTestOutputParser() #endif "XPASS: irrelevant\n" "PASS : MyTest::anotherTest()"; - const QString expectedChildOutput = - "random output\n" - "PASS : MyTest::someTest()\n" - "XPASS: irrelevant\n" - "PASS : MyTest::anotherTest()\n"; + const QStringList expectedChildOutput{ + "random output", + "PASS : MyTest::someTest()", + "XPASS: irrelevant", + "PASS : MyTest::anotherTest()\n"}; const FilePath theFile = FilePath::fromString(HostOsInfo::isWindowsHost() ? QString("C:/dev/tests/tst_mytest.cpp") : QString("/home/me/tests/tst_mytest.cpp")); const Tasks expectedTasks{ @@ -121,7 +121,7 @@ void QtTestParserTest::testQtTestOutputParser() " Expected (true) : 1", theFile, 220, Constants::TASK_CATEGORY_AUTOTEST)}; testbench.testParsing(input, OutputParserTester::STDOUT, expectedTasks, expectedChildOutput, - QString()); + QStringList()); } QObject *createQtTestParserTest() From b8f8f8bfd8b34bf491db3fdac78206140556e450 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 25 Nov 2024 12:30:08 +0100 Subject: [PATCH 279/989] QmlDesigner: Fix application output color Only relevant for QmlDesigner running in Qt Creator (not QDS), and for non-QDS themes. Fixes: QTCREATORBUG-31830 Change-Id: I075f5df41edb0ea7c4a76681c7ca1ec7c2d55389 Reviewed-by: Christian Stenger --- share/qtcreator/themes/dark-2024.creatortheme | 2 +- share/qtcreator/themes/dark.creatortheme | 2 +- share/qtcreator/themes/default.creatortheme | 2 +- share/qtcreator/themes/flat-dark.creatortheme | 2 +- share/qtcreator/themes/flat-light.creatortheme | 2 +- share/qtcreator/themes/flat.creatortheme | 2 +- share/qtcreator/themes/light-2024.creatortheme | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/share/qtcreator/themes/dark-2024.creatortheme b/share/qtcreator/themes/dark-2024.creatortheme index f1a9ca352b8..9e85abfe2fe 100644 --- a/share/qtcreator/themes/dark-2024.creatortheme +++ b/share/qtcreator/themes/dark-2024.creatortheme @@ -196,7 +196,7 @@ DSdockContainerBackground=ff242424 DSdockContainerSplitter=ff323232 DSdockAreaBackground=ff262728 -DSdockWidgetBackground=ff00ff00 +DSdockWidgetBackground=dawnGrey DSdockWidgetSplitter=fullBlack DSdockWidgetTitleBar=dawnGrey diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index e12a4d893c3..264b3aa055c 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -212,7 +212,7 @@ DSdockContainerBackground=ff242424 DSdockContainerSplitter=ff323232 DSdockAreaBackground=ff262728 -DSdockWidgetBackground=ff00ff00 +DSdockWidgetBackground=dawnGrey DSdockWidgetSplitter=fullBlack DSdockWidgetTitleBar=dawnGrey diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index f822eaa287a..327f1a1eb82 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -207,7 +207,7 @@ DSdockContainerBackground=ff323232 DSdockContainerSplitter=ff323232 DSdockAreaBackground=ff262728 -DSdockWidgetBackground=ff00ff00 +DSdockWidgetBackground=dawnGrey DSdockWidgetSplitter=ff595959 DSdockWidgetTitleBar=ffeaeaea diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index 100a5e8c74c..db6a057fe1a 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -216,7 +216,7 @@ DSdockContainerBackground=ff242424 DSdockContainerSplitter=ff323232 DSdockAreaBackground=ff262728 -DSdockWidgetBackground=ff00ff00 +DSdockWidgetBackground=dawnGrey DSdockWidgetSplitter=fullBlack DSdockWidgetTitleBar=dawnGrey diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index 7d39156e23a..6f76942b3a9 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -218,7 +218,7 @@ DSdockContainerBackground=ff323232 DSdockContainerSplitter=ff323232 DSdockAreaBackground=ff262728 -DSdockWidgetBackground=ff00ff00 +DSdockWidgetBackground=dawnGrey DSdockWidgetSplitter=ff595959 DSdockWidgetTitleBar=ffeaeaea diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index 9e9d14e7fd0..0512ff08ac8 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -213,7 +213,7 @@ DSdockContainerBackground=ff242424 DSdockContainerSplitter=ff323232 DSdockAreaBackground=ff262728 -DSdockWidgetBackground=ff00ff00 +DSdockWidgetBackground=dawnGrey DSdockWidgetSplitter=fullBlack DSdockWidgetTitleBar=dawnGrey diff --git a/share/qtcreator/themes/light-2024.creatortheme b/share/qtcreator/themes/light-2024.creatortheme index 88d3e820674..722710b2d39 100644 --- a/share/qtcreator/themes/light-2024.creatortheme +++ b/share/qtcreator/themes/light-2024.creatortheme @@ -199,7 +199,7 @@ DSdockContainerBackground=ff323232 DSdockContainerSplitter=ff323232 DSdockAreaBackground=ff262728 -DSdockWidgetBackground=ff00ff00 +DSdockWidgetBackground=dawnGrey DSdockWidgetSplitter=ff595959 DSdockWidgetTitleBar=ffeaeaea From 7d6c3beb50016ba7f85d57204ed6d6f5dca9919a Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 20 Nov 2024 14:31:18 +0100 Subject: [PATCH 280/989] ProjectExplorer: Use Widget as project delegate in ProjectWelcomePage Less manual pixel calculation, more Layouting. Change-Id: I33e0ce82a83d7561c73e9b6a92e349354d8f758b Reviewed-by: hjk --- .../projectexplorer/projectwelcomepage.cpp | 210 ++++++++++-------- 1 file changed, 113 insertions(+), 97 deletions(-) diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 50a98a364a6..7cd956d253d 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -630,104 +631,128 @@ private: mutable QRect m_activeActionRects[3]; }; +class ProjectItemWidget final : public QWidget +{ +public: + ProjectItemWidget(QWidget *parent = nullptr) + : QWidget(parent) + { + m_shortcut = new QLabel; + applyTf(m_shortcut, shortcutNumberTF, false); + const int shortcutWidth = HPaddingXs + shortcutNumberWidth + HGapXs; + m_shortcut->setMinimumWidth(shortcutWidth); + + const QPixmap icon = pixmap("project", Theme::Token_Text_Muted); + const QSize iconS = icon.deviceIndependentSize().toSize(); + auto iconLabel = new QLabel; + iconLabel->setFixedSize(iconS); + iconLabel->setPixmap(icon); + + m_projectName = new ElidingLabel; + applyTf(m_projectName, projectNameTF); + m_projectName->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + + m_projectPath = new ElidingLabel; + applyTf(m_projectPath, projectPathTF); + m_projectPath->setElideMode(Qt::ElideMiddle); + m_projectPath->setSizePolicy(m_projectName->sizePolicy()); + + using namespace Layouting; + Row { + m_shortcut, + iconLabel, + Space(HGapXs), + Column { + m_projectName, + m_projectPath, + customMargins(0, VPaddingXs, 0, VPaddingXs), + spacing(VGapXs), + }, + customMargins(0, 0, HPaddingXs, 0), + spacing(0), + }.attachTo(this); + + setAutoFillBackground(false); + } + + void setData(const QModelIndex &index) + { + const int row = index.row() + 1; + m_shortcut->setText(row <= 9 ? QString::number(row) : QString()); + + const QString projectName = index.data(Qt::DisplayRole).toString(); + m_projectName->setText(projectName); + + const FilePath projectPath = + FilePath::fromVariant(index.data(ProjectModel::FilePathRole)); + const QString displayPath = + projectPath.osType() == OsTypeWindows ? projectPath.displayName() + : projectPath.withTildeHomePath(); + m_projectPath->setText(displayPath); + } + + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) + { + const bool hovered = option.widget->isActiveWindow() + && option.state & QStyle::State_MouseOver; + + const QRect bgRGlobal = option.rect.adjusted(0, 0, -s(HPaddingXs), -itemSpacing()); + const QRect bgR = bgRGlobal.translated(-option.rect.topLeft()); + + QFont projectNameFont = m_projectName->font(); + projectNameFont.setUnderline(hovered); + m_projectName->setFont(projectNameFont); + setFixedWidth(bgR.width()); + + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + painter->translate(bgRGlobal.topLeft()); + + drawBackgroundRect(painter, bgR, hovered); + render(painter, bgR.topLeft(), {}, QWidget::DrawChildren); + + painter->restore(); + } + +private: + QLabel *m_shortcut; + ElidingLabel *m_projectName; + ElidingLabel *m_projectPath; +}; + class ProjectDelegate : public BaseDelegate { +public: + explicit ProjectDelegate() + : BaseDelegate() + {} + + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) + const override + { + m_itemWidget.setData(index); + m_itemWidget.paint(painter, option, index); + } + + QSize sizeHint([[maybe_unused]] const QStyleOptionViewItem &option, + const QModelIndex &index) const override + { + return {-1, m_itemWidget.minimumSizeHint().height() + itemSpacing()}; + } + +protected: QString entryType() override { return Tr::tr("project", "Appears in \"Open project \""); } - int shortcutRole() const override { return ProjectModel::ShortcutRole; } -public: - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const final + int shortcutRole() const override { - // visible on with Icon() Extra margin right of project item - // | | - // +--------+-------+ +------+-----+ - // | | | | - // - // +------------+--------+--------+------+---------+-------------+------------+------------+ - // | | | | | | (VPaddingXs)| | | - // | | | | | +-------------+ | | - // | | | | | || | | - // | | | | | +-------------+ | | - // |(HPaddingXs)||(HGapXs)||(HGapXxs)| (VGapXs) |(HPaddingXs)|(HPaddingXs)| - // | |(w:6) | | | +-------------+ | | - // | | | | | || | | - // | | | | | +-------------+ | | - // | | | | | | (VPaddingXs)| | | - // +------------+--------+--------+------+---------+-------------+------------+------------+ --+ - // | (VGapL) | +-- Gap between project items - // +---------------------------------------------------------------------------------------+ --+ - - const bool hovered = option.widget->isActiveWindow() - && option.state & QStyle::State_MouseOver; - - const QRect bgR = option.rect.adjusted(0, 0, -s(HPaddingXs), -itemSpacing()); - - static const QPixmap icon = pixmap("project", Theme::Token_Text_Muted); - const QSize iconS = icon.deviceIndependentSize().toSize(); - - const int x = bgR.x(); - const int numberX = x + s(HPaddingXs); - const int iconX = numberX + shortcutNumberWidth + s(HGapXs); - const int iconWidth = iconS.width(); - const int textX = withIcon() ? iconX + iconWidth + s(HGapXs) : iconX; - const int textWidth = bgR.width() - s(HPaddingXs) - textX; - - const int y = bgR.y(); - const int iconHeight = iconS.height(); - const int iconY = y + (bgR.height() - iconHeight) / 2; - const int projectNameY = y + s(VPaddingXs); - const QRect projectNameR(textX, projectNameY, textWidth, projectNameTF.lineHeight()); - const int projectPathY = projectNameY + projectNameR.height() + s(VGapXs); - const QRect projectPathR(textX, projectPathY, textWidth, projectPathTF.lineHeight()); - - QTC_CHECK(option.rect.bottom() == projectPathR.bottom() + s(VPaddingXs) + itemSpacing()); - - { - drawBackgroundRect(painter, bgR, hovered); - } - if (idx.row() < 9) { - painter->setPen(shortcutNumberTF.color()); - painter->setFont(shortcutNumberTF.font()); - const QRect numberR(numberX, y, shortcutNumberWidth, bgR.height()); - const QString numberString = QString::number(idx.row() + 1); - painter->drawText(numberR, shortcutNumberTF.drawTextFlags, numberString); - } - if (withIcon()) { - painter->drawPixmap(iconX, iconY, icon); - } - { - painter->setPen(projectNameTF.color()); - painter->setFont(projectNameTF.font(hovered)); - const QString projectName = idx.data(Qt::DisplayRole).toString(); - const QString projectNameElided = - painter->fontMetrics().elidedText(projectName, Qt::ElideRight, textWidth); - painter->drawText(projectNameR, projectNameTF.drawTextFlags, projectNameElided); - } - { - painter->setPen(projectPathTF.color()); - painter->setFont(projectPathTF.font()); - const FilePath projectPath = - FilePath::fromVariant(idx.data(ProjectModel::FilePathRole)); - const QString displayPath = - projectPath.osType() == OsTypeWindows ? projectPath.displayName() - : projectPath.withTildeHomePath(); - const QString displayPathElided = - painter->fontMetrics().elidedText(displayPath, Qt::ElideMiddle, textWidth); - painter->drawText(projectPathR, projectPathTF.drawTextFlags, displayPathElided); - } - } - - QSize sizeHint([[maybe_unused]] const QStyleOptionViewItem &option, - [[maybe_unused]] const QModelIndex &idx) const override - { - return QSize(-1, itemHeight() + itemSpacing()); + return ProjectModel::ShortcutRole; } bool editorEvent(QEvent *ev, QAbstractItemModel *model, - const QStyleOptionViewItem &, const QModelIndex &idx) final + const QStyleOptionViewItem &, const QModelIndex &idx) final { if (ev->type() == QEvent::MouseButtonRelease) { const QMouseEvent *mouseEvent = static_cast(ev); @@ -762,16 +787,7 @@ public: } private: - static int itemHeight() - { - const int height = - s(VPaddingXs) - + projectNameTF.lineHeight() - + s(VGapXs) - + projectPathTF.lineHeight() - + s(VPaddingXs); - return height; - } + mutable ProjectItemWidget m_itemWidget; }; class TreeView : public QTreeView From 0f7a386d87b40e9ba0427be6cbe9add5c45c735e Mon Sep 17 00:00:00 2001 From: Markus Redeker Date: Mon, 25 Nov 2024 17:16:30 +0100 Subject: [PATCH 281/989] Bug fix: Crash when an application is stopped Added a new class ButtonWidget that contains the QPushButton that was before part of the CocoBuildStep class. The change was necessary because now the button can be destroyed and recreated by Qt Creator (via CocoBuildStep::createConfigWidget()) wihout creating dangling pointers or other memory problems. Fixes: QTCREATORBUG-32045 Change-Id: I4789160cf3d9ef0d286d0456eeb15304cd297677 Reviewed-by: Christian Kandeler --- src/plugins/coco/cocobuildstep.cpp | 67 ++++++++++++++++++++---------- src/plugins/coco/cocobuildstep.h | 9 ++-- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/plugins/coco/cocobuildstep.cpp b/src/plugins/coco/cocobuildstep.cpp index 75c0bb3a7c5..e809785f493 100644 --- a/src/plugins/coco/cocobuildstep.cpp +++ b/src/plugins/coco/cocobuildstep.cpp @@ -8,15 +8,11 @@ #include "cocotr.h" #include - #include #include #include - #include - #include - #include #include @@ -25,6 +21,39 @@ namespace Coco::Internal { using namespace ProjectExplorer; +class ButtonWidget : public QWidget +// The configuration button of the CocoBuildstep must be part of a separated object +// because it may be several times recreated by createConfigWidget(). +{ +public: + explicit ButtonWidget(CocoBuildStep *step); + +private slots: + void setButtonState(bool enabled, const QString &text); + +private: + QPushButton *m_button; +}; + +ButtonWidget::ButtonWidget(CocoBuildStep *step) + : m_button{new QPushButton} +{ + connect(m_button, &QPushButton::clicked, step, &CocoBuildStep::onButtonClicked); + connect(step, &CocoBuildStep::setButtonState, this, &ButtonWidget::setButtonState); + + Layouting::Form builder; + builder.addRow({m_button, new QLabel}); + builder.setNoMargins(); + builder.attachTo(this); +} + +void ButtonWidget::setButtonState(bool enabled, const QString &text) +{ + m_button->setEnabled(enabled); + if (!text.isEmpty()) + m_button->setText(text); +} + CocoBuildStep *CocoBuildStep::create(BuildConfiguration *buildConfig) { // The "new" command creates a small memory leak which we can tolerate. @@ -34,7 +63,6 @@ CocoBuildStep *CocoBuildStep::create(BuildConfiguration *buildConfig) CocoBuildStep::CocoBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id) : BuildStep(bsl, id) - , m_reconfigureButton{new QPushButton} {} bool CocoBuildStep::init() @@ -47,12 +75,13 @@ void CocoBuildStep::buildSystemUpdated() updateDisplay(); } -void CocoBuildStep::onReconfigureButtonClicked() +void CocoBuildStep::onButtonClicked() { m_valid = !m_valid; setSummaryText(Tr::tr("Coco Code Coverage: Reconfiguring...")); - m_reconfigureButton->setEnabled(false); + emit setButtonState(false); + m_buildSettings->setCoverage(m_valid); m_buildSettings->provideFile(); m_buildSettings->reconfigure(); @@ -60,17 +89,10 @@ void CocoBuildStep::onReconfigureButtonClicked() QWidget *CocoBuildStep::createConfigWidget() { - connect( - m_reconfigureButton, - &QPushButton::clicked, - this, - &CocoBuildStep::onReconfigureButtonClicked); + auto widget = new ButtonWidget{this}; + updateDisplay(); - Layouting::Form builder; - builder.addRow({m_reconfigureButton, new QLabel}); - builder.setNoMargins(); - - return builder.emerge(); + return widget; } void CocoBuildStep::updateDisplay() @@ -78,7 +100,7 @@ void CocoBuildStep::updateDisplay() CocoInstallation coco; if (!coco.isValid()) { setSummaryText("" + Tr::tr("Coco Code Coverage: No working Coco installation") + ""); - m_reconfigureButton->setEnabled(false); + emit setButtonState(false); return; } @@ -86,13 +108,12 @@ void CocoBuildStep::updateDisplay() if (m_valid) { setSummaryText("" + Tr::tr("Coco Code Coverage: Enabled") + ""); - m_reconfigureButton->setText(Tr::tr("Disable Coverage")); + emit setButtonState(true, Tr::tr("Disable Coverage")); } else { setSummaryText(Tr::tr("Coco Code Coverage: Disabled")); - m_reconfigureButton->setText(Tr::tr("Enable Coverage")); + // m_reconfigureButton->setText(Tr::tr("Enable Coverage")); + emit setButtonState(true, Tr::tr("Enable Coverage")); } - - m_reconfigureButton->setEnabled(true); } void CocoBuildStep::display(BuildConfiguration *buildConfig) @@ -157,7 +178,7 @@ void setupCocoBuildSteps() static QMakeStepFactory theQmakeStepFactory; static CMakeStepFactory theCmakeStepFactory; - QObject::connect(ProjectManager::instance(), &ProjectManager::projectAdded, [&](Project *project) { + QObject::connect(ProjectManager::instance(), &ProjectManager::projectAdded, [](Project *project) { if (Target *target = project->activeTarget()) addBuildStep(target); diff --git a/src/plugins/coco/cocobuildstep.h b/src/plugins/coco/cocobuildstep.h index d87bb0f76b1..ae7869b57ba 100644 --- a/src/plugins/coco/cocobuildstep.h +++ b/src/plugins/coco/cocobuildstep.h @@ -18,6 +18,7 @@ namespace Coco::Internal { class CocoBuildStep : public ProjectExplorer::BuildStep { Q_OBJECT + public: static CocoBuildStep *create(ProjectExplorer::BuildConfiguration *buildConfig); @@ -26,11 +27,12 @@ public: bool init() override; void display(ProjectExplorer::BuildConfiguration *buildConfig); +signals: + void setButtonState(bool enabled, const QString &text = {}); + public slots: void buildSystemUpdated(); - -private slots: - void onReconfigureButtonClicked(); + void onButtonClicked(); protected: QWidget *createConfigWidget() override; @@ -41,7 +43,6 @@ private: QPointer m_buildSettings; bool m_valid; - QPushButton *m_reconfigureButton; }; void setupCocoBuildSteps(); From 654cc4d756a62fb0a65f55cf23c8c634af66f746 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 26 Nov 2024 11:13:48 +0100 Subject: [PATCH 282/989] MarketPlace: Disable by default Change-Id: Ifcc7acb9a1f19a916b49e5a9396a6f2246504492 Reviewed-by: Eike Ziller --- src/plugins/marketplace/Marketplace.json.in | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/marketplace/Marketplace.json.in b/src/plugins/marketplace/Marketplace.json.in index 8a41da400da..eb9405abb3f 100644 --- a/src/plugins/marketplace/Marketplace.json.in +++ b/src/plugins/marketplace/Marketplace.json.in @@ -4,6 +4,7 @@ "Name" : "Marketplace", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", + "DisabledByDefault" : true, "VendorId" : "theqtcompany", "Vendor" : "The Qt Company Ltd", "Copyright" : "${IDE_COPYRIGHT}", From a6768807dce99bfd52cd73dcd5960d95f8b5ec0d Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 26 Nov 2024 09:21:10 +0100 Subject: [PATCH 283/989] Git: Add nullptr checks Add some checks for possible nullptr as we saw a crash in Sentry (Event Id: c5d14c9a5f9e4e6fb1e14c3cdb756c76) Change-Id: I5c30751ffaa10ccdd218f0aef7de4b4feacdb887 Reviewed-by: David Schulz --- src/plugins/git/branchmodel.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index aca355f2cb3..88cc12a4e4a 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -281,6 +281,7 @@ QModelIndex BranchModel::parent(const QModelIndex &index) const return {}; BranchNode *node = indexToNode(index); + QTC_ASSERT(node, return {}); if (node->parent == d->rootNode) return {}; return nodeToIndex(node->parent, ColumnBranch); @@ -553,6 +554,7 @@ QString BranchModel::sha(const QModelIndex &idx) const if (!idx.isValid()) return {}; BranchNode *node = indexToNode(idx); + QTC_ASSERT(node, return {}); return node->sha; } @@ -561,6 +563,8 @@ QDateTime BranchModel::dateTime(const QModelIndex &idx) const if (!idx.isValid()) return {}; BranchNode *node = indexToNode(idx); + QTC_ASSERT(node, return {}); + return node->dateTime; } @@ -569,6 +573,8 @@ bool BranchModel::isHead(const QModelIndex &idx) const if (!idx.isValid()) return false; BranchNode *node = indexToNode(idx); + QTC_ASSERT(node, return false); + return node == d->headNode; } @@ -577,6 +583,8 @@ bool BranchModel::isLocal(const QModelIndex &idx) const if (!idx.isValid()) return false; BranchNode *node = indexToNode(idx); + QTC_ASSERT(node, return false); + return node == d->headNode ? false : node->isLocal(); } @@ -585,6 +593,8 @@ bool BranchModel::isLeaf(const QModelIndex &idx) const if (!idx.isValid()) return false; BranchNode *node = indexToNode(idx); + QTC_ASSERT(node, return false); + return node->isLeaf(); } @@ -770,6 +780,8 @@ void BranchModel::refreshCurrentBranch() { const QModelIndex currentIndex = currentBranch(); BranchNode *node = indexToNode(currentIndex); + QTC_ASSERT(node, return); + updateUpstreamStatus(node); } @@ -888,6 +900,8 @@ QModelIndex BranchModel::nodeToIndex(BranchNode *node, int column) const { if (node == d->rootNode) return {}; + QTC_ASSERT(node->parent, return {}); + return createIndex(node->parent->rowOf(node), column, static_cast(node)); } @@ -895,6 +909,8 @@ void BranchModel::removeNode(const QModelIndex &idx) { QModelIndex nodeIndex = idx; // idx is a leaf, so count must be 0. BranchNode *node = indexToNode(nodeIndex); + QTC_ASSERT(node, return); + while (node->count() == 0 && node->parent != d->rootNode) { BranchNode *parentNode = node->parent; const QModelIndex parentIndex = nodeToIndex(parentNode, ColumnBranch); From da481be88560f808d2b41f9012ca2d00ba0563b1 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 26 Nov 2024 13:16:53 +0100 Subject: [PATCH 284/989] Utils: Make "Async::takeResult" dependent of the Qt Version QFuture::takeResult is buggy before QTBUG-112513 as it resets the future state to "NoState". This in turn causes the FutureSynchronizer to deadlock in "waitForFinished", as the future is not in the finished state anymore. Change-Id: I8d09bdd53960f65ab9690286e890432c03dcf8da Reviewed-by: Jarek Kobus --- src/libs/utils/async.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/utils/async.h b/src/libs/utils/async.h index 76e4f01aa40..4643ea161bb 100644 --- a/src/libs/utils/async.h +++ b/src/libs/utils/async.h @@ -171,7 +171,12 @@ public: QFuture future() const { return m_watcher.future(); } ResultType result() const { return m_watcher.result(); } +#if QT_VERSION > QT_VERSION_CHECK(6, 5, 2) + // takeResult is buggy before QTBUG-112513 as it resets the future state to "NoState". + // This in turn causes the FutureSynchronizer to deadlock in "waitForFinished", as the + // future is not in the finished state anymore. ResultType takeResult() const { return m_watcher.future().takeResult(); } +#endif ResultType resultAt(int index) const { return m_watcher.resultAt(index); } QList results() const { return future().results(); } bool isResultAvailable() const { return future().resultCount(); } From 828df3d0ea35b307d21f51f6a48849e4579308cb Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 18 Nov 2024 13:58:42 +0100 Subject: [PATCH 285/989] Core: Move some outputpane helper class definitions to .cpp Change-Id: I328bb53f5c3ba88c4ffe969129f2952f3dd59322 Reviewed-by: Jarek Kobus --- src/plugins/coreplugin/outputpanemanager.cpp | 84 +++++++++++++++++--- src/plugins/coreplugin/outputpanemanager.h | 61 -------------- 2 files changed, 72 insertions(+), 73 deletions(-) diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 7da3ab02c60..9f2ae40e60f 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -46,12 +46,78 @@ using namespace Utils; using namespace Core::Internal; namespace Core { +namespace Internal { Q_GLOBAL_STATIC(QList, sPlaceholders) -class OutputPanePlaceHolderPrivate { +class BadgeLabel +{ public: - explicit OutputPanePlaceHolderPrivate(Id mode, QSplitter *parent); + BadgeLabel(); + void paint(QPainter *p, int x, int y, bool isChecked); + void setText(const QString &text); + QString text() const; + QSize sizeHint() const; + +private: + void calculateSize(); + + QSize m_size; + QString m_text; + QFont m_font; + static const int m_padding = 6; +}; + +class OutputPaneToggleButton : public QToolButton +{ + Q_OBJECT + +public: + OutputPaneToggleButton(int number, const QString &text, QAction *action); + + QSize sizeHint() const override; + void paintEvent(QPaintEvent*) override; + void flash(int count = 3); + void setIconBadgeNumber(int number); + bool isPaneVisible() const; + + void contextMenuEvent(QContextMenuEvent *e) override; + +signals: + void contextMenuRequested(); + +private: + void updateToolTip(); + void checkStateSet() override; + + QString m_number; + QString m_text; + QAction *m_action; + QTimeLine *m_flashTimer; + BadgeLabel m_badgeNumberLabel; +}; + +class OutputPaneManageButton : public QToolButton +{ + Q_OBJECT +public: + OutputPaneManageButton(); + void paintEvent(QPaintEvent *) override; + + void contextMenuEvent(QContextMenuEvent *e) override; + +signals: + void menuRequested(); +}; + +} // Internal + +class OutputPanePlaceHolderPrivate +{ +public: + OutputPanePlaceHolderPrivate(Id mode, QSplitter *parent) + : m_mode(mode), m_splitter(parent) + {} Id m_mode; QSplitter *m_splitter; @@ -61,14 +127,8 @@ public: static OutputPanePlaceHolder* m_current; }; -OutputPanePlaceHolderPrivate::OutputPanePlaceHolderPrivate(Id mode, QSplitter *parent) : - m_mode(mode), m_splitter(parent) -{ -} - OutputPanePlaceHolder *OutputPanePlaceHolderPrivate::m_current = nullptr; - OutputPanePlaceHolder::OutputPanePlaceHolder(Id mode, QSplitter *parent) : QWidget(parent), d(new OutputPanePlaceHolderPrivate(mode, parent)) { @@ -1138,10 +1198,8 @@ int OutputPaneManager::currentIndex() const // /////////////////////////////////////////////////////////////////////// -OutputPaneToggleButton::OutputPaneToggleButton(int number, const QString &text, - QAction *action, QWidget *parent) - : QToolButton(parent) - , m_number(QString::number(number)) +OutputPaneToggleButton::OutputPaneToggleButton(int number, const QString &text, QAction *action) + : m_number(QString::number(number)) , m_text(text) , m_action(action) , m_flashTimer(new QTimeLine(1000, this)) @@ -1395,3 +1453,5 @@ void BadgeLabel::calculateSize() } // namespace Internal } // namespace Core + +#include "outputpanemanager.moc" diff --git a/src/plugins/coreplugin/outputpanemanager.h b/src/plugins/coreplugin/outputpanemanager.h index 4a96d57dcc7..6976d62144c 100644 --- a/src/plugins/coreplugin/outputpanemanager.h +++ b/src/plugins/coreplugin/outputpanemanager.h @@ -11,7 +11,6 @@ QT_BEGIN_NAMESPACE class QAction; class QLabel; class QStackedWidget; -class QTimeLine; QT_END_NAMESPACE namespace Core { @@ -23,7 +22,6 @@ namespace Internal { class ICorePrivate; class MainWindow; -class OutputPaneToggleButton; class OutputPaneManageButton; class OutputPaneManager : public QWidget @@ -92,64 +90,5 @@ private: bool m_initialized = false; }; -class BadgeLabel -{ -public: - BadgeLabel(); - void paint(QPainter *p, int x, int y, bool isChecked); - void setText(const QString &text); - QString text() const; - QSize sizeHint() const; - -private: - void calculateSize(); - - QSize m_size; - QString m_text; - QFont m_font; - static const int m_padding = 6; -}; - -class OutputPaneToggleButton : public QToolButton -{ - Q_OBJECT -public: - OutputPaneToggleButton(int number, const QString &text, QAction *action, - QWidget *parent = nullptr); - QSize sizeHint() const override; - void paintEvent(QPaintEvent*) override; - void flash(int count = 3); - void setIconBadgeNumber(int number); - bool isPaneVisible() const; - - void contextMenuEvent(QContextMenuEvent *e) override; - -signals: - void contextMenuRequested(); - -private: - void updateToolTip(); - void checkStateSet() override; - - QString m_number; - QString m_text; - QAction *m_action; - QTimeLine *m_flashTimer; - BadgeLabel m_badgeNumberLabel; -}; - -class OutputPaneManageButton : public QToolButton -{ - Q_OBJECT -public: - OutputPaneManageButton(); - void paintEvent(QPaintEvent *) override; - - void contextMenuEvent(QContextMenuEvent *e) override; - -signals: - void menuRequested(); -}; - } // namespace Internal } // namespace Core From 1571bcc141540b8f5612135eeee0acf3bf4ec5a8 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 27 Nov 2024 06:33:04 +0100 Subject: [PATCH 286/989] Utils: Fix build before Qt6.5.3 Amends da481be88560f808d2b41f9012ca2d00ba0563b1. This explicitly makes the MarkdownBrowser disfunctional for builds before Qt6.5.3. Change-Id: I0375a23a2a2238b2a40f4a86160cf93593996079 Reviewed-by: Marcus Tillmanns --- src/libs/utils/markdownbrowser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/utils/markdownbrowser.cpp b/src/libs/utils/markdownbrowser.cpp index aaffc4b020d..958837f5073 100644 --- a/src/libs/utils/markdownbrowser.cpp +++ b/src/libs/utils/markdownbrowser.cpp @@ -338,7 +338,11 @@ public: }; auto onLocalDone = [localIterator, this](const Async &async) { +#if QT_VERSION > QT_VERSION_CHECK(6, 5, 2) EntryPointer result = async.takeResult(); +#else + EntryPointer result = {}; +#endif if (result) m_imageHandler.set(localIterator->toString(), std::move(result)); }; From 16e7b0f1ccd958c04f9e1732ba6ab6a280f2197e Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 09:55:09 +0100 Subject: [PATCH 287/989] Debugger: Simplify error reading ... and potentially fix it for incomplete multibyte codepoints and anything non-UTF8. Change-Id: I2c9a8e15a3d6c24fa98e6941ef14b3bb4460525d Reviewed-by: Marcus Tillmanns --- src/plugins/debugger/gdb/gdbengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 21cb36f7715..d8bfdfb2a6a 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -605,7 +605,7 @@ void GdbEngine::handleAsyncOutput(const QStringView asyncClass, const GdbMi &res void GdbEngine::readGdbStandardError() { - QString err = QString::fromUtf8(m_gdbProc.readAllRawStandardError()); + QString err = m_gdbProc.readAllStandardError(); showMessage("UNEXPECTED GDB STDERR: " + err); if (err == "Undefined command: \"bb\". Try \"help\".\n") return; From 607750f98f8ea42a6cd5bb68a56531113472a740 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 21 Nov 2024 15:41:09 +0100 Subject: [PATCH 288/989] Utils: Import a copy of QMovie QMovie has a bug where it cannot be moved to a different Thread. We import qmovie.{cpp|h} from Qt 6.8.1 so we can fix it in Qt Creator. Task-number: QTBUG-131448 Change-Id: I04d23363fbc139aff99fb85d9db0f84a538cf4f7 Reviewed-by: hjk --- src/libs/utils/CMakeLists.txt | 1 + src/libs/utils/movie.cpp | 927 ++++++++++++++++++++++++++++++++++ src/libs/utils/movie.h | 109 ++++ 3 files changed, 1037 insertions(+) create mode 100644 src/libs/utils/movie.cpp create mode 100644 src/libs/utils/movie.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 891a0f66ff9..ac418d4b2e9 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -205,6 +205,7 @@ add_qtc_library(Utils winutils.cpp winutils.h wizard.cpp wizard.h wizardpage.cpp wizardpage.h + movie.cpp movie.h ) extend_qtc_library(Utils diff --git a/src/libs/utils/movie.cpp b/src/libs/utils/movie.cpp new file mode 100644 index 00000000000..85ef066c6f6 --- /dev/null +++ b/src/libs/utils/movie.cpp @@ -0,0 +1,927 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +// COPY OF QMOVIE BECAUSE QTBUG-131448 + +#include "movie.h" + +#include "private/qobject_p.h" +#include "private/qproperty_p.h" +#include "qbuffer.h" +#include "qdir.h" +#include "qelapsedtimer.h" +#include "qimage.h" +#include "qimagereader.h" +#include "qlist.h" +#include "qloggingcategory.h" +#include "qmap.h" +#include "qpixmap.h" +#include "qrect.h" +#include "qtimer.h" + +#define QTC_MOVIE_INVALID_DELAY -1 + +class QtcFrameInfo +{ +public: + QPixmap pixmap; + int delay; + bool endMark; + inline QtcFrameInfo(bool endMark) + : pixmap(QPixmap()) + , delay(QTC_MOVIE_INVALID_DELAY) + , endMark(endMark) + {} + + inline QtcFrameInfo() + : pixmap(QPixmap()) + , delay(QTC_MOVIE_INVALID_DELAY) + , endMark(false) + {} + + inline QtcFrameInfo(QPixmap &&pixmap, int delay) + : pixmap(std::move(pixmap)) + , delay(delay) + , endMark(false) + {} + + inline bool isValid() + { + return endMark || !(pixmap.isNull() && (delay == QTC_MOVIE_INVALID_DELAY)); + } + + inline bool isEndMarker() { return endMark; } + + static inline QtcFrameInfo endMarker() { return QtcFrameInfo(true); } +}; +Q_DECLARE_TYPEINFO(QtcFrameInfo, Q_RELOCATABLE_TYPE); + +class QtcMoviePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QtcMovie) + +public: + QtcMoviePrivate(QtcMovie *qq); + bool isDone(); + bool next(); + int speedAdjustedDelay(int delay) const; + bool isValid() const; + bool jumpToFrame(int frameNumber); + int frameCount() const; + bool jumpToNextFrame(); + QtcFrameInfo infoForFrame(int frameNumber); + void reset(); + + inline void enterState(QtcMovie::MovieState newState) + { + movieState = newState; + emit q_func() -> stateChanged(newState); + } + + // private slots + void _q_loadNextFrame(); + void _q_loadNextFrame(bool starting); + + QImageReader *reader = nullptr; + + void setSpeed(int percentSpeed) { q_func()->setSpeed(percentSpeed); } + Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QtcMoviePrivate, int, speed, &QtcMoviePrivate::setSpeed, 100) + + QtcMovie::MovieState movieState = QtcMovie::NotRunning; + QRect frameRect; + QPixmap currentPixmap; + int currentFrameNumber = -1; + int nextFrameNumber = 0; + int greatestFrameNumber = -1; + int nextDelay = 0; + int playCounter = -1; + qint64 initialDevicePos = 0; + Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS( + QtcMoviePrivate, QtcMovie::CacheMode, cacheMode, QtcMovie::CacheNone) + bool haveReadAll = false; + bool isFirstIteration = true; + QMap frameMap; + QString absoluteFilePath; + + QTimer nextImageTimer; +}; + +/*! \internal + */ +QtcMoviePrivate::QtcMoviePrivate(QtcMovie *qq) +{ + q_ptr = qq; + nextImageTimer.setSingleShot(true); +} + +/*! \internal + */ +void QtcMoviePrivate::reset() +{ + nextImageTimer.stop(); + if (reader->device()) + initialDevicePos = reader->device()->pos(); + currentFrameNumber = -1; + nextFrameNumber = 0; + greatestFrameNumber = -1; + nextDelay = 0; + playCounter = -1; + haveReadAll = false; + isFirstIteration = true; + frameMap.clear(); +} + +/*! \internal + */ +bool QtcMoviePrivate::isDone() +{ + return (playCounter == 0); +} + +/*! + \internal + + Given the original \a delay, this function returns the + actual number of milliseconds to delay according to + the current speed. E.g. if the speed is 200%, the + result will be half of the original delay. +*/ +int QtcMoviePrivate::speedAdjustedDelay(int delay) const +{ + return int((qint64(delay) * qint64(100)) / qint64(speed)); +} + +/*! + \internal + + Returns the QtcFrameInfo for the given \a frameNumber. + + If the frame number is invalid, an invalid QtcFrameInfo is + returned. + + If the end of the animation has been reached, a + special end marker QtcFrameInfo is returned. + +*/ +QtcFrameInfo QtcMoviePrivate::infoForFrame(int frameNumber) +{ + Q_Q(QtcMovie); + + if (frameNumber < 0) + return QtcFrameInfo(); // Invalid + + if (haveReadAll && (frameNumber > greatestFrameNumber)) { + if (frameNumber == greatestFrameNumber + 1) + return QtcFrameInfo::endMarker(); + return QtcFrameInfo(); // Invalid + } + + // For an animated image format, the tradition is that QtcMovie calls read() + // until canRead() == false, because the number of frames may not be known + // in advance; but if we're abusing a multi-frame format as an animation, + // canRead() may remain true, and we need to stop after reading the maximum + // number of frames that the image provides. + const bool supportsAnimation = reader->supportsOption(QImageIOHandler::Animation); + const int stopAtFrame = supportsAnimation ? -1 : frameCount(); + + // For an animated image format, QImageIOHandler::nextImageDelay() should + // provide the time to wait until showing the next frame; but multi-frame + // formats are not expected to provide this value, so use 1000 ms by default. + const auto nextFrameDelay = [&]() { + return supportsAnimation ? reader->nextImageDelay() : 1000; + }; + + if (cacheMode == QtcMovie::CacheNone) { + if (frameNumber != currentFrameNumber + 1) { + // Non-sequential frame access + if (!reader->jumpToImage(frameNumber)) { + if (frameNumber == 0) { + // Special case: Attempt to "rewind" so we can loop + // ### This could be implemented as QImageReader::rewind() + if (reader->device()->isSequential()) + return QtcFrameInfo(); // Invalid + QString fileName = reader->fileName(); + QByteArray format = reader->format(); + QIODevice *device = reader->device(); + QColor bgColor = reader->backgroundColor(); + QSize scaledSize = reader->scaledSize(); + delete reader; + if (fileName.isEmpty()) + reader = new QImageReader(device, format); + else + reader = new QImageReader(absoluteFilePath, format); + if (!reader->canRead()) // Provoke a device->open() call + emit q->error(reader->error()); + reader->device()->seek(initialDevicePos); + reader->setBackgroundColor(bgColor); + reader->setScaledSize(scaledSize); + } else { + return QtcFrameInfo(); // Invalid + } + } + } + //qCDebug(lcImageIo, "CacheNone: read frame %d of %d", frameNumber, stopAtFrame); + if (stopAtFrame > 0 ? (frameNumber < stopAtFrame) : reader->canRead()) { + // reader says we can read. Attempt to actually read image + // But if it's a non-animated multi-frame format and we know the frame count, stop there. + if (stopAtFrame > 0) + reader->jumpToImage(frameNumber); + QImage anImage = reader->read(); + if (anImage.isNull()) { + // Reading image failed. + return QtcFrameInfo(); // Invalid + } + if (frameNumber > greatestFrameNumber) + greatestFrameNumber = frameNumber; + return QtcFrameInfo(QPixmap::fromImage(std::move(anImage)), nextFrameDelay()); + } else if (frameNumber != 0) { + // We've read all frames now. Return an end marker + haveReadAll = true; + return QtcFrameInfo::endMarker(); + } else { + // No readable frames + haveReadAll = true; + return QtcFrameInfo(); + } + } + + // CacheMode == CacheAll + if (frameNumber > greatestFrameNumber) { + // Frame hasn't been read from file yet. Try to do it + for (int i = greatestFrameNumber + 1; i <= frameNumber; ++i) { + //qCDebug(lcImageIo, "CacheAll: read frame %d of %d", frameNumber, stopAtFrame); + if (stopAtFrame > 0 ? (frameNumber < stopAtFrame) : reader->canRead()) { + // reader says we can read. Attempt to actually read image + // But if it's a non-animated multi-frame format and we know the frame count, stop there. + if (stopAtFrame > 0) + reader->jumpToImage(frameNumber); + QImage anImage = reader->read(); + if (anImage.isNull()) { + // Reading image failed. + return QtcFrameInfo(); // Invalid + } + greatestFrameNumber = i; + QtcFrameInfo info(QPixmap::fromImage(std::move(anImage)), nextFrameDelay()); + // Cache it! + frameMap.insert(i, info); + if (i == frameNumber) { + return info; + } + } else { + // We've read all frames now. Return an end marker + haveReadAll = true; + return frameNumber == greatestFrameNumber + 1 ? QtcFrameInfo::endMarker() + : QtcFrameInfo(); + } + } + } + // Return info for requested (cached) frame + return frameMap.value(frameNumber); +} + +/*! + \internal + + Attempts to advance the animation to the next frame. + If successful, currentFrameNumber, currentPixmap and + nextDelay are updated accordingly, and true is returned. + Otherwise, false is returned. + When false is returned, isDone() can be called to + determine whether the animation ended gracefully or + an error occurred when reading the frame. +*/ +bool QtcMoviePrivate::next() +{ + QElapsedTimer time; + time.start(); + QtcFrameInfo info = infoForFrame(nextFrameNumber); + if (!info.isValid()) + return false; + if (info.isEndMarker()) { + // We reached the end of the animation. + if (isFirstIteration) { + if (nextFrameNumber == 0) { + // No frames could be read at all (error). + return false; + } + // End of first iteration. Initialize play counter + playCounter = reader->loopCount(); + isFirstIteration = false; + } + // Loop as appropriate + if (playCounter != 0) { + if (playCounter != -1) // Infinite? + playCounter--; // Nope + nextFrameNumber = 0; + return next(); + } + // Loop no more. Done + return false; + } + // Image and delay OK, update internal state + currentFrameNumber = nextFrameNumber++; + currentPixmap = info.pixmap; + + if (!speed) + return true; + + nextDelay = speedAdjustedDelay(info.delay); + // Adjust delay according to the time it took to read the frame + int processingTime = time.elapsed(); + if (processingTime > nextDelay) + nextDelay = 0; + else + nextDelay = nextDelay - processingTime; + return true; +} + +/*! \internal + */ +void QtcMoviePrivate::_q_loadNextFrame() +{ + _q_loadNextFrame(false); +} + +void QtcMoviePrivate::_q_loadNextFrame(bool starting) +{ + Q_Q(QtcMovie); + if (next()) { + if (starting && movieState == QtcMovie::NotRunning) { + enterState(QtcMovie::Running); + emit q->started(); + } + + if (frameRect.size() != currentPixmap.rect().size()) { + frameRect = currentPixmap.rect(); + emit q->resized(frameRect.size()); + } + + emit q->updated(frameRect); + emit q->frameChanged(currentFrameNumber); + + if (speed && movieState == QtcMovie::Running) + nextImageTimer.start(nextDelay); + } else { + // Could not read another frame + if (!isDone()) { + emit q->error(reader->error()); + } + + // Graceful finish + if (movieState != QtcMovie::Paused) { + nextFrameNumber = 0; + isFirstIteration = true; + playCounter = -1; + enterState(QtcMovie::NotRunning); + emit q->finished(); + } + } +} + +/*! + \internal +*/ +bool QtcMoviePrivate::isValid() const +{ + Q_Q(const QtcMovie); + + if (greatestFrameNumber >= 0) + return true; // have we seen valid data + bool canRead = reader->canRead(); + if (!canRead) { + // let the consumer know it's broken + // + // ### the const_cast here is ugly, but 'const' of this method is + // technically wrong right now, since it may cause the underlying device + // to open. + emit const_cast(q)->error(reader->error()); + } + return canRead; +} + +/*! + \internal +*/ +bool QtcMoviePrivate::jumpToFrame(int frameNumber) +{ + if (frameNumber < 0) + return false; + if (currentFrameNumber == frameNumber) + return true; + nextFrameNumber = frameNumber; + if (movieState == QtcMovie::Running) + nextImageTimer.stop(); + _q_loadNextFrame(); + return (nextFrameNumber == currentFrameNumber + 1); +} + +/*! + \internal +*/ +int QtcMoviePrivate::frameCount() const +{ + int result; + if ((result = reader->imageCount()) != 0) + return result; + if (haveReadAll) + return greatestFrameNumber + 1; + return 0; // Don't know +} + +/*! + \internal +*/ +bool QtcMoviePrivate::jumpToNextFrame() +{ + return jumpToFrame(currentFrameNumber + 1); +} + +/*! + Constructs a QtcMovie object, passing the \a parent object to QObject's + constructor. + + \sa setFileName(), setDevice(), setFormat() + */ +QtcMovie::QtcMovie(QObject *parent) + : QObject(*new QtcMoviePrivate(this), parent) +{ + Q_D(QtcMovie); + d->reader = new QImageReader; + connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); +} + +/*! + Constructs a QtcMovie object. QtcMovie will use read image data from \a + device, which it assumes is open and readable. If \a format is not empty, + QtcMovie will use the image format \a format for decoding the image + data. Otherwise, QtcMovie will attempt to guess the format. + + The \a parent object is passed to QObject's constructor. + */ +QtcMovie::QtcMovie(QIODevice *device, const QByteArray &format, QObject *parent) + : QObject(*new QtcMoviePrivate(this), parent) +{ + Q_D(QtcMovie); + d->reader = new QImageReader(device, format); + d->initialDevicePos = device->pos(); + connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); +} + +/*! + Constructs a QtcMovie object. QtcMovie will use read image data from \a + fileName. If \a format is not empty, QtcMovie will use the image format \a + format for decoding the image data. Otherwise, QtcMovie will attempt to + guess the format. + + The \a parent object is passed to QObject's constructor. + */ +QtcMovie::QtcMovie(const QString &fileName, const QByteArray &format, QObject *parent) + : QObject(*new QtcMoviePrivate(this), parent) +{ + Q_D(QtcMovie); + d->absoluteFilePath = QDir(fileName).absolutePath(); + d->reader = new QImageReader(fileName, format); + if (d->reader->device()) + d->initialDevicePos = d->reader->device()->pos(); + connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); +} + +/*! + Destructs the QtcMovie object. +*/ +QtcMovie::~QtcMovie() +{ + Q_D(QtcMovie); + delete d->reader; +} + +/*! + Sets the current device to \a device. QtcMovie will read image data from + this device when the movie is running. + + \sa device(), setFormat() +*/ +void QtcMovie::setDevice(QIODevice *device) +{ + Q_D(QtcMovie); + d->reader->setDevice(device); + d->reset(); +} + +/*! + Returns the device QtcMovie reads image data from. If no device has + currently been assigned, \nullptr is returned. + + \sa setDevice(), fileName() +*/ +QIODevice *QtcMovie::device() const +{ + Q_D(const QtcMovie); + return d->reader->device(); +} + +/*! + Sets the name of the file that QtcMovie reads image data from, to \a + fileName. + + \sa fileName(), setDevice(), setFormat() +*/ +void QtcMovie::setFileName(const QString &fileName) +{ + Q_D(QtcMovie); + d->absoluteFilePath = QDir(fileName).absolutePath(); + d->reader->setFileName(fileName); + d->reset(); +} + +/*! + Returns the name of the file that QtcMovie reads image data from. If no file + name has been assigned, or if the assigned device is not a file, an empty + QString is returned. + + \sa setFileName(), device() +*/ +QString QtcMovie::fileName() const +{ + Q_D(const QtcMovie); + return d->reader->fileName(); +} + +/*! + Sets the format that QtcMovie will use when decoding image data, to \a + format. By default, QtcMovie will attempt to guess the format of the image + data. + + You can call supportedFormats() for the full list of formats + QtcMovie supports. + + \sa QImageReader::supportedImageFormats() +*/ +void QtcMovie::setFormat(const QByteArray &format) +{ + Q_D(QtcMovie); + d->reader->setFormat(format); +} + +/*! + Returns the format that QtcMovie uses when decoding image data. If no format + has been assigned, an empty QByteArray() is returned. + + \sa setFormat() +*/ +QByteArray QtcMovie::format() const +{ + Q_D(const QtcMovie); + return d->reader->format(); +} + +/*! + For image formats that support it, this function sets the background color + to \a color. + + \sa backgroundColor() +*/ +void QtcMovie::setBackgroundColor(const QColor &color) +{ + Q_D(QtcMovie); + d->reader->setBackgroundColor(color); +} + +/*! + Returns the background color of the movie. If no background color has been + assigned, an invalid QColor is returned. + + \sa setBackgroundColor() +*/ +QColor QtcMovie::backgroundColor() const +{ + Q_D(const QtcMovie); + return d->reader->backgroundColor(); +} + +/*! + Returns the current state of QtcMovie. + + \sa MovieState, stateChanged() +*/ +QtcMovie::MovieState QtcMovie::state() const +{ + Q_D(const QtcMovie); + return d->movieState; +} + +/*! + Returns the rect of the last frame. If no frame has yet been updated, an + invalid QRect is returned. + + \sa currentImage(), currentPixmap() +*/ +QRect QtcMovie::frameRect() const +{ + Q_D(const QtcMovie); + return d->frameRect; +} + +/*! + Returns the current frame as a QPixmap. + + \sa currentImage(), updated() +*/ +QPixmap QtcMovie::currentPixmap() const +{ + Q_D(const QtcMovie); + return d->currentPixmap; +} + +/*! + Returns the current frame as a QImage. + + \sa currentPixmap(), updated() +*/ +QImage QtcMovie::currentImage() const +{ + Q_D(const QtcMovie); + return d->currentPixmap.toImage(); +} + +/*! + Returns \c true if the movie is valid (e.g., the image data is readable and + the image format is supported); otherwise returns \c false. + + For information about why the movie is not valid, see lastError(). +*/ +bool QtcMovie::isValid() const +{ + Q_D(const QtcMovie); + return d->isValid(); +} + +/*! + Returns the most recent error that occurred while attempting to read image data. + + \sa lastErrorString() +*/ +QImageReader::ImageReaderError QtcMovie::lastError() const +{ + Q_D(const QtcMovie); + return d->reader->error(); +} + +/*! + Returns a human-readable representation of the most recent error that occurred + while attempting to read image data. + + \sa lastError() +*/ +QString QtcMovie::lastErrorString() const +{ + Q_D(const QtcMovie); + return d->reader->errorString(); +} + +/*! + Returns the number of frames in the movie. + + Certain animation formats do not support this feature, in which + case 0 is returned. +*/ +int QtcMovie::frameCount() const +{ + Q_D(const QtcMovie); + return d->frameCount(); +} + +/*! + Returns the number of milliseconds QtcMovie will wait before updating the + next frame in the animation. +*/ +int QtcMovie::nextFrameDelay() const +{ + Q_D(const QtcMovie); + return d->nextDelay; +} + +/*! + Returns the sequence number of the current frame. The number of the first + frame in the movie is 0. +*/ +int QtcMovie::currentFrameNumber() const +{ + Q_D(const QtcMovie); + return d->currentFrameNumber; +} + +/*! + Jumps to the next frame. Returns \c true on success; otherwise returns \c false. +*/ +bool QtcMovie::jumpToNextFrame() +{ + Q_D(QtcMovie); + return d->jumpToNextFrame(); +} + +/*! + Jumps to frame number \a frameNumber. Returns \c true on success; otherwise + returns \c false. +*/ +bool QtcMovie::jumpToFrame(int frameNumber) +{ + Q_D(QtcMovie); + return d->jumpToFrame(frameNumber); +} + +/*! + Returns the number of times the movie will loop before it finishes. + If the movie will only play once (no looping), loopCount returns 0. + If the movie loops forever, loopCount returns -1. + + Note that, if the image data comes from a sequential device (e.g. a + socket), QtcMovie can only loop the movie if the cacheMode is set to + QtcMovie::CacheAll. +*/ +int QtcMovie::loopCount() const +{ + Q_D(const QtcMovie); + return d->reader->loopCount(); +} + +/*! + If \a paused is true, QtcMovie will enter \l Paused state and emit + stateChanged(Paused); otherwise it will enter \l Running state and emit + stateChanged(Running). + + \sa state() +*/ +void QtcMovie::setPaused(bool paused) +{ + Q_D(QtcMovie); + if (paused) { + if (d->movieState == NotRunning) + return; + d->enterState(Paused); + d->nextImageTimer.stop(); + } else { + if (d->movieState == Running) + return; + d->enterState(Running); + d->nextImageTimer.start(nextFrameDelay()); + } +} + +/*! + \property QtcMovie::speed + \brief the movie's speed + + The speed is measured in percentage of the original movie speed. + The default speed is 100%. + Example: + + \snippet code/src_gui_image_Qtcmovie.cpp 1 +*/ +void QtcMovie::setSpeed(int percentSpeed) +{ + Q_D(QtcMovie); + if (!d->speed && d->movieState == Running) + d->nextImageTimer.start(nextFrameDelay()); + if (percentSpeed != d->speed) { + d->speed = percentSpeed; + d->speed.notify(); + } else { + d->speed.removeBindingUnlessInWrapper(); + } +} + +int QtcMovie::speed() const +{ + Q_D(const QtcMovie); + return d->speed; +} + +QBindable QtcMovie::bindableSpeed() +{ + Q_D(QtcMovie); + return &d->speed; +} + +/*! + Starts the movie. QtcMovie will enter \l Running state, and start emitting + updated() and resized() as the movie progresses. + + If QtcMovie is in the \l Paused state, this function is equivalent + to calling setPaused(false). If QtcMovie is already in the \l + Running state, this function does nothing. + + \sa stop(), setPaused() +*/ +void QtcMovie::start() +{ + Q_D(QtcMovie); + if (d->movieState == NotRunning) { + d->_q_loadNextFrame(true); + } else if (d->movieState == Paused) { + setPaused(false); + } +} + +/*! + Stops the movie. QtcMovie enters \l NotRunning state, and stops emitting + updated() and resized(). If start() is called again, the movie will + restart from the beginning. + + If QtcMovie is already in the \l NotRunning state, this function + does nothing. + + \sa start(), setPaused() +*/ +void QtcMovie::stop() +{ + Q_D(QtcMovie); + if (d->movieState == NotRunning) + return; + d->enterState(NotRunning); + d->nextImageTimer.stop(); + d->nextFrameNumber = 0; +} + +/*! + Returns the scaled size of frames. + + \sa QImageReader::scaledSize() +*/ +QSize QtcMovie::scaledSize() +{ + Q_D(QtcMovie); + return d->reader->scaledSize(); +} + +/*! + Sets the scaled frame size to \a size. + + \sa QImageReader::setScaledSize() +*/ +void QtcMovie::setScaledSize(const QSize &size) +{ + Q_D(QtcMovie); + d->reader->setScaledSize(size); +} + +/*! + Returns the list of image formats supported by QtcMovie. + + \sa QImageReader::supportedImageFormats() +*/ +QList QtcMovie::supportedFormats() +{ + QList list = QImageReader::supportedImageFormats(); + + QBuffer buffer; + buffer.open(QIODevice::ReadOnly); + + const auto doesntSupportAnimation = [&buffer](const QByteArray &format) { + return !QImageReader(&buffer, format).supportsOption(QImageIOHandler::Animation); + }; + + list.removeIf(doesntSupportAnimation); + return list; +} + +/*! + \property QtcMovie::cacheMode + \brief the movie's cache mode + + Caching frames can be useful when the underlying animation format handler + that QtcMovie relies on to decode the animation data does not support + jumping to particular frames in the animation, or even "rewinding" the + animation to the beginning (for looping). Furthermore, if the image data + comes from a sequential device, it is not possible for the underlying + animation handler to seek back to frames whose data has already been read + (making looping altogether impossible). + + To aid in such situations, a QtcMovie object can be instructed to cache the + frames, at the added memory cost of keeping the frames in memory for the + lifetime of the object. + + By default, this property is set to \l CacheNone. + + \sa QtcMovie::CacheMode +*/ + +QtcMovie::CacheMode QtcMovie::cacheMode() const +{ + Q_D(const QtcMovie); + return d->cacheMode; +} + +void QtcMovie::setCacheMode(CacheMode cacheMode) +{ + Q_D(QtcMovie); + d->cacheMode = cacheMode; +} + +QBindable QtcMovie::bindableCacheMode() +{ + Q_D(QtcMovie); + return &d->cacheMode; +} + +#include "moc_movie.cpp" diff --git a/src/libs/utils/movie.h b/src/libs/utils/movie.h new file mode 100644 index 00000000000..1e9515f0daa --- /dev/null +++ b/src/libs/utils/movie.h @@ -0,0 +1,109 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QtcMovie_H +#define QtcMovie_H + +#include + +#include +#include +#include +#include + +QT_REQUIRE_CONFIG(movie); + +QT_BEGIN_NAMESPACE + +class QByteArray; +class QColor; +class QIODevice; +class QImage; +class QPixmap; +class QRect; +class QSize; + +class QtcMoviePrivate; +class QtcMovie : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QtcMovie) + Q_PROPERTY(int speed READ speed WRITE setSpeed BINDABLE bindableSpeed) + Q_PROPERTY(CacheMode cacheMode READ cacheMode WRITE setCacheMode BINDABLE bindableCacheMode) +public: + enum MovieState { NotRunning, Paused, Running }; + Q_ENUM(MovieState) + enum CacheMode { CacheNone, CacheAll }; + Q_ENUM(CacheMode) + + explicit QtcMovie(QObject *parent = nullptr); + explicit QtcMovie( + QIODevice *device, const QByteArray &format = QByteArray(), QObject *parent = nullptr); + explicit QtcMovie( + const QString &fileName, const QByteArray &format = QByteArray(), QObject *parent = nullptr); + ~QtcMovie(); + + static QList supportedFormats(); + + void setDevice(QIODevice *device); + QIODevice *device() const; + + void setFileName(const QString &fileName); + QString fileName() const; + + void setFormat(const QByteArray &format); + QByteArray format() const; + + void setBackgroundColor(const QColor &color); + QColor backgroundColor() const; + + MovieState state() const; + + QRect frameRect() const; + QImage currentImage() const; + QPixmap currentPixmap() const; + + bool isValid() const; + QImageReader::ImageReaderError lastError() const; + QString lastErrorString() const; + + bool jumpToFrame(int frameNumber); + int loopCount() const; + int frameCount() const; + int nextFrameDelay() const; + int currentFrameNumber() const; + + int speed() const; + QBindable bindableSpeed(); + + QSize scaledSize(); + void setScaledSize(const QSize &size); + + CacheMode cacheMode() const; + void setCacheMode(CacheMode mode); + QBindable bindableCacheMode(); + +Q_SIGNALS: + void started(); + void resized(const QSize &size); + void updated(const QRect &rect); + void stateChanged(QtcMovie::MovieState state); + void error(QImageReader::ImageReaderError error); + void finished(); + void frameChanged(int frameNumber); + +public Q_SLOTS: + void start(); + bool jumpToNextFrame(); + void setPaused(bool paused); + void stop(); + void setSpeed(int percentSpeed); + +private: + Q_DISABLE_COPY(QtcMovie) + Q_PRIVATE_SLOT(d_func(), void _q_loadNextFrame()) +}; + +QT_END_NAMESPACE + +#endif // QtcMovie_H From c1e7b186fdbef0da90734062bdcea099eb948e63 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 09:52:09 +0100 Subject: [PATCH 289/989] Utils: Use converter state in Process::readAll*Output() Should fix incomplete multibyte codepoints and anything non-UTF8. Change-Id: I5bae892c4606802eac3945642cb8ed23101bdcab Reviewed-by: Marcus Tillmanns --- src/libs/utils/qtcprocess.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 4bcaad92a15..29de1f01759 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -193,7 +193,14 @@ public: void handleRest(); void append(const QByteArray &text); - QByteArray readAllData() { return std::exchange(rawData, {}); } + QByteArray readAllRawData() { return std::exchange(rawData, {}); } + + QString readAllData() + { + QString msg = codec->toUnicode(rawData.data(), rawData.size(), codecState.get()); + rawData.clear(); + return msg; + } QByteArray rawData; QString incompleteLineBuffer; // lines not yet signaled @@ -1456,12 +1463,12 @@ bool Process::waitForFinished(QDeadlineTimer timeout) QByteArray Process::readAllRawStandardOutput() { - return d->m_stdOut.readAllData(); + return d->m_stdOut.readAllRawData(); } QByteArray Process::readAllRawStandardError() { - return d->m_stdErr.readAllData(); + return d->m_stdErr.readAllRawData(); } qint64 Process::write(const QString &input) @@ -1526,12 +1533,12 @@ void Process::stop() QString Process::readAllStandardOutput() { - return QString::fromUtf8(readAllRawStandardOutput()); + return d->m_stdOut.readAllData(); } QString Process::readAllStandardError() { - return QString::fromUtf8(readAllRawStandardError()); + return d->m_stdErr.readAllData(); } QString Process::exitMessage(const CommandLine &command, ProcessResult result, From 76f0c8547b8d2955c779090e8887c178d6ce0c77 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 27 Nov 2024 11:23:43 +0100 Subject: [PATCH 290/989] Utils: Add files to qbs build Amends 607750f98f8ea42a6cd5bb68a56531113472a740. Change-Id: Id76cb587196b9aa65e67415eda326d163a2c883c Reviewed-by: Marcus Tillmanns --- src/libs/utils/utils.qbs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index aede804c6c1..d03387e71ee 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -197,6 +197,8 @@ QtcLibrary { "minimizableinfobars.h", "multitextcursor.cpp", "multitextcursor.h", + "movie.cpp", + "movie.h", "namevaluedictionary.cpp", "namevaluedictionary.h", "namevalueitem.cpp", From a11c6ff19a3bc04a3fe05a54b6ebdc8e11142964 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 27 Nov 2024 09:57:16 +0100 Subject: [PATCH 291/989] Utils: Fix QMovie::moveToThread() We change the nextImageTimer to a pointer and create it with the movie as parent so that QtcMovie::moveToThread() works as expected. Task-number: QTBUG-131448 Change-Id: I544742cb1cd134de73a7a87a6e7a4b19cbd6aa5d Reviewed-by: Jarek Kobus --- src/libs/utils/movie.cpp | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/libs/utils/movie.cpp b/src/libs/utils/movie.cpp index 85ef066c6f6..3d622c6a703 100644 --- a/src/libs/utils/movie.cpp +++ b/src/libs/utils/movie.cpp @@ -103,7 +103,7 @@ public: QMap frameMap; QString absoluteFilePath; - QTimer nextImageTimer; + QTimer *nextImageTimer; }; /*! \internal @@ -111,14 +111,13 @@ public: QtcMoviePrivate::QtcMoviePrivate(QtcMovie *qq) { q_ptr = qq; - nextImageTimer.setSingleShot(true); } /*! \internal */ void QtcMoviePrivate::reset() { - nextImageTimer.stop(); + nextImageTimer->stop(); if (reader->device()) initialDevicePos = reader->device()->pos(); currentFrameNumber = -1; @@ -360,7 +359,7 @@ void QtcMoviePrivate::_q_loadNextFrame(bool starting) emit q->frameChanged(currentFrameNumber); if (speed && movieState == QtcMovie::Running) - nextImageTimer.start(nextDelay); + nextImageTimer->start(nextDelay); } else { // Could not read another frame if (!isDone()) { @@ -410,7 +409,7 @@ bool QtcMoviePrivate::jumpToFrame(int frameNumber) return true; nextFrameNumber = frameNumber; if (movieState == QtcMovie::Running) - nextImageTimer.stop(); + nextImageTimer->stop(); _q_loadNextFrame(); return (nextFrameNumber == currentFrameNumber + 1); } @@ -436,6 +435,13 @@ bool QtcMoviePrivate::jumpToNextFrame() return jumpToFrame(currentFrameNumber + 1); } +static QTimer *createTimer(QObject *parent) +{ + auto timer = new QTimer(parent); + timer->setSingleShot(true); + return timer; +} + /*! Constructs a QtcMovie object, passing the \a parent object to QObject's constructor. @@ -446,8 +452,9 @@ QtcMovie::QtcMovie(QObject *parent) : QObject(*new QtcMoviePrivate(this), parent) { Q_D(QtcMovie); + d->nextImageTimer = createTimer(this); d->reader = new QImageReader; - connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); + connect(d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); } /*! @@ -462,9 +469,10 @@ QtcMovie::QtcMovie(QIODevice *device, const QByteArray &format, QObject *parent) : QObject(*new QtcMoviePrivate(this), parent) { Q_D(QtcMovie); + d->nextImageTimer = createTimer(this); d->reader = new QImageReader(device, format); d->initialDevicePos = device->pos(); - connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); + connect(d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); } /*! @@ -479,11 +487,12 @@ QtcMovie::QtcMovie(const QString &fileName, const QByteArray &format, QObject *p : QObject(*new QtcMoviePrivate(this), parent) { Q_D(QtcMovie); + d->nextImageTimer = createTimer(this); d->absoluteFilePath = QDir(fileName).absolutePath(); d->reader = new QImageReader(fileName, format); if (d->reader->device()) d->initialDevicePos = d->reader->device()->pos(); - connect(&d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); + connect(d->nextImageTimer, SIGNAL(timeout()), this, SLOT(_q_loadNextFrame())); } /*! @@ -759,12 +768,12 @@ void QtcMovie::setPaused(bool paused) if (d->movieState == NotRunning) return; d->enterState(Paused); - d->nextImageTimer.stop(); + d->nextImageTimer->stop(); } else { if (d->movieState == Running) return; d->enterState(Running); - d->nextImageTimer.start(nextFrameDelay()); + d->nextImageTimer->start(nextFrameDelay()); } } @@ -782,7 +791,7 @@ void QtcMovie::setSpeed(int percentSpeed) { Q_D(QtcMovie); if (!d->speed && d->movieState == Running) - d->nextImageTimer.start(nextFrameDelay()); + d->nextImageTimer->start(nextFrameDelay()); if (percentSpeed != d->speed) { d->speed = percentSpeed; d->speed.notify(); @@ -839,7 +848,7 @@ void QtcMovie::stop() if (d->movieState == NotRunning) return; d->enterState(NotRunning); - d->nextImageTimer.stop(); + d->nextImageTimer->stop(); d->nextFrameNumber = 0; } From 1ad41ba1d41aef83b8ffea10957d19bed98ff72f Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 11:37:10 +0100 Subject: [PATCH 292/989] Debugger: Use Utils::Process's decoding for LLDB output Change-Id: I6e38901b33fcc498c06d44a4185953776d6b79b9 Reviewed-by: Marcus Tillmanns --- src/plugins/debugger/lldb/lldbengine.cpp | 18 +++++++++--------- src/plugins/debugger/lldb/lldbengine.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index a3f2c5c32e1..65b45cbda61 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -847,27 +847,27 @@ QString LldbEngine::errorMessage(QProcess::ProcessError error) const void LldbEngine::readLldbStandardError() { - QString err = QString::fromUtf8(m_lldbProc.readAllRawStandardError()); + const QString err = m_lldbProc.readAllStandardError(); qDebug() << "\nLLDB STDERR UNEXPECTED: " << err; showMessage("Lldb stderr: " + err, LogError); } void LldbEngine::readLldbStandardOutput() { - const QByteArray out = m_lldbProc.readAllRawStandardOutput(); - showMessage(QString::fromUtf8(out), LogOutput); + const QString out = m_lldbProc.readAllStandardOutput(); + showMessage(out, LogOutput); m_inbuffer.append(out); while (true) { - if (int pos = m_inbuffer.indexOf("@\n"); pos >= 0) { - const QByteArray response = m_inbuffer.left(pos).trimmed(); + if (int pos = m_inbuffer.indexOf(u"@\n"); pos >= 0) { + const QString response = m_inbuffer.left(pos).trimmed(); m_inbuffer = m_inbuffer.mid(pos + 2); - emit outputReady(QString::fromUtf8(response)); + emit outputReady(response); continue; } - if (int pos = m_inbuffer.indexOf("@\r\n"); pos >= 0) { - const QByteArray response = m_inbuffer.left(pos).trimmed(); + if (int pos = m_inbuffer.indexOf(u"@\r\n"); pos >= 0) { + const QString response = m_inbuffer.left(pos).trimmed(); m_inbuffer = m_inbuffer.mid(pos + 3); - emit outputReady(QString::fromUtf8(response)); + emit outputReady(response); continue; } break; diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index faf2cc3f6fb..2f5fe0d7688 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -111,7 +111,7 @@ private: private: DebuggerCommand m_lastDebuggableCommand; - QByteArray m_inbuffer; + QString m_inbuffer; QString m_scriptFileName; Utils::Process m_lldbProc; From 18cd9359b9378dca470a04c782cca4d35ac8636c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 19 Nov 2024 15:21:50 +0100 Subject: [PATCH 293/989] LanguageClient: Allow to disable server per project Fixes: QTCREATORBUG-31987 Change-Id: I5eb1fd672e8b07b54795fffd70173ba1884b9426 Reviewed-by: Sami Shalayel Reviewed-by: Christian Stenger --- .../languageclient/languageclientmanager.cpp | 20 ++++- .../languageclient/languageclientmanager.h | 1 + .../languageclient/languageclientsettings.cpp | 88 +++++++++++++++++++ .../languageclient/languageclientsettings.h | 9 ++ 4 files changed, 117 insertions(+), 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 5cecf79a411..4c64f478366 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -298,6 +298,14 @@ void LanguageClientManager::applySettings() applySettings(settings); } +void LanguageClientManager::applySettings(const QString &settingsId) +{ + if (BaseSettings *settings = Utils::findOrDefault( + LanguageClientSettings::pageSettings(), Utils::equal(&BaseSettings::m_id, settingsId))) { + applySettings(settings); + } +} + void LanguageClientManager::applySettings(BaseSettings *setting) { QList documents; @@ -308,16 +316,20 @@ void LanguageClientManager::applySettings(BaseSettings *setting) } for (auto document : std::as_const(documents)) managerInstance->m_clientForDocument.remove(document); - if (!setting->isValid() || !setting->m_enabled) + if (!setting->isValid()) return; switch (setting->m_startBehavior) { case BaseSettings::AlwaysOn: { + if (!setting->m_enabled) + return; Client *client = startClient(setting); for (TextEditor::TextDocument *document : std::as_const(documents)) managerInstance->m_clientForDocument[document] = client; break; } case BaseSettings::RequiresFile: { + if (!setting->m_enabled) + return; Client *client = nullptr; for (TextEditor::TextDocument *previousDocument : std::as_const(documents)) { if (setting->m_languageFilter.isSupported(previousDocument)) { @@ -350,6 +362,12 @@ void LanguageClientManager::applySettings(BaseSettings *setting) const Utils::FilePath filePath = textDocument->filePath(); for (ProjectExplorer::Project *project : ProjectExplorer::ProjectManager::projects()) { + const bool settingIsEnabled + = ProjectSettings(project).enabledSettings().contains(setting->m_id) + || (setting->m_enabled + && !ProjectSettings(project).disabledSettings().contains(setting->m_id)); + if (!settingIsEnabled) + continue; if (project->isKnownFile(filePath)) { Client *client = clientForProject[project]; if (!client) { diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index d39844e16d0..018e46ea7df 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -52,6 +52,7 @@ public: const TextEditor::TextDocument *doc, bool onlyReachable = true); static void applySettings(); + static void applySettings(const QString &settingsId); static void applySettings(BaseSettings *settings); static QList currentSettings(); static void registerClientSettings(BaseSettings *settings); diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 4474d4a8d63..5d2a10eb243 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -53,6 +53,7 @@ #include #include #include +#include constexpr char typeIdKey[] = "typeId"; constexpr char nameKey[] = "name"; @@ -1168,11 +1169,15 @@ TextEditor::BaseTextEditor *createJsonEditor(QObject *parent) } constexpr const char projectSettingsId[] = "LanguageClient.ProjectSettings"; +constexpr const char enabledSettingsId[] = "LanguageClient.EnabledSettings"; +constexpr const char disabledSettingsId[] = "LanguageClient.DisabledSettings"; ProjectSettings::ProjectSettings(ProjectExplorer::Project *project) : m_project(project) { m_json = m_project->namedSettings(projectSettingsId).toByteArray(); + m_enabledSettings = m_project->namedSettings(enabledSettingsId).toStringList(); + m_disabledSettings = m_project->namedSettings(disabledSettingsId).toStringList(); } QJsonValue ProjectSettings::workspaceConfiguration() const @@ -1200,6 +1205,50 @@ void ProjectSettings::setJson(const QByteArray &json) LanguageClientManager::updateWorkspaceConfiguration(m_project, newConfig); } +void ProjectSettings::enableSetting(const QString &id) +{ + if (m_disabledSettings.removeAll(id) > 0) + m_project->setNamedSettings(disabledSettingsId, m_disabledSettings); + if (m_enabledSettings.contains(id)) + return; + m_enabledSettings << id; + m_project->setNamedSettings(enabledSettingsId, m_enabledSettings); + LanguageClientManager::applySettings(id); +} + +void ProjectSettings::disableSetting(const QString &id) +{ + if (m_enabledSettings.removeAll(id) > 0) + m_project->setNamedSettings(enabledSettingsId, m_enabledSettings); + if (m_disabledSettings.contains(id)) + return; + m_disabledSettings << id; + m_project->setNamedSettings(disabledSettingsId, m_disabledSettings); + LanguageClientManager::applySettings(id); +} + +void ProjectSettings::clearOverride(const QString &id) +{ + const bool changedEnabled = m_enabledSettings.removeAll(id) > 0; + if (changedEnabled) + m_project->setNamedSettings(enabledSettingsId, m_enabledSettings); + const bool changedDisabled = m_disabledSettings.removeAll(id) > 0; + if (changedDisabled) + m_project->setNamedSettings(disabledSettingsId, m_disabledSettings); + if (changedEnabled || changedDisabled) + LanguageClientManager::applySettings(id); +} + +QStringList ProjectSettings::enabledSettings() +{ + return m_enabledSettings; +} + +QStringList ProjectSettings::disabledSettings() +{ + return m_disabledSettings; +} + class LanguageClientProjectSettingsWidget : public ProjectSettingsWidget { public: @@ -1215,6 +1264,45 @@ public: auto layout = new QVBoxLayout; setLayout(layout); + + QFormLayout *settingsLayout = nullptr; + for (auto settings : LanguageClientSettings::pageSettings()) { + + if (settings->m_startBehavior != BaseSettings::RequiresProject) + continue; + if (!settingsLayout) { + auto group = new QGroupBox(Tr::tr("Project Specific Language Servers")); + settingsLayout = new QFormLayout; + settingsLayout->setFormAlignment(Qt::AlignLeft); + settingsLayout->setFieldGrowthPolicy(QFormLayout::FieldsStayAtSizeHint); + group->setLayout(settingsLayout); + layout->addWidget(group); + } + QComboBox *comboBox = new QComboBox; + comboBox->addItem(Tr::tr("Use Global Settings")); + comboBox->addItem(Tr::tr("Enabled")); + comboBox->addItem(Tr::tr("Disabled")); + if (m_settings.enabledSettings().contains(settings->m_id)) + comboBox->setCurrentIndex(1); + else if (m_settings.disabledSettings().contains(settings->m_id)) + comboBox->setCurrentIndex(2); + else + comboBox->setCurrentIndex(0); + connect( + comboBox, + &QComboBox::currentIndexChanged, + this, + [id = settings->m_id, this](int index) { + if (index == 0) + m_settings.clearOverride(id); + else if (index == 1) + m_settings.enableSetting(id); + else if (index == 2) + m_settings.disableSetting(id); + }); + settingsLayout->addRow(settings->m_name, comboBox); + } + auto group = new QGroupBox(Tr::tr("Workspace Configuration")); group->setLayout(new QVBoxLayout); group->layout()->addWidget(new QLabel(Tr::tr( diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index 4d2cd757c01..b909c9c19e8 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -209,9 +209,18 @@ public: QByteArray json() const; void setJson(const QByteArray &json); + void enableSetting(const QString &id); + void disableSetting(const QString &id); + void clearOverride(const QString &id); + + QStringList enabledSettings(); + QStringList disabledSettings(); + private: ProjectExplorer::Project *m_project = nullptr; QByteArray m_json; + QStringList m_enabledSettings; + QStringList m_disabledSettings; }; LANGUAGECLIENT_EXPORT TextEditor::BaseTextEditor *createJsonEditor(QObject *parent = nullptr); From 2a93a8ff30e2585da431bba55f95b718ebe62d9a Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 12:13:07 +0100 Subject: [PATCH 294/989] QMake: Use Process's decoding for qmake output and uic Change-Id: I6c5d349104cf850c369b66106a28be80bc657e50 Reviewed-by: Christian Kandeler --- src/plugins/qmakeprojectmanager/qmakeproject.cpp | 4 ++-- src/plugins/qtsupport/uicgenerator.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index fd0a65f6373..ffd219cd164 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -1602,10 +1602,10 @@ void QmakeBuildSystem::runGenerator(Utils::Id id) const auto proc = new Process(this); connect(proc, &Process::done, proc, &Process::deleteLater); connect(proc, &Process::readyReadStandardOutput, this, [proc] { - Core::MessageManager::writeFlashing(QString::fromLocal8Bit(proc->readAllRawStandardOutput())); + Core::MessageManager::writeFlashing(proc->readAllStandardOutput()); }); connect(proc, &Process::readyReadStandardError, this, [proc] { - Core::MessageManager::writeDisrupting(QString::fromLocal8Bit(proc->readAllRawStandardError())); + Core::MessageManager::writeDisrupting(proc->readAllStandardError()); }); proc->setWorkingDirectory(outDir); proc->setEnvironment(buildConfiguration()->environment()); diff --git a/src/plugins/qtsupport/uicgenerator.cpp b/src/plugins/qtsupport/uicgenerator.cpp index e79788f174e..f152242e958 100644 --- a/src/plugins/qtsupport/uicgenerator.cpp +++ b/src/plugins/qtsupport/uicgenerator.cpp @@ -61,7 +61,7 @@ FileNameToContentsHash UicGenerator::handleProcessFinished(Process *process) return result; // As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The // conversion below is to normalize both the encoding, and the line terminators. - QByteArray content = QString::fromLocal8Bit(process->readAllRawStandardOutput()).toUtf8(); + QByteArray content = process->readAllStandardOutput().toUtf8(); content.prepend("#pragma once\n"); result[targetList.first()] = content; return result; From 876730195cb9e93731afdf657ca632a9b2ec2eab Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 21 Nov 2024 09:45:14 +0100 Subject: [PATCH 295/989] VCS: Remove an unnecessary indirection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove VcsBaseClient::findTopLevelForFile. It was only used by a few IVersionControl subclasses and always only redirected to VcsBase::findRepositoryForFile in these cases. Change-Id: I7af0d98b3289566ca82384e51b357654f4990d56 Reviewed-by: André Hartmann Reviewed-by: Orgad Shaneh --- src/plugins/bazaar/bazaarclient.cpp | 7 ------- src/plugins/bazaar/bazaarclient.h | 1 - src/plugins/bazaar/bazaarplugin.cpp | 3 ++- src/plugins/fossil/fossilclient.cpp | 5 ----- src/plugins/fossil/fossilclient.h | 1 - src/plugins/fossil/fossilplugin.cpp | 2 +- src/plugins/mercurial/mercurialclient.cpp | 6 ------ src/plugins/mercurial/mercurialclient.h | 1 - src/plugins/mercurial/mercurialplugin.cpp | 3 ++- src/plugins/vcsbase/vcsbaseclient.h | 2 -- 10 files changed, 5 insertions(+), 26 deletions(-) diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp index 77005d410b3..ff1cbd5ba8c 100644 --- a/src/plugins/bazaar/bazaarclient.cpp +++ b/src/plugins/bazaar/bazaarclient.cpp @@ -151,13 +151,6 @@ bool BazaarClient::isVcsDirectory(const FilePath &filePath) const && filePath.isDir(); } -FilePath BazaarClient::findTopLevelForFile(const FilePath &file) const -{ - const QString repositoryCheckFile = - QLatin1String(Constants::BAZAARREPO) + QLatin1String("/branch-format"); - return VcsBase::findRepositoryForFile(file, repositoryCheckFile); -} - bool BazaarClient::managesFile(const FilePath &workingDirectory, const QString &fileName) const { const CommandResult result = vcsSynchronousExec(workingDirectory, {"status", fileName}); diff --git a/src/plugins/bazaar/bazaarclient.h b/src/plugins/bazaar/bazaarclient.h index d4a2c6032f8..ceb708e6d91 100644 --- a/src/plugins/bazaar/bazaarclient.h +++ b/src/plugins/bazaar/bazaarclient.h @@ -24,7 +24,6 @@ public: int lineNumber = -1, const QString &revision = {}, const QStringList &extraOptions = {}, int firstLine = -1) override; bool isVcsDirectory(const Utils::FilePath &filePath) const; - Utils::FilePath findTopLevelForFile(const Utils::FilePath &file) const override; bool managesFile(const Utils::FilePath &workingDirectory, const QString &fileName) const; void view(const Utils::FilePath &source, const QString &id, const QStringList &extraOptions = {}) override; diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 6510d3ad7bf..277bcbab353 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -871,7 +871,8 @@ bool BazaarPluginPrivate::isVcsFileOrDirectory(const Utils::FilePath &fileName) bool BazaarPluginPrivate::managesDirectory(const FilePath &directory, FilePath *topLevel) const { - const FilePath topLevelFound = m_client.findTopLevelForFile(directory); + const FilePath topLevelFound = VcsBase::findRepositoryForFile( + directory, QLatin1String(Constants::BAZAARREPO) + "/branch-format"); if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); diff --git a/src/plugins/fossil/fossilclient.cpp b/src/plugins/fossil/fossilclient.cpp index 843397fa2c4..deb2ed9c296 100644 --- a/src/plugins/fossil/fossilclient.cpp +++ b/src/plugins/fossil/fossilclient.cpp @@ -737,11 +737,6 @@ bool FossilClient::isVcsFileOrDirectory(const FilePath &filePath) const && filePath.isFile(); } -FilePath FossilClient::findTopLevelForFile(const FilePath &file) const -{ - return findRepositoryForFile(file, Constants::FOSSILREPO); -} - bool FossilClient::managesFile(const FilePath &workingDirectory, const QString &fileName) const { const CommandResult result = vcsSynchronousExec(workingDirectory, {"finfo", fileName}); diff --git a/src/plugins/fossil/fossilclient.h b/src/plugins/fossil/fossilclient.h index 6df70502bd0..0973b85f9d0 100644 --- a/src/plugins/fossil/fossilclient.h +++ b/src/plugins/fossil/fossilclient.h @@ -83,7 +83,6 @@ public: void revertAll(const Utils::FilePath &workingDir, const QString &revision = {}, const QStringList &extraOptions = {}) final; bool isVcsFileOrDirectory(const Utils::FilePath &filePath) const; - Utils::FilePath findTopLevelForFile(const Utils::FilePath &file) const final; bool managesFile(const Utils::FilePath &workingDirectory, const QString &fileName) const; unsigned int binaryVersion() const; QString binaryVersionString() const; diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 999e3f2edb8..b52afbafcd7 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -800,7 +800,7 @@ bool FossilPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) const bool FossilPluginPrivate::managesDirectory(const FilePath &directory, FilePath *topLevel) const { - const FilePath topLevelFound = fossilClient().findTopLevelForFile(directory); + const FilePath topLevelFound = VcsBase::findRepositoryForFile(directory, Constants::FOSSILREPO); if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 9f86d7f7470..c4e3be177e0 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -361,12 +361,6 @@ void MercurialClient::view(const FilePath &source, const QString &id, VcsBaseClient::view(source, id, args << extraOptions); } -FilePath MercurialClient::findTopLevelForFile(const FilePath &file) const -{ - const QString repositoryCheckFile = QLatin1String(Constants::MERCURIALREPO) + QLatin1String("/requires"); - return VcsBase::findRepositoryForFile(file, repositoryCheckFile); -} - Utils::Id MercurialClient::vcsEditorKind(VcsCommandTag cmd) const { switch (cmd) { diff --git a/src/plugins/mercurial/mercurialclient.h b/src/plugins/mercurial/mercurialclient.h index a00ea74e475..1b28541bfe7 100644 --- a/src/plugins/mercurial/mercurialclient.h +++ b/src/plugins/mercurial/mercurialclient.h @@ -52,7 +52,6 @@ public: const QStringList &extraOptions = {}) override; bool isVcsDirectory(const Utils::FilePath &filePath) const; - Utils::FilePath findTopLevelForFile(const Utils::FilePath &file) const override; void view(const Utils::FilePath &source, const QString &id, const QStringList &extraOptions = QStringList()) override; diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index b1be13e4521..242ad0eec0a 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -655,7 +655,8 @@ bool MercurialPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) cons bool MercurialPluginPrivate::managesDirectory(const FilePath &filePath, FilePath *topLevel) const { - const FilePath topLevelFound = mercurialClient().findTopLevelForFile(filePath); + const FilePath topLevelFound = VcsBase::findRepositoryForFile( + filePath, QLatin1String(Constants::MERCURIALREPO) + "/requires"); if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h index 9bdf18059b6..33aaf71d352 100644 --- a/src/plugins/vcsbase/vcsbaseclient.h +++ b/src/plugins/vcsbase/vcsbaseclient.h @@ -174,8 +174,6 @@ public: const QString &commitMessageFile, const QStringList &extraOptions = {}); - virtual Utils::FilePath findTopLevelForFile(const Utils::FilePath &/*file*/) const { return {}; } - virtual void view(const Utils::FilePath &source, const QString &id, const QStringList &extraOptions = QStringList()); From 9862de8e06e0026f3888170e22c98abfcfefdbcb Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 20 Nov 2024 13:37:27 +0100 Subject: [PATCH 296/989] Core: Replace the FileUtils class by a namespace Change-Id: I954109e15f9ea48ccd4a436e7ae35bdb20f50320 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/fileutils.cpp | 110 +++++++++++++-------------- src/plugins/coreplugin/fileutils.h | 44 +++++------ 2 files changed, 74 insertions(+), 80 deletions(-) diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 1b6af89db22..30d02bd3ad7 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -42,7 +42,7 @@ using namespace Utils; -namespace Core { +namespace Core::FileUtils { static FilePath windowsDirectory() { @@ -69,7 +69,7 @@ static void showGraphicalShellError(QWidget *parent, const QString &app, const Q ICore::showOptionsDialog(Constants::SETTINGS_ID_INTERFACE, parent); } -void FileUtils::showInGraphicalShell(QWidget *parent, const FilePath &pathIn) +void showInGraphicalShell(QWidget *parent, const FilePath &pathIn) { const QFileInfo fileInfo = pathIn.toFileInfo(); // Mac, Windows support folder or file. @@ -102,7 +102,7 @@ void FileUtils::showInGraphicalShell(QWidget *parent, const FilePath &pathIn) } } -void FileUtils::showInFileSystemView(const FilePath &path) +void showInFileSystemView(const FilePath &path) { QWidget *widget = NavigationWidget::activateSubWidget(FolderNavigationWidgetFactory::instance()->id(), @@ -111,22 +111,22 @@ void FileUtils::showInFileSystemView(const FilePath &path) navWidget->syncWithFilePath(path); } -void FileUtils::openTerminal(const FilePath &path, const Environment &env) +void openTerminal(const FilePath &path, const Environment &env) { Terminal::Hooks::instance().openTerminal({path, env}); } -QString FileUtils::msgFindInDirectory() +QString msgFindInDirectory() { return Tr::tr("Find in This Directory..."); } -QString FileUtils::msgFileSystemAction() +QString msgFileSystemAction() { return Tr::tr("Show in File System View"); } -QString FileUtils::msgGraphicalShellAction() +QString msgGraphicalShellAction() { if (HostOsInfo::isWindowsHost()) return Tr::tr("Show in Explorer"); @@ -135,14 +135,14 @@ QString FileUtils::msgGraphicalShellAction() return Tr::tr("Show Containing Folder"); } -QString FileUtils::msgTerminalHereAction() +QString msgTerminalHereAction() { if (HostOsInfo::isWindowsHost()) return Tr::tr("Open Command Prompt Here"); return Tr::tr("Open Terminal Here"); } -QString FileUtils::msgTerminalWithAction() +QString msgTerminalWithAction() { if (HostOsInfo::isWindowsHost()) return Tr::tr("Open Command Prompt With", @@ -151,7 +151,7 @@ QString FileUtils::msgTerminalWithAction() "Opens a submenu for choosing an environment, such as \"Run Environment\""); } -void FileUtils::removeFiles(const FilePaths &filePaths, bool deleteFromFS) +void removeFiles(const FilePaths &filePaths, bool deleteFromFS) { // remove from version control VcsManager::promptToDelete(filePaths); @@ -171,47 +171,9 @@ void FileUtils::removeFiles(const FilePaths &filePaths, bool deleteFromFS) } } -bool FileUtils::renameFile(const FilePath &orgFilePath, const FilePath &newFilePath, - HandleIncludeGuards handleGuards) -{ - if (orgFilePath.equalsCaseSensitive(newFilePath)) - return false; - - const FilePath dir = orgFilePath.absolutePath(); - IVersionControl *vc = VcsManager::findVersionControlForDirectory(dir); - const FilePath newDir = newFilePath.absolutePath(); - if (newDir != dir && !newDir.ensureWritableDir()) - return false; - - bool result = false; - if (vc && vc->supportsOperation(IVersionControl::MoveOperation)) - result = vc->vcsMove(orgFilePath, newFilePath); - if (!result) // The moving via vcs failed or the vcs does not support moving, fall back - result = bool(orgFilePath.renameFile(newFilePath)); - if (result) { - DocumentManager::renamedFile(orgFilePath, newFilePath); - updateHeaderFileGuardIfApplicable(orgFilePath, newFilePath, handleGuards); - } - return result; -} - -void FileUtils::updateHeaderFileGuardIfApplicable(const Utils::FilePath &oldFilePath, - const Utils::FilePath &newFilePath, - HandleIncludeGuards handleGuards) -{ - if (handleGuards == HandleIncludeGuards::No) - return; - const bool headerUpdateSuccess = updateHeaderFileGuardAfterRename(newFilePath.toString(), - oldFilePath.baseName()); - if (headerUpdateSuccess) - return; - MessageManager::writeDisrupting( - Tr::tr("Failed to rename the include guard in file \"%1\".") - .arg(newFilePath.toUserOutput())); -} - -bool FileUtils::updateHeaderFileGuardAfterRename(const QString &headerPath, - const QString &oldHeaderBaseName) +// This method is used to refactor the include guards in the renamed headers +static bool updateHeaderFileGuardAfterRename(const QString &headerPath, + const QString &oldHeaderBaseName) { bool ret = true; QFile headerFile(headerPath); @@ -228,7 +190,7 @@ bool FileUtils::updateHeaderFileGuardAfterRename(const QString &headerPath, const QByteArray data = headerFile.readAll(); headerFile.close(); - auto headerFileTextFormat = Utils::TextFileFormat::detect(data); + auto headerFileTextFormat = TextFileFormat::detect(data); if (!headerFileTextFormat.codec) headerFileTextFormat.codec = EditorManager::defaultTextCodec(); QString stringContent; @@ -315,8 +277,7 @@ bool FileUtils::updateHeaderFileGuardAfterRename(const QString &headerPath, QFile tmpHeader(headerPath + ".tmp"); if (tmpHeader.open(QFile::WriteOnly)) { const auto lineEnd = - headerFileTextFormat.lineTerminationMode - == Utils::TextFileFormat::LFLineTerminator + headerFileTextFormat.lineTerminationMode == TextFileFormat::LFLineTerminator ? QStringLiteral("\n") : QStringLiteral("\r\n"); // write into temporary string, // after that write with codec into file (QTextStream::setCodec is gone in Qt 6) @@ -355,4 +316,43 @@ bool FileUtils::updateHeaderFileGuardAfterRename(const QString &headerPath, return ret; } -} // namespace Core +bool renameFile(const FilePath &orgFilePath, const FilePath &newFilePath, + HandleIncludeGuards handleGuards) +{ + if (orgFilePath.equalsCaseSensitive(newFilePath)) + return false; + + const FilePath dir = orgFilePath.absolutePath(); + IVersionControl *vc = VcsManager::findVersionControlForDirectory(dir); + const FilePath newDir = newFilePath.absolutePath(); + if (newDir != dir && !newDir.ensureWritableDir()) + return false; + + bool result = false; + if (vc && vc->supportsOperation(IVersionControl::MoveOperation)) + result = vc->vcsMove(orgFilePath, newFilePath); + if (!result) // The moving via vcs failed or the vcs does not support moving, fall back + result = bool(orgFilePath.renameFile(newFilePath)); + if (result) { + DocumentManager::renamedFile(orgFilePath, newFilePath); + updateHeaderFileGuardIfApplicable(orgFilePath, newFilePath, handleGuards); + } + return result; +} + +void updateHeaderFileGuardIfApplicable(const FilePath &oldFilePath, + const FilePath &newFilePath, + HandleIncludeGuards handleGuards) +{ + if (handleGuards == HandleIncludeGuards::No) + return; + const bool headerUpdateSuccess = updateHeaderFileGuardAfterRename(newFilePath.toString(), + oldFilePath.baseName()); + if (headerUpdateSuccess) + return; + MessageManager::writeDisrupting( + Tr::tr("Failed to rename the include guard in file \"%1\".") + .arg(newFilePath.toUserOutput())); +} + +} // namespace Core::FileUtils diff --git a/src/plugins/coreplugin/fileutils.h b/src/plugins/coreplugin/fileutils.h index 46639f8a8bd..984673ec44e 100644 --- a/src/plugins/coreplugin/fileutils.h +++ b/src/plugins/coreplugin/fileutils.h @@ -17,31 +17,25 @@ namespace Core { enum class HandleIncludeGuards { No, Yes }; -struct CORE_EXPORT FileUtils -{ - // Helpers for common directory browser options. - static void showInGraphicalShell(QWidget *parent, const Utils::FilePath &path); - static void showInFileSystemView(const Utils::FilePath &path); - static void openTerminal(const Utils::FilePath &path, const Utils::Environment &env); - static QString msgFindInDirectory(); - static QString msgFileSystemAction(); - // Platform-dependent action descriptions - static QString msgGraphicalShellAction(); - static QString msgTerminalHereAction(); - static QString msgTerminalWithAction(); - // File operations aware of version control and file system case-insensitiveness - static void removeFiles(const Utils::FilePaths &filePaths, bool deleteFromFS); - static bool renameFile(const Utils::FilePath &from, const Utils::FilePath &to, - HandleIncludeGuards handleGuards = HandleIncludeGuards::No); +namespace FileUtils { - static void updateHeaderFileGuardIfApplicable(const Utils::FilePath &oldFilePath, - const Utils::FilePath &newFilePath, - HandleIncludeGuards handleGuards); - -private: - // This method is used to refactor the include guards in the renamed headers - static bool updateHeaderFileGuardAfterRename(const QString &headerPath, - const QString &oldHeaderBaseName); -}; +// Helpers for common directory browser options. +CORE_EXPORT void showInGraphicalShell(QWidget *parent, const Utils::FilePath &path); +CORE_EXPORT void showInFileSystemView(const Utils::FilePath &path); +CORE_EXPORT void openTerminal(const Utils::FilePath &path, const Utils::Environment &env); +CORE_EXPORT QString msgFindInDirectory(); +CORE_EXPORT QString msgFileSystemAction(); +// Platform-dependent action descriptions +CORE_EXPORT QString msgGraphicalShellAction(); +CORE_EXPORT QString msgTerminalHereAction(); +CORE_EXPORT QString msgTerminalWithAction(); +// File operations aware of version control and file system case-insensitiveness +CORE_EXPORT void removeFiles(const Utils::FilePaths &filePaths, bool deleteFromFS); +CORE_EXPORT bool renameFile(const Utils::FilePath &from, const Utils::FilePath &to, + HandleIncludeGuards handleGuards = HandleIncludeGuards::No); +CORE_EXPORT void updateHeaderFileGuardIfApplicable(const Utils::FilePath &oldFilePath, + const Utils::FilePath &newFilePath, + HandleIncludeGuards handleGuards); +} // namespace FileUtils } // namespace Core From 6377c9cd316c8064f146b85aae3e0000d51e21f8 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 16:04:14 +0100 Subject: [PATCH 297/989] Qnx: Move an #include to a smaller scope Change-Id: I9546e04c97afd5b66167b42d74b97f6ab8cc4d72 Reviewed-by: Jarek Kobus --- src/plugins/qnx/qnxqtversion.h | 2 -- src/plugins/qnx/qnxsettingspage.cpp | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/qnx/qnxqtversion.h b/src/plugins/qnx/qnxqtversion.h index 8c3b54f2550..5dbc79bf8ea 100644 --- a/src/plugins/qnx/qnxqtversion.h +++ b/src/plugins/qnx/qnxqtversion.h @@ -3,8 +3,6 @@ #pragma once -#include "qnxconstants.h" - #include #include diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index bc1ee131ef9..8127e0715ab 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -3,6 +3,7 @@ #include "qnxsettingspage.h" +#include "qnxconstants.h" #include "qnxqtversion.h" #include "qnxtoolchain.h" #include "qnxtr.h" From 692776d1d301a2363a40a15e452b3d4c1389faee Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 11:54:02 +0100 Subject: [PATCH 298/989] ProjectExplorer: Use Process' output decoding for SimpleTargetRunner Change-Id: Ie268e3b5d9fce200d027e334f48465fde849e598 Reviewed-by: Jarek Kobus --- src/plugins/projectexplorer/runcontrol.cpp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index ea5d5efccd6..7041a168631 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1390,10 +1390,6 @@ public: Process m_process; QTimer m_waitForDoneTimer; - QTextCodec *m_outputCodec = nullptr; - QTextCodec::ConverterState m_outputCodecState; - QTextCodec::ConverterState m_errorCodecState; - State m_state = Inactive; bool m_stopRequested = false; @@ -1511,9 +1507,7 @@ void SimpleTargetRunnerPrivate::handleStandardOutput() if (m_suppressDefaultStdOutHandling) return; - const QByteArray data = m_process.readAllRawStandardOutput(); - const QString msg = m_outputCodec->toUnicode( - data.constData(), data.length(), &m_outputCodecState); + const QString msg = m_process.readAllStandardOutput(); q->appendMessage(msg, StdOutFormat, false); } @@ -1522,9 +1516,7 @@ void SimpleTargetRunnerPrivate::handleStandardError() if (m_suppressDefaultStdOutHandling) return; - const QByteArray data = m_process.readAllRawStandardError(); - const QString msg = m_outputCodec->toUnicode( - data.constData(), data.length(), &m_errorCodecState); + const QString msg = m_process.readAllStandardError(); q->appendMessage(msg, StdErrFormat, false); } @@ -1573,12 +1565,7 @@ void SimpleTargetRunnerPrivate::start() m_state = Run; m_process.setWorkingDirectory(m_workingDirectory); - - if (isLocal) - m_outputCodec = QTextCodec::codecForLocale(); - else - m_outputCodec = QTextCodec::codecForName("utf8"); - + m_process.setCodec(isLocal ? QTextCodec::codecForLocale() : QTextCodec::codecForName("utf8")); m_process.setForceDefaultErrorModeOnWindows(true); m_process.start(); } From 38be6222ee03d1829fc98fd23af79c997968ea09 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 25 Nov 2024 16:26:09 +0100 Subject: [PATCH 299/989] TextEditor: simplify guessSpacesForTabs Change-Id: I31356d766c1e85b22d1ae1b7e77140baedb765d9 Reviewed-by: Christian Stenger --- src/plugins/texteditor/tabsettings.cpp | 38 +++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp index 6c01907958e..d3aa8eb40f4 100644 --- a/src/plugins/texteditor/tabsettings.cpp +++ b/src/plugins/texteditor/tabsettings.cpp @@ -223,31 +223,31 @@ int TabSettings::indentedColumn(int column, bool doIndent) const return qMax(0, aligned - m_indentSize); } -bool TabSettings::guessSpacesForTabs(const QTextBlock &_block) const +bool TabSettings::guessSpacesForTabs(const QTextBlock &block) const { - if (m_tabPolicy == MixedTabPolicy && _block.isValid()) { - const QTextDocument *doc = _block.document(); - QVector currentBlocks(2, _block); // [0] looks back; [1] looks forward - int maxLookAround = 100; - while (maxLookAround-- > 0) { - if (currentBlocks.at(0).isValid()) - currentBlocks[0] = currentBlocks.at(0).previous(); - if (currentBlocks.at(1).isValid()) - currentBlocks[1] = currentBlocks.at(1).next(); - bool done = true; - for (const QTextBlock &block : std::as_const(currentBlocks)) { - if (block.isValid()) - done = false; - if (!block.isValid() || block.length() == 0) - continue; + if (m_tabPolicy == MixedTabPolicy && block.isValid()) { + QTextBlock prev = block.previous(); + QTextBlock next = block.next(); + + auto checkFirstChar = + [doc = block.document()](const QTextBlock &block) -> std::optional { + if (block.length() > 0) { const QChar firstChar = doc->characterAt(block.position()); if (firstChar == QLatin1Char(' ')) return true; - else if (firstChar == QLatin1Char('\t')) + if (firstChar == QLatin1Char('\t')) return false; } - if (done) - break; + return {}; + }; + + for (int delta = 1; delta <= 100 && (prev.isValid() || next.isValid()); ++delta) { + if (auto result = checkFirstChar(prev)) + return *result; + if (auto result = checkFirstChar(next)) + return *result; + prev = prev.previous(); + next = next.next(); } } return m_tabPolicy != TabsOnlyTabPolicy; From 71be035eb3d1aa9f2bffbd6c1498c74ab06c4b50 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 27 Nov 2024 15:37:24 +0100 Subject: [PATCH 300/989] VCS: Consolidate managesDirectory() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most version control implementations use one or one of a set of specific files to find a toplevel directory for that version control. Share the code that searches for these. Change-Id: Ia308262018f79e59de33b862a020b8cb8138f17f Reviewed-by: Orgad Shaneh Reviewed-by: André Hartmann --- src/plugins/bazaar/bazaarplugin.cpp | 2 +- src/plugins/fossil/fossilplugin.cpp | 3 +- src/plugins/git/gitclient.cpp | 15 +------- src/plugins/mercurial/mercurialplugin.cpp | 4 +-- src/plugins/subversion/subversionplugin.cpp | 40 ++++----------------- src/plugins/vcsbase/vcsbaseplugin.cpp | 28 ++++++--------- src/plugins/vcsbase/vcsbaseplugin.h | 4 +-- 7 files changed, 25 insertions(+), 71 deletions(-) diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 277bcbab353..a8b0baa67c1 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -872,7 +872,7 @@ bool BazaarPluginPrivate::isVcsFileOrDirectory(const Utils::FilePath &fileName) bool BazaarPluginPrivate::managesDirectory(const FilePath &directory, FilePath *topLevel) const { const FilePath topLevelFound = VcsBase::findRepositoryForFile( - directory, QLatin1String(Constants::BAZAARREPO) + "/branch-format"); + directory, {QString(Constants::BAZAARREPO) + "/branch-format"}); if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index b52afbafcd7..3c28916a778 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -800,7 +800,8 @@ bool FossilPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) const bool FossilPluginPrivate::managesDirectory(const FilePath &directory, FilePath *topLevel) const { - const FilePath topLevelFound = VcsBase::findRepositoryForFile(directory, Constants::FOSSILREPO); + const FilePath topLevelFound + = VcsBase::findRepositoryForFile(directory, {Constants::FOSSILREPO}); if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 5973851fa20..b7ac7428de9 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -59,7 +59,6 @@ #include #include -const char GIT_DIRECTORY[] = ".git"; const char HEAD[] = "HEAD"; const char CHERRY_PICK_HEAD[] = "CHERRY_PICK_HEAD"; const char BRANCHES_PREFIX[] = "Branches: "; @@ -838,19 +837,7 @@ GitSettings &GitClient::settings() FilePath GitClient::findRepositoryForDirectory(const FilePath &directory) const { - if (directory.isEmpty() || directory.endsWith("/.git") || directory.path().contains("/.git/")) - return {}; - FilePath parent; - for (FilePath dir = directory; !dir.isEmpty(); dir = dir.parentDir()) { - const FilePath gitName = dir.pathAppended(GIT_DIRECTORY); - if (!gitName.exists()) - continue; // parent might exist - if (gitName.isFile()) - return dir; - if (gitName.pathAppended("config").exists()) - return dir; - } - return {}; + return VcsBase::findRepositoryForFile(directory, {".git", ".git/config"}); } FilePath GitClient::findGitDirForRepository(const FilePath &repositoryDir) const diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 242ad0eec0a..d45af47fd18 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -655,8 +655,8 @@ bool MercurialPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) cons bool MercurialPluginPrivate::managesDirectory(const FilePath &filePath, FilePath *topLevel) const { - const FilePath topLevelFound = VcsBase::findRepositoryForFile( - filePath, QLatin1String(Constants::MERCURIALREPO) + "/requires"); + const FilePath topLevelFound + = VcsBase::findRepositoryForFile(filePath, {QString(Constants::MERCURIALREPO) + "/requires"}); if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 406ecf2ef96..8c27cad92e0 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -216,7 +216,6 @@ private: bool enableAnnotationContextMenu = false); void svnStatus(const FilePath &workingDir, const QString &relativePath = {}); void svnUpdate(const FilePath &workingDir, const QString &relativePath = {}); - bool checkSVNSubDir(const QDir &directory) const; void startCommit(const FilePath &workingDir, const QStringList &files = {}); const QStringList m_svnDirectories; @@ -1024,25 +1023,13 @@ bool SubversionPluginPrivate::vcsCheckout(const FilePath &directory, const QByte bool SubversionPluginPrivate::managesDirectory(const FilePath &directory, FilePath *topLevel /* = 0 */) const { - const QDir dir(directory.toString()); + const QStringList filesToCheck = transform(m_svnDirectories, [](const QString &s) { + return QString(s + "/wc.db"); + }); + const FilePath topLevelFound = VcsBase::findRepositoryForFile(directory, filesToCheck); if (topLevel) - topLevel->clear(); - - /* Subversion >= 1.7 has ".svn" directory in the root of the working copy. Check for - * furthest parent containing ".svn/wc.db". Need to check for furthest parent as closer - * parents may be svn:externals. */ - QDir parentDir = dir; - while (!parentDir.isRoot()) { - if (checkSVNSubDir(parentDir)) { - if (topLevel) - *topLevel = FilePath::fromString(parentDir.absolutePath()); - return true; - } - if (!parentDir.cdUp()) - break; - } - - return false; + *topLevel = topLevelFound; + return !topLevelFound.isEmpty(); } bool SubversionPluginPrivate::managesFile(const FilePath &workingDirectory, const QString &fileName) const @@ -1054,21 +1041,6 @@ bool SubversionPluginPrivate::managesFile(const FilePath &workingDirectory, cons return output.isEmpty() || output.front() != QLatin1Char('?'); } -// Check whether SVN management subdirs exist. -bool SubversionPluginPrivate::checkSVNSubDir(const QDir &directory) const -{ - const int dirCount = m_svnDirectories.size(); - for (int i = 0; i < dirCount; i++) { - const QDir svnDir(directory.absoluteFilePath(m_svnDirectories.at(i))); - if (!svnDir.exists()) - continue; - if (!svnDir.exists(QLatin1String("wc.db"))) - continue; - return true; - } - return false; -} - Utils::Id SubversionPluginPrivate::id() const { return Utils::Id(VcsBase::Constants::VCS_ID_SUBVERSION); diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index 631eb0f248f..e8b051377f2 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -712,27 +712,21 @@ void VersionControlBase::discardCommit() // AutoFS is used (due its automatically creating mountpoints when querying // a directory). In addition, bail out when reaching the home directory // of the user or root (generally avoid '/', where mountpoints are created). -FilePath findRepositoryForFile(const FilePath &fileOrDir, const QString &checkFile) +FilePath findRepositoryForFile(const FilePath &fileOrDir, const QStringList &checkFiles) { const FilePath dirS = fileOrDir.isDir() ? fileOrDir : fileOrDir.parentDir(); - qCDebug(findRepoLog) << ">" << dirS << checkFile; - QTC_ASSERT(!dirS.isEmpty() && !checkFile.isEmpty(), return {}); + qCDebug(findRepoLog) << ">" << dirS << checkFiles; + QTC_ASSERT(!dirS.isEmpty(), return {}); - const QString root = QDir::rootPath(); - const QString home = QDir::homePath(); - - QDir directory(dirS.toString()); - do { - const QString absDirPath = directory.absolutePath(); - if (absDirPath == root || absDirPath == home) - break; - - if (QFileInfo(directory, checkFile).isFile()) { - qCDebug(findRepoLog) << "<" << absDirPath; - return FilePath::fromString(absDirPath); + FilePath parent; + for (FilePath dir = dirS; !dir.isEmpty() && !dir.isRootPath(); dir = dir.parentDir()) { + for (const QString &checkFile : checkFiles) { + if (dir.pathAppended(checkFile).isFile()) { + qCDebug(findRepoLog) << "<" << dir.toUserOutput(); + return dir; + } } - } while (!directory.isRoot() && directory.cdUp()); - qCDebug(findRepoLog) << "< bailing out at" << directory.absolutePath(); + } return {}; } diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h index b1c9abf32a8..7d7f38b0e56 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.h +++ b/src/plugins/vcsbase/vcsbaseplugin.h @@ -98,8 +98,8 @@ private: // systems that do not have directories like "CVS" in each managed subdirectory // but have a directory at the top of the repository like ".git" containing // a well known file. See implementation for gory details. -VCSBASE_EXPORT Utils::FilePath findRepositoryForFile(const Utils::FilePath &fileOrDir, - const QString &checkFile); +VCSBASE_EXPORT Utils::FilePath findRepositoryForFile( + const Utils::FilePath &fileOrDir, const QStringList &checkFiles); // Set up the environment for a version control command line call. // Sets up SSH graphical password prompting (note that the latter From 15f1cc2fceba79b4dbb58e3717626c65330e3db6 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 28 Nov 2024 14:22:41 +0100 Subject: [PATCH 301/989] VCS: Move convenience function to Core::VcsManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn't have any dependencies to VcsBase, and this way we can utilize it in VcsManager directly. Change-Id: I62c6314b363904055127bc11c4f7426948805c3d Reviewed-by: André Hartmann Reviewed-by: Orgad Shaneh --- src/plugins/bazaar/bazaarplugin.cpp | 2 +- src/plugins/coreplugin/vcsmanager.cpp | 28 +++++++++++++++++++++ src/plugins/coreplugin/vcsmanager.h | 7 ++++++ src/plugins/fossil/fossilplugin.cpp | 2 +- src/plugins/git/gitclient.cpp | 2 +- src/plugins/mercurial/mercurialplugin.cpp | 4 +-- src/plugins/subversion/subversionplugin.cpp | 2 +- src/plugins/vcsbase/vcsbaseplugin.cpp | 26 ------------------- src/plugins/vcsbase/vcsbaseplugin.h | 7 ------ 9 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index a8b0baa67c1..9102966a3dc 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -871,7 +871,7 @@ bool BazaarPluginPrivate::isVcsFileOrDirectory(const Utils::FilePath &fileName) bool BazaarPluginPrivate::managesDirectory(const FilePath &directory, FilePath *topLevel) const { - const FilePath topLevelFound = VcsBase::findRepositoryForFile( + const FilePath topLevelFound = VcsManager::findRepositoryForFiles( directory, {QString(Constants::BAZAARREPO) + "/branch-format"}); if (topLevel) *topLevel = topLevelFound; diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp index 3a419d507c7..de146a5656b 100644 --- a/src/plugins/coreplugin/vcsmanager.cpp +++ b/src/plugins/coreplugin/vcsmanager.cpp @@ -25,6 +25,8 @@ #include +static Q_LOGGING_CATEGORY(findRepoLog, "qtc.vcs.find-repo", QtWarningMsg) + using namespace Utils; namespace Core { @@ -436,6 +438,32 @@ void VcsManager::clearVersionControlCache() emit m_instance->repositoryChanged(repo); } +// Find top level for version controls like git/Mercurial that have +// a directory at the top of the repository. +// Note that checking for the existence of files is preferred over directories +// since checking for directories can cause them to be created when +// AutoFS is used (due its automatically creating mountpoints when querying +// a directory). In addition, bail out when reaching the home directory +// of the user or root (generally avoid '/', where mountpoints are created). +FilePath VcsManager::findRepositoryForFiles( + const Utils::FilePath &fileOrDir, const QStringList &checkFiles) +{ + const FilePath dirS = fileOrDir.isDir() ? fileOrDir : fileOrDir.parentDir(); + qCDebug(findRepoLog) << ">" << dirS << checkFiles; + QTC_ASSERT(!dirS.isEmpty(), return {}); + + FilePath parent; + for (FilePath dir = dirS; !dir.isEmpty() && !dir.isRootPath(); dir = dir.parentDir()) { + for (const QString &checkFile : checkFiles) { + if (dir.pathAppended(checkFile).isFile()) { + qCDebug(findRepoLog) << "<" << dir.toUserOutput(); + return dir; + } + } + } + return {}; +} + void VcsManager::handleConfigurationChanges(IVersionControl *vc) { d->m_cachedAdditionalToolsPathsDirty = true; diff --git a/src/plugins/coreplugin/vcsmanager.h b/src/plugins/coreplugin/vcsmanager.h index 4daad33124d..f12b0df9ffa 100644 --- a/src/plugins/coreplugin/vcsmanager.h +++ b/src/plugins/coreplugin/vcsmanager.h @@ -76,6 +76,13 @@ public: static void clearVersionControlCache(); + // Convenience that searches for the repository specifically for version control + // systems that do not have directories like "CVS" in each managed subdirectory + // but have a directory at the top of the repository like ".git" containing + // a well known file. See implementation for gory details. + static Utils::FilePath findRepositoryForFiles( + const Utils::FilePath &fileOrDir, const QStringList &checkFiles); + signals: void repositoryChanged(const Utils::FilePath &repository); void configurationChanged(const IVersionControl *vcs); diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 3c28916a778..ea049c95d93 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -801,7 +801,7 @@ bool FossilPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) const bool FossilPluginPrivate::managesDirectory(const FilePath &directory, FilePath *topLevel) const { const FilePath topLevelFound - = VcsBase::findRepositoryForFile(directory, {Constants::FOSSILREPO}); + = VcsManager::findRepositoryForFiles(directory, {Constants::FOSSILREPO}); if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index b7ac7428de9..6bb1301f40b 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -837,7 +837,7 @@ GitSettings &GitClient::settings() FilePath GitClient::findRepositoryForDirectory(const FilePath &directory) const { - return VcsBase::findRepositoryForFile(directory, {".git", ".git/config"}); + return VcsManager::findRepositoryForFiles(directory, {".git", ".git/config"}); } FilePath GitClient::findGitDirForRepository(const FilePath &repositoryDir) const diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index d45af47fd18..92d50bae398 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -655,8 +655,8 @@ bool MercurialPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) cons bool MercurialPluginPrivate::managesDirectory(const FilePath &filePath, FilePath *topLevel) const { - const FilePath topLevelFound - = VcsBase::findRepositoryForFile(filePath, {QString(Constants::MERCURIALREPO) + "/requires"}); + const FilePath topLevelFound = Core::VcsManager::findRepositoryForFiles( + filePath, {QString(Constants::MERCURIALREPO) + "/requires"}); if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 8c27cad92e0..e07e9ad3a26 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -1026,7 +1026,7 @@ bool SubversionPluginPrivate::managesDirectory(const FilePath &directory, FilePa const QStringList filesToCheck = transform(m_svnDirectories, [](const QString &s) { return QString(s + "/wc.db"); }); - const FilePath topLevelFound = VcsBase::findRepositoryForFile(directory, filesToCheck); + const FilePath topLevelFound = VcsManager::findRepositoryForFiles(directory, filesToCheck); if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index e8b051377f2..1a8f33258e0 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -38,7 +38,6 @@ using namespace ProjectExplorer; namespace { static Q_LOGGING_CATEGORY(baseLog, "qtc.vcs.base", QtWarningMsg) -static Q_LOGGING_CATEGORY(findRepoLog, "qtc.vcs.find-repo", QtWarningMsg) static Q_LOGGING_CATEGORY(stateLog, "qtc.vcs.state", QtWarningMsg) } @@ -705,31 +704,6 @@ void VersionControlBase::discardCommit() { } -// Find top level for version controls like git/Mercurial that have -// a directory at the top of the repository. -// Note that checking for the existence of files is preferred over directories -// since checking for directories can cause them to be created when -// AutoFS is used (due its automatically creating mountpoints when querying -// a directory). In addition, bail out when reaching the home directory -// of the user or root (generally avoid '/', where mountpoints are created). -FilePath findRepositoryForFile(const FilePath &fileOrDir, const QStringList &checkFiles) -{ - const FilePath dirS = fileOrDir.isDir() ? fileOrDir : fileOrDir.parentDir(); - qCDebug(findRepoLog) << ">" << dirS << checkFiles; - QTC_ASSERT(!dirS.isEmpty(), return {}); - - FilePath parent; - for (FilePath dir = dirS; !dir.isEmpty() && !dir.isRootPath(); dir = dir.parentDir()) { - for (const QString &checkFile : checkFiles) { - if (dir.pathAppended(checkFile).isFile()) { - qCDebug(findRepoLog) << "<" << dir.toUserOutput(); - return dir; - } - } - } - return {}; -} - static const char SOURCE_PROPERTY[] = "qtcreator_source"; void setSource(IDocument *document, const FilePath &source) diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h index 7d7f38b0e56..3505f41d160 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.h +++ b/src/plugins/vcsbase/vcsbaseplugin.h @@ -94,13 +94,6 @@ private: QSharedDataPointer data; }; -// Convenience that searches for the repository specifically for version control -// systems that do not have directories like "CVS" in each managed subdirectory -// but have a directory at the top of the repository like ".git" containing -// a well known file. See implementation for gory details. -VCSBASE_EXPORT Utils::FilePath findRepositoryForFile( - const Utils::FilePath &fileOrDir, const QStringList &checkFiles); - // Set up the environment for a version control command line call. // Sets up SSH graphical password prompting (note that the latter // requires a terminal-less process) and sets LANG to 'C' to force English From 704642a552d14a7aa7fdf71cec19341668e73455 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 25 Nov 2024 16:40:45 +0100 Subject: [PATCH 302/989] QtSupport: Do not warn if there is no QML utility That's only relevant for .qmlproject Projects, and the QmlProjectManager has its own checks and warnings for that. Also inline the few remaining short functions in DesktopQtVersion. Fixes: QTCREATORBUG-32052 Change-Id: I7617dfae7becf11fca6ca85a09056317b6bca243 Reviewed-by: Christian Stenger --- src/plugins/qtsupport/qtversions.cpp | 57 ++++++++++------------------ 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/src/plugins/qtsupport/qtversions.cpp b/src/plugins/qtsupport/qtversions.cpp index 03a841ff563..f38dc48dba1 100644 --- a/src/plugins/qtsupport/qtversions.cpp +++ b/src/plugins/qtsupport/qtversions.cpp @@ -24,46 +24,29 @@ namespace QtSupport::Internal { class DesktopQtVersion final : public QtVersion { public: - DesktopQtVersion() = default; - - QStringList warningReason() const final; - - QString description() const final; - - QSet availableFeatures() const final; - QSet targetDeviceTypes() const final; -}; - -QStringList DesktopQtVersion::warningReason() const -{ - QStringList ret = QtVersion::warningReason(); - if (qtVersion() >= QVersionNumber(5, 0, 0)) { - if (qmlRuntimeFilePath().isEmpty()) - ret << Tr::tr("No QML utility installed."); + QString description() const final + { + return Tr::tr("Desktop", "Qt Version is meant for the desktop"); } - return ret; -} -QString DesktopQtVersion::description() const -{ - return Tr::tr("Desktop", "Qt Version is meant for the desktop"); -} + QSet availableFeatures() const final + { + QSet features = QtVersion::availableFeatures(); + features.insert(Constants::FEATURE_DESKTOP); + features.insert(Constants::FEATURE_QMLPROJECT); + return features; + } -QSet DesktopQtVersion::availableFeatures() const -{ - QSet features = QtVersion::availableFeatures(); - features.insert(Constants::FEATURE_DESKTOP); - features.insert(Constants::FEATURE_QMLPROJECT); - return features; -} - -QSet DesktopQtVersion::targetDeviceTypes() const -{ - QSet result = {ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE}; - if (Utils::contains(qtAbis(), [](const ProjectExplorer::Abi a) { return a.os() == ProjectExplorer::Abi::LinuxOS; })) - result.insert(RemoteLinux::Constants::GenericLinuxOsType); - return result; -} + QSet targetDeviceTypes() const final + { + QSet result = {ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE}; + if (Utils::contains(qtAbis(), [](const ProjectExplorer::Abi a) { + return a.os() == ProjectExplorer::Abi::LinuxOS; + })) + result.insert(RemoteLinux::Constants::GenericLinuxOsType); + return result; + } +}; // Factory From c3377b369e96d18b22ec56f11f6859d2cedd3815 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 11:15:33 +0100 Subject: [PATCH 303/989] Core: Simplify ExecuteFilter output handling Re-use the decoding capabilities of Utils::Process. Change-Id: I89959f8c58f4ed5a7dc66e0a6f91ce0650187761 Reviewed-by: Eike Ziller Reviewed-by: Orgad Shaneh --- src/plugins/coreplugin/locator/executefilter.cpp | 10 ++++------ src/plugins/coreplugin/locator/executefilter.h | 3 --- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 5feeae26592..863ed8834dd 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -17,6 +17,7 @@ #include #include #include +#include using namespace Tasking; using namespace Utils; @@ -123,17 +124,13 @@ void ExecuteFilter::done() void ExecuteFilter::readStdOutput() { QTC_ASSERT(m_process, return); - const QByteArray data = m_process->readAllRawStandardOutput(); - MessageManager::writeSilently( - QTextCodec::codecForLocale()->toUnicode(data.constData(), data.size(), &m_stdoutState)); + MessageManager::writeSilently(m_process->readAllStandardOutput()); } void ExecuteFilter::readStdError() { QTC_ASSERT(m_process, return); - const QByteArray data = m_process->readAllRawStandardError(); - MessageManager::writeSilently( - QTextCodec::codecForLocale()->toUnicode(data.constData(), data.size(), &m_stderrState)); + MessageManager::writeSilently(m_process->readAllStandardError()); } void ExecuteFilter::runHeadCommand() @@ -163,6 +160,7 @@ void ExecuteFilter::createProcess() m_process = new Process; m_process->setEnvironment(Environment::systemEnvironment()); + m_process->setCodec(QTextCodec::codecForLocale()); connect(m_process, &Process::done, this, &ExecuteFilter::done); connect(m_process, &Process::readyReadStandardOutput, this, &ExecuteFilter::readStdOutput); connect(m_process, &Process::readyReadStandardError, this, &ExecuteFilter::readStdError); diff --git a/src/plugins/coreplugin/locator/executefilter.h b/src/plugins/coreplugin/locator/executefilter.h index 2e51d320d3c..f21f6500369 100644 --- a/src/plugins/coreplugin/locator/executefilter.h +++ b/src/plugins/coreplugin/locator/executefilter.h @@ -8,7 +8,6 @@ #include #include -#include namespace Utils { class Process; } @@ -45,8 +44,6 @@ private: QList m_taskQueue; QStringList m_commandHistory; Utils::Process *m_process = nullptr; - QTextCodec::ConverterState m_stdoutState; - QTextCodec::ConverterState m_stderrState; }; } // namespace Core::Internal From 5bce480170bebd79d941af2cc48a0b300c8bbd9b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 28 Nov 2024 16:41:14 +0100 Subject: [PATCH 304/989] ExtensionSystem: Centralize registering MIME types Instead of letting all places that nowadays load plugins handle MIME type registration themselves, just add that to the plugin loading functions in PluginManager directly. Change-Id: Ice5f102632b255b89d82cb57891ae5d8a75989c5 Reviewed-by: Marcus Tillmanns --- src/libs/extensionsystem/pluginmanager.cpp | 17 +++++++++++++++++ src/plugins/coreplugin/coreplugin.cpp | 15 --------------- src/plugins/coreplugin/coreplugin.h | 2 -- src/plugins/coreplugin/plugindialog.cpp | 2 -- .../extensionmanager/extensionmanagerwidget.cpp | 12 ------------ 5 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index a9ee6d60cf2..ab47f228b9b 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -232,6 +233,15 @@ enum { debugLeaks = 0 }; using namespace Utils; +static void registerMimeFromPlugin(const ExtensionSystem::PluginSpec *plugin) +{ + const QJsonObject metaData = plugin->metaData(); + const QJsonValue mimetypes = metaData.value("Mimetypes"); + QString mimetypeString; + if (Utils::readMultiLineString(mimetypes, &mimetypeString)) + Utils::addMimeTypes(plugin->id() + ".mimetypes", mimetypeString.trimmed().toUtf8()); +} + namespace ExtensionSystem { using namespace Internal; @@ -1420,6 +1430,11 @@ void PluginManagerPrivate::loadPlugins() } Utils::setMimeStartupPhase(MimeStartupPhase::PluginsInitializing); + { + NANOTRACE_SCOPE("ExtensionSystem", "RegisterMimeTypes"); + for (PluginSpec *spec : queue) + registerMimeFromPlugin(spec); + } { NANOTRACE_SCOPE("ExtensionSystem", "Initialize"); for (PluginSpec *spec : queue) @@ -1480,6 +1495,8 @@ void PluginManagerPrivate::loadPluginsAtRuntime(const QSet &plugin std::queue localDelayedInitializeQueue; for (PluginSpec *spec : queue) loadPlugin(spec, PluginSpec::Loaded); + for (PluginSpec *spec : queue) + registerMimeFromPlugin(spec); for (PluginSpec *spec : queue) loadPlugin(spec, PluginSpec::Initialized); Utils::reverseForeach(queue, diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 68b8ed4bd0b..899eb5465bc 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -134,15 +134,6 @@ CoreArguments parseArguments(const QStringList &arguments) return args; } -void CorePlugin::loadMimeFromPlugin(const ExtensionSystem::PluginSpec *plugin) -{ - const QJsonObject metaData = plugin->metaData(); - const QJsonValue mimetypes = metaData.value("Mimetypes"); - QString mimetypeString; - if (Utils::readMultiLineString(mimetypes, &mimetypeString)) - Utils::addMimeTypes(plugin->id() + ".mimetypes", mimetypeString.trimmed().toUtf8()); -} - static void initProxyAuthDialog() { QObject::connect(Utils::NetworkAccessManager::instance(), @@ -241,12 +232,6 @@ static void addToPathChooserContextMenu(PathChooser *pathChooser, QMenu *menu) bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) { - // register all mime types from all plugins - for (ExtensionSystem::PluginSpec *plugin : ExtensionSystem::PluginManager::plugins()) { - if (!plugin->isEffectivelyEnabled()) - continue; - loadMimeFromPlugin(plugin); - } initTAndCAcceptDialog(); initProxyAuthDialog(); diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index 73cf441df1d..0499576fa86 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -40,8 +40,6 @@ public: static QString msgCrashpadInformation(); - static void loadMimeFromPlugin(const ExtensionSystem::PluginSpec *plugin); - public slots: void fileOpenRequest(const QString &); diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp index c51389c0292..bd1bc5c2f20 100644 --- a/src/plugins/coreplugin/plugindialog.cpp +++ b/src/plugins/coreplugin/plugindialog.cpp @@ -108,8 +108,6 @@ void PluginDialog::closeDialog() PluginManager::writeSettings(); PluginManager::loadPluginsAtRuntime(m_softLoad); - for (PluginSpec *plugin : std::as_const(m_softLoad)) - CorePlugin::loadMimeFromPlugin(plugin); if (m_isRestartRequired) ICore::askForRestart(Tr::tr("Plugin changes will take effect after restart.")); diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index 2f2fa4131ca..bd751148ee4 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -248,17 +248,6 @@ private: const char kRestartSetting[] = "RestartAfterPluginEnabledChanged"; -// Copy paste from Core::Internal::CorePlugin::loadMimeFromPlugin -// TODO make code usable by other plugins. -static void loadMimeFromPlugin(const ExtensionSystem::PluginSpec *plugin) -{ - const QJsonObject metaData = plugin->metaData(); - const QJsonValue mimetypes = metaData.value("Mimetypes"); - QString mimetypeString; - if (Utils::readMultiLineString(mimetypes, &mimetypeString)) - Utils::addMimeTypes(plugin->name() + ".mimetypes", mimetypeString.trimmed().toUtf8()); -} - class PluginStatusWidget : public QWidget { public: @@ -284,7 +273,6 @@ public: if (doIt) { if (checked && spec->isEffectivelySoftloadable()) { ExtensionSystem::PluginManager::loadPluginsAtRuntime({spec}); - loadMimeFromPlugin(spec); } else if (ICore::infoBar()->canInfoBeAdded(kRestartSetting)) { Utils::InfoBarEntry info( kRestartSetting, From 171556de2c2a27636c08b76264ea400f0e970fdf Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 29 Nov 2024 08:48:27 +0100 Subject: [PATCH 305/989] ExtensionSystem: Share function that asks about plugins & dependencies Move functionality that collects the dependencies of a set of plugins and asks the user if they want to enable/disable them to a function that can be used at multiple places. So far this was limited to the plugin view. Change-Id: I7a5f26b37963eaa7b95e621ccb16291a5a8b9ba3 Reviewed-by: Marcus Tillmanns --- src/libs/extensionsystem/pluginmanager.cpp | 62 ++++++++++++++++++++++ src/libs/extensionsystem/pluginmanager.h | 4 ++ src/libs/extensionsystem/pluginview.cpp | 49 ++--------------- 3 files changed, 71 insertions(+), 44 deletions(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index ab47f228b9b..38d1a01f288 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -1710,6 +1710,68 @@ PluginSpec *PluginManager::specForPlugin(IPlugin *plugin) return findOrDefault(d->pluginSpecs, equal(&PluginSpec::plugin, plugin)); } +static QString pluginListString(const QSet &plugins) +{ + QStringList names = Utils::transform(plugins, &PluginSpec::name); + names.sort(); + return names.join(QLatin1Char('\n')); +} + +/*! + Collects the dependencies of the \a plugins and asks the user if the + corresponding plugins should be enabled or disabled (dependening on \a enable). + + Returns a (possibly) empty set of additional plugins that should be enabled or disabled + respectively. Returns \c{std::nullopt} if the user canceled. + */ +std::optional> PluginManager::askForEnablingPlugins( + QWidget *dialogParent, const QSet &plugins, bool enable) +{ + QSet additionalPlugins; + if (enable) { + for (PluginSpec *spec : plugins) { + for (PluginSpec *other : PluginManager::pluginsRequiredByPlugin(spec)) { + if (!other->isEnabledBySettings()) + additionalPlugins.insert(other); + } + } + additionalPlugins.subtract(plugins); + if (!additionalPlugins.isEmpty()) { + if (QMessageBox::question( + dialogParent, + Tr::tr("Enabling Plugins"), + Tr::tr("Enabling\n%1\nwill also enable the following plugins:\n\n%2") + .arg(pluginListString(plugins), pluginListString(additionalPlugins)), + QMessageBox::Ok | QMessageBox::Cancel, + QMessageBox::Ok) + != QMessageBox::Ok) { + return {}; + } + } + } else { + for (PluginSpec *spec : plugins) { + for (PluginSpec *other : PluginManager::pluginsRequiringPlugin(spec)) { + if (other->isEnabledBySettings()) + additionalPlugins.insert(other); + } + } + additionalPlugins.subtract(plugins); + if (!additionalPlugins.isEmpty()) { + if (QMessageBox::question( + dialogParent, + Tr::tr("Disabling Plugins"), + Tr::tr("Disabling\n%1\nwill also disable the following plugins:\n\n%2") + .arg(pluginListString(plugins), pluginListString(additionalPlugins)), + QMessageBox::Ok | QMessageBox::Cancel, + QMessageBox::Ok) + != QMessageBox::Ok) { + return {}; + } + } + } + return additionalPlugins; +} + bool PluginManagerPrivate::acceptTermsAndConditions(PluginSpec *spec) { if (pluginsWithAcceptedTermsAndConditions.contains(spec->id())) diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h index 6dee40b2a3d..74141d157b5 100644 --- a/src/libs/extensionsystem/pluginmanager.h +++ b/src/libs/extensionsystem/pluginmanager.h @@ -83,6 +83,10 @@ public: static void addPlugins(const QVector &specs); + // UI + static std::optional> askForEnablingPlugins( + QWidget *dialogParent, const QSet &plugins, bool enable); + // Settings static void setSettings(Utils::QtcSettings *settings); static Utils::QtcSettings *settings(); diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp index 9aa8f5f7d0f..b2d0e27ee0e 100644 --- a/src/libs/extensionsystem/pluginview.cpp +++ b/src/libs/extensionsystem/pluginview.cpp @@ -380,53 +380,14 @@ PluginData &PluginView::data() return m_data; } -static QString pluginListString(const QSet &plugins) -{ - QStringList names = Utils::transform(plugins, &PluginSpec::name); - names.sort(); - return names.join(QLatin1Char('\n')); -} - bool PluginData::setPluginsEnabled(const QSet &plugins, bool enable) { - QSet additionalPlugins; - if (enable) { - for (PluginSpec *spec : plugins) { - for (PluginSpec *other : PluginManager::pluginsRequiredByPlugin(spec)) { - if (!other->isEnabledBySettings()) - additionalPlugins.insert(other); - } - } - additionalPlugins.subtract(plugins); - if (!additionalPlugins.isEmpty()) { - if (QMessageBox::question(m_parent, Tr::tr("Enabling Plugins"), - Tr::tr("Enabling\n%1\nwill also enable the following plugins:\n\n%2") - .arg(pluginListString(plugins), pluginListString(additionalPlugins)), - QMessageBox::Ok | QMessageBox::Cancel, - QMessageBox::Ok) != QMessageBox::Ok) { - return false; - } - } - } else { - for (PluginSpec *spec : plugins) { - for (PluginSpec *other : PluginManager::pluginsRequiringPlugin(spec)) { - if (other->isEnabledBySettings()) - additionalPlugins.insert(other); - } - } - additionalPlugins.subtract(plugins); - if (!additionalPlugins.isEmpty()) { - if (QMessageBox::question(m_parent, Tr::tr("Disabling Plugins"), - Tr::tr("Disabling\n%1\nwill also disable the following plugins:\n\n%2") - .arg(pluginListString(plugins), pluginListString(additionalPlugins)), - QMessageBox::Ok | QMessageBox::Cancel, - QMessageBox::Ok) != QMessageBox::Ok) { - return false; - } - } - } + std::optional> additionalPlugins + = PluginManager::askForEnablingPlugins(m_parent, plugins, enable); + if (!additionalPlugins) // canceled + return false; - const QSet affectedPlugins = plugins + additionalPlugins; + const QSet affectedPlugins = plugins + *additionalPlugins; for (PluginSpec *spec : affectedPlugins) { PluginItem *item = m_model->findItemAtLevel<2>([spec](PluginItem *item) { return item->m_spec == spec; From 3fa47aa96b3d5ca755a4eebb7e5564fc1f668ed8 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 29 Nov 2024 09:31:19 +0100 Subject: [PATCH 306/989] ExtensionSystem: Use display name in plugin details Change-Id: I8e80b1e53025f439933c78add1f502179b2b2d49 Reviewed-by: Marcus Tillmanns --- src/libs/extensionsystem/plugindetailsview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/extensionsystem/plugindetailsview.cpp b/src/libs/extensionsystem/plugindetailsview.cpp index 9647939e219..eba1058dcbe 100644 --- a/src/libs/extensionsystem/plugindetailsview.cpp +++ b/src/libs/extensionsystem/plugindetailsview.cpp @@ -147,7 +147,7 @@ PluginDetailsView::~PluginDetailsView() void PluginDetailsView::update(PluginSpec *spec) { d->id->setText(spec->id()); - d->name->setText(spec->name()); + d->name->setText(spec->displayName()); const QString revision = spec->revision(); const QString versionString = spec->version() + (revision.isEmpty() ? QString() : " (" + revision + ")"); @@ -185,7 +185,7 @@ void PluginDetailsView::showModal(QWidget *parent, PluginSpec *spec) auto dialog = new QDialog(parent); dialog->setModal(true); dialog->setAttribute(Qt::WA_DeleteOnClose); - dialog->setWindowTitle(Tr::tr("Plugin Details of %1").arg(spec->name())); + dialog->setWindowTitle(Tr::tr("Plugin Details of %1").arg(spec->displayName())); auto details = new ExtensionSystem::PluginDetailsView(dialog); details->update(spec); QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, From 442f538e7aa18ab954b4c5bb0457067fd97aa881 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 12:00:54 +0100 Subject: [PATCH 307/989] iOS: Use decoding capability of Utils::Process for tail output Change-Id: Ic167013f21b1ed1b45a307f63431cf5192c3c586 Reviewed-by: Eike Ziller --- src/plugins/ios/iostoolhandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index 88a6aa022f8..5174dcef299 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -68,9 +68,9 @@ public: auto logProcess = [&](Process *tailProcess, std::shared_ptr file) { QObject::connect(tailProcess, &Process::readyReadStandardOutput, &loop, [&, tailProcess] { if (!promise.isCanceled()) - emit logMessage(QString::fromLocal8Bit(tailProcess->readAllRawStandardOutput())); + emit logMessage(tailProcess->readAllStandardOutput()); }); - tailProcess->setCommand({FilePath::fromString("tail"), {"-f", file->fileName()}}); + tailProcess->setCommand({"tail", {"-f", file->fileName()}}); tailProcess->start(); }; From 96bea15fa0b12341eca919bf32955bfae8d215df Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Sat, 30 Nov 2024 22:40:45 +0100 Subject: [PATCH 308/989] Git: Allow showing current branch log in submit editor Change-Id: Iee88fc7e30088a3feb11d20d690ecc3a9402ced3 Reviewed-by: Orgad Shaneh --- src/plugins/git/gitsubmiteditor.cpp | 7 +++++++ src/plugins/git/gitsubmiteditor.h | 1 + src/plugins/git/gitsubmiteditorwidget.cpp | 12 +++++++++--- src/plugins/git/gitsubmiteditorwidget.h | 2 ++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index 78d51edad84..7fa77eb0883 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -83,6 +83,7 @@ GitSubmitEditor::GitSubmitEditor() : { connect(this, &VcsBaseSubmitEditor::diffSelectedRows, this, &GitSubmitEditor::slotDiffSelected); connect(submitEditorWidget(), &GitSubmitEditorWidget::showRequested, this, &GitSubmitEditor::showCommit); + connect(submitEditorWidget(), &GitSubmitEditorWidget::logRequested, this, &GitSubmitEditor::showLog); connect(versionControl(), &Core::IVersionControl::repositoryChanged, this, &GitSubmitEditor::forceUpdateFileModel); connect(&m_fetchWatcher, &QFutureWatcher::finished, @@ -191,6 +192,12 @@ void GitSubmitEditor::showCommit(const QString &commit) gitClient().show(m_workingDirectory, commit); } +void GitSubmitEditor::showLog(const QStringList &range) +{ + if (!m_workingDirectory.isEmpty()) + gitClient().log(m_workingDirectory, {}, false, range); +} + void GitSubmitEditor::updateFileModel() { // Commit data is set when the editor is initialized, and updateFileModel immediately follows, diff --git a/src/plugins/git/gitsubmiteditor.h b/src/plugins/git/gitsubmiteditor.h index 4c7c2e0161f..a25269a06a8 100644 --- a/src/plugins/git/gitsubmiteditor.h +++ b/src/plugins/git/gitsubmiteditor.h @@ -50,6 +50,7 @@ protected: private: void slotDiffSelected(const QList &rows); void showCommit(const QString &commit); + void showLog(const QStringList &range); void commitDataRetrieved(); inline GitSubmitEditorWidget *submitEditorWidget(); diff --git a/src/plugins/git/gitsubmiteditorwidget.cpp b/src/plugins/git/gitsubmiteditorwidget.cpp index d381a8284da..885dec4663a 100644 --- a/src/plugins/git/gitsubmiteditorwidget.cpp +++ b/src/plugins/git/gitsubmiteditorwidget.cpp @@ -114,18 +114,24 @@ GitSubmitEditorWidget::GitSubmitEditorWidget() : this, &GitSubmitEditorWidget::authorInformationChanged); connect(m_gitSubmitPanel->showHeadLabel, &QLabel::linkActivated, this, [this] { emit showRequested("HEAD"); }); + connect(m_gitSubmitPanel->branchLabel, &QLabel::linkActivated, + this, [this] { emit logRequested(m_range); }); } void GitSubmitEditorWidget::setPanelInfo(const GitSubmitEditorPanelInfo &info) { m_gitSubmitPanel->repositoryLabel->setText(info.repository.toUserOutput()); + QString label; if (info.branch.contains("(no branch)")) { const QString errorColor = Utils::creatorColor(Utils::Theme::TextColorError).name(); - m_gitSubmitPanel->branchLabel->setText(QString::fromLatin1("%2") - .arg(errorColor, Tr::tr("Detached HEAD"))); + m_range = {"HEAD", "--not", "--remotes"}; + label = QString("
    %2") + .arg(errorColor, Tr::tr("Detached HEAD")); } else { - m_gitSubmitPanel->branchLabel->setText(info.branch); + m_range = {info.branch.split(' ').first()}; // split removes "[ahead 3]" + label = "" + info.branch + " "; } + m_gitSubmitPanel->branchLabel->setText(label); } QString GitSubmitEditorWidget::amendHash() const diff --git a/src/plugins/git/gitsubmiteditorwidget.h b/src/plugins/git/gitsubmiteditorwidget.h index 0b8f07c9857..6d788e3a98e 100644 --- a/src/plugins/git/gitsubmiteditorwidget.h +++ b/src/plugins/git/gitsubmiteditorwidget.h @@ -51,6 +51,7 @@ protected: signals: void showRequested(const QString &commit); + void logRequested(const QStringList &range); private: void authorInformationChanged(); @@ -69,6 +70,7 @@ private: QValidator *m_emailValidator; QString m_originalAuthor; QString m_originalEmail; + QStringList m_range; bool m_hasUnmerged = false; bool m_isInitialized = false; }; From b748f52e995e4bfac61320995446426c20410dc6 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 19 Nov 2024 14:28:08 +0100 Subject: [PATCH 309/989] Help to distinguish meaning of None Task-number: QTCREATORBUG-31978 Change-Id: I5c250905406b933014b3b7a90630a147697b485c Reviewed-by: Eike Ziller --- src/plugins/autotest/projectsettingswidget.cpp | 2 +- src/plugins/autotest/testsettings.cpp | 2 +- src/plugins/axivion/axivionperspective.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/autotest/projectsettingswidget.cpp b/src/plugins/autotest/projectsettingswidget.cpp index 01cbb33fd1d..9a14b40345d 100644 --- a/src/plugins/autotest/projectsettingswidget.cpp +++ b/src/plugins/autotest/projectsettingswidget.cpp @@ -61,7 +61,7 @@ ProjectTestSettingsWidget::ProjectTestSettingsWidget(Project *project) m_activeFrameworks->setHeaderHidden(true); m_activeFrameworks->setRootIsDecorated(false); m_runAfterBuild = new QComboBox; - m_runAfterBuild->addItem(Tr::tr("None")); + m_runAfterBuild->addItem(Tr::tr("No Tests")); m_runAfterBuild->addItem(Tr::tr("All")); m_runAfterBuild->addItem(Tr::tr("Selected")); m_runAfterBuild->setCurrentIndex(int(m_projectSettings->runAfterBuild())); diff --git a/src/plugins/autotest/testsettings.cpp b/src/plugins/autotest/testsettings.cpp index 523a92499aa..af1767e4283 100644 --- a/src/plugins/autotest/testsettings.cpp +++ b/src/plugins/autotest/testsettings.cpp @@ -106,7 +106,7 @@ TestSettings::TestSettings() runAfterBuild.setSettingsKey("RunAfterBuild"); runAfterBuild.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox); runAfterBuild.setToolTip(Tr::tr("Runs chosen tests automatically if a build succeeded.")); - runAfterBuild.addOption(Tr::tr("None")); + runAfterBuild.addOption(Tr::tr("No Tests")); runAfterBuild.addOption(Tr::tr("All")); runAfterBuild.addOption(Tr::tr("Selected")); diff --git a/src/plugins/axivion/axivionperspective.cpp b/src/plugins/axivion/axivionperspective.cpp index 834c3a589c1..7d1f6476b66 100644 --- a/src/plugins/axivion/axivionperspective.cpp +++ b/src/plugins/axivion/axivionperspective.cpp @@ -449,7 +449,7 @@ void IssuesWidget::initDashboardList(const QString &preferredProject) hideOverlays(); GuardLocker lock(m_signalBlocker); - m_dashboards->addItem(Tr::tr("None")); + m_dashboards->addItem(Tr::tr("No Dashboard")); for (const AxivionServer &server : servers) m_dashboards->addItem(server.displayString(), QVariant::fromValue(server)); From e9dfde366cb99ceec52b170780d5e846a0498b0a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 22 Nov 2024 17:02:47 +0100 Subject: [PATCH 310/989] Axivion: Remove unused recipe Change-Id: I882bcd79d21cf0f78d2f087bc55327e227ffbf98 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionplugin.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 3befa77c520..1200b672876 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -372,7 +372,6 @@ static QUrl constructUrl(const QString &projectName, const QString &subPath, con static constexpr int httpStatusCodeOk = 200; constexpr char s_htmlContentType[] = "text/html"; -constexpr char s_plaintextContentType[] = "text/plain"; constexpr char s_jsonContentType[] = "application/json"; static bool isServerAccessEstablished() @@ -425,11 +424,6 @@ static Group fetchHtmlRecipe(const QUrl &url, const std::function &handler) -{ - return fetchSimpleRecipe(url, s_plaintextContentType, handler); -} - template typename DtoStorageType> static Group dtoRecipe(const Storage> &dtoStorage) { @@ -862,18 +856,6 @@ Group lineMarkerRecipe(const FilePath &filePath, const LineMarkerHandler &handle return fetchDataRecipe(url, handler); } -Group fileSourceRecipe(const FilePath &filePath, const std::function &handler) -{ - QTC_ASSERT(dd->m_currentProjectInfo, return {}); // TODO: Call handler with unexpected - QTC_ASSERT(!filePath.isEmpty(), return {}); // TODO: Call handler with unexpected - QTC_ASSERT(dd->m_analysisVersion, return {}); // TODO: Call handler with unexpected - - const QString fileName = QString::fromUtf8(QUrl::toPercentEncoding(filePath.path())); - const QUrlQuery query({{"filename", fileName}, {"version", *dd->m_analysisVersion}}); - const QUrl url = constructUrl(dd->m_currentProjectInfo->name, "sourcecode", query); - return fetchPlainTextRecipe(url, handler); -} - Group issueHtmlRecipe(const QString &issueId, const HtmlHandler &handler) { QTC_ASSERT(dd->m_currentProjectInfo, return {}); // TODO: Call handler with unexpected? From 8d06048ec0e0fe77bec4cf091aacbb1806bac671 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 22 Nov 2024 16:12:00 +0100 Subject: [PATCH 311/989] Axivion: Expose downloadDataRecipe Use DownloadData storage for input-output communication. Change-Id: I67e94884a53e959ed74edcf5c22a27a60b5a7757 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionplugin.cpp | 53 +++++++++++++++++++++------ src/plugins/axivion/axivionplugin.h | 22 ++++++++++- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 1200b672876..39811e93229 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -372,6 +372,8 @@ static QUrl constructUrl(const QString &projectName, const QString &subPath, con static constexpr int httpStatusCodeOk = 200; constexpr char s_htmlContentType[] = "text/html"; +constexpr char s_plaintextContentType[] = "text/plain"; +constexpr char s_svgContentType[] = "image/svg+xml"; constexpr char s_jsonContentType[] = "application/json"; static bool isServerAccessEstablished() @@ -380,17 +382,24 @@ static bool isServerAccessEstablished() || (dd->m_serverAccess == ServerAccess::WithAuthorization && dd->m_apiToken); } -static Group fetchSimpleRecipe(const QUrl &url, - const QByteArray &expectedContentType, - const std::function &handler) +static QByteArray contentTypeData(ContentType contentType) { - // TODO: Refactor so that it's a common code with fetchDataRecipe(). - const auto onQuerySetup = [url, expectedContentType](NetworkQuery &query) { + switch (contentType) { + case ContentType::Html: return s_htmlContentType; + case ContentType::PlainText: return s_plaintextContentType; + case ContentType::Svg: return s_svgContentType; + } + return {}; +} + +Group downloadDataRecipe(const Storage &storage) +{ + const auto onQuerySetup = [storage](NetworkQuery &query) { if (!isServerAccessEstablished()) return SetupResult::StopWithError; // TODO: start authorizationRecipe()? - QNetworkRequest request(url); - request.setRawHeader("Accept", expectedContentType); + QNetworkRequest request(storage->inputUrl); + request.setRawHeader("Accept", contentTypeData(storage->expectedContentType)); if (dd->m_serverAccess == ServerAccess::WithAuthorization && dd->m_apiToken) request.setRawHeader("Authorization", "AxToken " + *dd->m_apiToken); const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + @@ -400,7 +409,7 @@ static Group fetchSimpleRecipe(const QUrl &url, query.setNetworkAccessManager(&dd->m_networkAccessManager); return SetupResult::Continue; }; - const auto onQueryDone = [url, expectedContentType, handler](const NetworkQuery &query, DoneWith doneWith) { + const auto onQueryDone = [storage](const NetworkQuery &query, DoneWith doneWith) { QNetworkReply *reply = query.reply(); const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); const QString contentType = reply->header(QNetworkRequest::ContentTypeHeader) @@ -410,8 +419,8 @@ static Group fetchSimpleRecipe(const QUrl &url, .trimmed() .toLower(); if (doneWith == DoneWith::Success && statusCode == httpStatusCodeOk - && contentType == QString::fromUtf8(expectedContentType)) { - handler(reply->readAll()); + && contentType == QString::fromUtf8(contentTypeData(storage->expectedContentType))) { + storage->outputData = reply->readAll(); return DoneResult::Success; } return DoneResult::Error; @@ -419,9 +428,31 @@ static Group fetchSimpleRecipe(const QUrl &url, return {NetworkQueryTask(onQuerySetup, onQueryDone)}; } +static Group fetchSimpleRecipe(const QUrl &url, ContentType expectedContentType, + const std::function &handler) +{ + const Storage storage; + + const auto onSetup = [storage, url, expectedContentType] { + storage->inputUrl = url; + storage->expectedContentType = expectedContentType; + }; + + const auto onDone = [storage, handler] { + handler(storage->outputData); + }; + + return { + storage, + onGroupSetup(onSetup), + downloadDataRecipe(storage), + onGroupDone(onDone, CallDoneIf::Success) + }; +} + static Group fetchHtmlRecipe(const QUrl &url, const std::function &handler) { - return fetchSimpleRecipe(url, s_htmlContentType, handler); + return fetchSimpleRecipe(url, ContentType::Html, handler); } template typename DtoStorageType> diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index a3f26652fb7..8d6d2a14de7 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -19,7 +19,11 @@ QT_END_NAMESPACE namespace ProjectExplorer { class Project; } -namespace Tasking { class Group; } +namespace Tasking { +class Group; +template +class Storage; +} namespace Utils { class FilePath; } @@ -60,6 +64,22 @@ public: std::optional checkCredentialsUrl; }; +enum class ContentType { + Html, + PlainText, + Svg +}; + +class DownloadData +{ +public: + QUrl inputUrl; + ContentType expectedContentType = ContentType::Html; + QByteArray outputData; +}; + +Tasking::Group downloadDataRecipe(const Tasking::Storage &storage); + using DashboardInfoHandler = std::function &)>; Tasking::Group dashboardInfoRecipe(const DashboardInfoHandler &handler = {}); From e8c38becdd1e591e522960eb1cd0ca7ecc89e28e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 22 Nov 2024 17:15:09 +0100 Subject: [PATCH 312/989] Axivion: Refactor fetchIssueInfo() Remove issueHtmlRecipe(), fetchHtmlRecipe() and fetchSimpleRecipe(). Reuse downloadDataRecipe(). Change-Id: Ib68c56be4fa8fb86558b271934ee7785e8105aa6 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionplugin.cpp | 65 ++++++++------------------- src/plugins/axivion/axivionplugin.h | 3 -- 2 files changed, 19 insertions(+), 49 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 39811e93229..dd1c84abd0b 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -428,33 +428,6 @@ Group downloadDataRecipe(const Storage &storage) return {NetworkQueryTask(onQuerySetup, onQueryDone)}; } -static Group fetchSimpleRecipe(const QUrl &url, ContentType expectedContentType, - const std::function &handler) -{ - const Storage storage; - - const auto onSetup = [storage, url, expectedContentType] { - storage->inputUrl = url; - storage->expectedContentType = expectedContentType; - }; - - const auto onDone = [storage, handler] { - handler(storage->outputData); - }; - - return { - storage, - onGroupSetup(onSetup), - downloadDataRecipe(storage), - onGroupDone(onDone, CallDoneIf::Success) - }; -} - -static Group fetchHtmlRecipe(const QUrl &url, const std::function &handler) -{ - return fetchSimpleRecipe(url, ContentType::Html, handler); -} - template typename DtoStorageType> static Group dtoRecipe(const Storage> &dtoStorage) { @@ -887,18 +860,6 @@ Group lineMarkerRecipe(const FilePath &filePath, const LineMarkerHandler &handle return fetchDataRecipe(url, handler); } -Group issueHtmlRecipe(const QString &issueId, const HtmlHandler &handler) -{ - QTC_ASSERT(dd->m_currentProjectInfo, return {}); // TODO: Call handler with unexpected? - QTC_ASSERT(dd->m_analysisVersion, return {}); // TODO: Call handler with unexpected? - - const QUrl url = constructUrl( - dd->m_currentProjectInfo->name, - QString("issues/" + issueId + "/properties/"), - {{"version", *dd->m_analysisVersion}}); - return fetchHtmlRecipe(url, handler); -} - void AxivionPluginPrivate::fetchDashboardAndProjectInfo(const DashboardInfoHandler &handler, const QString &projectName) { @@ -914,19 +875,31 @@ Group tableInfoRecipe(const QString &prefix, const TableInfoHandler &handler) void AxivionPluginPrivate::fetchIssueInfo(const QString &id) { - if (!m_currentProjectInfo) + if (!m_currentProjectInfo || !dd->m_analysisVersion) return; - const auto ruleHandler = [](const QByteArray &htmlText) { - QByteArray fixedHtml = htmlText; - const int idx = htmlText.indexOf("
    "); - if (idx >= 0) - fixedHtml = "" + htmlText.mid(idx); + const QUrl url = constructUrl(dd->m_currentProjectInfo->name, + QString("issues/" + id + "/properties/"), + {{"version", *dd->m_analysisVersion}}); + const Storage storage; + + const auto onSetup = [storage, url] { storage->inputUrl = url; }; + + const auto onDone = [storage] { + QByteArray fixedHtml = storage->outputData; + const int idx = fixedHtml.indexOf("
    "); + if (idx >= 0) + fixedHtml = "" + fixedHtml.mid(idx); updateIssueDetails(QString::fromUtf8(fixedHtml)); }; - m_issueInfoRunner.start(issueHtmlRecipe(id, ruleHandler)); + m_issueInfoRunner.start({ + storage, + onGroupSetup(onSetup), + downloadDataRecipe(storage), + onGroupDone(onDone, CallDoneIf::Success) + }); } void AxivionPluginPrivate::handleOpenedDocs() diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index 8d6d2a14de7..5d1ffd16d1a 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -97,9 +97,6 @@ Tasking::Group issueTableRecipe(const IssueListSearch &search, const IssueTableH using LineMarkerHandler = std::function; Tasking::Group lineMarkerRecipe(const Utils::FilePath &filePath, const LineMarkerHandler &handler); -using HtmlHandler = std::function; -Tasking::Group issueHtmlRecipe(const QString &issueId, const HtmlHandler &handler); - void fetchDashboardAndProjectInfo(const DashboardInfoHandler &handler, const QString &projectName); std::optional projectInfo(); bool handleCertificateIssue(); From 1bc42646ab6caebb4e5ed9fc6ef99d6bcc0d61d7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 22 Nov 2024 17:35:06 +0100 Subject: [PATCH 313/989] Axivion: Implement loading images for issue info view Multiple images are downloaded sequentially now. Later, if needed, we may try to refactor it so that it's done in parallel. Fixes: QTCREATORBUG-31791 Change-Id: Ic8716994746a7edbad72acaa165d36b59595ab95 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionperspective.cpp | 68 +++++++++++++++++++++- src/plugins/axivion/axivionplugin.cpp | 5 ++ src/plugins/axivion/axivionplugin.h | 2 + 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/plugins/axivion/axivionperspective.cpp b/src/plugins/axivion/axivionperspective.cpp index 7d1f6476b66..ffd1b19a42c 100644 --- a/src/plugins/axivion/axivionperspective.cpp +++ b/src/plugins/axivion/axivionperspective.cpp @@ -21,11 +21,13 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -881,6 +883,68 @@ void IssuesWidget::hideOverlays() m_stack->setCurrentIndex(0); } +static void loadImage(QPromise &promise, const QByteArray &data) +{ + promise.addResult(QImage::fromData(data)); +} + +class LazyImageBrowser : public QTextBrowser +{ +public: + QVariant loadResource(int type, const QUrl &name) override + { + if (type == QTextDocument::ImageResource) { + if (!m_loadingQueue.contains(name)) { + m_loadingQueue.append(name); + if (!m_loaderTaskTree.isRunning()) + m_loaderTaskTree.start(m_recipe); + } + return QImage(); + } + return QTextBrowser::loadResource(type, name); + } +private: + Group recipe() { + const LoopUntil iterator([this](int) { return !m_loadingQueue.isEmpty(); }); + + const Storage storage; + + const auto onSetup = [this, storage] { + storage->inputUrl = resolveDashboardInfoUrl(m_loadingQueue.first()); + storage->expectedContentType = ContentType::Svg; + }; + + const auto onImageLoadSetup = [storage](Async &async) { + async.setConcurrentCallData(&loadImage, storage->outputData); + }; + const auto onImageLoadDone = [this, storage](const Async &async) { + if (!document() || !async.isResultAvailable()) + return; + const QImage image = async.result(); + // FIXME use a self-implemented resource handler instead! + document()->addResource(QTextDocument::ImageResource, m_loadingQueue.first(), QVariant(image)); + document()->markContentsDirty(0, document()->characterCount()); + }; + + const auto onDone = [this] { m_loadingQueue.removeFirst(); }; + + return For (iterator) >> Do { + Group { + storage, + onGroupSetup(onSetup), + If (downloadDataRecipe(storage)) >> Then { + AsyncTask(onImageLoadSetup, onImageLoadDone, CallDoneIf::Success) || successItem + }, + onGroupDone(onDone) + } + }; + } + + const Group m_recipe = recipe(); + QList m_loadingQueue; + TaskTreeRunner m_loaderTaskTree; +}; + class AxivionPerspective : public Perspective { public: @@ -901,7 +965,7 @@ private: void openFilterHelp(); IssuesWidget *m_issuesWidget = nullptr; - QTextBrowser *m_issueDetails = nullptr; + LazyImageBrowser *m_issueDetails = nullptr; QAction *m_showFilterHelp = nullptr; }; @@ -914,7 +978,7 @@ void AxivionPerspective::initPerspective() pal.setColor(QPalette::Window, creatorColor(Theme::Color::BackgroundColorNormal)); m_issuesWidget->setPalette(pal); - m_issueDetails = new QTextBrowser; + m_issueDetails = new LazyImageBrowser; m_issueDetails->setFrameStyle(QFrame::NoFrame); m_issueDetails->setObjectName("AxivionIssuesDetails"); m_issueDetails->setWindowTitle(Tr::tr("Issue Details")); diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index dd1c84abd0b..d241ec56b0d 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -392,6 +392,11 @@ static QByteArray contentTypeData(ContentType contentType) return {}; } +QUrl resolveDashboardInfoUrl(const QUrl &resource) +{ + return dd->m_dashboardInfo->source.resolved(resource); +} + Group downloadDataRecipe(const Storage &storage) { const auto onQuerySetup = [storage](NetworkQuery &query) { diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index 5d1ffd16d1a..bc3c2128414 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -78,6 +78,8 @@ public: QByteArray outputData; }; +QUrl resolveDashboardInfoUrl(const QUrl &url); + Tasking::Group downloadDataRecipe(const Tasking::Storage &storage); using DashboardInfoHandler = std::function &)>; From 86a8f7df3ba24bdd9bbf47ce8ba7b4943cc9ec61 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 22 Nov 2024 11:42:56 +0100 Subject: [PATCH 314/989] Boot2Qt: Add a "manual test" Only a description how to set up a local Linux machine to allow creating Boot2Qt related runconfig and build steps. Change-Id: I1b8f45e9aaa743076a51ac8f81405586c0365086 Reviewed-by: Christian Stenger --- tests/manual/boot2qt/README.md | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/manual/boot2qt/README.md diff --git a/tests/manual/boot2qt/README.md b/tests/manual/boot2qt/README.md new file mode 100644 index 00000000000..b41810f4af2 --- /dev/null +++ b/tests/manual/boot2qt/README.md @@ -0,0 +1,72 @@ + + +### Testing Boot2Qt setup without hardware ### + +It is possible to test Boot2Qt without hardware on a plain Linux host system. + +Note: You need an ssh-accessible "root" user on the machine, open X access, +and must be willing to use it. This is not meant for production environments! + + +# Prepare your machine + +ssh-copy-id -i ~/.ssh/id_??????.pub root@localhost +xhost + + +# Get appcontroller source and build + +git clone ssh://codereview.qt-project.org/qt-apps/boot2qt-appcontroller + +cd boot2qt-appcontroller +/path/to/qt-base/bin/qt-cmake ... +ninja ... + +# Copy binary to "proper" location + +sudo ln -s `pwd`/appcontroller /usr/bin/appcontroller + + +# Set up "Boot to Qt" Device in Creator + +Ensure the "Boot to Qt" plugin is enabled + +Edit -> Preferences -> Devices, "Add...", "Boot to Qt Device", "Start Wizard" +Device Name: LocalHostForBoot2Qt +Device Address: 127.0.0.1 + +Press "Apply" + +# Create a suitable Kit + +Clone your standard kit for normal local work +Change the "Run Device" to LocalHostForBoot2Qt +Keep the "Build Device" at "Desktop Device" + +Press "Apply" + +The kit will have a warning the "Device type is not supported by Qt version" - that's ok. + +# Create a test project + +File -> New Project -> Qt Quick Application + +# Tweak project settings + +Deployment method: "Deploy to Boot to Qt Target" + +Run Command line arguments: Add "-display :0" +Run Environment: Add LD_LIBRARY_PATH=/path/to/qt-base/lib + +"Executable on Device" may be red at that stage, it shold get black after a successful build + + +# Build + +Ctrl-B + + +# Test + +At that stage, the program should be runnable, debuggable (C++, QML, and combined QML/C++), +and Qml-Profilable + From fb6be52b7c70d83a91fe5e5022d28256870fe604 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Fri, 29 Nov 2024 15:02:32 +0100 Subject: [PATCH 315/989] LSP: recreate clients enabled on a project Add a method on BaseSettings to check whether it is enabled on a certain project via global or project settings, and use it when creating a client to create globally disabled but project-specifically enabled clients. Amends 18cd9359b9378dca470a04c782cca4d35ac8636c that introduced the enabling/disabling of settings project-wide. Change-Id: I1e6f2212ef6da965d01bd09348238c98a3a768ba Reviewed-by: David Schulz --- .../languageclient/languageclientsettings.cpp | 14 +++++++++++++- .../languageclient/languageclientsettings.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 5d2a10eb243..5ff219a50ce 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -593,9 +593,21 @@ Client *BaseSettings::createClient() const return createClient(static_cast(nullptr)); } + +bool BaseSettings::isEnabledOnProject(ProjectExplorer::Project *project) const +{ + LanguageClient::ProjectSettings settings(project); + if (settings.enabledSettings().contains(m_id)) + return true; + if (settings.disabledSettings().contains(m_id)) + return false; + + return m_enabled; +} + Client *BaseSettings::createClient(ProjectExplorer::Project *project) const { - if (!isValid() || !m_enabled) + if (!isValid() || !isEnabledOnProject(project)) return nullptr; BaseClientInterface *interface = createInterface(project); QTC_ASSERT(interface, return nullptr); diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index b909c9c19e8..3530b2c5242 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -82,6 +82,7 @@ public: virtual bool isValid() const; Client *createClient() const; Client *createClient(ProjectExplorer::Project *project) const; + bool isEnabledOnProject(ProjectExplorer::Project *project) const; virtual void toMap(Utils::Store &map) const; virtual void fromMap(const Utils::Store &map); From b9c75a5e87d69d5a70456a145621e636f56a2c7f Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Thu, 28 Nov 2024 13:44:46 +0100 Subject: [PATCH 316/989] Debugger: More fixes to the dumper test With any luck at least the Win11 test plan should not fail anymore. Change-Id: I9df98cef912ae4f5ab6ed07e62dfac0fe0a48190 Reviewed-by: hjk --- share/qtcreator/debugger/qttypes.py | 9 ++-- tests/auto/debugger/tst_dumpers.cpp | 76 +++++++++++++++++------------ 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index a0ab08f7eb7..3108214b17c 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -5,6 +5,7 @@ import platform import struct import re from dumper import Children, SubItem, UnnamedSubItem, toInteger, DumperBase +from stdtypes import qdump__std__pair from utils import DisplayFormat, TypeCode @@ -1492,9 +1493,11 @@ if False: d.putSpecialValue('minimumitemcount', 0) -# FIXME: Qt 5 -# remvign the _xxxx makes GDB work with Qt 5 but breaks LLDB -def qdump__QPair_xxxx(d, value): +def qdump__QPair(d, value): + if d.qtVersionAtLeast(0x060000): + qdump__std__pair(d, value) # `QPair` is just an alias for `std::pair` in Qt6 + return + typeCode = '{%s}@{%s}' % (value.type[0].name, value.type[1].name) first, pad, second = value.split(typeCode) with Children(d): diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 5ed89111b4c..5dad15185b3 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -182,6 +182,10 @@ struct GccVersion : VersionBase explicit GccVersion(int minimum = 0, int maximum = INT_MAX) : VersionBase(minimum, maximum) {} + + GccVersion(int majorMin, int minorMin, int patchMin) + : GccVersion{10000 * majorMin + 100 * minorMin + patchMin} + {} }; struct ClangVersion : VersionBase @@ -1421,7 +1425,7 @@ void tst_Dumpers::dumper() + QByteArray::number(data.neededQtVersion.max, 16))); } - if (data.neededGccVersion.isRestricted) { + if (data.neededGccVersion.isRestricted && m_debuggerEngine == GdbEngine) { QProcess gcc; gcc.setWorkingDirectory(t->buildPath); gcc.start("gcc", {"--version"}); @@ -4827,35 +4831,42 @@ void tst_Dumpers::dumper_data() + Check("deque2.1", "[1]", "", "Foo") + Check("deque2.1.a", "2", "int"); + // clang-format off + QTest::newRow("StdDequeConst") << Data{ + R"( + #include - QTest::newRow("StdDequeConst") - << Data("#include \n" + fooData, - - "struct MyItem {\n" - " MyItem(uint64_t a, uint16_t b) : a{a}, b{b} {}\n" - " const uint64_t a;\n" - " const uint16_t b;\n" - "};\n\n" - - "std::deque deq;\n" - "for (uint16_t i = 0; i < 100; ++i)\n" - " deq.push_back({i, i});\n", - - "&deq") - - + CoreProfile() - + Check("deq.0", "[0]", "", "MyItem") - + Check("deq.0.a", "0", "uint64_t") - + Check("deq.0.b", "0", "uint16_t") - - + Check("deq.50", "[50]", "", "MyItem") - + Check("deq.50.a", "50", "uint64_t") - + Check("deq.50.b", "50", "uint16_t") - - + Check("deq.99", "[99]", "", "MyItem") - + Check("deq.99.a", "99", "uint64_t") - + Check("deq.99.b", "99", "uint16_t"); - + struct MyItem { + MyItem(uint64_t a, uint16_t b) : a{a}, b{b} {} + const uint64_t a; + const uint16_t b; + }; + )", + R"( + std::deque deq; + for (uint16_t i = 0; i < 100; ++i) { + deq.push_back({i, i}); + } + )", + "&deq" + } + + CoreProfile{} + + Check{"deq.0", "[0]", "", "MyItem"} + + Check{"deq.0.a", "0", "uint64_t"} % NoCdbEngine + + Check{"deq.0.a", "0", "unsigned int64"} % CdbEngine + + Check{"deq.0.b", "0", "uint16_t"} % NoCdbEngine + + Check{"deq.0.b", "0", "unsigned short"} % CdbEngine + + Check{"deq.50", "[50]", "", "MyItem"} + + Check{"deq.50.a", "50", "uint64_t"} % NoCdbEngine + + Check{"deq.50.a", "50", "unsigned int64"} % CdbEngine + + Check{"deq.50.b", "50", "uint16_t"} % NoCdbEngine + + Check{"deq.50.b", "50", "unsigned short"} % CdbEngine + + Check{"deq.99", "[99]", "", "MyItem"} + + Check{"deq.99.a", "99", "uint64_t"} % NoCdbEngine + + Check{"deq.99.a", "99", "unsigned int64"} % CdbEngine + + Check{"deq.99.b", "99", "uint16_t"} % NoCdbEngine + + Check{"deq.99.b", "99", "unsigned short"} % CdbEngine; + // clang-format on QTest::newRow("StdHashSet") << Data("#include \n" @@ -5444,6 +5455,7 @@ void tst_Dumpers::dumper_data() "&view, &u16view, basicview, u16basicview") + + Cxx17Profile{} + Check("view", "\"test\"", TypeDef("std::basic_string_view >", "std::string_view")) + Check("u16view", "\"test\"", TypeDef("std::basic_string_view >", "std::u16string_view")) + Check("basicview", "\"test\"", "std::basic_string_view >") @@ -8619,7 +8631,7 @@ void tst_Dumpers::dumper_data() + Check("dir.entryList.1", "[1]", "\"..\"", "@QString") % NoCdbEngine; // clang-format off - QTest::newRow("tl__expected") << Data{ + QTest::newRow("TlExpected") << Data{ R"( #include @@ -8743,6 +8755,10 @@ void tst_Dumpers::dumper_data() "&d, &fl, &l, &s, &ms, &us, &ums, &m, &mm, &um, &umm, &v" } + Cxx17Profile{} + // `memory_resource` header is only available since GCC 9.1 + // (see https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2017) + // and the test are run with GCC (MinGW) as old as 8.1 + + GccVersion{9, 1, 0} + Check{"d", "<10 items>", "std::pmr::deque"} % NoGdbEngine + Check{"d", "<10 items>", "std::pmr::deque"} % GdbEngine + Check{"d.1", "[1]", "8", "int"} From acc7ba5c20ec328156cf4ecf6fab88156973130b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 2 Dec 2024 08:02:22 +0100 Subject: [PATCH 317/989] LanguageClient: fix text style for a diagnostic warning amends c231639a3591e73b0e8e4a921e3f29d8b1c47943 Change-Id: I3d0e2ae13aaf089b0c7511fc7b8396d809d86f2a Reviewed-by: Sami Shalayel --- src/plugins/languageclient/diagnosticmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/languageclient/diagnosticmanager.cpp b/src/plugins/languageclient/diagnosticmanager.cpp index d584f83134d..6b658edfcc4 100644 --- a/src/plugins/languageclient/diagnosticmanager.cpp +++ b/src/plugins/languageclient/diagnosticmanager.cpp @@ -268,7 +268,7 @@ QTextEdit::ExtraSelection DiagnosticManager::createDiagnosticSelection( if (severity == DiagnosticSeverity::Error) style = C_ERROR; else if (severity == DiagnosticSeverity::Warning) - style = C_ERROR; + style = C_WARNING; else return {}; From ffeb4358ec68a5d1563f14600d155b8c6641ad4a Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 12:09:30 +0100 Subject: [PATCH 318/989] Python: Use Utils::Process's decoding in PySideUicExtraCompiler Change-Id: Ia9d5bac9bc234d0203b040296525ae037204cbe0 Reviewed-by: David Schulz --- src/plugins/python/pysideuicextracompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/python/pysideuicextracompiler.cpp b/src/plugins/python/pysideuicextracompiler.cpp index c195aeaa1f7..60b3b220a9d 100644 --- a/src/plugins/python/pysideuicextracompiler.cpp +++ b/src/plugins/python/pysideuicextracompiler.cpp @@ -41,7 +41,7 @@ FileNameToContentsHash PySideUicExtraCompiler::handleProcessFinished(Process *pr return result; // As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The // conversion below is to normalize both the encoding, and the line terminators. - result[targetList.first()] = QString::fromLocal8Bit(process->readAllRawStandardOutput()).toUtf8(); + result[targetList.first()] = process->readAllStandardOutput().toUtf8(); return result; } From 4b9e2d3d8853c02d94854359d2c34063544b55fd Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 20 Nov 2024 17:13:40 +0100 Subject: [PATCH 319/989] Utils: Remove special newline handling in OutputFormatter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: QTCREATORBUG-31959 Task-number: QTCREATORBUG-24411 Change-Id: I169993505fba19036c8b4ff0144899b500dcc687 Reviewed-by: Alessandro Portale Reviewed-by: Błażej Szczygieł Reviewed-by: Orgad Shaneh --- src/libs/utils/outputformatter.cpp | 27 ++++++++++----------------- src/libs/utils/outputformatter.h | 4 ++-- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp index d5dd40106e5..bf25e3bec40 100644 --- a/src/libs/utils/outputformatter.cpp +++ b/src/libs/utils/outputformatter.cpp @@ -218,7 +218,6 @@ public: PostPrintAction postPrintAction; bool boldFontEnabled = true; bool prependCarriageReturn = false; - bool prependLineFeed = false; bool forwardStdOutToStdError = false; }; @@ -295,9 +294,13 @@ static void checkAndFineTuneColors(QTextCharFormat *format) format->setForeground(fgColor); } -void OutputFormatter::doAppendMessage(const QString &text, OutputFormat format) +void OutputFormatter::doAppendMessage(const QString &text, OutputFormat format, LineStatus lineStatus) { QTextCharFormat charFmt = charFormat(format); + const auto addNewlineIfApplicable = [&] { + if (lineStatus == LineStatus::Complete) + append("\n", charFmt); + }; QList formattedText = parseAnsi(text, charFmt); const QString cleanLine = std::accumulate(formattedText.begin(), formattedText.end(), QString(), @@ -321,6 +324,7 @@ void OutputFormatter::doAppendMessage(const QString &text, OutputFormat format) if (res.newContent) { append(*res.newContent, charFmt); + addNewlineIfApplicable(); return; } @@ -328,9 +332,9 @@ void OutputFormatter::doAppendMessage(const QString &text, OutputFormat format) for (FormattedText output : linkified) { checkAndFineTuneColors(&output.format); append(output.text, output.format); + charFmt = output.format; } - if (linkified.isEmpty()) - append({}, charFmt); // This might cause insertion of a newline character. + addNewlineIfApplicable(); for (OutputLineParser * const p : std::as_const(involvedParsers)) { if (d->postPrintAction) @@ -464,7 +468,6 @@ void OutputFormatter::append(const QString &text, const QTextCharFormat &format) { if (!plainTextEdit()) return; - flushTrailingNewline(); int startPos = 0; int crPos = -1; while ((crPos = text.indexOf('\r', startPos)) >= 0) { @@ -528,18 +531,10 @@ void OutputFormatter::initFormats() void OutputFormatter::flushIncompleteLine() { clearLastLine(); - doAppendMessage(d->incompleteLine.first, d->incompleteLine.second); + doAppendMessage(d->incompleteLine.first, d->incompleteLine.second, LineStatus::Incomplete); d->incompleteLine.first.clear(); } -void Utils::OutputFormatter::flushTrailingNewline() -{ - if (d->prependLineFeed) { - d->cursor.insertText("\n"); - d->prependLineFeed = false; - } -} - void OutputFormatter::dumpIncompleteLine(const QString &line, OutputFormat format) { if (line.isEmpty()) @@ -608,7 +603,6 @@ void OutputFormatter::flush() { if (!d->incompleteLine.first.isEmpty()) flushIncompleteLine(); - flushTrailingNewline(); d->escapeCodeHandler.endFormatScope(); for (OutputLineParser * const p : std::as_const(d->lineParsers)) p->flush(); @@ -690,8 +684,7 @@ void OutputFormatter::appendMessage(const QString &text, OutputFormat format) dumpIncompleteLine(out.mid(startPos), format); break; } - doAppendMessage(out.mid(startPos, eolPos - startPos), format); - d->prependLineFeed = true; + doAppendMessage(out.mid(startPos, eolPos - startPos), format, LineStatus::Complete); startPos = eolPos + 1; } } diff --git a/src/libs/utils/outputformatter.h b/src/libs/utils/outputformatter.h index da4dfe8a3a1..4da46bf6f1b 100644 --- a/src/libs/utils/outputformatter.h +++ b/src/libs/utils/outputformatter.h @@ -166,7 +166,8 @@ signals: void openInEditorRequested(const Utils::Link &link); private: - void doAppendMessage(const QString &text, OutputFormat format); + enum class LineStatus {Complete, Incomplete}; + void doAppendMessage(const QString &text, OutputFormat format, LineStatus lineStatus); OutputLineParser::Result handleMessage(const QString &text, OutputFormat format, QList &involvedParsers); @@ -174,7 +175,6 @@ private: void append(const QString &text, const QTextCharFormat &format); void initFormats(); void flushIncompleteLine(); - void flushTrailingNewline(); void dumpIncompleteLine(const QString &line, OutputFormat format); void clearLastLine(); QList parseAnsi(const QString &text, const QTextCharFormat &format); From 431bf4835185263bf6da45f6bab165823eaca17f Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 29 Nov 2024 13:13:33 +0100 Subject: [PATCH 320/989] iOS: Simplify tail process setup to read log files Change-Id: I0839185d5b4786c35d97e189c1c57979cb40d098 Reviewed-by: Eike Ziller --- src/plugins/ios/iostoolhandler.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index 5174dcef299..5f49d44e6a5 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -58,7 +58,7 @@ public: if (promise.isCanceled()) return; - // The future is canceled when app on simulator is stoped. + // The future is canceled when app on simulator is stopped. QEventLoop loop; QFutureWatcher watcher; connect(&watcher, &QFutureWatcher::canceled, &loop, [&] { loop.quit(); }); @@ -74,13 +74,13 @@ public: tailProcess->start(); }; - std::unique_ptr tailStdout(new Process); + Process tailStdout; if (stdoutFile) - logProcess(tailStdout.get(), stdoutFile); + logProcess(&tailStdout, stdoutFile); - std::unique_ptr tailStderr(new Process); + Process tailStderr; if (stderrFile) - logProcess(tailStderr.get(), stderrFile); + logProcess(&tailStderr, stderrFile); // Blocks untill tool is deleted or toolexited is called. loop.exec(); From 3370c3961518a2046ba4ee929ff4b04118d3b820 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 12:24:04 +0100 Subject: [PATCH 321/989] Utils: Use QImage instead of QPixmap for current frame in QtcMovie The current frame was internally stored as QPixmap, and in all cases unconditionally created from a QImage. This caused a QImage -> QPixmap -> QImage roundtrip for currentImage(). We now store the frame as QImage, effectively removing the round trip when using currentImage() and delaying the conversion when using currentPixmap(). A usage pattern of repeated calls to currentPixmap() which naively would result in multiple calls of QPixmap::fromImage() on the same image is counter-acted by caching and later re-using the first call's result. Change-Id: I1a76aee523ed289a266bd15511ad9f07803abdcf Reviewed-by: Marcus Tillmanns --- src/libs/utils/movie.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/libs/utils/movie.cpp b/src/libs/utils/movie.cpp index 3d622c6a703..02bc673ead4 100644 --- a/src/libs/utils/movie.cpp +++ b/src/libs/utils/movie.cpp @@ -24,30 +24,30 @@ class QtcFrameInfo { public: - QPixmap pixmap; + QImage image; int delay; bool endMark; inline QtcFrameInfo(bool endMark) - : pixmap(QPixmap()) + : image(QImage()) , delay(QTC_MOVIE_INVALID_DELAY) , endMark(endMark) {} inline QtcFrameInfo() - : pixmap(QPixmap()) + : image(QImage()) , delay(QTC_MOVIE_INVALID_DELAY) , endMark(false) {} - inline QtcFrameInfo(QPixmap &&pixmap, int delay) - : pixmap(std::move(pixmap)) + inline QtcFrameInfo(QImage &&image, int delay) + : image(std::move(image)) , delay(delay) , endMark(false) {} inline bool isValid() { - return endMark || !(pixmap.isNull() && (delay == QTC_MOVIE_INVALID_DELAY)); + return endMark || !(image.isNull() && (delay == QTC_MOVIE_INVALID_DELAY)); } inline bool isEndMarker() { return endMark; } @@ -89,7 +89,8 @@ public: QtcMovie::MovieState movieState = QtcMovie::NotRunning; QRect frameRect; - QPixmap currentPixmap; + QImage currentImage; + mutable std::optional currentPixmap; int currentFrameNumber = -1; int nextFrameNumber = 0; int greatestFrameNumber = -1; @@ -232,7 +233,7 @@ QtcFrameInfo QtcMoviePrivate::infoForFrame(int frameNumber) } if (frameNumber > greatestFrameNumber) greatestFrameNumber = frameNumber; - return QtcFrameInfo(QPixmap::fromImage(std::move(anImage)), nextFrameDelay()); + return QtcFrameInfo(std::move(anImage), nextFrameDelay()); } else if (frameNumber != 0) { // We've read all frames now. Return an end marker haveReadAll = true; @@ -260,7 +261,7 @@ QtcFrameInfo QtcMoviePrivate::infoForFrame(int frameNumber) return QtcFrameInfo(); // Invalid } greatestFrameNumber = i; - QtcFrameInfo info(QPixmap::fromImage(std::move(anImage)), nextFrameDelay()); + QtcFrameInfo info(std::move(anImage), nextFrameDelay()); // Cache it! frameMap.insert(i, info); if (i == frameNumber) { @@ -282,7 +283,7 @@ QtcFrameInfo QtcMoviePrivate::infoForFrame(int frameNumber) \internal Attempts to advance the animation to the next frame. - If successful, currentFrameNumber, currentPixmap and + If successful, currentFrameNumber, currentImage and nextDelay are updated accordingly, and true is returned. Otherwise, false is returned. When false is returned, isDone() can be called to @@ -319,7 +320,8 @@ bool QtcMoviePrivate::next() } // Image and delay OK, update internal state currentFrameNumber = nextFrameNumber++; - currentPixmap = info.pixmap; + currentImage = info.image; + currentPixmap.reset(); if (!speed) return true; @@ -350,8 +352,8 @@ void QtcMoviePrivate::_q_loadNextFrame(bool starting) emit q->started(); } - if (frameRect.size() != currentPixmap.rect().size()) { - frameRect = currentPixmap.rect(); + if (frameRect.size() != currentImage.rect().size()) { + frameRect = currentImage.rect(); emit q->resized(frameRect.size()); } @@ -639,7 +641,9 @@ QRect QtcMovie::frameRect() const QPixmap QtcMovie::currentPixmap() const { Q_D(const QtcMovie); - return d->currentPixmap; + if (!d->currentPixmap) + d->currentPixmap = QPixmap::fromImage(d->currentImage); + return *d->currentPixmap; } /*! @@ -650,7 +654,7 @@ QPixmap QtcMovie::currentPixmap() const QImage QtcMovie::currentImage() const { Q_D(const QtcMovie); - return d->currentPixmap.toImage(); + return d->currentImage; } /*! From 5d43c1de1c34868f5048accd6d062e6033e9557b Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 13:57:09 +0100 Subject: [PATCH 322/989] LayoutBuilder: Make the guard the first parameters in "slots" This is purely cosmetical: The guard is usually 'this' or another short expression and fits on the same line as the initial parts of the lambda, and is usually "obviously" right. Before it came after a potentially lengthy lambda, leading sometimes to "'this' - huh?" moments when reading. Change-Id: I5fb25cbf971ab54c491ab8cd9515879082af1924 Reviewed-by: Marcus Tillmanns --- src/libs/utils/layoutbuilder.cpp | 10 ++++---- src/libs/utils/layoutbuilder.h | 10 ++++---- src/plugins/autotest/testsettingspage.cpp | 2 +- src/plugins/coco/cocoprojectwidget.cpp | 6 ++--- src/plugins/copilot/copilotsettings.cpp | 2 +- .../extensionmanagersettings.cpp | 4 ++-- src/plugins/fakevim/fakevimactions.cpp | 12 +++++----- src/plugins/languageclient/lspinspector.cpp | 2 +- src/plugins/lua/bindings/gui.cpp | 12 +++++----- .../customqbspropertiesdialog.cpp | 2 +- .../qbsprofilessettingspage.cpp | 4 ++-- src/plugins/qnx/qnxsettingspage.cpp | 4 ++-- src/plugins/scxmleditor/common/stateview.cpp | 2 +- .../snippets/snippetssettingspage.cpp | 24 ++++++++++++------- src/plugins/vcsbase/commonvcssettings.cpp | 2 +- .../tst_manual_widgets_layoutbuilder.cpp | 6 ++--- 16 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index de6bc845ef4..896ecc8c43f 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -867,7 +867,7 @@ void Label::setOpenExternalLinks(bool on) access(this)->setOpenExternalLinks(on); } -void Label::onLinkHovered(const std::function &func, QObject *guard) +void Label::onLinkHovered(QObject *guard, const std::function &func) { QObject::connect(access(this), &QLabel::linkHovered, guard, func); } @@ -904,7 +904,7 @@ void SpinBox::setValue(int val) access(this)->setValue(val); } -void SpinBox::onTextChanged(const std::function &func, QObject *guard) +void SpinBox::onTextChanged(QObject *guard, const std::function &func) { QObject::connect(access(this), &QSpinBox::textChanged, guard, func); } @@ -971,7 +971,7 @@ void PushButton::setFlat(bool flat) access(this)->setFlat(flat); } -void PushButton::onClicked(const std::function &func, QObject *guard) +void PushButton::onClicked(QObject *guard, const std::function &func) { QObject::connect(access(this), &QAbstractButton::clicked, guard, func); } @@ -1228,13 +1228,13 @@ void LineEdit::setMinimumHeight(int height) access(this)->setMinimumHeight(height); } -void LineEdit::onReturnPressed(const std::function &func, QObject *guard) +void LineEdit::onReturnPressed(QObject *guard, const std::function &func) { static_cast(access(this))->acceptReturnKeys = true; QObject::connect(access(this), &Utils::FancyLineEdit::returnPressed, guard, func); } -void LineEdit::onRightSideIconClicked(const std::function &func, QObject *guard) +void LineEdit::onRightSideIconClicked(QObject *guard, const std::function &func) { QObject::connect(access(this), &Utils::FancyLineEdit::rightButtonClicked, guard, func); } diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index e1d0daf8d6e..4e19d7f5c84 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -282,7 +282,7 @@ public: void setWordWrap(bool); void setTextInteractionFlags(Qt::TextInteractionFlags); void setOpenExternalLinks(bool); - void onLinkHovered(const std::function &, QObject *guard); + void onLinkHovered(QObject *guard, const std::function &); }; class QTCREATOR_UTILS_EXPORT Group : public Widget @@ -306,7 +306,7 @@ public: SpinBox(std::initializer_list ps); void setValue(int); - void onTextChanged(const std::function &, QObject *guard); + void onTextChanged(QObject *guard, const std::function &); }; class QTCREATOR_UTILS_EXPORT PushButton : public Widget @@ -321,7 +321,7 @@ public: void setIconPath(const Utils::FilePath &); void setIconSize(const QSize &); void setFlat(bool); - void onClicked(const std::function &, QObject *guard); + void onClicked(QObject *guard, const std::function &); }; class QTCREATOR_UTILS_EXPORT TextEdit : public Widget @@ -354,8 +354,8 @@ public: void setPlaceHolderText(const QString &text); void setCompleter(QCompleter *completer); void setMinimumHeight(int height); - void onReturnPressed(const std::function &, QObject *guard); - void onRightSideIconClicked(const std::function &, QObject *guard); + void onReturnPressed(QObject *guard, const std::function &); + void onRightSideIconClicked(QObject *guard, const std::function &); }; class QTCREATOR_UTILS_EXPORT Splitter : public Widget diff --git a/src/plugins/autotest/testsettingspage.cpp b/src/plugins/autotest/testsettingspage.cpp index e707470c221..9af5b4b4f4b 100644 --- a/src/plugins/autotest/testsettingspage.cpp +++ b/src/plugins/autotest/testsettingspage.cpp @@ -77,7 +77,7 @@ TestSettingsWidget::TestSettingsWidget() text(Tr::tr("Reset Cached Choices")), Layouting::toolTip(Tr::tr("Clear all cached choices of run configurations for " "tests where the executable could not be deduced.")), - onClicked(&clearChoiceCache, this) + onClicked(this, &clearChoiceCache) }; TestSettings &s = Internal::testSettings(); diff --git a/src/plugins/coco/cocoprojectwidget.cpp b/src/plugins/coco/cocoprojectwidget.cpp index b0db3e42a8e..88138a716c0 100644 --- a/src/plugins/coco/cocoprojectwidget.cpp +++ b/src/plugins/coco/cocoprojectwidget.cpp @@ -48,10 +48,10 @@ CocoProjectWidget::CocoProjectWidget(Project *project, BuildConfiguration *build m_optionEdit, Row{PushButton{ text(Tr::tr("Exclude File...")), - onClicked([&] { onExcludeFileButtonClicked(); }, this)}, + onClicked(this, [this] { onExcludeFileButtonClicked(); })}, PushButton{ text(Tr::tr("Exclude Directory...")), - onClicked([&] { onExcludeDirButtonClicked(); }, this)}, + onClicked(this, [this] { onExcludeDirButtonClicked(); })}, m_tweaksButton, st}, m_tweaksDescriptionLabel, @@ -83,7 +83,7 @@ CocoProjectWidget::CocoProjectWidget(Project *project, BuildConfiguration *build connect(&m_optionEdit, &StringAspect::changed, this, &CocoProjectWidget::onTextChanged); connect(&m_tweaksEdit, &StringAspect::changed, this, &CocoProjectWidget::onTextChanged); - m_tweaksButton.onClicked([&] { onTweaksButtonClicked(); }, this); + m_tweaksButton.onClicked(this, [this] { onTweaksButtonClicked(); }); connect(&m_revertButton, &QPushButton::clicked, this, &CocoProjectWidget::onRevertButtonClicked); connect(&m_saveButton, &QPushButton::clicked, this, &CocoProjectWidget::onSaveButtonClicked); diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp index e4f98dccb2f..942c8e30451 100644 --- a/src/plugins/copilot/copilotsettings.cpp +++ b/src/plugins/copilot/copilotsettings.cpp @@ -198,7 +198,7 @@ CopilotSettings::CopilotSettings() textInteractionFlags( Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard | Qt::TextSelectableByMouse), openExternalLinks(true), - onLinkHovered([](const QString &link) { QToolTip::showText(QCursor::pos(), link); }, this), + onLinkHovered(this, [](const QString &link) { QToolTip::showText(QCursor::pos(), link); }), text(Tr::tr( "The Copilot plugin requires node.js and the Copilot neovim plugin. " "If you install the neovim plugin as described in %1, " diff --git a/src/plugins/extensionmanager/extensionmanagersettings.cpp b/src/plugins/extensionmanager/extensionmanagersettings.cpp index 8a96020a2d9..d3cc07f84af 100644 --- a/src/plugins/extensionmanager/extensionmanagersettings.cpp +++ b/src/plugins/extensionmanager/extensionmanagersettings.cpp @@ -64,11 +64,11 @@ ExtensionManagerSettings::ExtensionManagerSettings() Row { PushButton { text(Tr::tr("Install Extension...")), - onClicked([] { + onClicked(this, [] { if (Core::executePluginInstallWizard()) Core::ICore::askForRestart( Tr::tr("Plugin changes will take effect after restart.")); - }, this), + }), }, st, }, diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp index d04ee8bf0d6..53b622c2eb8 100644 --- a/src/plugins/fakevim/fakevimactions.cpp +++ b/src/plugins/fakevim/fakevimactions.cpp @@ -189,7 +189,7 @@ FakeVimSettings::FakeVimSettings() Row { PushButton { text(Tr::tr("Copy Text Editor Settings")), - onClicked([this] { + onClicked(this, [this] { TabSettings ts = TextEditorSettings::codeStyle()->tabSettings(); TypingSettings tps = globalTypingSettings(); expandTab.setValue(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy); @@ -200,11 +200,11 @@ FakeVimSettings::FakeVimSettings() autoIndent.setValue(true); smartIndent.setValue(tps.m_autoIndent); incSearch.setValue(true); - }, this), + }), }, PushButton { text(Tr::tr("Set Qt Style")), - onClicked([this] { + onClicked(this, [this] { expandTab.setVolatileValue(true); tabStop.setVolatileValue(4); shiftWidth.setVolatileValue(4); @@ -214,11 +214,11 @@ FakeVimSettings::FakeVimSettings() incSearch.setVolatileValue(true); backspace.setVolatileValue(QString("indent,eol,start")); passKeys.setVolatileValue(true); - }, this), + }), }, PushButton { text(Tr::tr("Set Plain Style")), - onClicked([this] { + onClicked(this, [this] { expandTab.setVolatileValue(false); tabStop.setVolatileValue(8); shiftWidth.setVolatileValue(8); @@ -228,7 +228,7 @@ FakeVimSettings::FakeVimSettings() incSearch.setVolatileValue(false); backspace.setVolatileValue(QString()); passKeys.setVolatileValue(false); - }, this), + }), }, st }, diff --git a/src/plugins/languageclient/lspinspector.cpp b/src/plugins/languageclient/lspinspector.cpp index 634f0d456c7..1f9dddfe7e3 100644 --- a/src/plugins/languageclient/lspinspector.cpp +++ b/src/plugins/languageclient/lspinspector.cpp @@ -498,7 +498,7 @@ LspInspectorWidget::LspInspectorWidget(LspInspector *inspector) // clang-format off using namespace Layouting; Column { - Row { Tr::tr("Language Server:"), m_clients, st, errorLabel, PushButton { text(Tr::tr("Send message")), onClicked(send, this) } }, + Row { Tr::tr("Language Server:"), m_clients, st, errorLabel, PushButton { text(Tr::tr("Send message")), onClicked(this, send) } }, messageEditor->editorWidget(), TabWidget { bindTo(&m_tabWidget), diff --git a/src/plugins/lua/bindings/gui.cpp b/src/plugins/lua/bindings/gui.cpp index 36c42326148..4f41c39926b 100644 --- a/src/plugins/lua/bindings/gui.cpp +++ b/src/plugins/lua/bindings/gui.cpp @@ -193,7 +193,7 @@ void setProperties(std::unique_ptr &item, const sol::table &children, QObject if constexpr (has_onReturnPressed) { const auto callback = children.get>("onReturnPressed"); if (callback) { - item->onReturnPressed([func = *callback]() { void_safe_call(func); }, guard); + item->onReturnPressed(guard, [func = *callback]() { void_safe_call(func); }); } } @@ -201,7 +201,7 @@ void setProperties(std::unique_ptr &item, const sol::table &children, QObject const auto callback = children.get>( "onRightSideIconClicked"); if (callback) - item->onRightSideIconClicked([func = *callback]() { void_safe_call(func); }, guard); + item->onRightSideIconClicked(guard, [func = *callback]() { void_safe_call(func); }); } if constexpr (has_setFlat) { @@ -261,11 +261,11 @@ void setProperties(std::unique_ptr &item, const sol::table &children, QObject = children.get>("onTextChanged"); if (onTextChanged) { item->onTextChanged( + guard, [f = *onTextChanged](const QString &text) { auto res = void_safe_call(f, text); QTC_CHECK_EXPECTED(res); - }, - guard); + }); } } if constexpr (has_onClicked) { @@ -273,11 +273,11 @@ void setProperties(std::unique_ptr &item, const sol::table &children, QObject = children.get>("onClicked"); if (onClicked) { item->onClicked( + guard, [f = *onClicked]() { auto res = void_safe_call(f); QTC_CHECK_EXPECTED(res); - }, - guard); + }); } } if constexpr (has_setText) { diff --git a/src/plugins/qbsprojectmanager/customqbspropertiesdialog.cpp b/src/plugins/qbsprojectmanager/customqbspropertiesdialog.cpp index 13e6e09dd31..4d106f723c0 100644 --- a/src/plugins/qbsprojectmanager/customqbspropertiesdialog.cpp +++ b/src/plugins/qbsprojectmanager/customqbspropertiesdialog.cpp @@ -50,7 +50,7 @@ CustomQbsPropertiesDialog::CustomQbsPropertiesDialog(const QVariantMap &properti Column { PushButton { text(Tr::tr("&Add")), - onClicked([this] { addProperty(); }, this), + onClicked(this, [this] { addProperty(); }), }, m_removeButton, st diff --git a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp index 34bc379db2a..c7d2f504239 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp @@ -133,11 +133,11 @@ QbsProfilesSettingsWidget::QbsProfilesSettingsWidget() Column { PushButton { text(Tr::tr("E&xpand All")), - onClicked([this] { m_propertiesView->expandAll(); }, this), + onClicked(this, [this] { m_propertiesView->expandAll(); }), }, PushButton { text(Tr::tr("&Collapse All")), - onClicked([this] { m_propertiesView->collapseAll(); }, this), + onClicked(this, [this] { m_propertiesView->collapseAll(); }), }, st, }, diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 8127e0715ab..03b2166f902 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -573,11 +573,11 @@ QnxSettingsWidget::QnxSettingsWidget() Column { PushButton { text(Tr::tr("Add...")), - onClicked([this] { addConfiguration(); }, this) + onClicked(this, [this] { addConfiguration(); }) }, PushButton { text(Tr::tr("Remove")), - onClicked([this] { removeConfiguration(); }, this) + onClicked(this, [this] { removeConfiguration(); }) }, st } diff --git a/src/plugins/scxmleditor/common/stateview.cpp b/src/plugins/scxmleditor/common/stateview.cpp index c31dd4f8507..f70fc9455c3 100644 --- a/src/plugins/scxmleditor/common/stateview.cpp +++ b/src/plugins/scxmleditor/common/stateview.cpp @@ -33,7 +33,7 @@ StateView::StateView(StateItem *state, QWidget *parent) using namespace Layouting; Row { - PushButton{ text(QString("Back")), onClicked([this] { closeView(); }, this) }, + PushButton{ text(QString("Back")), onClicked(this, [this] { closeView(); }) }, stateNameLabel, noMargin }.attachTo(titleBar); diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.cpp b/src/plugins/texteditor/snippets/snippetssettingspage.cpp index 9ce588ec39f..fd793503797 100644 --- a/src/plugins/texteditor/snippets/snippetssettingspage.cpp +++ b/src/plugins/texteditor/snippets/snippetssettingspage.cpp @@ -316,15 +316,23 @@ SnippetsSettingsWidget::SnippetsSettingsWidget() Row { snippetSplitter, Column { - PushButton { text(Tr::tr("Add")), - onClicked([this] { addSnippet(); }, this) }, - PushButton { text(Tr::tr("Remove")), - onClicked([this] { removeSnippet(); }, this) }, + PushButton { + text(Tr::tr("Add")), + onClicked(this, [this] { addSnippet(); }) + }, + PushButton { + text(Tr::tr("Remove")), + onClicked(this, [this] { removeSnippet(); }) + }, m_revertButton, - PushButton { text(Tr::tr("Restore Removed Built-ins")), - onClicked([this] { restoreRemovedBuiltInSnippets(); }, this) }, - PushButton { text(Tr::tr("Reset All")), - onClicked([this] { resetAllSnippets(); }, this) }, + PushButton { + text(Tr::tr("Restore Removed Built-ins")), + onClicked(this, [this] { restoreRemovedBuiltInSnippets(); }) + }, + PushButton { + text(Tr::tr("Reset All")), + onClicked(this, [this] { resetAllSnippets(); }) + }, st, } } diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index f546ae4154b..35be9fdbfd6 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -101,7 +101,7 @@ CommonVcsSettings::CommonVcsSettings() text(Tr::tr("Reset VCS Cache")), Layouting::toolTip(Tr::tr("Reset information about which " "version control system handles which directory.")), - onClicked(&VcsManager::clearVersionControlCache, this) + onClicked(this, &VcsManager::clearVersionControlCache) } } }; diff --git a/tests/manual/widgets/layoutbuilder/tst_manual_widgets_layoutbuilder.cpp b/tests/manual/widgets/layoutbuilder/tst_manual_widgets_layoutbuilder.cpp index 772b32ac04a..d25d47e1556 100644 --- a/tests/manual/widgets/layoutbuilder/tst_manual_widgets_layoutbuilder.cpp +++ b/tests/manual/widgets/layoutbuilder/tst_manual_widgets_layoutbuilder.cpp @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) auto lineEdit = new QLineEdit("0"); auto minusClick = [lineEdit] { - lineEdit->setText(QString::number(lineEdit->text().toInt() + 1)); + lineEdit->setText(QString::number(lineEdit->text().toInt() - 1)); }; auto plusClick = [lineEdit] { @@ -24,9 +24,9 @@ int main(int argc, char *argv[]) }; Row { - PushButton { text("-"), onClicked(minusClick, qApp) }, + PushButton { text("-"), onClicked(qApp, minusClick) }, lineEdit, - PushButton { text("+"), onClicked(plusClick, qApp) }, + PushButton { text("+"), onClicked(qApp, plusClick) }, Group { title("Splitter in Group"), Column { From 57275e3e98ab3da55ce19287c4f33f93b3c361a0 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 13:07:48 +0100 Subject: [PATCH 323/989] LanguangeClient: Remove some space in the project settings page Most other pages don't have that. Change-Id: I2dac62a09f98fe1482b42f8b789974a4222426bf Reviewed-by: David Schulz --- src/plugins/languageclient/languageclientsettings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 5ff219a50ce..b9b9d6ab9a8 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -1274,8 +1274,8 @@ public: TextEditor::BaseTextEditor *editor = createJsonEditor(this); editor->document()->setContents(m_settings.json()); - auto layout = new QVBoxLayout; - setLayout(layout); + auto layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); QFormLayout *settingsLayout = nullptr; for (auto settings : LanguageClientSettings::pageSettings()) { From bc7b83c0b0b10b20faf1501a42780bb90959e0eb Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 20 Nov 2024 15:34:48 +0100 Subject: [PATCH 324/989] CPlusPlus: Add test case for range-based for without init statement ... in C++20 mode. Task-number: QTCREATORBUG-32043 Change-Id: I885719381afc477777c263b8766bf1a1a4b90789 Reviewed-by: hjk --- tests/auto/cplusplus/cxx11/tst_cxx11.cpp | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index e2ab845e818..6059499fc42 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -151,6 +151,7 @@ private Q_SLOTS: void coroutines(); void genericLambdas(); void ifStatementWithInitialization(); + void rangeBasedForWithoutInitialization(); void rangeBasedForWithInitialization(); }; @@ -575,6 +576,31 @@ int main() QVERIFY(!hasErrors); } +void tst_cxx11::rangeBasedForWithoutInitialization() +{ + LanguageFeatures features; + features.cxxEnabled = true; + features.cxx11Enabled = features.cxx14Enabled = features.cxx17Enabled = features.cxx20Enabled + = true; + + const QString source = R"( +int main() +{ + std::vector v; + using Alias = int; + for (Alias i : v) + return 0; +} +)"; + QByteArray errors; + Document::Ptr doc = Document::create(FilePath::fromPathPart(u"testFile")); + processDocument(doc, source.toUtf8(), features, &errors); + const bool hasErrors = !errors.isEmpty(); + if (hasErrors) + qDebug().noquote() << errors; + QVERIFY(!hasErrors); +} + void tst_cxx11::rangeBasedForWithInitialization() { LanguageFeatures features; From 2dedad0b3ac77603e43309dc0da413e47d90d221 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Sat, 30 Nov 2024 23:26:17 +0100 Subject: [PATCH 325/989] VcsBaseSubmitEditor: Remove unused debug enum Change-Id: I9b0fc032d646ac606ada213ca006686a1858ed8e Reviewed-by: Orgad Shaneh --- src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 28120c4c916..49f58bb0687 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -57,8 +57,6 @@ #include -enum { debug = 0 }; - // Return true if word is meaningful and can be added to a completion model static bool acceptsWordForCompletion(const QString &word) { From 7ec4b2528e27ce9a27ca5d06a7817c3104ee4ca0 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Sat, 30 Nov 2024 23:34:02 +0100 Subject: [PATCH 326/989] Vcs: Modernize SubmitEditorWidget * use categorized logging * auto where appropriate * consolidate constants Change-Id: I250cfd3c3e41627dbe8aadf9d930ba37151dcf18 Reviewed-by: Orgad Shaneh --- src/plugins/vcsbase/submiteditorwidget.cpp | 29 ++++++++++------------ src/plugins/vcsbase/submiteditorwidget.h | 2 -- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/plugins/vcsbase/submiteditorwidget.cpp b/src/plugins/vcsbase/submiteditorwidget.cpp index dfc785e68a0..8a60f154513 100644 --- a/src/plugins/vcsbase/submiteditorwidget.cpp +++ b/src/plugins/vcsbase/submiteditorwidget.cpp @@ -19,11 +19,11 @@ #include #include -#include #include #include #include #include +#include #include #include #include @@ -39,8 +39,7 @@ using namespace Core; using namespace Utils; -enum { debug = 0 }; -enum { defaultLineWidth = 72 }; +static Q_LOGGING_CATEGORY(log, "qtc.vcs.submiteditor", QtWarningMsg); /*! \class VcsBase::SubmitEditorWidget @@ -68,6 +67,8 @@ enum { defaultLineWidth = 72 }; namespace VcsBase { +enum { MinSubjectLength = 20, MaxSubjectLength = 72, WarningSubjectLength = 55 }; + // QActionPushButton: A push button tied to an action // (similar to a QToolButton) class QActionPushButton : public QToolButton @@ -116,7 +117,7 @@ struct SubmitEditorWidgetPrivate QTimer delayedVerifyDescriptionTimer; int m_delayedVerifyDescriptionInterval = 2000; - int m_lineWidth = defaultLineWidth; + int m_lineWidth = MaxSubjectLength; int m_activatedRow = -1; bool m_filesSelected = false; @@ -186,7 +187,7 @@ SubmitEditorWidget::SubmitEditorWidget() : d->buttonLayout = new QHBoxLayout(); d->buttonLayout->setContentsMargins(0, -1, -1, -1); - QToolButton *openSettingsButton = new QToolButton; + auto openSettingsButton = new QToolButton; openSettingsButton->setIcon(Utils::Icons::SETTINGS.icon()); openSettingsButton->setToolTip(ICore::msgShowOptionsDialog()); connect(openSettingsButton, &QToolButton::clicked, this, [] { @@ -269,11 +270,10 @@ void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *edi } }; - if (debug) { - const SubmitFileModel *model = fileModel(); - int count = model ? model->rowCount() : 0; - qDebug() << Q_FUNC_INFO << submitAction << count << "items"; - } + const SubmitFileModel *model = fileModel(); + const int itemCount = model ? model->rowCount() : 0; + qCDebug(log) << Q_FUNC_INFO << submitAction << itemCount << "items"; + updateSubmitEnabled(); connect(this, &SubmitEditorWidget::submitActionEnabledChanged, this, updateSubmitEnabled); connect(this, &SubmitEditorWidget::submitActionTextChanged, this, updateSubmitEnabled); @@ -290,8 +290,7 @@ void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *edi }); } if (diffAction) { - if (debug) - qDebug() << diffAction << d->m_filesSelected; + qCDebug(log) << diffAction << d->m_filesSelected; diffAction->setEnabled(d->m_filesSelected); connect(this, &SubmitEditorWidget::fileSelectionChanged, diffAction, &QAction::setEnabled); connect(diffAction, &QAction::triggered, this, &SubmitEditorWidget::triggerDiffSelected); @@ -378,8 +377,7 @@ bool SubmitEditorWidget::lineWrap() const void SubmitEditorWidget::setLineWrap(bool v) { - if (debug) - qDebug() << Q_FUNC_INFO << v; + qCDebug(log) << Q_FUNC_INFO << v; if (v) { d->description->setLineWrapColumnOrWidth(d->m_lineWidth); d->description->setLineWrapMode(QTextEdit::FixedColumnWidth); @@ -396,8 +394,7 @@ int SubmitEditorWidget::lineWrapWidth() const void SubmitEditorWidget::setLineWrapWidth(int v) { - if (debug) - qDebug() << Q_FUNC_INFO << v << lineWrap(); + qCDebug(log) << Q_FUNC_INFO << v << lineWrap(); if (d->m_lineWidth == v) return; d->m_lineWidth = v; diff --git a/src/plugins/vcsbase/submiteditorwidget.h b/src/plugins/vcsbase/submiteditorwidget.h index 9e0d54ffc4c..b76de62989d 100644 --- a/src/plugins/vcsbase/submiteditorwidget.h +++ b/src/plugins/vcsbase/submiteditorwidget.h @@ -95,8 +95,6 @@ protected: void verifyDescription(); private: - enum { MinSubjectLength = 20, MaxSubjectLength = 72, WarningSubjectLength = 55 }; - void updateCheckAllComboBox(); void checkAllToggled(); From 9426633f938b6d0fa484124e2e84ae801e2fcf9a Mon Sep 17 00:00:00 2001 From: Liu Zhangjian Date: Tue, 26 Nov 2024 09:42:04 +0800 Subject: [PATCH 327/989] fix: [session] Disable delete action for active session Keep consistency with `SessionDialog` behavior by preventing deletion of active session in `ProjectWelcomePage`. Change-Id: I2bb4b6ea4314a219df083b9ef46b19b3eadcbf62 Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/projectwelcomepage.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 7cd956d253d..b02246d7499 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -420,9 +420,9 @@ public: if (withIcon()) { painter->drawPixmap(iconX, iconY, icon()); } + const bool isActiveSession = idx.data(SessionModel::ActiveSessionRole).toBool(); { const bool isLastSession = idx.data(SessionModel::LastSessionRole).toBool(); - const bool isActiveSession = idx.data(SessionModel::ActiveSessionRole).toBool(); const bool isDefaultVirgin = SessionManager::isDefaultVirgin(); const int sessionNameWidth = hdR.right() @@ -533,7 +533,8 @@ public: const QString &action = actions.at(i); const int ww = textWidths.at(i); const QRect actionR(xx, yy, s(ExPaddingGapM) + ww + s(ExPaddingGapM), buttonHeight); - const bool isDisabled = i > 0 && SessionManager::isDefaultSession(sessionName); + const bool isDisabled = (i > 0 && SessionManager::isDefaultSession(sessionName)) + || (i == 2 && isActiveSession); const bool isActive = actionR.adjusted(-s(VPaddingXs), 0, s(VPaddingXs) + 1, 0) .contains(mousePos) && !isDisabled; if (isActive) { From 5b8e6f9d26969fe862c75073a89d1349c6b19220 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 14:39:47 +0100 Subject: [PATCH 328/989] LanguageClient: Hide LanguageClientOutlineWidgetFactory in .cpp Also, sprinkle in a few 'final'. Change-Id: I063923b0654ca76f73731dd58010c6ea425a9621 Reviewed-by: David Schulz --- .../languageclient/languageclientoutline.cpp | 92 +++++++++++-------- .../languageclient/languageclientoutline.h | 21 +---- .../languageclient/languageclientplugin.cpp | 3 +- .../languageclient/languageclientutils.cpp | 2 +- 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index 30dea876882..135a9b6184a 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -10,11 +10,15 @@ #include #include + #include + +#include #include #include #include #include + #include #include #include @@ -90,34 +94,30 @@ private: Utils::FilePath m_filePath; }; -class DragSortFilterProxyModel : public QSortFilterProxyModel +class DragSortFilterProxyModel final : public QSortFilterProxyModel { public: - using QSortFilterProxyModel::QSortFilterProxyModel; - - Qt::DropActions supportedDragActions() const override + Qt::DropActions supportedDragActions() const final { return sourceModel()->supportedDragActions(); } }; -class LanguageClientOutlineWidget : public TextEditor::IOutlineWidget +class LanguageClientOutlineWidget final : public TextEditor::IOutlineWidget { public: LanguageClientOutlineWidget(Client *client, TextEditor::BaseTextEditor *editor); - // IOutlineWidget interface -public: - QList filterMenuActions() const override; - void setCursorSynchronization(bool syncWithCursor) override; - void setSorted(bool) override; - bool isSorted() const override; - void restoreSettings(const QVariantMap &map) override; - QVariantMap settings() const override; - - void contextMenuEvent(QContextMenuEvent *event) override; - private: + QList filterMenuActions() const final; + void setCursorSynchronization(bool syncWithCursor) final; + void setSorted(bool) final; + bool isSorted() const final; + void restoreSettings(const QVariantMap &map) final; + QVariantMap settings() const final; + + void contextMenuEvent(QContextMenuEvent *event) final; + void handleResponse(const DocumentUri &uri, const DocumentSymbolsResult &response); void updateTextCursor(const QModelIndex &proxyIndex); void updateSelectionInTree(const QTextCursor ¤tCursor); @@ -282,26 +282,6 @@ void LanguageClientOutlineWidget::onItemActivated(const QModelIndex &index) m_editor->widget()->setFocus(); } -bool LanguageClientOutlineWidgetFactory::supportsEditor(Core::IEditor *editor) const -{ - if (auto doc = qobject_cast(editor->document())) { - if (Client *client = LanguageClientManager::clientForDocument(doc)) - return client->supportsDocumentSymbols(doc); - } - return false; -} - -TextEditor::IOutlineWidget *LanguageClientOutlineWidgetFactory::createWidget(Core::IEditor *editor) -{ - auto textEditor = qobject_cast(editor); - QTC_ASSERT(textEditor, return nullptr); - if (Client *client = LanguageClientManager::clientForDocument(textEditor->textDocument())) { - if (client->supportsDocumentSymbols(textEditor->textDocument())) - return new LanguageClientOutlineWidget(client, textEditor); - } - return nullptr; -} - class OutlineComboBox : public Utils::TreeViewComboBox { public: @@ -321,8 +301,7 @@ private: const DocumentUri m_uri; }; -Utils::TreeViewComboBox *LanguageClientOutlineWidgetFactory::createComboBox( - Client *client, TextEditor::BaseTextEditor *editor) +Utils::TreeViewComboBox *createOutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor) { if (client && client->supportsDocumentSymbols(editor->textDocument())) return new OutlineComboBox(client, editor); @@ -448,4 +427,41 @@ Qt::ItemFlags LanguageClientOutlineItem::flags(int column) const Q_UNUSED(column) return Utils::TypedTreeItem::flags(column) | Qt::ItemIsDragEnabled; } + +// LanguageClientOutlineWidgetFactory + +class LanguageClientOutlineWidgetFactory final : public TextEditor::IOutlineWidgetFactory +{ +public: + using IOutlineWidgetFactory::IOutlineWidgetFactory; + +public: + bool supportsEditor(Core::IEditor *editor) const final + { + if (auto doc = qobject_cast(editor->document())) { + if (Client *client = LanguageClientManager::clientForDocument(doc)) + return client->supportsDocumentSymbols(doc); + } + return false; + } + + TextEditor::IOutlineWidget *createWidget(Core::IEditor *editor) final + { + auto textEditor = qobject_cast(editor); + QTC_ASSERT(textEditor, return nullptr); + if (Client *client = LanguageClientManager::clientForDocument(textEditor->textDocument())) { + if (client->supportsDocumentSymbols(textEditor->textDocument())) + return new LanguageClientOutlineWidget(client, textEditor); + } + return nullptr; + } + + bool supportsSorting() const final { return true; } +}; + +void setupLanguageClientOutline() +{ + static LanguageClientOutlineWidgetFactory theLanguageClientOutlineWidgetFactory; +} + } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientoutline.h b/src/plugins/languageclient/languageclientoutline.h index 4ddc9c79c08..6d222f05363 100644 --- a/src/plugins/languageclient/languageclientoutline.h +++ b/src/plugins/languageclient/languageclientoutline.h @@ -6,13 +6,9 @@ #include "languageclient_global.h" #include -#include #include -namespace TextEditor { -class TextDocument; -class BaseTextEditor; -} // namespace TextEditor +namespace TextEditor { class BaseTextEditor; } namespace Utils { class TreeViewComboBox; } namespace LanguageClient { @@ -51,19 +47,8 @@ private: int m_type = -1; }; -class Client; +Utils::TreeViewComboBox *createOutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor); -class LanguageClientOutlineWidgetFactory : public TextEditor::IOutlineWidgetFactory -{ -public: - using IOutlineWidgetFactory::IOutlineWidgetFactory; - - static Utils::TreeViewComboBox *createComboBox(Client *client, TextEditor::BaseTextEditor *editor); - // IOutlineWidgetFactory interface -public: - bool supportsEditor(Core::IEditor *editor) const override; - TextEditor::IOutlineWidget *createWidget(Core::IEditor *editor) override; - bool supportsSorting() const override { return true; } -}; +void setupLanguageClientOutline(); } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientplugin.cpp b/src/plugins/languageclient/languageclientplugin.cpp index 8422635fb33..b8af019f9a5 100644 --- a/src/plugins/languageclient/languageclientplugin.cpp +++ b/src/plugins/languageclient/languageclientplugin.cpp @@ -36,8 +36,6 @@ private: void initialize() final; void extensionsInitialized() final; ShutdownFlag aboutToShutdown() final; - - LanguageClientOutlineWidgetFactory m_outlineFactory; }; void LanguageClientPlugin::initialize() @@ -53,6 +51,7 @@ void LanguageClientPlugin::initialize() setupTypeHierarchyFactory(); setupLanguageClientProjectPanel(); setupLanguageClientManager(this); + setupLanguageClientOutline(); #ifdef WITH_TESTS addTestCreator(&createSnippetParsingTest); diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index e5685e296bc..a8c1a02c4ca 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -296,7 +296,7 @@ void updateEditorToolBar(Core::IEditor *editor) } if (!extras->m_client) { - extras->m_outline = LanguageClientOutlineWidgetFactory::createComboBox(client, textEditor); + extras->m_outline = createOutlineComboBox(client, textEditor); if (extras->m_outline) { widget->setToolbarOutline(extras->m_outline); extras->m_client = client; From 14a7878ff921cc5e3412f55dcafba7830df5c19e Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 13:13:34 +0100 Subject: [PATCH 329/989] QmlJSEditor: Remove some margin around the project settings page It's inconsistent across the different pages, but that majority doesn't seem to have it. Change-Id: Idb8291f529f9afe274e92b366d6783c88b8b72c3 Reviewed-by: David Schulz --- src/plugins/qmljseditor/qmljseditorsettings.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmljseditor/qmljseditorsettings.cpp b/src/plugins/qmljseditor/qmljseditorsettings.cpp index f731e27a0f9..f92a062ff98 100644 --- a/src/plugins/qmljseditor/qmljseditorsettings.cpp +++ b/src/plugins/qmljseditor/qmljseditorsettings.cpp @@ -564,12 +564,13 @@ public: using namespace Layouting; // clang-format off Column { - Group{ + Group { title(Tr::tr("QML Language Server")), - Column{ + Column { &m_settings.useQmlls, }, }, + tight, st, }.attachTo(this); // clang-format on From 379b421796b12d3df7429cec4ba13b7b89e4b6f5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 14:24:44 +0100 Subject: [PATCH 330/989] QmlJSEditor: Simplify QmlJsOutline interface We need only the factory setup public. Also de-Q_OBJECTIFY and remove some unneeded indirection. Change-Id: If3a9c690769eecb9d19f13f7acdd34394d372d42 Reviewed-by: David Schulz --- src/plugins/qmljseditor/qmljseditorplugin.cpp | 2 +- src/plugins/qmljseditor/qmljsoutline.cpp | 140 +++++++++++++----- src/plugins/qmljseditor/qmljsoutline.h | 89 +---------- 3 files changed, 108 insertions(+), 123 deletions(-) diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp index 986ab1346c6..3839765008d 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.cpp +++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp @@ -81,7 +81,6 @@ public: QmlJS::JsonSchemaManager m_jsonManager{ {ICore::userResourcePath("json/").toString(), ICore::resourcePath("json/").toString()}}; - QmlJSOutlineWidgetFactory m_qmlJSOutlineWidgetFactory; QmlJsEditingSettingsPage m_qmJSEditingSettingsPage; }; @@ -330,6 +329,7 @@ class QmlJSEditorPlugin final : public ExtensionSystem::IPlugin { dd = new QmlJSEditorPluginPrivate; + setupQmlJsOutline(); setupQmlJSEditor(); setupQmlJsEditingProjectPanel(); } diff --git a/src/plugins/qmljseditor/qmljsoutline.cpp b/src/plugins/qmljseditor/qmljsoutline.cpp index 51dfb56fa2b..f6ce828061d 100644 --- a/src/plugins/qmljseditor/qmljsoutline.cpp +++ b/src/plugins/qmljseditor/qmljsoutline.cpp @@ -12,9 +12,12 @@ #include #include +#include + #include -#include +#include #include +#include using namespace QmlJS; @@ -22,14 +25,33 @@ enum { debug = false }; -namespace QmlJSEditor { -namespace Internal { +namespace QmlJSEditor::Internal { -QmlJSOutlineFilterModel::QmlJSOutlineFilterModel(QObject *parent) : - QSortFilterProxyModel(parent) +// QmlJSOutlineFilterModel + +class QmlJSOutlineFilterModel final : public QSortFilterProxyModel { - setDynamicSortFilter(true); -} +public: + QmlJSOutlineFilterModel() + { + setDynamicSortFilter(true); + } + + Qt::ItemFlags flags(const QModelIndex &index) const final; + bool filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const final; + bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const final; + QVariant data(const QModelIndex &index, int role) const final; + Qt::DropActions supportedDragActions() const final; + + bool filterBindings() const; + void setFilterBindings(bool filterBindings); + void setSorted(bool sorted); + +private: + bool m_filterBindings = false; + bool m_sorted = false; +}; Qt::ItemFlags QmlJSOutlineFilterModel::flags(const QModelIndex &index) const { @@ -98,14 +120,49 @@ void QmlJSOutlineFilterModel::setSorted(bool sorted) invalidate(); } -QmlJSOutlineWidget::QmlJSOutlineWidget(QWidget *parent) - : TextEditor::IOutlineWidget(parent) - , m_treeView(new QmlJSOutlineTreeView(this)) - , m_filterModel(new QmlJSOutlineFilterModel(this)) -{ - m_filterModel->setFilterBindings(false); +// QmlJSOutlineWidget - m_treeView->setModel(m_filterModel); +class QmlJSOutlineWidget final : public TextEditor::IOutlineWidget +{ +public: + QmlJSOutlineWidget(); + + void setEditor(QmlJSEditorWidget *editor); + + // IOutlineWidget + QList filterMenuActions() const final; + void setCursorSynchronization(bool syncWithCursor) final; + bool isSorted() const final { return m_sorted; }; + void setSorted(bool sorted) final; + void restoreSettings(const QVariantMap &map) final; + QVariantMap settings() const final; + +private: + void updateSelectionInTree(const QModelIndex &index); + void updateSelectionInText(const QItemSelection &selection); + void updateTextCursor(const QModelIndex &index); + void focusEditor(); + void setShowBindings(bool showBindings); + bool syncCursor(); + +private: + QmlJSOutlineTreeView *m_treeView = nullptr; + QmlJSOutlineFilterModel m_filterModel; + QmlJSEditorWidget *m_editor = nullptr; + + QAction *m_showBindingsAction = nullptr; + + bool m_enableCursorSync = true; + bool m_blockCursorSync = false; + bool m_sorted = false; +}; + +QmlJSOutlineWidget::QmlJSOutlineWidget() + : m_treeView(new QmlJSOutlineTreeView(this)) +{ + m_filterModel.setFilterBindings(false); + + m_treeView->setModel(&m_filterModel); m_treeView->setSortingEnabled(true); setFocusProxy(m_treeView); @@ -129,7 +186,7 @@ void QmlJSOutlineWidget::setEditor(QmlJSEditorWidget *editor) { m_editor = editor; - m_filterModel->setSourceModel(m_editor->qmlJsEditorDocument()->outlineModel()); + m_filterModel.setSourceModel(m_editor->qmlJsEditorDocument()->outlineModel()); m_treeView->expandAll(); connect(m_editor->qmlJsEditorDocument()->outlineModel(), &QAbstractItemModel::modelAboutToBeReset, m_treeView, [this] { if (m_treeView->selectionModel()) @@ -173,7 +230,7 @@ void QmlJSOutlineWidget::setCursorSynchronization(bool syncWithCursor) void QmlJSOutlineWidget::setSorted(bool sorted) { m_sorted = sorted; - m_filterModel->setSorted(m_sorted); + m_filterModel.setSorted(m_sorted); } void QmlJSOutlineWidget::restoreSettings(const QVariantMap &map) @@ -199,10 +256,10 @@ void QmlJSOutlineWidget::updateSelectionInTree(const QModelIndex &index) m_blockCursorSync = true; QModelIndex baseIndex = index; - QModelIndex filterIndex = m_filterModel->mapFromSource(baseIndex); + QModelIndex filterIndex = m_filterModel.mapFromSource(baseIndex); while (baseIndex.isValid() && !filterIndex.isValid()) { // Search for ancestor index actually shown baseIndex = baseIndex.parent(); - filterIndex = m_filterModel->mapFromSource(baseIndex); + filterIndex = m_filterModel.mapFromSource(baseIndex); } m_treeView->setCurrentIndex(filterIndex); @@ -226,7 +283,7 @@ void QmlJSOutlineWidget::updateTextCursor(const QModelIndex &index) { const auto update = [this](const QModelIndex &index) { if (!m_editor->isOutlineCursorChangesBlocked()) { - QModelIndex sourceIndex = m_filterModel->mapToSource(index); + QModelIndex sourceIndex = m_filterModel.mapToSource(index); SourceLocation location = m_editor->qmlJsEditorDocument()->outlineModel()->sourceLocation(sourceIndex); @@ -261,7 +318,7 @@ void QmlJSOutlineWidget::focusEditor() void QmlJSOutlineWidget::setShowBindings(bool showBindings) { - m_filterModel->setFilterBindings(!showBindings); + m_filterModel.setFilterBindings(!showBindings); m_treeView->expandAll(); m_editor->updateOutlineIndexNow(); } @@ -271,25 +328,36 @@ bool QmlJSOutlineWidget::syncCursor() return m_enableCursorSync && !m_blockCursorSync; } -bool QmlJSOutlineWidgetFactory::supportsEditor(Core::IEditor *editor) const +class QmlJSOutlineWidgetFactory final : public TextEditor::IOutlineWidgetFactory { - if (qobject_cast(editor)) +public: + bool supportsEditor(Core::IEditor *editor) const final + { + return bool(qobject_cast(editor)); + } + + bool supportsSorting() const final + { return true; - return false; -} + } -TextEditor::IOutlineWidget *QmlJSOutlineWidgetFactory::createWidget(Core::IEditor *editor) + TextEditor::IOutlineWidget *createWidget(Core::IEditor *editor) final + { + auto widget = new QmlJSOutlineWidget; + + auto qmlJSEditable = qobject_cast(editor); + auto qmlJSEditor = qobject_cast(qmlJSEditable->widget()); + Q_ASSERT(qmlJSEditor); + + widget->setEditor(qmlJSEditor); + + return widget; + } +}; + +void setupQmlJsOutline() { - auto widget = new QmlJSOutlineWidget; - - auto qmlJSEditable = qobject_cast(editor); - auto qmlJSEditor = qobject_cast(qmlJSEditable->widget()); - Q_ASSERT(qmlJSEditor); - - widget->setEditor(qmlJSEditor); - - return widget; + static QmlJSOutlineWidgetFactory theQmlJSOutlineWidgetFactory; } -} // namespace Internal -} // namespace QmlJSEditor +} // namespace QmlJSEditor::Internal diff --git a/src/plugins/qmljseditor/qmljsoutline.h b/src/plugins/qmljseditor/qmljsoutline.h index 88c79b2d844..fbb58ed32a2 100644 --- a/src/plugins/qmljseditor/qmljsoutline.h +++ b/src/plugins/qmljseditor/qmljsoutline.h @@ -3,91 +3,8 @@ #pragma once -#include +namespace QmlJSEditor::Internal { -#include +void setupQmlJsOutline(); -QT_BEGIN_NAMESPACE -class QAction; -QT_END_NAMESPACE - -namespace Core { class IEditor; } - -namespace QmlJS { class Editor; } - -namespace QmlJSEditor { - -class QmlJSEditorWidget; - -namespace Internal { - -class QmlJSOutlineTreeView; - -class QmlJSOutlineFilterModel : public QSortFilterProxyModel -{ - Q_OBJECT -public: - QmlJSOutlineFilterModel(QObject *parent); - // QSortFilterProxyModel - Qt::ItemFlags flags(const QModelIndex &index) const override; - bool filterAcceptsRow(int sourceRow, - const QModelIndex &sourceParent) const override; - bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override; - QVariant data(const QModelIndex &index, int role) const override; - Qt::DropActions supportedDragActions() const override; - - bool filterBindings() const; - void setFilterBindings(bool filterBindings); - void setSorted(bool sorted); -private: - bool m_filterBindings = false; - bool m_sorted = false; -}; - -class QmlJSOutlineWidget : public TextEditor::IOutlineWidget -{ - Q_OBJECT -public: - QmlJSOutlineWidget(QWidget *parent = nullptr); - - void setEditor(QmlJSEditorWidget *editor); - - // IOutlineWidget - QList filterMenuActions() const override; - void setCursorSynchronization(bool syncWithCursor) override; - bool isSorted() const override { return m_sorted; }; - void setSorted(bool sorted) override; - void restoreSettings(const QVariantMap &map) override; - QVariantMap settings() const override; - -private: - void updateSelectionInTree(const QModelIndex &index); - void updateSelectionInText(const QItemSelection &selection); - void updateTextCursor(const QModelIndex &index); - void focusEditor(); - void setShowBindings(bool showBindings); - bool syncCursor(); - -private: - QmlJSOutlineTreeView *m_treeView = nullptr; - QmlJSOutlineFilterModel *m_filterModel = nullptr; - QmlJSEditorWidget *m_editor = nullptr; - - QAction *m_showBindingsAction = nullptr; - - bool m_enableCursorSync = true; - bool m_blockCursorSync = false; - bool m_sorted = false; -}; - -class QmlJSOutlineWidgetFactory : public TextEditor::IOutlineWidgetFactory -{ - Q_OBJECT -public: - bool supportsEditor(Core::IEditor *editor) const override; - bool supportsSorting() const override { return true; } - TextEditor::IOutlineWidget *createWidget(Core::IEditor *editor) override; -}; - -} // namespace Internal -} // namespace QmlJSEditor +} // namespace QmlJSEditor::Internal From a3e40cc8e14cbe55ed09262d9fab854e9f210b9e Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Sun, 1 Dec 2024 19:55:52 +0100 Subject: [PATCH 331/989] QtSupport: Adapt Core.json parsing to android_x86 Fixes "Could not determine target architecture" error message. modules/Core.json of android_x86 Qt installations says "architecture": "i386" This adds "i386" as "x86" alias to getArch. Change-Id: I769888eae83a6938cacab3ae296b1965b8a453f7 Reviewed-by: Joerg Bornemann --- src/plugins/qtsupport/qtabiextractor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qtsupport/qtabiextractor.cpp b/src/plugins/qtsupport/qtabiextractor.cpp index 00c4388f713..8661bed78e2 100644 --- a/src/plugins/qtsupport/qtabiextractor.cpp +++ b/src/plugins/qtsupport/qtabiextractor.cpp @@ -122,7 +122,7 @@ private: std::pair getArch(const QString &archString) { - if (archString == "x86") + if (archString == "x86" || archString == "i386") return std::make_pair(Abi::X86Architecture, 32); if (archString == "x86_64") return std::make_pair(Abi::X86Architecture, 64); From 3468a5c29829da064c40730653646b6264201759 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 15:25:53 +0100 Subject: [PATCH 332/989] ProjectExplorer: Un-seat NamedWidget from ProjectSettingsWidget again Amends 7954c4cc6998. The NamedWidgets are shown on the BuildSettings page, the ProjectSettingsWidgets on the lower left in ProjectMode, they are not really related. Change-Id: I64c3e95b82bb49932823ae0a8dae052d3a6a09c9 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/namedwidget.cpp | 2 +- src/plugins/projectexplorer/namedwidget.h | 3 +-- src/plugins/projectexplorer/projectexplorer.cpp | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/projectexplorer/namedwidget.cpp b/src/plugins/projectexplorer/namedwidget.cpp index c76a6dab771..1047224e663 100644 --- a/src/plugins/projectexplorer/namedwidget.cpp +++ b/src/plugins/projectexplorer/namedwidget.cpp @@ -6,7 +6,7 @@ namespace ProjectExplorer { NamedWidget::NamedWidget(const QString &displayName, QWidget *parent) - : ProjectSettingsWidget(parent), m_displayName(displayName) + : QWidget(parent), m_displayName(displayName) { } diff --git a/src/plugins/projectexplorer/namedwidget.h b/src/plugins/projectexplorer/namedwidget.h index 2551c8b56de..e67854d9230 100644 --- a/src/plugins/projectexplorer/namedwidget.h +++ b/src/plugins/projectexplorer/namedwidget.h @@ -4,13 +4,12 @@ #pragma once #include "projectexplorer_export.h" -#include "projectsettingswidget.h" #include namespace ProjectExplorer { -class PROJECTEXPLORER_EXPORT NamedWidget : public ProjectSettingsWidget +class PROJECTEXPLORER_EXPORT NamedWidget : public QWidget { public: explicit NamedWidget(const QString &displayName, QWidget *parent = nullptr); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 6d3ca9fb772..7f9f09201dd 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -372,10 +372,10 @@ public: } }; -class ProjectEnvironmentWidget : public NamedWidget +class ProjectEnvironmentWidget : public ProjectSettingsWidget { public: - explicit ProjectEnvironmentWidget(Project *project) : NamedWidget(Tr::tr("Project Environment")) + explicit ProjectEnvironmentWidget(Project *project) { setUseGlobalSettingsCheckBoxVisible(false); setUseGlobalSettingsLabelVisible(false); @@ -399,7 +399,7 @@ public: ProjectEnvironmentPanelFactory() { setPriority(60); - setDisplayName(Tr::tr("Environment")); + setDisplayName(Tr::tr("Project Environment")); setCreateWidgetFunction([](Project *project) { return new ProjectEnvironmentWidget(project); }); From 4585c8ab8bec3e76db941fbb7d6d9a78a2c7cf52 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 16:27:05 +0100 Subject: [PATCH 333/989] ProjectExplorer: Dismantle NamedWidget ... which was really just a widget with a name. Providing the name separately simplifies the code and makes the setup structurally more similar to the BaseAspect::addToLayout() machinery. Change-Id: I0c528e0afb3c22eb0acac8f181cc36a6ab74d95b Reviewed-by: Christian Kandeler --- .../cmakebuildconfiguration.cpp | 7 ++-- .../cmakebuildconfiguration.h | 4 +- .../compilationdatabaseproject.cpp | 1 - .../haskell/haskellbuildconfiguration.cpp | 9 ++--- src/plugins/ios/iosbuildconfiguration.cpp | 35 +++++++----------- .../mesonbuildconfiguration.cpp | 8 ++-- .../mesonbuildconfiguration.h | 2 +- src/plugins/projectexplorer/CMakeLists.txt | 1 - .../projectexplorer/buildconfiguration.cpp | 37 ++++++++----------- .../projectexplorer/buildconfiguration.h | 10 ++--- .../buildsettingspropertiespage.cpp | 12 +++--- .../buildsettingspropertiespage.h | 5 +-- .../projectexplorer/buildstepspage.cpp | 3 +- src/plugins/projectexplorer/buildstepspage.h | 4 +- src/plugins/projectexplorer/namedwidget.cpp | 18 --------- src/plugins/projectexplorer/namedwidget.h | 23 ------------ .../projectexplorer/projectexplorer.cpp | 1 - .../projectexplorer/projectexplorer.qbs | 1 - .../python/pythonbuildconfiguration.cpp | 7 ++-- src/plugins/python/pythonbuildconfiguration.h | 2 +- 20 files changed, 63 insertions(+), 127 deletions(-) delete mode 100644 src/plugins/projectexplorer/namedwidget.cpp delete mode 100644 src/plugins/projectexplorer/namedwidget.h diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index f920c647757..786a5e9493e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -111,7 +110,7 @@ const char VXWORKS_DEVICE_TYPE[] = "VxWorks.Device.Type"; namespace Internal { -class CMakeBuildSettingsWidget : public NamedWidget +class CMakeBuildSettingsWidget : public QWidget { public: explicit CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc); @@ -193,7 +192,6 @@ static CMakeConfigItem getPackageManagerAutoSetupParameter() } CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) : - NamedWidget(Tr::tr("CMake")), m_buildConfig(bc), m_configModel(new ConfigModel(this)), m_configFilterModel(new CategorySortFilterModel(this)), @@ -1408,6 +1406,7 @@ static Utils::EnvironmentItems getEnvironmentItemsFromCMakeBuildPreset( CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) : BuildConfiguration(target, id) { + setConfigWidgetDisplayName(Tr::tr("CMake")); m_buildSystem = new CMakeBuildSystem(this); buildDirectoryAspect()->setValueAcceptor( @@ -1839,7 +1838,7 @@ QString CMakeBuildSystem::warning() const return m_warning; } -NamedWidget *CMakeBuildConfiguration::createConfigWidget() +QWidget *CMakeBuildConfiguration::createConfigWidget() { m_configWidget = new CMakeBuildSettingsWidget(this); return m_configWidget; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index 532261aca02..62d733a8834 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -105,9 +105,7 @@ signals: private: BuildType buildType() const override; - - ProjectExplorer::NamedWidget *createConfigWidget() override; - + QWidget *createConfigWidget() override; virtual CMakeConfig signingFlags() const; void setInitialBuildAndCleanSteps(const ProjectExplorer::Target *target); diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp index 7d4752d4407..4f418e452c0 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/haskell/haskellbuildconfiguration.cpp b/src/plugins/haskell/haskellbuildconfiguration.cpp index bb8ef948705..05d5adf45dd 100644 --- a/src/plugins/haskell/haskellbuildconfiguration.cpp +++ b/src/plugins/haskell/haskellbuildconfiguration.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -34,6 +33,7 @@ public: HaskellBuildConfiguration(Target *target, Utils::Id id) : BuildConfiguration(target, id) { + setConfigWidgetDisplayName(Tr::tr("General")); setInitializer([this](const BuildInfo &info) { setBuildDirectory(info.buildDirectory); setBuildType(info.buildType); @@ -42,7 +42,7 @@ public: appendInitialBuildStep(Constants::C_STACK_BUILD_STEP_ID); } - NamedWidget *createConfigWidget() final; + QWidget *createConfigWidget() final; BuildType buildType() const final { @@ -58,11 +58,10 @@ private: BuildType m_buildType = BuildType::Release; }; -class HaskellBuildConfigurationWidget final : public NamedWidget +class HaskellBuildConfigurationWidget final : public QWidget { public: HaskellBuildConfigurationWidget(HaskellBuildConfiguration *bc) - : NamedWidget(Tr::tr("General")) { setLayout(new QVBoxLayout); layout()->setContentsMargins(0, 0, 0, 0); @@ -95,7 +94,7 @@ public: } }; -NamedWidget *HaskellBuildConfiguration::createConfigWidget() +QWidget *HaskellBuildConfiguration::createConfigWidget() { return new HaskellBuildConfigurationWidget(this); } diff --git a/src/plugins/ios/iosbuildconfiguration.cpp b/src/plugins/ios/iosbuildconfiguration.cpp index eadda24575c..bbca70a263e 100644 --- a/src/plugins/ios/iosbuildconfiguration.cpp +++ b/src/plugins/ios/iosbuildconfiguration.cpp @@ -8,7 +8,6 @@ #include "iostr.h" #include -#include #include #include @@ -44,7 +43,7 @@ const char autoManagedSigningKey[] = "Ios.AutoManagedSigning"; const int IdentifierRole = Qt::UserRole+1; -class IosSigningSettingsWidget final : public NamedWidget +class IosSigningSettingsWidget final : public QWidget { public: explicit IosSigningSettingsWidget(BuildConfiguration *buildConfiguration, @@ -84,8 +83,7 @@ private: IosSigningSettingsWidget::IosSigningSettingsWidget(BuildConfiguration *buildConfiguration, BoolAspect *autoManagedSigning, StringAspect *signingIdentifier) - : NamedWidget(Tr::tr("iOS Settings")) - , m_autoManagedSigning(autoManagedSigning) + : m_autoManagedSigning(autoManagedSigning) , m_signingIdentifier(signingIdentifier) , m_isDevice(RunDeviceTypeKitAspect::deviceTypeId(buildConfiguration->kit()) == Constants::IOS_DEVICE_TYPE) @@ -376,7 +374,7 @@ public: IosQmakeBuildConfiguration(Target *target, Id id); private: - QList createSubConfigWidgets() final; + void addSubConfigWidgets(const BuildConfiguration::WidgetAdder &adder) final; void fromMap(const Store &map) final; void updateQmakeCommand(); @@ -403,16 +401,13 @@ IosQmakeBuildConfiguration::IosQmakeBuildConfiguration(Target *target, Id id) &IosQmakeBuildConfiguration::updateQmakeCommand); } -QList IosQmakeBuildConfiguration::createSubConfigWidgets() +void IosQmakeBuildConfiguration::addSubConfigWidgets(const BuildConfiguration::WidgetAdder &adder) { - auto subConfigWidgets = QmakeBuildConfiguration::createSubConfigWidgets(); - // Ownership of this widget is with BuildSettingsWidget - auto buildSettingsWidget = new IosSigningSettingsWidget(this, - &m_autoManagedSigning, - &m_signingIdentifier); - subConfigWidgets.prepend(buildSettingsWidget); - return subConfigWidgets; + adder(new IosSigningSettingsWidget(this, &m_autoManagedSigning, &m_signingIdentifier), + Tr::tr("iOS Settings")); + + QmakeBuildConfiguration::addSubConfigWidgets(adder); } void IosQmakeBuildConfiguration::fromMap(const Store &map) @@ -493,7 +488,7 @@ public: IosCMakeBuildConfiguration(Target *target, Id id); private: - QList createSubConfigWidgets() final; + void addSubConfigWidgets(const BuildConfiguration::WidgetAdder &adder) final; CMakeProjectManager::CMakeConfig signingFlags() const final; @@ -519,16 +514,12 @@ IosCMakeBuildConfiguration::IosCMakeBuildConfiguration(Target *target, Id id) &IosCMakeBuildConfiguration::signingFlagsChanged); } -QList IosCMakeBuildConfiguration::createSubConfigWidgets() +void IosCMakeBuildConfiguration::addSubConfigWidgets(const WidgetAdder &adder) { - auto subConfigWidgets = CMakeBuildConfiguration::createSubConfigWidgets(); - // Ownership of this widget is with BuildSettingsWidget - auto buildSettingsWidget = new IosSigningSettingsWidget(this, - &m_autoManagedSigning, - &m_signingIdentifier); - subConfigWidgets.prepend(buildSettingsWidget); - return subConfigWidgets; + adder(new IosSigningSettingsWidget(this, &m_autoManagedSigning, &m_signingIdentifier), + Tr::tr("iOS Settings")); + CMakeBuildConfiguration::addSubConfigWidgets(adder); } CMakeConfig IosCMakeBuildConfiguration::signingFlags() const diff --git a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp index 385d9b13edc..324443d72bc 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp +++ b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -70,6 +69,7 @@ static FilePath shadowBuildDirectory(const FilePath &projectFilePath, MesonBuildConfiguration::MesonBuildConfiguration(ProjectExplorer::Target *target, Id id) : BuildConfiguration(target, id) { + setConfigWidgetDisplayName(Tr::tr("Meson")); appendInitialBuildStep(Constants::MESON_BUILD_STEP_ID); appendInitialCleanStep(Constants::MESON_BUILD_STEP_ID); setInitializer([this, target](const ProjectExplorer::BuildInfo &info) { @@ -152,11 +152,11 @@ void MesonBuildConfiguration::fromMap(const Store &map) m_parameters = map.value(Constants::BuildConfiguration::PARAMETERS_KEY).toString(); } -class MesonBuildSettingsWidget : public NamedWidget +class MesonBuildSettingsWidget : public QWidget { public: explicit MesonBuildSettingsWidget(MesonBuildConfiguration *buildCfg) - : NamedWidget(Tr::tr("Meson")), m_progressIndicator(ProgressIndicatorSize::Large) + : m_progressIndicator(ProgressIndicatorSize::Large) { auto configureButton = new QPushButton(Tr::tr("Apply Configuration Changes")); configureButton->setEnabled(false); @@ -300,7 +300,7 @@ private: QTimer m_showProgressTimer; }; -NamedWidget *MesonBuildConfiguration::createConfigWidget() +QWidget *MesonBuildConfiguration::createConfigWidget() { return new MesonBuildSettingsWidget{this}; } diff --git a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.h b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.h index 2ec2f9e00f4..58dea025811 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.h +++ b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.h @@ -34,7 +34,7 @@ private: void fromMap(const Utils::Store &map) override; MesonBuildType m_buildType; - ProjectExplorer::NamedWidget *createConfigWidget() final; + QWidget *createConfigWidget() final; MesonBuildSystem *m_buildSystem = nullptr; QString m_parameters; }; diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index bcd866cb5d3..70425459af4 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -116,7 +116,6 @@ add_qtc_plugin(ProjectExplorer miniprojecttargetselector.cpp miniprojecttargetselector.h msvcparser.cpp msvcparser.h msvctoolchain.cpp msvctoolchain.h - namedwidget.cpp namedwidget.h osparser.cpp osparser.h panelswidget.cpp panelswidget.h parseissuesdialog.cpp parseissuesdialog.h diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 9f2e3b32fda..1f076e0751b 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -13,7 +13,6 @@ #include "devicesupport/devicekitaspects.h" #include "environmentwidget.h" #include "kit.h" -#include "namedwidget.h" #include "projectexplorerconstants.h" #include "projectexplorer.h" #include "projectexplorertr.h" @@ -54,12 +53,10 @@ Q_LOGGING_CATEGORY(bcLog, "qtc.buildconfig", QtWarningMsg) namespace ProjectExplorer { namespace Internal { -class BuildEnvironmentWidget : public NamedWidget +class BuildEnvironmentWidget : public QWidget { - public: explicit BuildEnvironmentWidget(BuildConfiguration *bc) - : NamedWidget(Tr::tr("Build Environment")) { auto clearBox = new QCheckBox(Tr::tr("Clear system environment"), this); clearBox->setChecked(!bc->useSystemEnvironment()); @@ -97,10 +94,10 @@ public: } }; -class CustomParsersBuildWidget : public NamedWidget +class CustomParsersBuildWidget : public QWidget { public: - CustomParsersBuildWidget(BuildConfiguration *bc) : NamedWidget(Tr::tr("Custom Output Parsers")) + CustomParsersBuildWidget(BuildConfiguration *bc) { const auto layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -254,17 +251,17 @@ void BuildConfiguration::setBuildDirectory(const FilePath &dir) emitBuildDirectoryChanged(); } -void BuildConfiguration::addConfigWidgets(const std::function &adder) +void BuildConfiguration::addConfigWidgets(const WidgetAdder &adder) { - if (NamedWidget *generalConfigWidget = createConfigWidget()) - adder(generalConfigWidget); + if (QWidget *generalConfigWidget = createConfigWidget()) + adder(generalConfigWidget, d->m_configWidgetDisplayName); - adder(new Internal::BuildStepListWidget(buildSteps())); - adder(new Internal::BuildStepListWidget(cleanSteps())); + //: %1 is the name returned by BuildStepList::displayName + const QString title = Tr::tr("%1 Steps"); + adder(new Internal::BuildStepListWidget(buildSteps()), title.arg(buildSteps()->displayName())); + adder(new Internal::BuildStepListWidget(cleanSteps()), title.arg(cleanSteps()->displayName())); - const QList subConfigWidgets = createSubConfigWidgets(); - for (NamedWidget *subConfigWidget : subConfigWidgets) - adder(subConfigWidget); + addSubConfigWidgets(adder); } void BuildConfiguration::doInitialize(const BuildInfo &info) @@ -316,9 +313,9 @@ void BuildConfiguration::setInitializer(const std::functionm_initializer = initializer; } -NamedWidget *BuildConfiguration::createConfigWidget() +QWidget *BuildConfiguration::createConfigWidget() { - NamedWidget *named = new NamedWidget(d->m_configWidgetDisplayName); + QWidget *named = new QWidget; QWidget *widget = nullptr; @@ -348,12 +345,10 @@ NamedWidget *BuildConfiguration::createConfigWidget() return named; } -QList BuildConfiguration::createSubConfigWidgets() +void BuildConfiguration::addSubConfigWidgets(const WidgetAdder &adder) { - return { - new Internal::BuildEnvironmentWidget(this), - new Internal::CustomParsersBuildWidget(this) - }; + adder(new Internal::BuildEnvironmentWidget(this), Tr::tr("Build Environment")); + adder(new Internal::CustomParsersBuildWidget(this), Tr::tr("Custom Output Parsers")); } BuildSystem *BuildConfiguration::buildSystem() const diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h index 4f9ed30fe79..1e0f2fa097e 100644 --- a/src/plugins/projectexplorer/buildconfiguration.h +++ b/src/plugins/projectexplorer/buildconfiguration.h @@ -21,7 +21,6 @@ class BuildInfo; class BuildSystem; class BuildStepList; class Kit; -class NamedWidget; class Node; class RunConfiguration; class Target; @@ -43,8 +42,11 @@ public: virtual BuildSystem *buildSystem() const; - virtual NamedWidget *createConfigWidget(); - virtual QList createSubConfigWidgets(); + virtual QWidget *createConfigWidget(); + + using WidgetAdder = std::function; + void addConfigWidgets(const WidgetAdder &adder); + virtual void addSubConfigWidgets(const WidgetAdder &adder); // Maybe the BuildConfiguration is not the best place for the environment Utils::Environment baseEnvironment() const; @@ -107,8 +109,6 @@ public: void setConfigWidgetHasFrame(bool configWidgetHasFrame); void setBuildDirectorySettingsKey(const Utils::Key &key); - void addConfigWidgets(const std::function &adder); - void doInitialize(const BuildInfo &info); bool createBuildDirectory(); diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp index c3000ca5bcb..a253fe8daff 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp @@ -6,7 +6,6 @@ #include "buildconfiguration.h" #include "buildinfo.h" #include "buildmanager.h" -#include "namedwidget.h" #include "project.h" #include "projectconfigurationmodel.h" #include "projectexplorertr.h" @@ -121,13 +120,13 @@ BuildSettingsWidget::BuildSettingsWidget(Target *target) : connect(m_target, &Target::kitChanged, this, &BuildSettingsWidget::updateAddButtonMenu); } -void BuildSettingsWidget::addSubWidget(NamedWidget *widget) +void BuildSettingsWidget::addSubWidget(QWidget *widget, const QString &displayName) { widget->setParent(this); widget->setContentsMargins(0, 2, 0, 0); auto label = new QLabel(this); - label->setText(widget->displayName()); + label->setText(displayName); label->setFont(StyleHelper::uiFont(StyleHelper::UiElementH4)); label->setContentsMargins(0, 18, 0, 0); @@ -174,8 +173,11 @@ void BuildSettingsWidget::updateBuildSettings() m_renameButton->setEnabled(!bcs.isEmpty()); m_cloneButton->setEnabled(!bcs.isEmpty()); - if (m_buildConfiguration) - m_buildConfiguration->addConfigWidgets([this](NamedWidget *w) { addSubWidget(w); }); + if (m_buildConfiguration) { + m_buildConfiguration->addConfigWidgets([this](QWidget *w, const QString &displayName) { + addSubWidget(w, displayName); + }); + } } void BuildSettingsWidget::currentIndexChanged(int index) diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.h b/src/plugins/projectexplorer/buildsettingspropertiespage.h index 1f02aa47aa9..7451ed43363 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.h +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.h @@ -16,7 +16,6 @@ namespace ProjectExplorer { class BuildConfiguration; class BuildInfo; -class NamedWidget; class Target; namespace Internal { @@ -29,7 +28,7 @@ public: ~BuildSettingsWidget() override; void clearWidgets(); - void addSubWidget(NamedWidget *widget); + void addSubWidget(QWidget *widget, const QString &displayName); private: void updateBuildSettings(); @@ -56,7 +55,7 @@ private: QComboBox *m_buildConfigurationComboBox = nullptr; QMenu *m_addButtonMenu = nullptr; - QList m_subWidgets; + QList m_subWidgets; QList m_labels; }; diff --git a/src/plugins/projectexplorer/buildstepspage.cpp b/src/plugins/projectexplorer/buildstepspage.cpp index 0971de90eaa..dc799752168 100644 --- a/src/plugins/projectexplorer/buildstepspage.cpp +++ b/src/plugins/projectexplorer/buildstepspage.cpp @@ -167,8 +167,7 @@ BuildStepsWidgetData::~BuildStepsWidgetData() } BuildStepListWidget::BuildStepListWidget(BuildStepList *bsl) - //: %1 is the name returned by BuildStepList::displayName - : NamedWidget(Tr::tr("%1 Steps").arg(bsl->displayName())), m_buildStepList(bsl) + : m_buildStepList(bsl) { setupUi(); diff --git a/src/plugins/projectexplorer/buildstepspage.h b/src/plugins/projectexplorer/buildstepspage.h index 165dfb1497a..f4b9eb1c716 100644 --- a/src/plugins/projectexplorer/buildstepspage.h +++ b/src/plugins/projectexplorer/buildstepspage.h @@ -4,7 +4,7 @@ #pragma once #include "buildstep.h" -#include "namedwidget.h" + #include QT_BEGIN_NAMESPACE @@ -65,7 +65,7 @@ public: ToolWidget *toolWidget; }; -class BuildStepListWidget : public NamedWidget +class BuildStepListWidget : public QWidget { Q_OBJECT diff --git a/src/plugins/projectexplorer/namedwidget.cpp b/src/plugins/projectexplorer/namedwidget.cpp deleted file mode 100644 index 1047224e663..00000000000 --- a/src/plugins/projectexplorer/namedwidget.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "namedwidget.h" - -namespace ProjectExplorer { - -NamedWidget::NamedWidget(const QString &displayName, QWidget *parent) - : QWidget(parent), m_displayName(displayName) -{ -} - -QString NamedWidget::displayName() const -{ - return m_displayName; -} - -} // ProjectExplorer diff --git a/src/plugins/projectexplorer/namedwidget.h b/src/plugins/projectexplorer/namedwidget.h deleted file mode 100644 index e67854d9230..00000000000 --- a/src/plugins/projectexplorer/namedwidget.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "projectexplorer_export.h" - -#include - -namespace ProjectExplorer { - -class PROJECTEXPLORER_EXPORT NamedWidget : public QWidget -{ -public: - explicit NamedWidget(const QString &displayName, QWidget *parent = nullptr); - - QString displayName() const; - -private: - QString m_displayName; -}; - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 7f9f09201dd..80535e5c958 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -52,7 +52,6 @@ #include "kitfeatureprovider.h" #include "kitmanager.h" #include "miniprojecttargetselector.h" -#include "namedwidget.h" #include "outputparser_test.h" #include "parseissuesdialog.h" #include "processstep.h" diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index fa2c8dea645..ce6ba8ab597 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -90,7 +90,6 @@ QtcPlugin { "miniprojecttargetselector.cpp", "miniprojecttargetselector.h", "msvcparser.cpp", "msvcparser.h", "msvctoolchain.cpp", "msvctoolchain.h", - "namedwidget.cpp", "namedwidget.h", "osparser.cpp", "osparser.h", "panelswidget.cpp", "panelswidget.h", "parseissuesdialog.cpp", "parseissuesdialog.h", diff --git a/src/plugins/python/pythonbuildconfiguration.cpp b/src/plugins/python/pythonbuildconfiguration.cpp index 7affc59950a..6297104ddf9 100644 --- a/src/plugins/python/pythonbuildconfiguration.cpp +++ b/src/plugins/python/pythonbuildconfiguration.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -211,11 +210,10 @@ Id PySideBuildStep::id() return Id("Python.PysideBuildStep"); } -class PythonBuildSettingsWidget : public NamedWidget +class PythonBuildSettingsWidget : public QWidget { public: PythonBuildSettingsWidget(PythonBuildConfiguration *bc) - : NamedWidget(Tr::tr("Python")) { using namespace Layouting; m_configureDetailsWidget = new DetailsWidget; @@ -262,6 +260,7 @@ PythonBuildConfiguration::PythonBuildConfiguration(Target *target, const Id &id) , m_buildSystem(std::make_unique(this)) { setInitializer([this](const BuildInfo &info) { initialize(info); }); + setConfigWidgetDisplayName(Tr::tr("Python")); updateCacheAndEmitEnvironmentChanged(); @@ -288,7 +287,7 @@ PythonBuildConfiguration::PythonBuildConfiguration(Target *target, const Id &id) &PythonBuildConfiguration::handlePythonUpdated); } -NamedWidget *PythonBuildConfiguration::createConfigWidget() +QWidget *PythonBuildConfiguration::createConfigWidget() { return new PythonBuildSettingsWidget(this); } diff --git a/src/plugins/python/pythonbuildconfiguration.h b/src/plugins/python/pythonbuildconfiguration.h index 9696722d0bc..ede4bfe077d 100644 --- a/src/plugins/python/pythonbuildconfiguration.h +++ b/src/plugins/python/pythonbuildconfiguration.h @@ -52,7 +52,7 @@ class PythonBuildConfiguration : public ProjectExplorer::BuildConfiguration public: PythonBuildConfiguration(ProjectExplorer::Target *target, const Utils::Id &id); - ProjectExplorer::NamedWidget *createConfigWidget() override; + QWidget *createConfigWidget() override; void fromMap(const Utils::Store &map) override; void toMap(Utils::Store &map) const override; ProjectExplorer::BuildSystem *buildSystem() const override; From 743709f31e9bd0599d479f676970d5877567d56d Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 18:02:49 +0100 Subject: [PATCH 334/989] ProjectExplorer: Un-export PanelsWidget ... and restrict interface to what is used. Change-Id: Ifbcfcbdcaf5b777ca870a8605dd00039715ca620 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/panelswidget.cpp | 18 +++++----------- src/plugins/projectexplorer/panelswidget.h | 22 ++++++++------------ 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/plugins/projectexplorer/panelswidget.cpp b/src/plugins/projectexplorer/panelswidget.cpp index 35198c422b2..4baf92d6159 100644 --- a/src/plugins/projectexplorer/panelswidget.cpp +++ b/src/plugins/projectexplorer/panelswidget.cpp @@ -13,26 +13,18 @@ #include #include #include -#include #include #include using namespace Utils; -namespace ProjectExplorer { -namespace { +namespace ProjectExplorer::Internal { const int ABOVE_HEADING_MARGIN = 10; const int CONTENTS_MARGIN = 5; const int BELOW_CONTENTS_MARGIN = 16; -} - -/// -// PanelsWidget -/// - -PanelsWidget::PanelsWidget(QWidget *parent, bool addStretch) : QWidget(parent) +PanelsWidget::PanelsWidget(bool addStretch) { m_root = new QWidget(nullptr); m_root->setFocusPolicy(Qt::NoFocus); @@ -66,14 +58,14 @@ PanelsWidget::PanelsWidget(QWidget *parent, bool addStretch) : QWidget(parent) } PanelsWidget::PanelsWidget(const QString &displayName, QWidget *widget, bool addStretch) - : PanelsWidget(nullptr, addStretch) + : PanelsWidget(addStretch) { addPropertiesPanel(displayName); addWidget(widget); } PanelsWidget::PanelsWidget(const QString &displayName, ProjectSettingsWidget *widget) - : PanelsWidget(nullptr, !widget->expanding()) + : PanelsWidget(!widget->expanding()) { addPropertiesPanel(displayName); addGlobalSettingsProperties(widget); @@ -156,4 +148,4 @@ void PanelsWidget::addGlobalSettingsProperties(ProjectSettingsWidget *widget) m_layout->addWidget(Layouting::createHr()); } -} // ProjectExplorer +} // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/panelswidget.h b/src/plugins/projectexplorer/panelswidget.h index 64ef56265df..8abb08624ee 100644 --- a/src/plugins/projectexplorer/panelswidget.h +++ b/src/plugins/projectexplorer/panelswidget.h @@ -3,36 +3,32 @@ #pragma once -#include "projectexplorer_export.h" #include "projectsettingswidget.h" -#include - QT_BEGIN_NAMESPACE class QVBoxLayout; QT_END_NAMESPACE -namespace ProjectExplorer { +namespace ProjectExplorer::Internal { -class PROJECTEXPLORER_EXPORT PanelsWidget : public QWidget +class PanelsWidget final : public QWidget { - Q_OBJECT + explicit PanelsWidget(bool addStretch); public: - explicit PanelsWidget(QWidget *parent = nullptr, bool addStretch = true); PanelsWidget(const QString &displayName, QWidget *widget, bool addStretch = true); PanelsWidget(const QString &displayName, ProjectSettingsWidget *widget); - ~PanelsWidget() override; - - void addPropertiesPanel(const QString &displayName); - void addGlobalSettingsProperties(ProjectSettingsWidget *widget); - void addWidget(QWidget *widget); + ~PanelsWidget() final; static int constexpr PanelVMargin = 14; private: + void addPropertiesPanel(const QString &displayName); + void addGlobalSettingsProperties(ProjectSettingsWidget *widget); + void addWidget(QWidget *widget); + QVBoxLayout *m_layout; QWidget *m_root; }; -} // namespace ProjectExplorer +} // ProjectExplorer::Internal From bea44886fb26b79396d2d8ee52007da5d5b518ba Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 2 Dec 2024 09:27:48 +0100 Subject: [PATCH 335/989] Axivion: Use less irritating text Change-Id: I0930092da3940b312220670ba36d513ede18c845 Reviewed-by: Eike Ziller --- src/plugins/axivion/axivionperspective.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionperspective.cpp b/src/plugins/axivion/axivionperspective.cpp index ffd1b19a42c..f175fe48871 100644 --- a/src/plugins/axivion/axivionperspective.cpp +++ b/src/plugins/axivion/axivionperspective.cpp @@ -1000,7 +1000,7 @@ void AxivionPerspective::initPerspective() auto showIssuesAct = new QAction(this); showIssuesAct->setIcon(MARKER_ICON.icon()); - showIssuesAct->setToolTip(Tr::tr("Show Inline Issues")); + showIssuesAct->setToolTip(Tr::tr("Show Issues in Editor")); showIssuesAct->setCheckable(true); showIssuesAct->setChecked(true); connect(showIssuesAct, &QAction::toggled, From 31023a7a4ec27e3e3acb64e34133715731b0266e Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Tue, 3 Dec 2024 11:09:21 +0100 Subject: [PATCH 336/989] Debugger: Dumper test GCC version determination When determining the GCC version we did not use the same environment that the tests actually use. As a bonus: an attempt to narrow down UnboundLocalError that occurs in the QXmlAttributes test in the Win 10 + MinGW + Qt5 test plan and which I cannot reproduce locally. Change-Id: Ib12b66091eed7b27871c0bed59d8de019ee2285b Reviewed-by: Christian Stenger --- share/qtcreator/debugger/gdbbridge.py | 2 ++ tests/auto/debugger/tst_dumpers.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index fec4ee84b3d..967d1ce3921 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -1179,6 +1179,8 @@ class Dumper(DumperBase): return self.qtNamespace() + 'Qt::' + enumValue def lookupNativeType(self, type_name): + typeobj = None + if type_name == 'void': typeobj = gdb.lookup_type(type_name) self.typesToReport[type_name] = typeobj diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 5dad15185b3..da0b895ac8a 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1428,6 +1428,7 @@ void tst_Dumpers::dumper() if (data.neededGccVersion.isRestricted && m_debuggerEngine == GdbEngine) { QProcess gcc; gcc.setWorkingDirectory(t->buildPath); + gcc.setProcessEnvironment(m_env); gcc.start("gcc", {"--version"}); QVERIFY(gcc.waitForFinished()); output = gcc.readAllStandardOutput(); From ed211f1d47e51b3551be96e81761f24bcd760c99 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 2 Dec 2024 15:28:56 +0100 Subject: [PATCH 337/989] LanguageClient: assert on using null project for setting Change-Id: I64532c0890210e2ccae0a25eb9abc04b72244a97 Reviewed-by: Sami Shalayel --- src/plugins/languageclient/languageclientsettings.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index b9b9d6ab9a8..8a151cb1119 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -1187,6 +1187,7 @@ constexpr const char disabledSettingsId[] = "LanguageClient.DisabledSettings"; ProjectSettings::ProjectSettings(ProjectExplorer::Project *project) : m_project(project) { + QTC_ASSERT(project, return); m_json = m_project->namedSettings(projectSettingsId).toByteArray(); m_enabledSettings = m_project->namedSettings(enabledSettingsId).toStringList(); m_disabledSettings = m_project->namedSettings(disabledSettingsId).toStringList(); @@ -1209,6 +1210,7 @@ QByteArray ProjectSettings::json() const void ProjectSettings::setJson(const QByteArray &json) { + QTC_ASSERT(m_project, return); const QJsonValue oldConfig = workspaceConfiguration(); m_json = json; m_project->setNamedSettings(projectSettingsId, m_json); @@ -1219,6 +1221,7 @@ void ProjectSettings::setJson(const QByteArray &json) void ProjectSettings::enableSetting(const QString &id) { + QTC_ASSERT(m_project, return); if (m_disabledSettings.removeAll(id) > 0) m_project->setNamedSettings(disabledSettingsId, m_disabledSettings); if (m_enabledSettings.contains(id)) @@ -1230,6 +1233,7 @@ void ProjectSettings::enableSetting(const QString &id) void ProjectSettings::disableSetting(const QString &id) { + QTC_ASSERT(m_project, return); if (m_enabledSettings.removeAll(id) > 0) m_project->setNamedSettings(enabledSettingsId, m_enabledSettings); if (m_disabledSettings.contains(id)) @@ -1241,6 +1245,7 @@ void ProjectSettings::disableSetting(const QString &id) void ProjectSettings::clearOverride(const QString &id) { + QTC_ASSERT(m_project, return); const bool changedEnabled = m_enabledSettings.removeAll(id) > 0; if (changedEnabled) m_project->setNamedSettings(enabledSettingsId, m_enabledSettings); From 071bd23bf997a3efba1e8aa42c4d4ca431771bcf Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 2 Dec 2024 15:30:04 +0100 Subject: [PATCH 338/989] LanguageClient: check project before accessing project setting Change-Id: I48842fc6cfc4bdff33411fbe0fed4f4a704c0125 Reviewed-by: Sami Shalayel --- .../languageclient/languageclientsettings.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 8a151cb1119..29abe9ba9c4 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -596,12 +596,13 @@ Client *BaseSettings::createClient() const bool BaseSettings::isEnabledOnProject(ProjectExplorer::Project *project) const { - LanguageClient::ProjectSettings settings(project); - if (settings.enabledSettings().contains(m_id)) - return true; - if (settings.disabledSettings().contains(m_id)) - return false; - + if (project) { + LanguageClient::ProjectSettings settings(project); + if (settings.enabledSettings().contains(m_id)) + return true; + if (settings.disabledSettings().contains(m_id)) + return false; + } return m_enabled; } From 67b51d15056459863009493d1c9e5a8f040e53b3 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 2 Dec 2024 13:24:35 +0100 Subject: [PATCH 339/989] QbsProjectManager: Force full resolving on "Reparse Qbs" This option is intended for "trying again" if something failed in a way that changes to the problematic file won't get picked up because it was so broken that it did not end up in the list of build system files to watch. However, if that is the case, then qbs' own change tracking mechanism will also not detect a change, so the whole procedure was useless. We fix this by explicitly instrucing qbs to do a full (re-)resolve for that particular action. Change-Id: I8d686e5e5a4312c3c8f23498edd4af871090e96e Reviewed-by: Christian Stenger --- .../qbsprojectmanager/qbsbuildstep.cpp | 2 +- src/plugins/qbsprojectmanager/qbsproject.cpp | 11 +++++--- src/plugins/qbsprojectmanager/qbsproject.h | 4 +-- .../qbsprojectmanagerconstants.h | 1 + .../qbsprojectmanagerplugin.cpp | 2 +- .../qbsprojectmanager/qbsprojectparser.cpp | 2 ++ src/plugins/qbsprojectmanager/qbsrequest.cpp | 28 +++++++++++-------- src/plugins/qbsprojectmanager/qbsrequest.h | 8 ++++-- 8 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index c28e52e0262..9aec496e0ef 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -382,7 +382,7 @@ Tasking::GroupItem QbsBuildStep::runRecipe() { using namespace Tasking; const auto onPreParserSetup = [this](QbsRequest &request) { - request.setParseData(qbsBuildSystem()); + request.setParseData({qbsBuildSystem(), {}}); }; const auto onBuildSetup = [this](QbsRequest &request) { QbsSession *session = qbsBuildSystem()->session(); diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 2a14b493ecd..508d9eac36a 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -599,7 +599,7 @@ void QbsBuildSystem::changeActiveTarget(Target *t) void QbsBuildSystem::triggerParsing() { - scheduleParsing(); + scheduleParsing({}); } void QbsBuildSystem::delayParsing() @@ -613,17 +613,17 @@ ExtraCompiler *QbsBuildSystem::findExtraCompiler(const ExtraCompilerFilter &filt return Utils::findOrDefault(m_extraCompilers, filter); } -void QbsBuildSystem::scheduleParsing() +void QbsBuildSystem::scheduleParsing(const QVariantMap &extraConfig) { m_parseRequest.reset(new QbsRequest); - m_parseRequest->setParseData(this); + m_parseRequest->setParseData({this, extraConfig}); connect(m_parseRequest.get(), &QbsRequest::done, this, [this] { m_parseRequest.release()->deleteLater(); }); m_parseRequest->start(); } -void QbsBuildSystem::startParsing() +void QbsBuildSystem::startParsing(const QVariantMap &extraConfig) { QTC_ASSERT(!m_qbsProjectParser, return); @@ -632,6 +632,9 @@ void QbsBuildSystem::startParsing() config.insert(Constants::QBS_INSTALL_ROOT_KEY, m_buildConfiguration->macroExpander() ->expand(QbsSettings::defaultInstallDirTemplate())); } + config.insert(Constants::QBS_RESTORE_BEHAVIOR_KEY, "restore-and-track-changes"); + for (auto it = extraConfig.begin(); it != extraConfig.end(); ++it) + config.insert(keyFromString(it.key()), it.value()); Environment env = m_buildConfiguration->environment(); FilePath dir = m_buildConfiguration->buildDirectory(); diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 4dffaf01044..0edb7e67c41 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -96,7 +96,7 @@ public: static ProjectExplorer::FileType fileTypeFor(const QSet &tags); QString profile() const; - void scheduleParsing(); + void scheduleParsing(const QVariantMap &extraConfig); void updateAfterBuild(); QbsSession *session() const { return m_session; } @@ -110,7 +110,7 @@ private: friend class QbsProject; friend class QbsRequestObject; - void startParsing(); + void startParsing(const QVariantMap &extraConfig); void cancelParsing(); ProjectExplorer::ExtraCompiler *findExtraCompiler( diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h b/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h index c03ef27356a..b5a3fa4272c 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerconstants.h @@ -48,6 +48,7 @@ const char QBS_CONFIG_QUICK_DEBUG_KEY[] = "modules.Qt.quick.qmlDebugging"; const char QBS_CONFIG_QUICK_COMPILER_KEY[] = "modules.Qt.quick.useCompiler"; const char QBS_CONFIG_SEPARATE_DEBUG_INFO_KEY[] = "modules.cpp.separateDebugInformation"; const char QBS_FORCE_PROBES_KEY[] = "qbspm.forceProbes"; +const char QBS_RESTORE_BEHAVIOR_KEY[] = "restore-behavior"; // Toolchain related settings: const char QBS_TARGETPLATFORM[] = "qbs.targetPlatform"; diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index 1290d0162f3..4e9dc0de72b 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -613,7 +613,7 @@ void QbsProjectManagerPlugin::reparseProject(QbsProject *project) return; if (auto bs = qobject_cast(t->buildSystem())) - bs->scheduleParsing(); + bs->scheduleParsing({{Constants::QBS_RESTORE_BEHAVIOR_KEY, "resolve-only"}}); } void buildNamedProduct(QbsProject *project, const QString &product) diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp index 88fb59bc0fc..dd69935e185 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp @@ -69,6 +69,8 @@ void QbsProjectParser::parse(const Store &config, const Environment &env, request.insert("configuration-name", configName); request.insert("force-probe-execution", userConfig.take(Constants::QBS_FORCE_PROBES_KEY).toBool()); + request.insert(Constants::QBS_RESTORE_BEHAVIOR_KEY, + userConfig.take(Constants::QBS_RESTORE_BEHAVIOR_KEY).toString()); if (QbsSettings::useCreatorSettingsDirForQbs()) request.insert("settings-directory", QbsSettings::qbsSettingsBaseDir()); request.insert("overridden-properties", QJsonObject::fromVariantMap(mapFromStore(userConfig))); diff --git a/src/plugins/qbsprojectmanager/qbsrequest.cpp b/src/plugins/qbsprojectmanager/qbsrequest.cpp index e6ac1c2fb89..ba984d84cbc 100644 --- a/src/plugins/qbsprojectmanager/qbsrequest.cpp +++ b/src/plugins/qbsprojectmanager/qbsrequest.cpp @@ -36,7 +36,8 @@ public: void setSession(QbsSession *session) { m_session = session; } QbsSession *session() const { return m_session; } void setRequestData(const QJsonObject &requestData) { m_requestData = requestData; } - void setParseData(const QPointer &buildSystem) { m_parseData = buildSystem; } + void setParseData(const ParseData &parseData) { m_parseData = parseData; } + void start(); void cancel(); @@ -49,7 +50,7 @@ signals: private: QbsSession *m_session = nullptr; QJsonObject m_requestData; - QPointer m_parseData; + ParseData m_parseData; QString m_description; int m_maxProgress = 100; }; @@ -112,13 +113,15 @@ static QbsRequestManager &manager() void QbsRequestObject::start() { - if (m_parseData) { - connect(m_parseData->target(), &Target::parsingFinished, this, [this](bool success) { - disconnect(m_parseData->target(), &Target::parsingFinished, this, nullptr); + if (m_parseData.first) { + connect(m_parseData.first->target(), &Target::parsingFinished, this, [this](bool success) { + disconnect(m_parseData.first->target(), &Target::parsingFinished, this, nullptr); emit done(toDoneResult(success)); }); - QMetaObject::invokeMethod(m_parseData.get(), &QbsBuildSystem::startParsing, - Qt::QueuedConnection); + QMetaObject::invokeMethod( + m_parseData.first.get(), + [parseData = m_parseData] { parseData.first->startParsing(parseData.second); }, + Qt::QueuedConnection); return; } @@ -172,8 +175,8 @@ void QbsRequestObject::start() void QbsRequestObject::cancel() { - if (m_parseData) - m_parseData->cancelParsing(); + if (m_parseData.first) + m_parseData.first->cancelParsing(); else m_session->cancelCurrentJob(); } @@ -189,14 +192,15 @@ QbsRequest::~QbsRequest() void QbsRequest::start() { QTC_ASSERT(!m_requestObject, return); - QTC_ASSERT(m_parseData || (m_session && m_requestData), emit done(DoneResult::Error); return); + QTC_ASSERT(m_parseData.first || (m_session && m_requestData), emit done(DoneResult::Error); + return); m_requestObject = new QbsRequestObject; m_requestObject->setSession(m_session); if (m_requestData) m_requestObject->setRequestData(*m_requestData); - if (m_parseData) { - m_requestObject->setSession(m_parseData->session()); + if (m_parseData.first) { + m_requestObject->setSession(m_parseData.first->session()); m_requestObject->setParseData(m_parseData); } diff --git a/src/plugins/qbsprojectmanager/qbsrequest.h b/src/plugins/qbsprojectmanager/qbsrequest.h index 340bbe0f12f..763a44fced6 100644 --- a/src/plugins/qbsprojectmanager/qbsrequest.h +++ b/src/plugins/qbsprojectmanager/qbsrequest.h @@ -9,12 +9,16 @@ #include +#include + namespace QbsProjectManager::Internal { class QbsBuildSystem; class QbsRequestObject; class QbsSession; +using ParseData = std::pair, QVariantMap>; + class QbsRequest final : public QObject { Q_OBJECT @@ -24,7 +28,7 @@ public: void setSession(QbsSession *session) { m_session = session; } void setRequestData(const QJsonObject &requestData) { m_requestData = requestData; } - void setParseData(const QPointer &buildSystem) { m_parseData = buildSystem; } + void setParseData(const ParseData &parseData) { m_parseData = parseData; } void start(); signals: @@ -36,7 +40,7 @@ signals: private: QbsSession *m_session = nullptr; // TODO: Should we keep a QPointer? std::optional m_requestData; - QPointer m_parseData; + ParseData m_parseData; QbsRequestObject *m_requestObject = nullptr; }; From 8cc973371d7e9d575161bdf330f32fb311b9432e Mon Sep 17 00:00:00 2001 From: Patryk Stachniak Date: Mon, 2 Dec 2024 12:33:14 +0100 Subject: [PATCH 340/989] Ensure UI tour starts with Icons and Text mode Changed runUiTour to set mode style to Icons and Text before starting the UI tour. This ensures a consistent user experience during the tour. After the tour, the previous mode style is restored to maintain user preferences. Task-number: QTCREATORBUG-31979 Pick-to: 15.0 Change-Id: I0e303cad9afd4fd99dc76a342ebc8408c3a1a5f7 Reviewed-by: Eike Ziller --- src/plugins/welcome/introductionwidget.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/plugins/welcome/introductionwidget.cpp b/src/plugins/welcome/introductionwidget.cpp index 1869947503f..bc9b80c3284 100644 --- a/src/plugins/welcome/introductionwidget.cpp +++ b/src/plugins/welcome/introductionwidget.cpp @@ -5,6 +5,7 @@ #include "welcometr.h" #include +#include #include #include @@ -40,7 +41,7 @@ struct Item class IntroductionWidget : public QWidget { public: - IntroductionWidget(); + IntroductionWidget(Core::ModeManager::Style previousModeStyle); protected: bool event(QEvent *e) override; @@ -63,12 +64,16 @@ private: std::vector m_items; QPointer m_stepPointerAnchor; uint m_step = 0; + Core::ModeManager::Style m_previousModeStyle; }; -IntroductionWidget::IntroductionWidget() +IntroductionWidget::IntroductionWidget(Core::ModeManager::Style previousModeStyle) : QWidget(ICore::dialogParent()), - m_borderImage(":/welcome/images/border.png") + m_borderImage(":/welcome/images/border.png"), + m_previousModeStyle(previousModeStyle) { + Core::ModeManager::setModeStyle(Core::ModeManager::Style::IconsAndText); + setFocusPolicy(Qt::StrongFocus); setFocus(); parentWidget()->installEventFilter(this); @@ -363,6 +368,7 @@ void IntroductionWidget::mouseReleaseEvent(QMouseEvent *me) void IntroductionWidget::finish() { + Core::ModeManager::setModeStyle(m_previousModeStyle); hide(); deleteLater(); } @@ -405,7 +411,7 @@ void IntroductionWidget::resizeToParent() void runUiTour() { - auto intro = new IntroductionWidget; + auto intro = new IntroductionWidget(Core::ModeManager::modeStyle()); intro->show(); } From a737828d7d6b385ef09355e0c56b4ff9620b4f0a Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Thu, 14 Nov 2024 16:06:40 +0100 Subject: [PATCH 341/989] qmlls: Make LanguageClientManager manage qmlls Remove the custom unfit qmlls-managing functionality from QmlJSEditorDocumentPrivate and use the LanguageClient implementation instead. Move the settings page from Qt Quick to the Language Server settings page to have all language servers in one central point. Introduce new class for QmllsClientSettings and QmllsClientSettingsWidget that allows the LanguageClient code to manage the qmlls state (starting, restarting, shutdown etc) and to configure qmlls from the Language Server settings page. Split qmlls specific functionality away from QmlJSEditingSettings into QmllsClientSettings and squash QmllsSettingsManager into QmllsClientSettings as its not needed anymore. Remove QmlJSEditorDocumentPrivate::settingsChanged() because thats almost completely handled by the LanguageClient generic implementation. The missing bits (enabling/disabling of the builtin code model) will be re-added in a future commit, tracked by QTCREATORBUG-32025. Currently the ProjectSettings::save() does not do anything, such that the project specific settings under Qt Quick does not do anything anymore (before the checkbox there allowed to disable/enable qmlls project-wise), tracked by QTCREATORBUG-32026. Task-number: QTCREATORBUG-31897 Change-Id: I62d807e478ab105e67ec7d94af6782810e6bd2ed Reviewed-by: David Schulz --- src/plugins/qmljseditor/CMakeLists.txt | 1 + src/plugins/qmljseditor/qmljseditor.cpp | 7 +- .../qmljseditor/qmljseditorconstants.h | 2 + .../qmljseditor/qmljseditordocument.cpp | 108 +----- .../qmljseditor/qmljseditordocument_p.h | 1 - src/plugins/qmljseditor/qmljseditorplugin.cpp | 4 +- .../qmljseditor/qmljseditorsettings.cpp | 165 +-------- src/plugins/qmljseditor/qmljseditorsettings.h | 36 -- src/plugins/qmljseditor/qmljshoverhandler.cpp | 5 +- src/plugins/qmljseditor/qmllsclient.cpp | 36 +- src/plugins/qmljseditor/qmllsclient.h | 1 - .../qmljseditor/qmllsclientsettings.cpp | 332 ++++++++++++++++++ src/plugins/qmljseditor/qmllsclientsettings.h | 46 +++ src/plugins/qmljseditor/qmltaskmanager.cpp | 4 +- 14 files changed, 409 insertions(+), 339 deletions(-) create mode 100644 src/plugins/qmljseditor/qmllsclientsettings.cpp create mode 100644 src/plugins/qmljseditor/qmllsclientsettings.h diff --git a/src/plugins/qmljseditor/CMakeLists.txt b/src/plugins/qmljseditor/CMakeLists.txt index fcba4765f3b..06e848b8b83 100644 --- a/src/plugins/qmljseditor/CMakeLists.txt +++ b/src/plugins/qmljseditor/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(QmlJSEditor SOURCES qmlexpressionundercursor.cpp qmlexpressionundercursor.h qmllsclient.h qmllsclient.cpp + qmllsclientsettings.h qmllsclientsettings.cpp qmljsautocompleter.cpp qmljsautocompleter.h qmljscompletionassist.cpp qmljscompletionassist.h qmljscomponentfromobjectdef.cpp qmljscomponentfromobjectdef.h diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index a079fdf3b75..b09a9f57e06 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -5,15 +5,16 @@ #include "qmljsautocompleter.h" #include "qmljscompletionassist.h" -#include "qmljseditorsettings.h" #include "qmljseditorconstants.h" #include "qmljseditordocument.h" #include "qmljseditorplugin.h" +#include "qmljseditorsettings.h" #include "qmljseditortr.h" #include "qmljsfindreferences.h" #include "qmljshighlighter.h" #include "qmljshoverhandler.h" #include "qmljsquickfixassist.h" +#include "qmllsclientsettings.h" #include "qmloutlinemodel.h" #include "quicktoolbar.h" @@ -98,15 +99,13 @@ namespace QmlJSEditor { static LanguageClient::Client *getQmllsClient(const Utils::FilePath &fileName) { - // the value in disableBuiltinCodemodel is only valid when useQmlls is enabled - if (settings().useQmlls() && !settings().disableBuiltinCodemodel()) + if (qmllsSettings()->useQmllsWithBuiltinCodemodelOnProject(fileName)) return nullptr; auto client = LanguageClient::LanguageClientManager::clientForFilePath(fileName); return client; } - // // QmlJSEditorWidget // diff --git a/src/plugins/qmljseditor/qmljseditorconstants.h b/src/plugins/qmljseditor/qmljseditorconstants.h index 5ffbbc98c3b..75500d36f56 100644 --- a/src/plugins/qmljseditor/qmljseditorconstants.h +++ b/src/plugins/qmljseditor/qmljseditorconstants.h @@ -25,5 +25,7 @@ const char QML_SNIPPETS_GROUP_ID[] = "QML"; const char QMLLINT_BUILD_TARGET[] = "all_qmllint"; +const char QMLLS_CLIENT_SETTINGS_ID[] = "LanguageClient::QmllsClientSettingsID"; + } // namespace Constants } // namespace QmlJSEditor diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp index 1bec169fe1e..b9460ad3c21 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.cpp +++ b/src/plugins/qmljseditor/qmljseditordocument.cpp @@ -6,13 +6,12 @@ #include "qmljseditordocument_p.h" #include "qmljseditorplugin.h" #include "qmljseditortr.h" -#include "qmljseditorsettings.h" #include "qmljshighlighter.h" #include "qmljsquickfixassist.h" #include "qmljssemantichighlighter.h" #include "qmljssemanticinfoupdater.h" #include "qmljstextmark.h" -#include "qmllsclient.h" +#include "qmllsclientsettings.h" #include "qmloutlinemodel.h" #include @@ -43,8 +42,6 @@ using namespace Utils; namespace { -Q_LOGGING_CATEGORY(qmllsLog, "qtc.qmlls.editor", QtWarningMsg); - enum { UPDATE_DOCUMENT_DEFAULT_INTERVAL = 100, UPDATE_OUTLINE_INTERVAL = 500 @@ -480,13 +477,6 @@ QmlJSEditorDocumentPrivate::QmlJSEditorDocumentPrivate(QmlJSEditorDocument *pare this, &QmlJSEditorDocumentPrivate::reparseDocument); connect(modelManager, &ModelManagerInterface::documentUpdated, this, &QmlJSEditorDocumentPrivate::onDocumentUpdated); - connect(QmllsSettingsManager::instance(), &QmllsSettingsManager::settingsChanged, - this, &QmlJSEditorDocumentPrivate::settingsChanged); - connect( - modelManager, - &ModelManagerInterface::projectInfoUpdated, - this, - &QmlJSEditorDocumentPrivate::settingsChanged); // semantic info m_semanticInfoUpdater = new SemanticInfoUpdater(); @@ -734,104 +724,12 @@ void QmlJSEditorDocumentPrivate::setSourcesWithCapabilities( setSemanticWarningSource(QmllsStatus::Source::Qmlls); else setSemanticWarningSource(QmllsStatus::Source::EmbeddedCodeModel); - if (cap.semanticTokensProvider() && settings().enableQmllsSemanticHighlighting()) + if (cap.semanticTokensProvider() && qmllsSettings()->m_useQmllsSemanticHighlighting) setSemanticHighlightSource(QmllsStatus::Source::Qmlls); else setSemanticHighlightSource(QmllsStatus::Source::EmbeddedCodeModel); } -static FilePath qmllsForFile(const FilePath &file, QmlJS::ModelManagerInterface *modelManager) -{ - QmllsSettingsManager *settingsManager = QmllsSettingsManager::instance(); - ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile(file); - const bool enabled = settingsManager->useQmlls(project); - if (!enabled) - return {}; - if (settingsManager->useLatestQmlls()) - return settingsManager->latestQmlls(); - QmlJS::ModelManagerInterface::ProjectInfo pInfo = modelManager->projectInfoForPath(file); - - if (!settings().ignoreMinimumQmllsVersion() - && QVersionNumber::fromString(pInfo.qtVersionString) - < QmlJsEditingSettings::mininumQmllsVersion) { - return {}; - } - return pInfo.qmllsPath.exists() ? pInfo.qmllsPath : Utils::FilePath(); -} - -void QmlJSEditorDocumentPrivate::settingsChanged() -{ - if (q->isTemporary()) - return; - - FilePath newQmlls = qmllsForFile(q->filePath(), ModelManagerInterface::instance()); - if (m_qmllsStatus.qmllsPath == newQmlls) { - if (QmllsClient *client = QmllsClient::clientForQmlls(newQmlls)) { - client->updateQmllsSemanticHighlightingCapability(); - setSourcesWithCapabilities(client->capabilities()); - client->activateDocument(q); - } - return; - } - - using namespace LanguageClient; - m_qmllsStatus.qmllsPath = newQmlls; - if (newQmlls.isEmpty()) { - qCDebug(qmllsLog) << "disabling qmlls for" << q->filePath(); - if (LanguageClientManager::clientForDocument(q) != nullptr) { - qCDebug(qmllsLog) << "deactivating " << q->filePath() << "in qmlls" << newQmlls; - LanguageClientManager::openDocumentWithClient(q, nullptr); - } else - qCWarning(qmllsLog) << "Could not find client to disable for document " << q->filePath() - << " in LanguageClient::LanguageClientManager"; - setCompletionSource(QmllsStatus::Source::EmbeddedCodeModel); - setSemanticWarningSource(QmllsStatus::Source::EmbeddedCodeModel); - setSemanticHighlightSource(QmllsStatus::Source::EmbeddedCodeModel); - } else if (QmllsClient *client = QmllsClient::clientForQmlls(newQmlls)) { - bool shouldActivate = false; - if (auto oldClient = LanguageClientManager::clientForDocument(q)) { - // check if it was disabled - if (client == oldClient) - shouldActivate = true; - } - client->updateQmllsSemanticHighlightingCapability(); - switch (client->state()) { - case Client::State::Uninitialized: - case Client::State::InitializeRequested: - connect(client, - &Client::initialized, - this, - &QmlJSEditorDocumentPrivate::setSourcesWithCapabilities); - break; - case Client::State::Initialized: - setSourcesWithCapabilities(client->capabilities()); - break; - case Client::State::FailedToInitialize: - case Client::State::Error: - qCWarning(qmllsLog) << "qmlls" << newQmlls << "requested for document" << q->filePath() - << "had errors, skipping setSourcesWithCababilities"; - break; - case Client::State::Shutdown: - qCWarning(qmllsLog) << "qmlls" << newQmlls << "requested for document" << q->filePath() - << "did stop, skipping setSourcesWithCababilities"; - break; - case Client::State::ShutdownRequested: - qCWarning(qmllsLog) << "qmlls" << newQmlls << "requested for document" << q->filePath() - << "is stopping, skipping setSourcesWithCababilities"; - break; - } - if (shouldActivate) { - qCDebug(qmllsLog) << "reactivating " << q->filePath() << "in qmlls" << newQmlls; - client->activateDocument(q); - } else { - qCDebug(qmllsLog) << "opening " << q->filePath() << "in qmlls" << newQmlls; - LanguageClientManager::openDocumentWithClient(q, client); - } - } else { - qCWarning(qmllsLog) << "could not start qmlls " << newQmlls << "for" << q->filePath(); - } -} - } // Internal QmlJSEditorDocument::QmlJSEditorDocument(Utils::Id id) @@ -840,8 +738,6 @@ QmlJSEditorDocument::QmlJSEditorDocument(Utils::Id id) setId(id); connect(this, &TextEditor::TextDocument::tabSettingsChanged, d, &Internal::QmlJSEditorDocumentPrivate::invalidateFormatterCache); - connect(this, &TextEditor::TextDocument::openFinishedSuccessfully, - d, &Internal::QmlJSEditorDocumentPrivate::settingsChanged); resetSyntaxHighlighter([] { return new QmlJSHighlighter(); }); setCodec(QTextCodec::codecForName("UTF-8")); // qml files are defined to be utf-8 setIndenter(createQmlJsIndenter(document())); diff --git a/src/plugins/qmljseditor/qmljseditordocument_p.h b/src/plugins/qmljseditor/qmljseditordocument_p.h index 6c4d5bb78c2..fcddf1d5ac9 100644 --- a/src/plugins/qmljseditor/qmljseditordocument_p.h +++ b/src/plugins/qmljseditor/qmljseditordocument_p.h @@ -62,7 +62,6 @@ public: void setCompletionSource(QmllsStatus::Source newSource); public slots: void setSourcesWithCapabilities(const LanguageServerProtocol::ServerCapabilities &); - void settingsChanged(); public: QmlJSEditorDocument *q = nullptr; diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp index 3839765008d..b95c19f0689 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.cpp +++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp @@ -9,6 +9,7 @@ #include "qmljseditortr.h" #include "qmljsoutline.h" #include "qmljsquickfixassist.h" +#include "qmllsclientsettings.h" #include "qmltaskmanager.h" #include @@ -89,7 +90,7 @@ static QmlJSEditorPluginPrivate *dd = nullptr; QmlJSEditorPluginPrivate::QmlJSEditorPluginPrivate() { QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); - QmllsSettingsManager::instance(); + setupQmllsClientSettings(); // QML task updating manager connect(modelManager, &QmlJS::ModelManagerInterface::documentChangedOnDisk, @@ -346,7 +347,6 @@ class QmlJSEditorPlugin final : public ExtensionSystem::IPlugin Tr::tr("QML Analysis"), Tr::tr("Issues that the QML static analyzer found."), false}); - QmllsSettingsManager::instance()->setupAutoupdate(); } }; diff --git a/src/plugins/qmljseditor/qmljseditorsettings.cpp b/src/plugins/qmljseditor/qmljseditorsettings.cpp index f92a062ff98..7d34f296df5 100644 --- a/src/plugins/qmljseditor/qmljseditorsettings.cpp +++ b/src/plugins/qmljseditor/qmljseditorsettings.cpp @@ -4,10 +4,17 @@ #include "qmljseditorsettings.h" #include "qmljseditorconstants.h" #include "qmljseditortr.h" +#include "qmllsclient.h" +#include "qmllsclientsettings.h" #include #include +#include +#include +#include + +#include #include #include #include @@ -49,8 +56,6 @@ using namespace ProjectExplorer; namespace QmlJSEditor::Internal { -static Q_LOGGING_CATEGORY(qmllsLog, "qtc.qmlls.settings", QtWarningMsg) - const char SETTINGS_KEY_MAIN[] = "QmlJSEditor"; const char AUTO_FORMAT_ON_SAVE[] = "QmlJSEditor.AutoFormatOnSave"; const char AUTO_FORMAT_ONLY_CURRENT_PROJECT[] = "QmlJSEditor.AutoFormatOnlyCurrentProject"; @@ -59,11 +64,6 @@ const char QML_CONTEXTPANEPIN_KEY[] = "QmlJSEditor.ContextPanePinned"; const char FOLD_AUX_DATA[] = "QmlJSEditor.FoldAuxData"; const char USE_GLOBAL_SETTINGS[] = "QmlJSEditor.UseGlobalSettings"; const char USE_QMLLS[] = "QmlJSEditor.UseQmlls"; -const char USE_LATEST_QMLLS[] = "QmlJSEditor.UseLatestQmlls"; -const char IGNORE_MINIMUM_QMLLS_VERSION[] = "QmlJSEditor.IgnoreMinimumQmllsVersion"; -const char USE_QMLLS_SEMANTIC_HIGHLIGHTING[] = "QmlJSEditor.EnableQmllsSemanticHighlighting"; -const char DISABLE_BUILTIN_CODEMODEL[] = "QmlJSEditor.DisableBuiltinCodemodel"; -const char GENERATE_QMLLS_INI_FILES[] = "QmlJSEditor.GenerateQmllsIniFiles"; const char UIQML_OPEN_MODE[] = "QmlJSEditor.openUiQmlMode"; const char FORMAT_COMMAND[] = "QmlJSEditor.formatCommand"; const char FORMAT_COMMAND_OPTIONS[] = "QmlJSEditor.formatCommandOptions"; @@ -81,110 +81,7 @@ QmlJsEditingSettings &settings() return settings; } -static FilePath evaluateLatestQmlls() -{ - // find latest qmlls, i.e. vals - if (!QtVersionManager::isLoaded()) - return {}; - const QtVersions versions = QtVersionManager::versions(); - FilePath latestQmlls; - QVersionNumber latestVersion; - FilePath latestQmakeFilePath; - int latestUniqueId = std::numeric_limits::min(); - for (QtVersion *v : versions) { - // check if we find qmlls - QVersionNumber vNow = v->qtVersion(); - FilePath qmllsNow = QmlJS::ModelManagerInterface::qmllsForBinPath(v->hostBinPath(), vNow); - if (!qmllsNow.isExecutableFile()) - continue; - if (latestVersion > vNow) - continue; - FilePath qmakeNow = v->qmakeFilePath(); - int uniqueIdNow = v->uniqueId(); - if (latestVersion == vNow) { - if (latestQmakeFilePath > qmakeNow) - continue; - if (latestQmakeFilePath == qmakeNow && latestUniqueId >= v->uniqueId()) - continue; - } - latestVersion = vNow; - latestQmlls = qmllsNow; - latestQmakeFilePath = qmakeNow; - latestUniqueId = uniqueIdNow; - } - return latestQmlls; -} - -QmllsSettingsManager *QmllsSettingsManager::instance() -{ - static QmllsSettingsManager *manager = new QmllsSettingsManager; - return manager; -} - -FilePath QmllsSettingsManager::latestQmlls() -{ - QMutexLocker l(&m_mutex); - return m_latestQmlls; -} - -void QmllsSettingsManager::setupAutoupdate() -{ - QObject::connect(QtVersionManager::instance(), - &QtVersionManager::qtVersionsChanged, - this, - &QmllsSettingsManager::checkForChanges); - if (QtVersionManager::isLoaded()) - checkForChanges(); - else - QObject::connect(QtVersionManager::instance(), - &QtVersionManager::qtVersionsLoaded, - this, - &QmllsSettingsManager::checkForChanges); -} - -void QmllsSettingsManager::checkForChanges() -{ - const QmlJsEditingSettings &newSettings = settings(); - FilePath newLatest = newSettings.useLatestQmlls() && newSettings.useQmlls() - ? evaluateLatestQmlls() : m_latestQmlls; - if (m_useQmlls == newSettings.useQmlls() - && m_useLatestQmlls == newSettings.useLatestQmlls() - && m_disableBuiltinCodemodel == newSettings.disableBuiltinCodemodel() - && m_generateQmllsIniFiles == newSettings.generateQmllsIniFiles() - && m_enableQmllsSemanticHighlighting == newSettings.enableQmllsSemanticHighlighting() - && newLatest == m_latestQmlls) - return; - qCDebug(qmllsLog) << "qmlls settings changed:" << newSettings.useQmlls() - << newSettings.useLatestQmlls() << newLatest; - { - QMutexLocker l(&m_mutex); - m_latestQmlls = newLatest; - m_useQmlls = newSettings.useQmlls(); - m_useLatestQmlls = newSettings.useLatestQmlls(); - m_disableBuiltinCodemodel = newSettings.disableBuiltinCodemodel(); - m_enableQmllsSemanticHighlighting = newSettings.enableQmllsSemanticHighlighting(); - m_generateQmllsIniFiles = newSettings.generateQmllsIniFiles(); - } - emit settingsChanged(); -} - -bool QmllsSettingsManager::useLatestQmlls() const -{ - return m_useLatestQmlls; -} - -bool QmllsSettingsManager::useQmlls(Project* onProject) const -{ - if (!onProject) - return m_useQmlls; - // check if disabled via project specific settings - ProjectSettings projectSettings{onProject}; - - const bool result = projectSettings.useGlobalSettings() ? m_useQmlls - : projectSettings.useQmlls(); - - return result; -} +using namespace LanguageClient; static QList defaultDisabledMessages() { @@ -220,10 +117,6 @@ QmlJsEditingSettings::QmlJsEditingSettings() { const Key group = QmlJSEditor::Constants::SETTINGS_CATEGORY_QML; - useQmlls.setSettingsKey(group, USE_QMLLS); - useQmlls.setDefaultValue(true); - useQmlls.setLabelText(Tr::tr("Turn on")); - enableContextPane.setSettingsKey(group, QML_CONTEXTPANE_KEY); enableContextPane.setLabelText(Tr::tr("Always show Qt Quick Toolbar")); @@ -249,27 +142,6 @@ QmlJsEditingSettings::QmlJsEditingSettings() uiQmlOpenMode.addOption({Tr::tr("Qt Design Studio"), {}, Core::Constants::MODE_DESIGN}); uiQmlOpenMode.addOption({Tr::tr("Qt Creator"), {}, Core::Constants::MODE_EDIT}); - useLatestQmlls.setSettingsKey(group, USE_LATEST_QMLLS); - useLatestQmlls.setLabelText(Tr::tr("Use from latest Qt version")); - - disableBuiltinCodemodel.setSettingsKey(group, DISABLE_BUILTIN_CODEMODEL); - disableBuiltinCodemodel.setLabelText( - Tr::tr("Use advanced features (renaming, find usages, and so on) " - "(experimental)")); - - generateQmllsIniFiles.setSettingsKey(group, GENERATE_QMLLS_INI_FILES); - generateQmllsIniFiles.setLabelText( - Tr::tr("Create .qmlls.ini files for new projects")); - - ignoreMinimumQmllsVersion.setSettingsKey(group, IGNORE_MINIMUM_QMLLS_VERSION); - ignoreMinimumQmllsVersion.setLabelText( - Tr::tr("Allow versions below Qt %1") - .arg(QmlJsEditingSettings::mininumQmllsVersion.toString())); - - enableQmllsSemanticHighlighting.setSettingsKey(group, USE_QMLLS_SEMANTIC_HIGHLIGHTING); - enableQmllsSemanticHighlighting.setLabelText( - Tr::tr("Enable semantic highlighting (experimental)")); - useCustomFormatCommand.setSettingsKey(group, CUSTOM_COMMAND); useCustomFormatCommand.setLabelText( Tr::tr("Use custom command instead of built-in formatter")); @@ -299,11 +171,6 @@ QmlJsEditingSettings::QmlJsEditingSettings() readSettings(); autoFormatOnlyCurrentProject.setEnabler(&autoFormatOnSave); - useLatestQmlls.setEnabler(&useQmlls); - disableBuiltinCodemodel.setEnabler(&useQmlls); - generateQmllsIniFiles.setEnabler(&useQmlls); - ignoreMinimumQmllsVersion.setEnabler(&useQmlls); - enableQmllsSemanticHighlighting.setEnabler(&useQmlls); formatCommand.setEnabler(&useCustomFormatCommand); formatCommandOptions.setEnabler(&useCustomFormatCommand); } @@ -426,14 +293,7 @@ public: }, Group{ title(Tr::tr("QML Language Server")), - Column { - s.useQmlls, - s.ignoreMinimumQmllsVersion, - s.disableBuiltinCodemodel, - s.enableQmllsSemanticHighlighting, - s.useLatestQmlls, - s.generateQmllsIniFiles - }, + // TODO: link to new settings }, Group { title(Tr::tr("Static Analyzer")), @@ -469,7 +329,6 @@ public: s.disabledMessages.setValue(disabled); s.disabledMessagesForNonQuickUi.setValue(disabledForNonQuickUi); s.writeSettings(); - QmllsSettingsManager::instance()->checkForChanges(); } private: @@ -544,7 +403,11 @@ void ProjectSettings::save(Project *project) toMap(map); project->setNamedSettings(SETTINGS_KEY_MAIN, variantFromStore(map)); - emit QmllsSettingsManager::instance()->settingsChanged(); + // TODO: this does not do anything for now. Either force re-apply when the functionality + // is available in LanguageClient (tracked in QTCREATORBUG-32015) or remove ProjectSettings + // class completely in favor of the LanguageClient project specific settings implementation + // (tracked in QTCREATORBUG-31987). + LanguageClientManager::applySettings(); } class QmlJsEditingProjectSettingsWidget final : public ProjectSettingsWidget diff --git a/src/plugins/qmljseditor/qmljseditorsettings.h b/src/plugins/qmljseditor/qmljseditorsettings.h index 4aa1608d7c3..f2bf64d1a9d 100644 --- a/src/plugins/qmljseditor/qmljseditorsettings.h +++ b/src/plugins/qmljseditor/qmljseditorsettings.h @@ -18,8 +18,6 @@ namespace QmlJSEditor::Internal { class QmlJsEditingSettings final : public Utils::AspectContainer { public: - static const inline QVersionNumber mininumQmllsVersion = QVersionNumber(6, 8); - QmlJsEditingSettings(); QString defaultFormatCommand() const; @@ -31,12 +29,6 @@ public: Utils::BoolAspect foldAuxData{this}; Utils::BoolAspect useCustomFormatCommand{this}; Utils::BoolAspect useCustomAnalyzer{this}; - Utils::BoolAspect useQmlls{this}; - Utils::BoolAspect useLatestQmlls{this}; - Utils::BoolAspect ignoreMinimumQmllsVersion{this}; - Utils::BoolAspect enableQmllsSemanticHighlighting{this}; - Utils::BoolAspect disableBuiltinCodemodel{this}; - Utils::BoolAspect generateQmllsIniFiles{this}; Utils::SelectionAspect uiQmlOpenMode{this}; Utils::StringAspect formatCommand{this}; Utils::StringAspect formatCommandOptions{this}; @@ -44,34 +36,6 @@ public: Utils::IntegersAspect disabledMessagesForNonQuickUi{this}; }; -class QmllsSettingsManager : public QObject -{ - Q_OBJECT - -public: - static QmllsSettingsManager *instance(); - - Utils::FilePath latestQmlls(); - void setupAutoupdate(); - - bool useQmlls(ProjectExplorer::Project* project) const; - bool useLatestQmlls() const; - -public slots: - void checkForChanges(); -signals: - void settingsChanged(); - -private: - QMutex m_mutex; - bool m_useQmlls = true; - bool m_useLatestQmlls = false; - bool m_disableBuiltinCodemodel = false; - bool m_generateQmllsIniFiles = false; - bool m_enableQmllsSemanticHighlighting = false; - Utils::FilePath m_latestQmlls; -}; - QmlJsEditingSettings &settings(); class QmlJsEditingSettingsPage : public Core::IOptionsPage diff --git a/src/plugins/qmljseditor/qmljshoverhandler.cpp b/src/plugins/qmljseditor/qmljshoverhandler.cpp index f17ec289254..cf61970974e 100644 --- a/src/plugins/qmljseditor/qmljshoverhandler.cpp +++ b/src/plugins/qmljseditor/qmljshoverhandler.cpp @@ -5,8 +5,8 @@ #include "qmljseditor.h" #include "qmljseditordocument.h" -#include "qmljseditorsettings.h" #include "qmljseditortr.h" +#include "qmllsclientsettings.h" #include #include @@ -382,7 +382,8 @@ void QmlJSHoverHandler::reset() void QmlJSHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) { // disable hoverhandling in case qmlls is enabled - if (settings().useQmlls()) { + if (editorWidget->textDocument() + && qmllsSettings()->isEnabledOnProjectFile(editorWidget->textDocument()->filePath())) { BaseHoverHandler::operateTooltip(editorWidget, point); return; } diff --git a/src/plugins/qmljseditor/qmllsclient.cpp b/src/plugins/qmljseditor/qmllsclient.cpp index 1fdc30a124a..5976ce7880f 100644 --- a/src/plugins/qmljseditor/qmllsclient.cpp +++ b/src/plugins/qmljseditor/qmllsclient.cpp @@ -4,9 +4,8 @@ #include "qmllsclient.h" #include "qmljseditorconstants.h" -#include "qmljseditortr.h" -#include "qmljseditorsettings.h" #include "qmljsquickfix.h" +#include "qmllsclientsettings.h" #include #include @@ -43,37 +42,6 @@ static QHash &qmllsClients() return clients; } -QmllsClient *QmllsClient::clientForQmlls(const FilePath &qmlls) -{ - if (auto client = qmllsClients()[qmlls]) { - switch (client->state()) { - case Client::State::Uninitialized: - case Client::State::InitializeRequested: - case Client::State::Initialized: - return client; - case Client::State::FailedToInitialize: - case Client::State::ShutdownRequested: - case Client::State::Shutdown: - case Client::State::Error: - qCDebug(qmllsLog) << "client was stopping or failed, restarting"; - break; - } - } - auto interface = new StdIOClientInterface; - interface->setCommandLine(CommandLine(qmlls)); - auto client = new QmllsClient(interface); - client->setName(Tr::tr("Qmlls (%1)").arg(qmlls.toUserOutput())); - client->setActivateDocumentAutomatically(true); - LanguageFilter filter; - using namespace Utils::Constants; - filter.mimeTypes = {QML_MIMETYPE, QMLUI_MIMETYPE, QBS_MIMETYPE, QMLPROJECT_MIMETYPE, - QMLTYPES_MIMETYPE, JS_MIMETYPE, JSON_MIMETYPE}; - client->setSupportedLanguage(filter); - client->start(); - qmllsClients()[qmlls] = client; - return client; -} - QMap QmllsClient::semanticTokenTypesMap() { QMap result; @@ -90,7 +58,7 @@ QMap QmllsClient::semanticTokenTypesMap() void QmllsClient::updateQmllsSemanticHighlightingCapability() { const QString methodName = QStringLiteral("textDocument/semanticTokens"); - if (!QmlJSEditor::Internal::settings().enableQmllsSemanticHighlighting()) { + if (!qmllsSettings()->m_useQmllsSemanticHighlighting) { LanguageServerProtocol::Unregistration unregister; unregister.setMethod(methodName); unregister.setId({}); diff --git a/src/plugins/qmljseditor/qmllsclient.h b/src/plugins/qmljseditor/qmllsclient.h index a174d0f0e2d..8ea9dfbeec7 100644 --- a/src/plugins/qmljseditor/qmllsclient.h +++ b/src/plugins/qmljseditor/qmllsclient.h @@ -54,7 +54,6 @@ public: ~QmllsClient(); void startImpl() override; - static QmllsClient *clientForQmlls(const Utils::FilePath &qmlls); void updateQmllsSemanticHighlightingCapability(); private: static QMap semanticTokenTypesMap(); diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp new file mode 100644 index 00000000000..663ed0ed91c --- /dev/null +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -0,0 +1,332 @@ +// 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 "qmllsclientsettings.h" +#include "qmljseditorconstants.h" +#include "qmljseditortr.h" +#include "qmllsclient.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace LanguageClient; +using namespace QtSupport; +using namespace Utils; +using namespace ProjectExplorer; + +namespace QmlJSEditor { + +constexpr char useLatestQmllsKey[] = "useLatestQmlls"; +constexpr char disableBuiltinCodemodelKey[] = "disableBuiltinCodemodel"; +constexpr char generateQmllsIniFilesKey[] = "generateQmllsIniFiles"; +constexpr char ignoreMinimumQmllsVersionKey[] = "ignoreMinimumQmllsVersion"; +constexpr char useQmllsSemanticHighlightingKey[] = "enableQmllsSemanticHighlighting"; + +QmllsClientSettings *qmllsSettings() +{ + BaseSettings *qmllsSettings + = Utils::findOrDefault(LanguageClientManager::currentSettings(), [](BaseSettings *setting) { + return setting->m_settingsTypeId == Constants::QMLLS_CLIENT_SETTINGS_ID; + }); + return static_cast(qmllsSettings); +} + +QmllsClientSettings::QmllsClientSettings() +{ + m_name = "QML Language Server"; + + using namespace Utils::Constants; + m_languageFilter.mimeTypes + = {QML_MIMETYPE, + QMLUI_MIMETYPE, + QBS_MIMETYPE, + QMLPROJECT_MIMETYPE, + QMLTYPES_MIMETYPE, + JS_MIMETYPE, + JSON_MIMETYPE}; + + m_settingsTypeId = Constants::QMLLS_CLIENT_SETTINGS_ID; + m_startBehavior = RequiresProject; +} + +static QtVersion *qtVersionFromProject(const Project *project) +{ + if (!project) + return {}; + auto *target = project->activeTarget(); + if (!target) + return {}; + auto *kit = target->kit(); + if (!kit) + return {}; + auto qtVersion = QtKitAspect::qtVersion(kit); + return qtVersion; +} + +static std::pair evaluateLatestQmlls() +{ + // find latest qmlls, i.e. vals + if (!QtVersionManager::isLoaded()) + return {}; + const QtVersions versions = QtVersionManager::versions(); + FilePath latestQmlls; + QVersionNumber latestVersion; + FilePath latestQmakeFilePath; + int latestUniqueId = std::numeric_limits::min(); + for (QtVersion *v : versions) { + // check if we find qmlls + QVersionNumber vNow = v->qtVersion(); + FilePath qmllsNow = QmlJS::ModelManagerInterface::qmllsForBinPath(v->hostBinPath(), vNow); + if (!qmllsNow.isExecutableFile()) + continue; + if (latestVersion > vNow) + continue; + FilePath qmakeNow = v->qmakeFilePath(); + int uniqueIdNow = v->uniqueId(); + if (latestVersion == vNow) { + if (latestQmakeFilePath > qmakeNow) + continue; + if (latestQmakeFilePath == qmakeNow && latestUniqueId >= v->uniqueId()) + continue; + } + latestVersion = vNow; + latestQmlls = qmllsNow; + latestQmakeFilePath = qmakeNow; + latestUniqueId = uniqueIdNow; + } + return std::make_pair(latestQmlls, latestVersion); +} + +static CommandLine commandLineForQmlls(const Project *project) +{ + const auto *qtVersion = qtVersionFromProject(project); + if (!qtVersion) + return {}; + + auto [executable, version] + = qmllsSettings()->m_useLatestQmlls + ? evaluateLatestQmlls() + : std::make_pair(qtVersion->binPath() / "qmlls", qtVersion->qtVersion()); + + CommandLine result{executable, {}}; + + if (auto *configuration = project->activeTarget()->activeBuildConfiguration()) + result.addArgs({"-b", configuration->buildDirectory().path()}); + + // qmlls 6.8 and later require the import path + if (version >= QVersionNumber(6, 8, 0)) + result.addArgs({"-I", qtVersion->qmlPath().path()}); + + // qmlls 6.8.1 and later require the documentation path + if (version >= QVersionNumber(6, 8, 1)) + result.addArgs({"-d", qtVersion->docsPath().path()}); + + return result; +} + +BaseClientInterface *QmllsClientSettings::createInterface(Project *project) const +{ + auto interface = new StdIOClientInterface; + interface->setCommandLine(commandLineForQmlls(project)); + return interface; +} + +Client *QmllsClientSettings::createClient(BaseClientInterface *interface) const +{ + return new QmllsClient(static_cast(interface)); +} + +class QmllsClientSettingsWidget : public QWidget +{ + Q_OBJECT +public: + explicit QmllsClientSettingsWidget( + const QmllsClientSettings *settings, QWidget *parent = nullptr); + + bool useLatestQmlls() const; + bool disableBuiltinCodemodel() const; + bool generateQmllsIniFiles() const; + bool ignoreMinimumQmllsVersion() const; + bool useQmllsSemanticHighlighting() const; + +private: + QCheckBox *m_useLatestQmlls; + QCheckBox *m_disableBuiltinCodemodel; + QCheckBox *m_generateQmllsIniFiles; + QCheckBox *m_ignoreMinimumQmllsVersion; + QCheckBox *m_useQmllsSemanticHighlighting; +}; + +QWidget *QmllsClientSettings::createSettingsWidget(QWidget *parent) const +{ + return new QmllsClientSettingsWidget(this, parent); +} + +bool QmllsClientSettings::applyFromSettingsWidget(QWidget *widget) +{ + bool changed = BaseSettings::applyFromSettingsWidget(widget); + + QmllsClientSettingsWidget *qmllsWidget = qobject_cast(widget); + if (!qmllsWidget) + return changed; + + if (m_useLatestQmlls != qmllsWidget->useLatestQmlls()) { + m_useLatestQmlls = qmllsWidget->useLatestQmlls(); + changed = true; + } + + if (m_disableBuiltinCodemodel != qmllsWidget->disableBuiltinCodemodel()) { + m_disableBuiltinCodemodel = qmllsWidget->disableBuiltinCodemodel(); + changed = true; + } + + if (m_generateQmllsIniFiles != qmllsWidget->generateQmllsIniFiles()) { + m_generateQmllsIniFiles = qmllsWidget->generateQmllsIniFiles(); + changed = true; + } + + if (m_ignoreMinimumQmllsVersion != qmllsWidget->ignoreMinimumQmllsVersion()) { + m_ignoreMinimumQmllsVersion = qmllsWidget->ignoreMinimumQmllsVersion(); + changed = true; + } + + if (m_useQmllsSemanticHighlighting != qmllsWidget->useQmllsSemanticHighlighting()) { + m_useQmllsSemanticHighlighting = qmllsWidget->useQmllsSemanticHighlighting(); + changed = true; + } + + return changed; +} + +void QmllsClientSettings::toMap(Store &map) const +{ + BaseSettings::toMap(map); + + map.insert(useLatestQmllsKey, m_useLatestQmlls); + map.insert(disableBuiltinCodemodelKey, m_disableBuiltinCodemodel); + map.insert(generateQmllsIniFilesKey, m_generateQmllsIniFiles); + map.insert(ignoreMinimumQmllsVersionKey, m_ignoreMinimumQmllsVersion); + map.insert(useQmllsSemanticHighlightingKey, m_useQmllsSemanticHighlighting); +} + +void QmllsClientSettings::fromMap(const Store &map) +{ + BaseSettings::fromMap(map); + + m_useLatestQmlls = map[useLatestQmllsKey].toBool(); + m_disableBuiltinCodemodel = map[disableBuiltinCodemodelKey].toBool(); + m_generateQmllsIniFiles = map[generateQmllsIniFilesKey].toBool(); + m_ignoreMinimumQmllsVersion = map[ignoreMinimumQmllsVersionKey].toBool(); + m_useQmllsSemanticHighlighting = map[useQmllsSemanticHighlightingKey].toBool(); + return; +} + +bool QmllsClientSettings::isEnabledOnProjectFile(const Utils::FilePath &file) const +{ + Project *project = ProjectManager::projectForFile(file); + return isEnabledOnProject(project); +} + +bool QmllsClientSettings::useQmllsWithBuiltinCodemodelOnProject(const Utils::FilePath &file) const +{ + if (m_disableBuiltinCodemodel) + return false; + + // disableBuitinCodemodel only makes sense when qmlls is enabled + Project *project = ProjectManager::projectForFile(file); + return isEnabledOnProject(project); +} + +void setupQmllsClientSettings() +{ + using namespace LanguageClient; + QmllsClientSettings *clientSettings = new QmllsClientSettings(); + + const ClientType type{ + Constants::QMLLS_CLIENT_SETTINGS_ID, + clientSettings->m_name, + []() { return new QmllsClientSettings; }, + false}; + + const QList savedSettings = LanguageClientSettings::storesBySettingsType(type.id); + + if (!savedSettings.isEmpty()) + clientSettings->fromMap(savedSettings.first()); + + LanguageClientManager::registerClientSettings(clientSettings); + LanguageClientSettings::registerClientType(type); +} + +QmllsClientSettingsWidget::QmllsClientSettingsWidget( + const QmllsClientSettings *settings, QWidget *parent) + : QWidget(parent) + , m_useLatestQmlls(new QCheckBox(Tr::tr("Use from latest Qt version"), this)) + , m_disableBuiltinCodemodel(new QCheckBox( + Tr::tr("Use advanced features (renaming, find usages, and so on) (experimental)"), this)) + , m_generateQmllsIniFiles( + new QCheckBox(Tr::tr("Create .qmlls.ini files for new projects"), this)) + , m_ignoreMinimumQmllsVersion(new QCheckBox( + Tr::tr("Allow versions below Qt %1") + .arg(QmllsClientSettings::mininumQmllsVersion.toString()), + this)) + , m_useQmllsSemanticHighlighting( + new QCheckBox(Tr::tr("Enable semantic highlighting (experimental)"), this)) +{ + m_useLatestQmlls->setChecked(settings->m_useLatestQmlls); + m_disableBuiltinCodemodel->setChecked(settings->m_disableBuiltinCodemodel); + m_generateQmllsIniFiles->setChecked(settings->m_generateQmllsIniFiles); + m_ignoreMinimumQmllsVersion->setChecked(settings->m_ignoreMinimumQmllsVersion); + m_useQmllsSemanticHighlighting->setChecked(settings->m_useQmllsSemanticHighlighting); + + using namespace Layouting; + // clang-format off + auto form = Form { + m_ignoreMinimumQmllsVersion, br, + m_disableBuiltinCodemodel, br, + m_useQmllsSemanticHighlighting, br, + m_useLatestQmlls, br, + m_generateQmllsIniFiles, br, + }; + // clang-format on + + form.attachTo(this); +} +bool QmllsClientSettingsWidget::useLatestQmlls() const +{ + return m_useLatestQmlls->isChecked(); +} +bool QmllsClientSettingsWidget::disableBuiltinCodemodel() const +{ + return m_disableBuiltinCodemodel->isChecked(); +} +bool QmllsClientSettingsWidget::generateQmllsIniFiles() const +{ + return m_generateQmllsIniFiles->isChecked(); +} +bool QmllsClientSettingsWidget::ignoreMinimumQmllsVersion() const +{ + return m_ignoreMinimumQmllsVersion->isChecked(); +} +bool QmllsClientSettingsWidget::useQmllsSemanticHighlighting() const +{ + return m_useQmllsSemanticHighlighting->isChecked(); +} + +} // namespace QmlJSEditor + +#include "qmllsclientsettings.moc" diff --git a/src/plugins/qmljseditor/qmllsclientsettings.h b/src/plugins/qmljseditor/qmllsclientsettings.h new file mode 100644 index 00000000000..d27f0ad350b --- /dev/null +++ b/src/plugins/qmljseditor/qmllsclientsettings.h @@ -0,0 +1,46 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +#include + +namespace QmlJSEditor { + +class QmllsClientSettings : public LanguageClient::BaseSettings +{ +public: + static const inline QVersionNumber mininumQmllsVersion = QVersionNumber(6, 8); + + QmllsClientSettings(); + BaseSettings *copy() const override { return new QmllsClientSettings(*this); } + + QWidget *createSettingsWidget(QWidget *parent = nullptr) const override; + bool applyFromSettingsWidget(QWidget *widget) override; + + void toMap(Utils::Store &map) const override; + void fromMap(const Utils::Store &map) override; + + // helpers: + bool isEnabledOnProjectFile(const Utils::FilePath &file) const; + bool useQmllsWithBuiltinCodemodelOnProject(const Utils::FilePath &file) const; + + bool m_useLatestQmlls = false; + bool m_ignoreMinimumQmllsVersion = false; + bool m_useQmllsSemanticHighlighting = false; + bool m_disableBuiltinCodemodel = false; + bool m_generateQmllsIniFiles = false; + +protected: + LanguageClient::BaseClientInterface *createInterface(ProjectExplorer::Project *) const override; + LanguageClient::Client *createClient( + LanguageClient::BaseClientInterface *interface) const override; +}; + +QmllsClientSettings *qmllsSettings(); +void setupQmllsClientSettings(); + +} // namespace QmlJSEditor diff --git a/src/plugins/qmljseditor/qmltaskmanager.cpp b/src/plugins/qmljseditor/qmltaskmanager.cpp index 43c908a6445..9f7423b794c 100644 --- a/src/plugins/qmljseditor/qmltaskmanager.cpp +++ b/src/plugins/qmljseditor/qmltaskmanager.cpp @@ -3,7 +3,7 @@ #include "qmltaskmanager.h" #include "qmljseditorconstants.h" -#include "qmljseditorsettings.h" +#include "qmllsclientsettings.h" #include #include @@ -122,7 +122,7 @@ void QmlTaskManager::updateSemanticMessagesNow() const bool isCMake = buildSystem->name() == "cmake"; // heuristic: qmllint will output meaningful warnings if qmlls is enabled - if (isCMake && QmllsSettingsManager::instance()->useQmlls(buildSystem->project())) { + if (isCMake && qmllsSettings()->isEnabledOnProject(buildSystem->project())) { // abort any update that's going on already, and remove old codemodel warnings m_messageCollector.cancel(); removeAllTasks(true); From 1b11ba2772e27a7ed7c89fcf1e7cc6e79ca10769 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Thu, 14 Nov 2024 16:14:27 +0100 Subject: [PATCH 342/989] qmlls: enabled/disable embedded codemodel Make the (de)activateDocument() method in Client virtual, and override it in QmllsClient to actually be able to enable or disable the embedded codemodel. Also add a setSourcesWithCapabilities method to QmlJSEditorDocument that calls the same-named method in QmlJSEditorDocumentPrivate. Fixes: QTCREATORBUG-32025 Task-number: QTCREATORBUG-31897 Change-Id: I5802c1c3f2f983236182bbefa58ff425692b2532 Reviewed-by: David Schulz --- src/plugins/languageclient/client.h | 4 ++-- src/plugins/qmljseditor/qmljseditordocument.cpp | 7 +++++++ src/plugins/qmljseditor/qmljseditordocument.h | 5 ++++- src/plugins/qmljseditor/qmljseditorsettings.cpp | 1 - src/plugins/qmljseditor/qmllsclient.cpp | 17 +++++++++++++++++ src/plugins/qmljseditor/qmllsclient.h | 5 +++++ 6 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 079d3eb9677..d57d3fdbe73 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -114,9 +114,9 @@ public: virtual void openDocument(TextEditor::TextDocument *document); void closeDocument(TextEditor::TextDocument *document, const std::optional &overwriteFilePath = {}); - void activateDocument(TextEditor::TextDocument *document); + virtual void activateDocument(TextEditor::TextDocument *document); void activateEditor(Core::IEditor *editor); - void deactivateDocument(TextEditor::TextDocument *document); + virtual void deactivateDocument(TextEditor::TextDocument *document); bool documentOpen(const TextEditor::TextDocument *document) const; TextEditor::TextDocument *documentForFilePath(const Utils::FilePath &file) const; void setShadowDocument(const Utils::FilePath &filePath, const QString &contents); diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp index b9460ad3c21..266867ac6ca 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.cpp +++ b/src/plugins/qmljseditor/qmljseditordocument.cpp @@ -831,4 +831,11 @@ void QmlJSEditorDocument::triggerPendingUpdates() } } +void QmlJSEditorDocument::setSourcesWithCapabilities( + const LanguageServerProtocol::ServerCapabilities &cap) +{ + d->setSourcesWithCapabilities(cap); +} + + } // QmlJSEditor diff --git a/src/plugins/qmljseditor/qmljseditordocument.h b/src/plugins/qmljseditor/qmljseditordocument.h index 3428952370a..0334cb6336b 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.h +++ b/src/plugins/qmljseditor/qmljseditordocument.h @@ -5,8 +5,9 @@ #include "qmljseditor_global.h" -#include +#include #include +#include #include @@ -37,6 +38,8 @@ public: void setIsDesignModePreferred(bool value); bool isDesignModePreferred() const; + void setSourcesWithCapabilities(const LanguageServerProtocol::ServerCapabilities &cap); + signals: void updateCodeWarnings(QmlJS::Document::Ptr doc); void semanticInfoUpdated(const QmlJSTools::SemanticInfo &semanticInfo); diff --git a/src/plugins/qmljseditor/qmljseditorsettings.cpp b/src/plugins/qmljseditor/qmljseditorsettings.cpp index 7d34f296df5..179086aacf5 100644 --- a/src/plugins/qmljseditor/qmljseditorsettings.cpp +++ b/src/plugins/qmljseditor/qmljseditorsettings.cpp @@ -5,7 +5,6 @@ #include "qmljseditorconstants.h" #include "qmljseditortr.h" #include "qmllsclient.h" -#include "qmllsclientsettings.h" #include #include diff --git a/src/plugins/qmljseditor/qmllsclient.cpp b/src/plugins/qmljseditor/qmllsclient.cpp index 5976ce7880f..9749ccd7d6d 100644 --- a/src/plugins/qmljseditor/qmllsclient.cpp +++ b/src/plugins/qmljseditor/qmllsclient.cpp @@ -4,6 +4,7 @@ #include "qmllsclient.h" #include "qmljseditorconstants.h" +#include "qmljseditordocument.h" #include "qmljsquickfix.h" #include "qmllsclientsettings.h" @@ -114,6 +115,22 @@ public: } }; +void QmllsClient::activateDocument(TextEditor::TextDocument *document) +{ + Client::activateDocument(document); + + if (auto qmljseditor = qobject_cast(document)) + qmljseditor->setSourcesWithCapabilities(capabilities()); +} + +void QmllsClient::deactivateDocument(TextEditor::TextDocument *document) +{ + Client::deactivateDocument(document); + + if (auto qmljseditor = qobject_cast(document)) + qmljseditor->setSourcesWithCapabilities(LanguageServerProtocol::ServerCapabilities{}); +} + QmllsClient::QmllsClient(StdIOClientInterface *interface) : Client(interface) { diff --git a/src/plugins/qmljseditor/qmllsclient.h b/src/plugins/qmljseditor/qmllsclient.h index 8ea9dfbeec7..ffe2114e511 100644 --- a/src/plugins/qmljseditor/qmllsclient.h +++ b/src/plugins/qmljseditor/qmllsclient.h @@ -10,6 +10,8 @@ #include #include +#include "qmllsclientsettings.h" + namespace QmlJSEditor { class QMLJSEDITOR_EXPORT QmllsClient : public LanguageClient::Client @@ -55,6 +57,9 @@ public: void startImpl() override; void updateQmllsSemanticHighlightingCapability(); + + void activateDocument(TextEditor::TextDocument *document) override; + void deactivateDocument(TextEditor::TextDocument *document) override; private: static QMap semanticTokenTypesMap(); }; From 68309a5e855ff13aa3614ff3d76befec74361b73 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Wed, 13 Nov 2024 17:52:17 +0100 Subject: [PATCH 343/989] qmlls: link new settings page from old settings page Add a button from the old settings page that opens up the new qmlls settings page, for both global and project specific settings. Task-number: QTCREATORBUG-31897 Change-Id: Ib6b83d7b2427aea99b7be0eec6219ba2fb0c2e59 Reviewed-by: David Schulz --- .../languageclient/languageclient_global.h | 1 + .../languageclient/languageclientsettings.cpp | 1 + .../qmljseditor/qmljseditorsettings.cpp | 73 +++++-------------- src/plugins/qmljseditor/qmljseditorsettings.h | 11 --- 4 files changed, 21 insertions(+), 65 deletions(-) diff --git a/src/plugins/languageclient/languageclient_global.h b/src/plugins/languageclient/languageclient_global.h index cdcd1fb5ddc..4f8ed160eef 100644 --- a/src/plugins/languageclient/languageclient_global.h +++ b/src/plugins/languageclient/languageclient_global.h @@ -18,6 +18,7 @@ namespace Constants { const char LANGUAGECLIENT_SETTINGS_CATEGORY[] = "ZY.LanguageClient"; const char LANGUAGECLIENT_SETTINGS_PAGE[] = "LanguageClient.General"; +const char LANGUAGECLIENT_SETTINGS_PANEL[] = "LanguageClient.General"; const char LANGUAGECLIENT_STDIO_SETTINGS_ID[] = "LanguageClient::StdIOSettingsID"; const char LANGUAGECLIENT_SETTINGS_TR[] = QT_TRANSLATE_NOOP("QtC::LanguageClient", "Language Client"); const char LANGUAGECLIENT_DOCUMENT_FILTER_ID[] = "Current Document Symbols"; diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 29abe9ba9c4..d00974c1be2 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -1344,6 +1344,7 @@ public: { setPriority(35); setDisplayName(Tr::tr("Language Server")); + setId(Constants::LANGUAGECLIENT_SETTINGS_PANEL); setCreateWidgetFunction([](Project *project) { return new LanguageClientProjectSettingsWidget(project); }); diff --git a/src/plugins/qmljseditor/qmljseditorsettings.cpp b/src/plugins/qmljseditor/qmljseditorsettings.cpp index 179086aacf5..adfebf3bb98 100644 --- a/src/plugins/qmljseditor/qmljseditorsettings.cpp +++ b/src/plugins/qmljseditor/qmljseditorsettings.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -41,6 +42,7 @@ #include #include #include +#include #include #include @@ -259,6 +261,7 @@ public: analyzerMessagesView->setContextMenuPolicy(Qt::CustomContextMenu); connect(analyzerMessagesView, &QTreeView::customContextMenuRequested, this, &QmlJsEditingSettingsPageWidget::showContextMenu); + using namespace Layouting; // clang-format off QWidget *formattingGroup = nullptr; @@ -290,9 +293,15 @@ public: Row { s.uiQmlOpenMode, st } }, }, - Group{ + Group { title(Tr::tr("QML Language Server")), - // TODO: link to new settings + Row { + PushButton { + text(Tr::tr("Open Language Server preferences...")), + onClicked(this, [] { Core::ICore::showOptionsDialog(LanguageClient::Constants::LANGUAGECLIENT_SETTINGS_PAGE); }) + }, + st + }, }, Group { title(Tr::tr("Static Analyzer")), @@ -375,77 +384,33 @@ QmlJsEditingSettingsPage::QmlJsEditingSettingsPage() setSettingsProvider([] { return &settings(); }); } -ProjectSettings::ProjectSettings(Project *project) -{ - setAutoApply(true); - - const Key group = QmlJSEditor::Constants::SETTINGS_CATEGORY_QML; - - useQmlls.setSettingsKey(group, USE_QMLLS); - useQmlls.setDefaultValue(true); - useQmlls.setLabelText(Tr::tr("Turn on")); - useQmlls.setToolTip(Tr::tr("Enable QML Language Server on this project.")); - - useGlobalSettings.setSettingsKey(group, USE_GLOBAL_SETTINGS); - useGlobalSettings.setDefaultValue(true); - - Store map = storeFromVariant(project->namedSettings(SETTINGS_KEY_MAIN)); - fromMap(map); - - useQmlls.addOnChanged(this, [this, project] { save(project); }); - useGlobalSettings.addOnChanged(this, [this, project] { save(project); }); -} - -void ProjectSettings::save(Project *project) -{ - Store map; - toMap(map); - project->setNamedSettings(SETTINGS_KEY_MAIN, variantFromStore(map)); - - // TODO: this does not do anything for now. Either force re-apply when the functionality - // is available in LanguageClient (tracked in QTCREATORBUG-32015) or remove ProjectSettings - // class completely in favor of the LanguageClient project specific settings implementation - // (tracked in QTCREATORBUG-31987). - LanguageClientManager::applySettings(); -} - class QmlJsEditingProjectSettingsWidget final : public ProjectSettingsWidget { public: - explicit QmlJsEditingProjectSettingsWidget(Project *project) - : m_settings{project} + explicit QmlJsEditingProjectSettingsWidget(Project *) { - setUseGlobalSettingsCheckBoxVisible(true); + setUseGlobalSettingsCheckBoxVisible(false); setGlobalSettingsId(SETTINGS_PAGE); setExpanding(true); - setUseGlobalSettings(m_settings.useGlobalSettings()); - - setEnabled(!m_settings.useGlobalSettings()); - using namespace Layouting; // clang-format off Column { Group { title(Tr::tr("QML Language Server")), - Column { - &m_settings.useQmlls, + Row { + PushButton { + text(Tr::tr("Open Language Server preferences...")), + onClicked(this, [] { ProjectExplorerPlugin::activateProjectPanel(LanguageClient::Constants::LANGUAGECLIENT_SETTINGS_PANEL); }) + }, + st, }, }, tight, st, }.attachTo(this); // clang-format on - - connect( - this, &ProjectSettingsWidget::useGlobalSettingsChanged, this, [this](bool newUseGlobal) { - setEnabled(!newUseGlobal); - m_settings.useGlobalSettings.setValue(newUseGlobal); - }); } - -private: - ProjectSettings m_settings; }; class QmlJsEditingProjectPanelFactory : public ProjectPanelFactory diff --git a/src/plugins/qmljseditor/qmljseditorsettings.h b/src/plugins/qmljseditor/qmljseditorsettings.h index f2bf64d1a9d..21e435c2b0c 100644 --- a/src/plugins/qmljseditor/qmljseditorsettings.h +++ b/src/plugins/qmljseditor/qmljseditorsettings.h @@ -44,17 +44,6 @@ public: QmlJsEditingSettingsPage(); }; -class ProjectSettings : public Utils::AspectContainer -{ -public: - ProjectSettings(ProjectExplorer::Project *project); - - Utils::BoolAspect useQmlls{this}; - Utils::BoolAspect useGlobalSettings{this}; - - void save(ProjectExplorer::Project *project); -}; - void setupQmlJsEditingProjectPanel(); } // QmlJSEditor::Internal From 3d3323fa0e7715682b1ad40b784b23afd548b2d4 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Thu, 14 Nov 2024 16:06:40 +0100 Subject: [PATCH 344/989] qmlls: port old settings to new ones Load the values from the BaseAspect settings (where they were previously stored before the introduction of QmllsClientSettings). if the new qmlls settings do no exist yet. Task-number: QTCREATORBUG-31897 Change-Id: I438f1489671ed1843d2390910f46730a270eac6b Reviewed-by: Fabian Kosmale Reviewed-by: David Schulz --- .../qmljseditor/qmllsclientsettings.cpp | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index 663ed0ed91c..b0f90f648ee 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -233,7 +233,6 @@ void QmllsClientSettings::fromMap(const Store &map) m_generateQmllsIniFiles = map[generateQmllsIniFilesKey].toBool(); m_ignoreMinimumQmllsVersion = map[ignoreMinimumQmllsVersionKey].toBool(); m_useQmllsSemanticHighlighting = map[useQmllsSemanticHighlightingKey].toBool(); - return; } bool QmllsClientSettings::isEnabledOnProjectFile(const Utils::FilePath &file) const @@ -252,6 +251,34 @@ bool QmllsClientSettings::useQmllsWithBuiltinCodemodelOnProject(const Utils::Fil return isEnabledOnProject(project); } +// first time initialization: port old settings from the QmlJsEditingSettings AspectContainer +static void portFromOldSettings(QmllsClientSettings* qmllsClientSettings) +{ + QtcSettings *settings = BaseAspect::qtcSettings(); + + const Key baseKey = Key{QmlJSEditor::Constants::SETTINGS_CATEGORY_QML} + "/"; + + auto portSetting = [&settings](const Key &key, bool *output) { + if (settings->contains(key)) + *output = settings->value(key).toBool(); + }; + + constexpr char USE_QMLLS[] = "QmlJSEditor.UseQmlls"; + constexpr char USE_LATEST_QMLLS[] = "QmlJSEditor.UseLatestQmlls"; + constexpr char DISABLE_BUILTIN_CODEMODEL[] = "QmlJSEditor.DisableBuiltinCodemodel"; + constexpr char GENERATE_QMLLS_INI_FILES[] = "QmlJSEditor.GenerateQmllsIniFiles"; + constexpr char IGNORE_MINIMUM_QMLLS_VERSION[] = "QmlJSEditor.IgnoreMinimumQmllsVersion"; + constexpr char USE_QMLLS_SEMANTIC_HIGHLIGHTING[] + = "QmlJSEditor.EnableQmllsSemanticHighlighting"; + + portSetting(baseKey + USE_QMLLS, &qmllsClientSettings->m_enabled); + portSetting(baseKey + USE_LATEST_QMLLS, &qmllsClientSettings->m_useLatestQmlls); + portSetting(baseKey + DISABLE_BUILTIN_CODEMODEL, &qmllsClientSettings->m_disableBuiltinCodemodel); + portSetting(baseKey + GENERATE_QMLLS_INI_FILES, &qmllsClientSettings->m_generateQmllsIniFiles); + portSetting(baseKey + IGNORE_MINIMUM_QMLLS_VERSION, &qmllsClientSettings->m_ignoreMinimumQmllsVersion); + portSetting(baseKey + USE_QMLLS_SEMANTIC_HIGHLIGHTING, &qmllsClientSettings->m_useQmllsSemanticHighlighting); +} + void setupQmllsClientSettings() { using namespace LanguageClient; @@ -267,6 +294,8 @@ void setupQmllsClientSettings() if (!savedSettings.isEmpty()) clientSettings->fromMap(savedSettings.first()); + else + portFromOldSettings(clientSettings); LanguageClientManager::registerClientSettings(clientSettings); LanguageClientSettings::registerClientType(type); From 8b767caf312007e92a22b9d66b0a8fde54a8b770 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 3 Dec 2024 15:08:01 +0100 Subject: [PATCH 345/989] TextEditor: Simplify ColorScheme::save() signature Change-Id: I1ea25996a97e1cdbfb97f1f19231322e8a804cc6 Reviewed-by: David Schulz --- src/plugins/texteditor/colorscheme.cpp | 6 ++++-- src/plugins/texteditor/colorscheme.h | 2 +- src/plugins/texteditor/fontsettings.cpp | 4 ++-- src/plugins/texteditor/fontsettingspage.cpp | 10 +++++----- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/plugins/texteditor/colorscheme.cpp b/src/plugins/texteditor/colorscheme.cpp index 67f99c5226f..ed653518219 100644 --- a/src/plugins/texteditor/colorscheme.cpp +++ b/src/plugins/texteditor/colorscheme.cpp @@ -6,6 +6,8 @@ #include "texteditorconstants.h" #include "texteditortr.h" +#include + #include #include @@ -216,7 +218,7 @@ void ColorScheme::clear() m_formats.clear(); } -bool ColorScheme::save(const FilePath &filePath, QWidget *parent) const +bool ColorScheme::save(const FilePath &filePath) const { FileSaver saver(filePath); if (!saver.hasError()) { @@ -262,7 +264,7 @@ bool ColorScheme::save(const FilePath &filePath, QWidget *parent) const saver.setResult(&w); } - return saver.finalize(parent); + return saver.finalize(Core::ICore::dialogParent()); } namespace { diff --git a/src/plugins/texteditor/colorscheme.h b/src/plugins/texteditor/colorscheme.h index 3532dc57ba3..bd4487f05ba 100644 --- a/src/plugins/texteditor/colorscheme.h +++ b/src/plugins/texteditor/colorscheme.h @@ -97,7 +97,7 @@ public: void clear(); - bool save(const Utils::FilePath &filePath, QWidget *parent) const; + bool save(const Utils::FilePath &filePath) const; bool load(const Utils::FilePath &filePath); bool equals(const ColorScheme &cs) const diff --git a/src/plugins/texteditor/fontsettings.cpp b/src/plugins/texteditor/fontsettings.cpp index 54e384984b3..f64b5550add 100644 --- a/src/plugins/texteditor/fontsettings.cpp +++ b/src/plugins/texteditor/fontsettings.cpp @@ -464,9 +464,9 @@ bool FontSettings::loadColorScheme(const Utils::FilePath &filePath, return loaded; } -bool FontSettings::saveColorScheme(const Utils::FilePath &fileName) +bool FontSettings::saveColorScheme(const FilePath &fileName) { - const bool saved = m_scheme.save(fileName, Core::ICore::dialogParent()); + const bool saved = m_scheme.save(fileName); if (saved) m_schemeFileName = fileName; return saved; diff --git a/src/plugins/texteditor/fontsettingspage.cpp b/src/plugins/texteditor/fontsettingspage.cpp index 5f38e583a12..67fe67b6973 100644 --- a/src/plugins/texteditor/fontsettingspage.cpp +++ b/src/plugins/texteditor/fontsettingspage.cpp @@ -552,7 +552,7 @@ void FontSettingsPageWidget::copyColorScheme(const QString &name) ColorScheme scheme = m_value.colorScheme(); scheme.setDisplayName(name); - if (scheme.save(filePath, Core::ICore::dialogParent())) + if (scheme.save(filePath)) m_value.setColorSchemeFileName(filePath); refreshColorSchemeList(); @@ -629,7 +629,7 @@ void FontSettingsPageWidget::importScheme() ColorScheme scheme; if (scheme.load(importedFile)) { scheme.setDisplayName(name); - scheme.save(saveFileName, Core::ICore::dialogParent()); + scheme.save(saveFileName); m_value.loadColorScheme(saveFileName, m_descriptions); } else { qWarning() << "Failed to import color scheme:" << importedFile; @@ -656,7 +656,7 @@ void FontSettingsPageWidget::exportScheme() Tr::tr("Color scheme (*.xml);;All files (*)")); if (!filePath.isEmpty()) - m_value.colorScheme().save(filePath, Core::ICore::dialogParent()); + m_value.colorScheme().save(filePath); } void FontSettingsPageWidget::maybeSaveColorScheme() @@ -680,7 +680,7 @@ void FontSettingsPageWidget::maybeSaveColorScheme() if (messageBox.exec() == QMessageBox::Save) { const ColorScheme &scheme = m_schemeEdit->colorScheme(); - scheme.save(m_value.colorSchemeFileName(), Core::ICore::dialogParent()); + scheme.save(m_value.colorSchemeFileName()); } } @@ -726,7 +726,7 @@ void FontSettingsPageWidget::apply() // Update the scheme and save it under the name it already has m_value.setColorScheme(m_schemeEdit->colorScheme()); const ColorScheme &scheme = m_value.colorScheme(); - scheme.save(m_value.colorSchemeFileName(), Core::ICore::dialogParent()); + scheme.save(m_value.colorSchemeFileName()); } bool ok; From 70bf792b99cddac6ad4d81a1b64f1cc9dec5c97b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 5 Dec 2024 05:45:00 +0100 Subject: [PATCH 346/989] QmlJSEditor: Fix qbs build Amends a737828d7d6b385ef09355e0c56b4ff9620b4f0a. Change-Id: Ib07e645bba9661606b56996e355b230044b1f036 Reviewed-by: David Schulz --- src/plugins/qmljseditor/qmljseditor.qbs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmljseditor/qmljseditor.qbs b/src/plugins/qmljseditor/qmljseditor.qbs index 1ed1d976ac7..7bdd51e5461 100644 --- a/src/plugins/qmljseditor/qmljseditor.qbs +++ b/src/plugins/qmljseditor/qmljseditor.qbs @@ -21,6 +21,8 @@ QtcPlugin { "qmlexpressionundercursor.h", "qmllsclient.cpp", "qmllsclient.h", + "qmllsclientsettings.cpp", + "qmllsclientsettings.h", "qmljsautocompleter.cpp", "qmljsautocompleter.h", "qmljscompletionassist.cpp", From 3690bef597d8fc2d002c25ce987b11dc152b5008 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 16 Aug 2023 13:10:50 +0200 Subject: [PATCH 347/989] Editor: Add tab settings button to editor toolbar The button summarizes the tab settings in the form of : . The button opens a menu that lets the user modify the tab settings for the current document. Change-Id: Ieacab1a55c9814d1248eccf72622a6e92399f545 Reviewed-by: Christian Stenger --- src/plugins/texteditor/texteditor.cpp | 103 +++++++++++++++++++++++++- src/plugins/texteditor/texteditor.h | 1 + 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index e07a1a61d87..83f7f7e549f 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -72,12 +72,14 @@ #include #include +#include #include #include -#include #include +#include #include #include +#include #include #include #include @@ -91,7 +93,6 @@ #include #include #include -#include #include #include #include @@ -268,6 +269,97 @@ QSize LineColumnButton::sizeHint() const namespace Internal { +class TabSettingsButton : public QToolButton +{ +public: + TabSettingsButton(TextEditorWidget *parent) + : QToolButton(parent) + { + connect(this, &QToolButton::clicked, this, &TabSettingsButton::showMenu); + } + + void setDocument(TextDocument *doc) + { + if (m_doc) + disconnect(m_doc, &TextDocument::tabSettingsChanged, this, &TabSettingsButton::update); + m_doc = doc; + if (QTC_GUARD(m_doc)) { + connect(m_doc, &TextDocument::tabSettingsChanged, this, &TabSettingsButton::update); + update(); + } + } + +private: + void update() + { + QTC_ASSERT(m_doc, return); + const TabSettings ts = m_doc->tabSettings(); + QString policy; + switch (ts.m_tabPolicy) { + case TabSettings::SpacesOnlyTabPolicy: + policy = Tr::tr("Spaces"); + break; + case TabSettings::TabsOnlyTabPolicy: + policy = Tr::tr("Tabs"); + break; + case TabSettings::MixedTabPolicy: + policy = Tr::tr("Mixed"); + break; + } + setText(QString("%1: %2").arg(policy).arg(ts.m_indentSize)); + } + + void showMenu() + { + QTC_ASSERT(m_doc, return); + auto menu = new QMenu; + menu->addAction(ActionManager::command(Constants::AUTO_INDENT_SELECTION)->action()); + auto documentSettings = menu->addMenu(Tr::tr("Document Settings")); + + auto tabSettings = documentSettings->addMenu(Tr::tr("Tab Settings")); + auto modifyTabSettings = [this](std::function modifier) { + return [this, modifier]() { + auto ts = m_doc->tabSettings(); + modifier(ts); + m_doc->setTabSettings(ts); + }; + }; + tabSettings->addAction(Tr::tr("Spaces"), modifyTabSettings([](TabSettings &tabSettings) { + tabSettings.m_tabPolicy = TabSettings::SpacesOnlyTabPolicy; + })); + tabSettings->addAction(Tr::tr("Tabs"), modifyTabSettings([](TabSettings &tabSettings) { + tabSettings.m_tabPolicy = TabSettings::TabsOnlyTabPolicy; + })); + auto indentSize = documentSettings->addMenu(Tr::tr("Indent Size")); + auto indentSizeGroup = new QActionGroup(indentSize); + indentSizeGroup->setExclusive(true); + for (int i = 1; i <= 8; ++i) { + auto action = indentSizeGroup->addAction(QString::number(i)); + action->setCheckable(true); + action->setChecked(i == m_doc->tabSettings().m_indentSize); + connect(action, &QAction::triggered, modifyTabSettings([i](TabSettings &tabSettings) { + tabSettings.m_indentSize = i; + })); + } + indentSize->addActions(indentSizeGroup->actions()); + auto tabSize = documentSettings->addMenu(Tr::tr("Tab Size")); + auto tabSizeGroup = new QActionGroup(tabSize); + tabSizeGroup->setExclusive(true); + for (int i = 1; i <= 8; ++i) { + auto action = tabSizeGroup->addAction(QString::number(i)); + action->setCheckable(true); + action->setChecked(i == m_doc->tabSettings().m_tabSize); + connect(action, &QAction::triggered, modifyTabSettings([i](TabSettings &tabSettings) { + tabSettings.m_tabSize = i; + })); + } + tabSize->addActions(tabSizeGroup->actions()); + menu->popup(QCursor::pos()); + } + + TextDocument *m_doc = nullptr; +}; + class TextEditorAnimator : public QObject { Q_OBJECT @@ -776,6 +868,7 @@ public: QAction *m_stretchAction = nullptr; QAction *m_toolbarOutlineAction = nullptr; LineColumnButton *m_cursorPositionButton = nullptr; + TabSettingsButton *m_tabSettingsButton = nullptr; QToolButton *m_fileEncodingButton = nullptr; QAction *m_fileEncodingLabelAction = nullptr; BaseTextFind *m_find = nullptr; @@ -1117,6 +1210,10 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent) m_cursorPositionButton->setContentsMargins(spacing, 0, spacing, 0); m_toolBarWidget->layout()->addWidget(m_cursorPositionButton); + m_tabSettingsButton = new TabSettingsButton(q); + m_tabSettingsButton->setContentsMargins(spacing, 0, spacing, 0); + m_toolBarWidget->layout()->addWidget(m_tabSettingsButton); + m_fileLineEnding = new QToolButton(q); m_fileLineEnding->setContentsMargins(spacing, 0, spacing, 0); m_fileLineEndingAction = m_toolBar->addWidget(m_fileLineEnding); @@ -1490,6 +1587,7 @@ void TextEditorWidgetPrivate::setDocument(const QSharedPointer &do q->setCompletionSettings(TextEditorSettings::completionSettings()); q->setExtraEncodingSettings(globalExtraEncodingSettings()); q->setCodeStyle(TextEditorSettings::codeStyle(m_tabSettingsId)); + m_tabSettingsButton->setDocument(q->textDocument()); m_blockCount = doc->document()->blockCount(); @@ -10077,6 +10175,7 @@ void TextEditorWidgetPrivate::applyTabSettings() { updateTabStops(); m_autoCompleter->setTabSettings(m_document->tabSettings()); + emit q->tabSettingsChanged(); } int TextEditorWidget::columnCount() const diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 0b320c9c706..ed2bdf7d775 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -556,6 +556,7 @@ signals: void requestRename(const QTextCursor &cursor); void requestCallHierarchy(const QTextCursor &cursor); void toolbarOutlineChanged(QWidget *newOutline); + void tabSettingsChanged(); // used by the IEditor void saveCurrentStateForNavigationHistory(); From 05724a2d464d78d37622ba2fab7a9c71bd259f98 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 2 Dec 2024 14:51:00 +0100 Subject: [PATCH 348/989] Utils: Un-export TreeViewComboBoxView It's only used as QTreeView in user code. Change-Id: I1db77e6a5acc6b6feec914a025c403e74cb6cef2 Reviewed-by: Eike Ziller --- src/libs/utils/treeviewcombobox.cpp | 30 ++++++++++++++++------------- src/libs/utils/treeviewcombobox.h | 14 ++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/libs/utils/treeviewcombobox.cpp b/src/libs/utils/treeviewcombobox.cpp index a83979f45fb..e8c8b4ab9b5 100644 --- a/src/libs/utils/treeviewcombobox.cpp +++ b/src/libs/utils/treeviewcombobox.cpp @@ -5,21 +5,23 @@ #include -using namespace Utils; +namespace Utils { -TreeViewComboBoxView::TreeViewComboBoxView(QWidget *parent) - : QTreeView(parent) +class TreeViewComboBoxView final : public QTreeView { - // TODO: Disable the root for all items (with a custom delegate?) - setRootIsDecorated(false); -} - -void TreeViewComboBoxView::adjustWidth(int width) -{ - setMaximumWidth(width); - setMinimumWidth(qMin(qMax(sizeHintForColumn(0), minimumSizeHint().width()), width)); -} +public: + TreeViewComboBoxView() + { + // TODO: Disable the root for all items (with a custom delegate?) + setRootIsDecorated(false); + } + void adjustWidth(int width) + { + setMaximumWidth(width); + setMinimumWidth(qMin(qMax(sizeHintForColumn(0), minimumSizeHint().width()), width)); + } +}; TreeViewComboBox::TreeViewComboBox(QWidget *parent) : QComboBox(parent) @@ -135,7 +137,9 @@ void TreeViewComboBox::hidePopup() QComboBox::hidePopup(); } -TreeViewComboBoxView *TreeViewComboBox::view() const +QTreeView *TreeViewComboBox::view() const { return m_view; } + +} // Utils diff --git a/src/libs/utils/treeviewcombobox.h b/src/libs/utils/treeviewcombobox.h index 32169f3db36..7237347f1c2 100644 --- a/src/libs/utils/treeviewcombobox.h +++ b/src/libs/utils/treeviewcombobox.h @@ -10,13 +10,6 @@ namespace Utils { -class QTCREATOR_UTILS_EXPORT TreeViewComboBoxView : public QTreeView -{ -public: - TreeViewComboBoxView(QWidget *parent = nullptr); - void adjustWidth(int width); -}; - class QTCREATOR_UTILS_EXPORT TreeViewComboBox : public QComboBox { public: @@ -29,14 +22,15 @@ public: void showPopup() override; void hidePopup() override; - TreeViewComboBoxView *view() const; + QTreeView *view() const; private: QModelIndex indexBelow(QModelIndex index); QModelIndex indexAbove(QModelIndex index); QModelIndex lastIndex(const QModelIndex &index); - TreeViewComboBoxView *m_view; + class TreeViewComboBoxView *m_view; bool m_skipNextHide = false; }; -} + +} // Utils From 11cef62b9eec2982e6c359858326eaa901272bdf Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 4 Dec 2024 08:57:56 +0100 Subject: [PATCH 349/989] Core: Always use dialogParent() for FileUtils::showInGraphicalShell() Change-Id: I02b0ded14c78872b59bd9ec4cfb53878d3f96ad5 Reviewed-by: Eike Ziller --- src/plugins/android/androidbuildapkstep.cpp | 2 +- src/plugins/coreplugin/coreplugin.cpp | 2 +- src/plugins/coreplugin/editormanager/editormanager.cpp | 4 ++-- src/plugins/coreplugin/fileutils.cpp | 10 +++++----- src/plugins/coreplugin/fileutils.h | 6 +----- src/plugins/coreplugin/icore.cpp | 4 ++-- src/plugins/projectexplorer/projectexplorer.cpp | 2 +- .../assetexporterplugin/assetexportdialog.cpp | 2 +- .../components/assetslibrary/assetslibrarywidget.cpp | 2 +- 9 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index b6563eb870f..9b6e99be433 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -826,7 +826,7 @@ void AndroidBuildApkStep::showInGraphicalShell() return; } } - Core::FileUtils::showInGraphicalShell(Core::ICore::dialogParent(), packagePath); + Core::FileUtils::showInGraphicalShell(packagePath); } QWidget *AndroidBuildApkStep::createConfigWidget() diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 899eb5465bc..2ac1b1dceac 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -204,7 +204,7 @@ static void addToPathChooserContextMenu(PathChooser *pathChooser, QMenu *menu) if (pathChooser->filePath().exists()) { auto showInGraphicalShell = new QAction(FileUtils::msgGraphicalShellAction(), menu); QObject::connect(showInGraphicalShell, &QAction::triggered, pathChooser, [pathChooser] { - Core::FileUtils::showInGraphicalShell(pathChooser, pathChooser->filePath()); + Core::FileUtils::showInGraphicalShell(pathChooser->filePath()); }); menu->insertAction(firstAction, showInGraphicalShell); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 946836f740c..937f4b2082c 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -518,7 +518,7 @@ void EditorManagerPrivate::init() return; const FilePath fp = EditorManager::currentDocument()->filePath(); if (!fp.isEmpty()) - FileUtils::showInGraphicalShell(ICore::dialogParent(), fp); + FileUtils::showInGraphicalShell(fp); }); ActionBuilder showInFileSystem(this, Constants::SHOWINFILESYSTEMVIEW); @@ -560,7 +560,7 @@ void EditorManagerPrivate::init() connect(m_openGraphicalShellContextAction, &QAction::triggered, this, [this] { if (!m_contextMenuDocument || m_contextMenuEntry->filePath().isEmpty()) return; - FileUtils::showInGraphicalShell(ICore::dialogParent(), m_contextMenuEntry->filePath()); + FileUtils::showInGraphicalShell(m_contextMenuEntry->filePath()); }); connect(m_showInFileSystemViewContextAction, &QAction::triggered, this, [this] { if (!m_contextMenuDocument || m_contextMenuEntry->filePath().isEmpty()) diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 30d02bd3ad7..85915cd8f0d 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -55,21 +55,21 @@ static FilePath windowsDirectory() } // Show error with option to open settings. -static void showGraphicalShellError(QWidget *parent, const QString &app, const QString &error) +static void showGraphicalShellError(const QString &app, const QString &error) { const QString title = Tr::tr("Launching a file browser failed"); const QString msg = Tr::tr("Unable to start the file manager:\n\n%1\n\n").arg(app); - QMessageBox mbox(QMessageBox::Warning, title, msg, QMessageBox::Close, parent); + QMessageBox mbox(QMessageBox::Warning, title, msg, QMessageBox::Close, ICore::dialogParent()); if (!error.isEmpty()) mbox.setDetailedText(Tr::tr("\"%1\" returned the following error:\n\n%2").arg(app, error)); QAbstractButton *settingsButton = mbox.addButton(Core::ICore::msgShowOptionsDialog(), QMessageBox::ActionRole); mbox.exec(); if (mbox.clickedButton() == settingsButton) - ICore::showOptionsDialog(Constants::SETTINGS_ID_INTERFACE, parent); + ICore::showOptionsDialog(Constants::SETTINGS_ID_INTERFACE, ICore::dialogParent()); } -void showInGraphicalShell(QWidget *parent, const FilePath &pathIn) +void showInGraphicalShell(const FilePath &pathIn) { const QFileInfo fileInfo = pathIn.toFileInfo(); // Mac, Windows support folder or file. @@ -98,7 +98,7 @@ void showInGraphicalShell(QWidget *parent, const FilePath &pathIn) error = Tr::tr("Error while starting file browser."); } if (!error.isEmpty()) - showGraphicalShellError(parent, app, error); + showGraphicalShellError(app, error); } } diff --git a/src/plugins/coreplugin/fileutils.h b/src/plugins/coreplugin/fileutils.h index 984673ec44e..d762ad09eb7 100644 --- a/src/plugins/coreplugin/fileutils.h +++ b/src/plugins/coreplugin/fileutils.h @@ -7,10 +7,6 @@ #include -QT_BEGIN_NAMESPACE -class QWidget; -QT_END_NAMESPACE - namespace Utils { class Environment; } namespace Core { @@ -20,7 +16,7 @@ enum class HandleIncludeGuards { No, Yes }; namespace FileUtils { // Helpers for common directory browser options. -CORE_EXPORT void showInGraphicalShell(QWidget *parent, const Utils::FilePath &path); +CORE_EXPORT void showInGraphicalShell(const Utils::FilePath &path); CORE_EXPORT void showInFileSystemView(const Utils::FilePath &path); CORE_EXPORT void openTerminal(const Utils::FilePath &path, const Utils::Environment &env); CORE_EXPORT QString msgFindInDirectory(); diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 617ece82771..6168acfd6c6 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -2539,9 +2539,9 @@ void ICorePrivate::changeLog() connect(showInExplorer, &QPushButton::clicked, this, [versionCombo, versionedFiles] { const int index = versionCombo->currentIndex(); if (index >= 0 && index < versionedFiles.size()) - FileUtils::showInGraphicalShell(ICore::dialogParent(), versionedFiles.at(index).second); + FileUtils::showInGraphicalShell(versionedFiles.at(index).second); else - FileUtils::showInGraphicalShell(ICore::dialogParent(), ICore::resourcePath("changelog")); + FileUtils::showInGraphicalShell(ICore::resourcePath("changelog")); }); dialog->show(); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 80535e5c958..437ba6b4101 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3795,7 +3795,7 @@ void ProjectExplorerPluginPrivate::showInGraphicalShell() { Node *currentNode = ProjectTree::currentNode(); QTC_ASSERT(currentNode, return); - Core::FileUtils::showInGraphicalShell(ICore::dialogParent(), currentNode->path()); + Core::FileUtils::showInGraphicalShell(currentNode->path()); } void ProjectExplorerPluginPrivate::showInFileSystemPane() diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp index cee25240cfc..658bbc88437 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp @@ -92,7 +92,7 @@ AssetExportDialog::AssetExportDialog(const FilePath &exportPath, m_exportPath->setPromptDialogFilter(tr("Metadata file (*.metadata)")); m_exportPath->lineEdit()->setReadOnly(true); m_exportPath->addButton(tr("Open"), this, [this] { - Core::FileUtils::showInGraphicalShell(Core::ICore::dialogParent(), m_exportPath->filePath()); + Core::FileUtils::showInGraphicalShell(m_exportPath->filePath()); }); m_exportAssetsCheck = new QCheckBox(tr("Export assets"), this); diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 7d182b99c42..4ac39bfc8c0 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -221,7 +221,7 @@ bool AssetsLibraryWidget::canCreateEffects() const void AssetsLibraryWidget::showInGraphicalShell(const QString &path) { - Core::FileUtils::showInGraphicalShell(Core::ICore::dialogParent(), Utils::FilePath::fromString(path)); + Core::FileUtils::showInGraphicalShell(Utils::FilePath::fromString(path)); } QString AssetsLibraryWidget::showInGraphicalShellMsg() const From c1f432ed12c3f012a5625fd3d1b353ebed2ab417 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 5 Dec 2024 10:55:08 +0100 Subject: [PATCH 350/989] LanguageClient: add artificial "); default: return Utils::TreeItem::data(column, role); } diff --git a/src/plugins/languageclient/languageclientoutline.h b/src/plugins/languageclient/languageclientoutline.h index 6d222f05363..4831c954e59 100644 --- a/src/plugins/languageclient/languageclientoutline.h +++ b/src/plugins/languageclient/languageclientoutline.h @@ -29,6 +29,8 @@ public: return m_range.contains(pos); } + bool valid() const { return m_client; } + protected: // TreeItem interface QVariant data(int column, int role) const override; From aa709cbbdb00a9968fbaacfbacdba89f5d1fa125 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Thu, 5 Dec 2024 11:30:45 +0100 Subject: [PATCH 351/989] qmlls: use hostbinpath instead of binpath Amends a737828d7d6b385ef09355e0c56b4ff9620b4f0a that used the binPath instead of the hostBinPath() when constructing the path to qmlls. This allows to run qmlls on a Boot2Qt project with the correct Qml import paths. Together with the above-mentioned commit, this fixes the undismissable warnings from QTBUG-114697 as QtC now starts the correct qmlls executable with the correct import paths on boot2qt projects. Fixes: QTBUG-114697 Change-Id: I1123d69a923f595869b980de1a0daf266cf2bc80 Reviewed-by: David Schulz --- src/plugins/qmljseditor/qmllsclientsettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index b0f90f648ee..3379111953d 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -121,7 +121,7 @@ static CommandLine commandLineForQmlls(const Project *project) auto [executable, version] = qmllsSettings()->m_useLatestQmlls ? evaluateLatestQmlls() - : std::make_pair(qtVersion->binPath() / "qmlls", qtVersion->qtVersion()); + : std::make_pair(qtVersion->hostBinPath() / "qmlls", qtVersion->qtVersion()); CommandLine result{executable, {}}; From 7f2d46a52e8572988603f4cedb3a636dd0e53163 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 5 Dec 2024 14:36:18 +0100 Subject: [PATCH 352/989] RemoteLinux: Add testing instructions Fixes: QTCREATORBUG-32020 Change-Id: Ia55c81bd1cd697e9bd778b8c80a9cdef77228ce7 Reviewed-by: hjk --- tests/manual/manual.qbs | 1 + .../remotelinux/remotelinux-testplan.md | 97 +++++++++++++++++++ tests/manual/remotelinux/remotelinux.qbs | 6 ++ 3 files changed, 104 insertions(+) create mode 100644 tests/manual/remotelinux/remotelinux-testplan.md create mode 100644 tests/manual/remotelinux/remotelinux.qbs diff --git a/tests/manual/manual.qbs b/tests/manual/manual.qbs index 43932d378f5..8670713723e 100644 --- a/tests/manual/manual.qbs +++ b/tests/manual/manual.qbs @@ -11,6 +11,7 @@ Project { "fakevim/fakevim.qbs", "pluginview/pluginview.qbs", "proparser/testreader.qbs", + "remotelinux/remotelinux.qbs", "scripts/scripts.qbs", "shootout/shootout.qbs", "spinner/spinner.qbs", diff --git a/tests/manual/remotelinux/remotelinux-testplan.md b/tests/manual/remotelinux/remotelinux-testplan.md new file mode 100644 index 00000000000..b2d59846197 --- /dev/null +++ b/tests/manual/remotelinux/remotelinux-testplan.md @@ -0,0 +1,97 @@ +# Prerequisites +- The usual set of development tools on the local machine. +- An ssh client on the local machine. +- SSH access to some machine (which might also be the local machine). + +Most of the following assumes a Linux host. On Windows, additional prerequisites +and some tweaks to the instructions are necessary. + +# Initial environment +Start Qt Creator with clean settings, preferably using the -tcs switch. + +# Basic tests + +## Create a device +1. Go to `Edit -> Preferences -> Devices`. +2. Click `Add ...`, choose `Remote Linux Device` from the list, and start the wizard. +3. Enter appropriate values for server and user name and proceed to the next page. + - Simplest is to use `localhost` for the server. + - You might want to create a dedicated test user for this purpose. +4. Deploy a public key. + - Removing the key from `~/.ssh/authorized_keys` before/after testing forces you to re-enter + the password the next time you run this test, which increases the test coverage. +5. Finish the wizard. Qt Creator should now start a device test, which should succeed. + - If you misconfigured something, fix it and re-run the device test via the `Test` button + until it succeeds. +6. Check that the `Current state` field has the value `Unknown`. +7. Press the `Apply` button. +8. On the right side of the settings widget, click `Show Running Processes ...` and + `Open Remote Shell` and check that they do what they are supposed to. + +## Create a Kit for running +1. Go to `Edit -> Preferences -> Kits`. +2. Create a new kit and set `Run Device` to `Remote Linux Device`. The device created + in the previous step should get chosen automatically in the `Device` combo box. +3. Make sure that the kit's toolchain is compatible with the device. +4. Press the "OK" button. + +## Deploy and run an application +1. Create a simple app via `File -> New Project -> Non-Qt Project -> Simple C Application`. + - Make sure you select the newly created kit in the last step. +2. Edit the project file such that the application will get deployed to an accessible + location on the target machine. + - For Qmake: Add `target.path = /tmp/mytest` and `INSTALLS += target`. + - For qbs: Add `qbs.installPrefix: "/tmp/mytest"`. + - For CMake and other exotic build tools, check the respective documentation. +3. Click the `Run` button. The project should get built and deployed, and the output + "Hello World" should appear in the application output pane. + +# Advanced tests + +## Try to deploy and run an application on a "broken" device +1. "Break" your device by pointing it to an invalid host name in the settings, + e.g. `1.2.3.4`. + - **Do not run the device test!** + - For extra test coverage, repeat this entire scenario with an invalid user + instead of an invalid host. +2. Press `OK`. +3. Click the `Run` button. Expected results: + - Deployment should fail and create an issue in the Issues pane. This may take some + time, and Qt Creator might appear frozen temporarily. + - A note should pop up informing you that the device is now marked as "disonnected". +4. Go back to the device settings. + - Verify that the device is now marked with a red dot and `Current state` is `Disconnected`. + - Revert the changes from step 1. **Again, do not run the device test.** +5. Click the `Run` button. This should fail again, but faster and without blocking. +6. Go to the device settings again. + - Re-run the device test and verify that is succeeds. + - The red dot should have disappeared and the state should be back to `Unknown`. + - Press `OK`. +7. Click the `Run` button. Deployment should work again, and "Hello World" should appear + in the application output pane. + +## Create a kit for building +1. Go to `Edit -> Preferences -> Kits`. +2. Create a new kit and set `Build Device` to `Remote Linux` device. The device created + in the previous step should get chosen automatically in the `Device` combo box. +3. Press the "OK" button. + +## Create a remote project +1. Create a simple app via `File -> New Project -> Non-Qt Project -> Simple C Application`. + - Make sure you choose a **remote path** on the first page + - Make sure you select the newly created kit in the last step. +2. Check that Qt Creator at least tries to load the project. + - This operation might be exceedingly slow. + - It is also possible that the build tool will error out. + - What is important is that some semblance of a project tree appears, with the project + file pointing to a remote path, and there is no device-related error message. + +## Open a project on a "broken" device +1. "Break" your device as described above. +2. Re-open your last project, e.g. via `File->Recent Projects`. +3. This should fail, possibly after some time, and a note about the device being + disconnected should appear. +4. Close the project. +5. "Fix" the device again as in the "deploy and run" scenario, once with and once + without re-running the device test, and again observe that the operation fails again + and succeeds, respectively. diff --git a/tests/manual/remotelinux/remotelinux.qbs b/tests/manual/remotelinux/remotelinux.qbs new file mode 100644 index 00000000000..8edd95c59a0 --- /dev/null +++ b/tests/manual/remotelinux/remotelinux.qbs @@ -0,0 +1,6 @@ +Product { + name: "RemoteLinux testing instructions" + files: [ + "remotelinux-testplan.md", + ] +} From d6a54cd322a06c726dafb4fd70ba8d2bb607eb96 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 6 Dec 2024 08:11:34 +0100 Subject: [PATCH 353/989] Editor: fix crash on resetting document Ensure the previous document still exist when setting the new document to the tab settings button Change-Id: Idddbf2bc25cffc7899994d1aca28d664df727a14 Reviewed-by: Christian Stenger --- src/plugins/texteditor/texteditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 83f7f7e549f..056ce0aab95 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -1466,6 +1466,7 @@ void TextEditorWidgetPrivate::setDocument(const QSharedPointer &do m_document = doc; q->QPlainTextEdit::setDocument(doc->document()); + m_tabSettingsButton->setDocument(q->textDocument()); previousDocument.clear(); q->setCursorWidth(2); // Applies to the document layout @@ -1587,7 +1588,6 @@ void TextEditorWidgetPrivate::setDocument(const QSharedPointer &do q->setCompletionSettings(TextEditorSettings::completionSettings()); q->setExtraEncodingSettings(globalExtraEncodingSettings()); q->setCodeStyle(TextEditorSettings::codeStyle(m_tabSettingsId)); - m_tabSettingsButton->setDocument(q->textDocument()); m_blockCount = doc->document()->blockCount(); From 0e839d3090e2983e35675964a71d6c4494d3f2f8 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 3 Dec 2024 14:45:46 +0100 Subject: [PATCH 354/989] Marketplace: Remove plugin Change-Id: I44a753ad3638a8a858de6a256f60f3a0a6a9efac Reviewed-by: Eike Ziller --- src/plugins/CMakeLists.txt | 1 - src/plugins/marketplace/CMakeLists.txt | 10 - src/plugins/marketplace/Marketplace.json.in | 24 -- src/plugins/marketplace/marketplace.qbs | 20 -- src/plugins/marketplace/marketplaceplugin.cpp | 23 -- src/plugins/marketplace/marketplacetr.h | 15 - src/plugins/marketplace/productlistmodel.cpp | 306 ------------------ src/plugins/marketplace/productlistmodel.h | 65 ---- .../marketplace/qtmarketplacewelcomepage.cpp | 129 -------- .../marketplace/qtmarketplacewelcomepage.h | 12 - src/plugins/plugins.qbs | 1 - 11 files changed, 606 deletions(-) delete mode 100644 src/plugins/marketplace/CMakeLists.txt delete mode 100644 src/plugins/marketplace/Marketplace.json.in delete mode 100644 src/plugins/marketplace/marketplace.qbs delete mode 100644 src/plugins/marketplace/marketplaceplugin.cpp delete mode 100644 src/plugins/marketplace/marketplacetr.h delete mode 100644 src/plugins/marketplace/productlistmodel.cpp delete mode 100644 src/plugins/marketplace/productlistmodel.h delete mode 100644 src/plugins/marketplace/qtmarketplacewelcomepage.cpp delete mode 100644 src/plugins/marketplace/qtmarketplacewelcomepage.h diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 59cb95790b0..2ec7c5a3795 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -8,7 +8,6 @@ add_subdirectory(serialterminal) add_subdirectory(extensionmanager) add_subdirectory(helloworld) add_subdirectory(imageviewer) -add_subdirectory(marketplace) add_subdirectory(screenrecorder) add_subdirectory(updateinfo) add_subdirectory(welcome) diff --git a/src/plugins/marketplace/CMakeLists.txt b/src/plugins/marketplace/CMakeLists.txt deleted file mode 100644 index e883b460b73..00000000000 --- a/src/plugins/marketplace/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_qtc_plugin(Marketplace - PLUGIN_DEPENDS Core - SOURCES - marketplaceplugin.cpp - marketplacetr.h - productlistmodel.cpp - productlistmodel.h - qtmarketplacewelcomepage.cpp - qtmarketplacewelcomepage.h -) diff --git a/src/plugins/marketplace/Marketplace.json.in b/src/plugins/marketplace/Marketplace.json.in deleted file mode 100644 index eb9405abb3f..00000000000 --- a/src/plugins/marketplace/Marketplace.json.in +++ /dev/null @@ -1,24 +0,0 @@ -{ - "Id" : "marketplace", - "DisplayName" : "Qt Marketplace", - "Name" : "Marketplace", - "Version" : "${IDE_VERSION}", - "CompatVersion" : "${IDE_VERSION_COMPAT}", - "DisabledByDefault" : true, - "VendorId" : "theqtcompany", - "Vendor" : "The Qt Company Ltd", - "Copyright" : "${IDE_COPYRIGHT}", - "License" : [ "Commercial Usage", - "", - "Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.", - "", - "GNU General Public License Usage", - "", - "Alternatively, this file may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this file. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html." - ], - "Description" : "Install applications from Qt Marketplace.", - "LongDescription" : [], - "Url" : "https://www.qt.io", - "DocumentationUrl" : "https://marketplace.qt.io", - ${IDE_PLUGIN_DEPENDENCIES} -} diff --git a/src/plugins/marketplace/marketplace.qbs b/src/plugins/marketplace/marketplace.qbs deleted file mode 100644 index 1bb20ad5ae8..00000000000 --- a/src/plugins/marketplace/marketplace.qbs +++ /dev/null @@ -1,20 +0,0 @@ -import qbs - -QtcPlugin { - name: "Marketplace" - - Depends { name: "Core" } - Depends { name: "Utils" } - - Depends { name: "Qt.widgets" } - Depends { name: "Qt.network" } - - files: [ - "marketplaceplugin.cpp", - "marketplacetr.h", - "productlistmodel.cpp", - "productlistmodel.h", - "qtmarketplacewelcomepage.cpp", - "qtmarketplacewelcomepage.h", - ] -} diff --git a/src/plugins/marketplace/marketplaceplugin.cpp b/src/plugins/marketplace/marketplaceplugin.cpp deleted file mode 100644 index fb9dfd09201..00000000000 --- a/src/plugins/marketplace/marketplaceplugin.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2019 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qtmarketplacewelcomepage.h" - -#include - -namespace Marketplace::Internal { - -class MarketplacePlugin final : public ExtensionSystem::IPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Marketplace.json") - - void initialize() final - { - setupQtMarketPlaceWelcomePage(this); - } -}; - -} // Marketplace::Internal - -#include "marketplaceplugin.moc" diff --git a/src/plugins/marketplace/marketplacetr.h b/src/plugins/marketplace/marketplacetr.h deleted file mode 100644 index 3f20fbf574b..00000000000 --- a/src/plugins/marketplace/marketplacetr.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Marketplace { - -struct Tr -{ - Q_DECLARE_TR_FUNCTIONS(QtC::Marketplace) -}; - -} // namespace Marketplace diff --git a/src/plugins/marketplace/productlistmodel.cpp b/src/plugins/marketplace/productlistmodel.cpp deleted file mode 100644 index 4d36c84db48..00000000000 --- a/src/plugins/marketplace/productlistmodel.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright (C) 2019 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "productlistmodel.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Core; - -namespace Marketplace { -namespace Internal { - -class ProductItemDelegate : public Core::ListItemDelegate -{ -public: - void clickAction(const Core::ListItem *item) const override - { - QTC_ASSERT(item, return); - auto productItem = static_cast(item); - const QUrl url(QString("https://marketplace.qt.io/products/").append(productItem->handle)); - QDesktopServices::openUrl(url); - } -}; - -static const QNetworkRequest constructRequest(const QString &collection) -{ - QString url("https://marketplace.qt.io"); - if (collection.isEmpty()) - url.append("/collections.json"); - else - url.append("/collections/").append(collection).append("/products.json"); - - return QNetworkRequest(url); -} - -static const QString plainTextFromHtml(const QString &original) -{ - QString plainText(original); - static const QRegularExpression breakReturn("<\\s*br/?\\s*>", - QRegularExpression::CaseInsensitiveOption); - static const QRegularExpression allTags("<[^>]*>"); - static const QRegularExpression moreThan2NewLines("\n{3,}"); - plainText.replace(breakReturn, "\n"); // "translate"
    into newline - plainText.remove(allTags); // remove all tags - plainText = plainText.trimmed(); - plainText.replace(moreThan2NewLines, "\n\n"); // consolidate some newlines - - // FIXME the description text is usually too long and needs to get elided sensibly - return (plainText.length() > 157) ? plainText.left(157).append("...") : plainText; -} - -static int priority(const QString &collection) -{ - if (collection == "featured") - return 10; - if (collection == "from-qt-partners") - return 20; - return 50; -} - -SectionedProducts::SectionedProducts(QWidget *parent) - : SectionedGridView(parent) - , m_productDelegate(new ProductItemDelegate) -{ - setItemDelegate(m_productDelegate); - setPixmapFunction([this](const QString &url) -> QPixmap { - queueImageForDownload(url); - return {}; - }); - connect(m_productDelegate, - &ProductItemDelegate::tagClicked, - this, - &SectionedProducts::onTagClicked); -} - -SectionedProducts::~SectionedProducts() -{ - delete m_productDelegate; -} - -void SectionedProducts::updateCollections() -{ - emit toggleProgressIndicator(true); - QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(constructRequest({})); - connect(reply, &QNetworkReply::finished, - this, [this, reply]() { onFetchCollectionsFinished(reply); }); -} - -void SectionedProducts::onFetchCollectionsFinished(QNetworkReply *reply) -{ - QTC_ASSERT(reply, return); - const QScopeGuard cleanup([reply] { reply->deleteLater(); }); - - if (reply->error() == QNetworkReply::NoError) { - const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll()); - if (doc.isNull()) - return; - - const QJsonArray collections = doc.object().value("collections").toArray(); - for (int i = 0, end = collections.size(); i < end; ++i) { - const QJsonObject obj = collections.at(i).toObject(); - const auto handle = obj.value("handle").toString(); - const int productsCount = obj.value("products_count").toInt(); - - if (productsCount > 0 && handle != "all-products" && handle != "qt-education-1") { - m_collectionTitles.insert(handle, obj.value("title").toString()); - m_pendingCollections.append(handle); - } - } - if (!m_pendingCollections.isEmpty()) - fetchCollectionsContents(); - } else { - QVariant status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); - if (status.isValid() && status.toInt() == 430) - QTimer::singleShot(30000, this, &SectionedProducts::updateCollections); - else - emit errorOccurred(reply->error(), reply->errorString()); - } -} - -void SectionedProducts::onFetchSingleCollectionFinished(QNetworkReply *reply) -{ - emit toggleProgressIndicator(false); - - QTC_ASSERT(reply, return); - const QScopeGuard cleanup([reply] { reply->deleteLater(); }); - - QList productsForCollection; - if (reply->error() == QNetworkReply::NoError) { - const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll()); - if (doc.isNull()) - return; - - QString collectionHandle = reply->url().path(); - if (QTC_GUARD(collectionHandle.endsWith("/products.json"))) { - collectionHandle.chop(14); - collectionHandle = collectionHandle.mid(collectionHandle.lastIndexOf('/') + 1); - } - - const QList presentItems = items(); - const QJsonArray products = doc.object().value("products").toArray(); - for (int i = 0, end = products.size(); i < end; ++i) { - const QJsonObject obj = products.at(i).toObject(); - const QString handle = obj.value("handle").toString(); - - bool foundItem = Utils::findOrDefault(presentItems, [handle](const Core::ListItem *it) { - return static_cast(it)->handle == handle; - }); - if (foundItem) - continue; - - ProductItem *product = new ProductItem; - product->name = obj.value("title").toString(); - product->description = plainTextFromHtml(obj.value("body_html").toString()); - - product->handle = handle; - const QJsonArray tags = obj.value("tags").toArray(); - for (const auto &val : tags) - product->tags.append(val.toString()); - - const auto images = obj.value("images").toArray(); - if (!images.isEmpty()) { - auto imgObj = images.first().toObject(); - const QJsonValue imageSrc = imgObj.value("src"); - if (imageSrc.isString()) - product->imageUrl = imageSrc.toString(); - } - - productsForCollection.append(product); - } - - if (!productsForCollection.isEmpty()) { - Section section{m_collectionTitles.value(collectionHandle), priority(collectionHandle)}; - addNewSection(section, productsForCollection); - } - } else { - // bad.. but we still might be able to fetch another collection - qWarning() << "Failed to fetch collection:" << reply->errorString() << reply->error(); - } - - if (!m_pendingCollections.isEmpty()) // more collections? go ahead.. - fetchCollectionsContents(); - else if (m_productModels.isEmpty()) - emit errorOccurred(0, "Failed to fetch any collection."); -} - -void SectionedProducts::fetchCollectionsContents() -{ - QTC_ASSERT(!m_pendingCollections.isEmpty(), return); - const QString collection = m_pendingCollections.dequeue(); - - QNetworkReply *reply - = Utils::NetworkAccessManager::instance()->get(constructRequest(collection)); - connect(reply, &QNetworkReply::finished, - this, [this, reply]() { onFetchSingleCollectionFinished(reply); }); -} - -void SectionedProducts::queueImageForDownload(const QString &url) -{ - m_pendingImages.insert(url); - if (!m_isDownloadingImage) - fetchNextImage(); -} - -static void updateModelIndexesForUrl(ListModel *model, const QString &url) -{ - const QList items = model->items(); - for (int row = 0, end = items.size(); row < end; ++row) { - if (items.at(row)->imageUrl == url) { - const QModelIndex index = model->index(row); - emit model->dataChanged(index, index, {ListModel::ItemImageRole, Qt::DisplayRole}); - } - } -} - -void SectionedProducts::fetchNextImage() -{ - if (m_pendingImages.isEmpty()) { - m_isDownloadingImage = false; - return; - } - - const auto it = m_pendingImages.constBegin(); - const QString nextUrl = *it; - m_pendingImages.erase(it); - - if (QPixmapCache::find(nextUrl, nullptr)) { - // this image is already cached it might have been added while downloading - for (ListModel *model : std::as_const(m_productModels)) - updateModelIndexesForUrl(model, nextUrl); - fetchNextImage(); - return; - } - - m_isDownloadingImage = true; - QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(QNetworkRequest(nextUrl)); - connect(reply, &QNetworkReply::finished, - this, [this, reply]() { onImageDownloadFinished(reply); }); -} - -void SectionedProducts::onImageDownloadFinished(QNetworkReply *reply) -{ - QTC_ASSERT(reply, return); - const QScopeGuard cleanup([reply] { reply->deleteLater(); }); - - if (reply->error() == QNetworkReply::NoError) { - const QByteArray data = reply->readAll(); - QPixmap pixmap; - const QUrl imageUrl = reply->request().url(); - const QString imageFormat = QFileInfo(imageUrl.fileName()).suffix(); - if (pixmap.loadFromData(data, imageFormat.toLatin1())) { - const QString url = imageUrl.toString(); - const int dpr = qApp->devicePixelRatio(); - pixmap = pixmap.scaled(WelcomePageHelpers::WelcomeThumbnailSize * dpr, - Qt::KeepAspectRatio, - Qt::SmoothTransformation); - pixmap.setDevicePixelRatio(dpr); - QPixmapCache::insert(url, pixmap); - for (ListModel *model : std::as_const(m_productModels)) - updateModelIndexesForUrl(model, url); - } - } // handle error not needed - it's okay'ish to have no images as long as the rest works - - fetchNextImage(); -} - -void SectionedProducts::addNewSection(const Section §ion, const QList &items) -{ - QTC_ASSERT(!items.isEmpty(), return); - m_productModels.append(addSection(section, items)); -} - -void SectionedProducts::onTagClicked(const QString &tag) -{ - setCurrentIndex(1 /* search */); - emit tagClicked(tag); -} - -QList SectionedProducts::items() -{ - QList result; - for (const ListModel *model : std::as_const(m_productModels)) - result.append(model->items()); - return result; -} - -} // namespace Internal -} // namespace Marketplace diff --git a/src/plugins/marketplace/productlistmodel.h b/src/plugins/marketplace/productlistmodel.h deleted file mode 100644 index 8da6e01ee90..00000000000 --- a/src/plugins/marketplace/productlistmodel.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2019 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -#include -#include - -QT_BEGIN_NAMESPACE -class QNetworkReply; -QT_END_NAMESPACE - -namespace Marketplace { -namespace Internal { - -class ProductGridView; -class ProductItemDelegate; - -class ProductItem : public Core::ListItem -{ -public: - QString handle; -}; - -class SectionedProducts : public Core::SectionedGridView -{ - Q_OBJECT -public: - explicit SectionedProducts(QWidget *parent); - ~SectionedProducts() override; - void updateCollections(); - void queueImageForDownload(const QString &url); - -signals: - void errorOccurred(int errorCode, const QString &errorString); - void toggleProgressIndicator(bool show); - void tagClicked(const QString &tag); - -private: - void onFetchCollectionsFinished(QNetworkReply *reply); - void onFetchSingleCollectionFinished(QNetworkReply *reply); - void fetchCollectionsContents(); - - void fetchNextImage(); - void onImageDownloadFinished(QNetworkReply *reply); - void addNewSection(const Core::Section §ion, const QList &items); - void onTagClicked(const QString &tag); - - QList items(); - - QQueue m_pendingCollections; - QSet m_pendingImages; - QMap m_collectionTitles; - QList m_productModels; - ProductItemDelegate *m_productDelegate = nullptr; - bool m_isDownloadingImage = false; - int m_columnCount = 1; -}; - -} // namespace Internal -} // namespace Marketplace - -Q_DECLARE_METATYPE(Marketplace::Internal::ProductItem *) diff --git a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp deleted file mode 100644 index cfa37c3d7c0..00000000000 --- a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (C) 2019 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qtmarketplacewelcomepage.h" - -#include "marketplacetr.h" -#include "productlistmodel.h" - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace Core; -using namespace Utils; - -namespace Marketplace::Internal { - -class QtMarketplacePageWidget final : public QWidget -{ -public: - QtMarketplacePageWidget() - { - m_searcher = new Core::SearchBox(this); - m_searcher->setPlaceholderText(Tr::tr("Search in Marketplace...")); - - m_errorLabel = new QLabel(this); - m_errorLabel->setVisible(false); - - m_sectionedProducts = new SectionedProducts(this); - auto progressIndicator = new Utils::ProgressIndicator(ProgressIndicatorSize::Large, this); - progressIndicator->attachToWidget(m_sectionedProducts); - progressIndicator->hide(); - - using namespace StyleHelper::SpacingTokens; - - using namespace Layouting; - Column { - Row { - m_searcher, - m_errorLabel, - customMargins(0, 0, ExVPaddingGapXl, 0), - }, - m_sectionedProducts, - spacing(ExVPaddingGapXl), - customMargins(ExVPaddingGapXl, ExVPaddingGapXl, 0, 0), - }.attachTo(this); - - connect(m_sectionedProducts, &SectionedProducts::toggleProgressIndicator, - progressIndicator, &Utils::ProgressIndicator::setVisible); - connect(m_sectionedProducts, &SectionedProducts::errorOccurred, this, - [this, progressIndicator](int, const QString &message) { - progressIndicator->hide(); - progressIndicator->deleteLater(); - m_errorLabel->setAlignment(Qt::AlignHCenter); - QFont f(m_errorLabel->font()); - f.setPixelSize(20); - m_errorLabel->setFont(f); - const QString txt - = Tr::tr( - "

    Could not fetch data from Qt Marketplace.

    Try with your browser " - "instead: https://marketplace.qt.io" - "


    Error: %1

    ").arg(message); - m_errorLabel->setText(txt); - m_errorLabel->setVisible(true); - m_searcher->setVisible(false); - connect(m_errorLabel, &QLabel::linkActivated, - this, []() { QDesktopServices::openUrl(QUrl("https://marketplace.qt.io")); }); - }); - - connect(m_searcher, - &QLineEdit::textChanged, - m_sectionedProducts, - &SectionedProducts::setSearchStringDelayed); - connect(m_sectionedProducts, &SectionedProducts::tagClicked, - this, &QtMarketplacePageWidget::onTagClicked); - } - - void showEvent(QShowEvent *event) final - { - if (!m_initialized) { - m_initialized = true; - m_sectionedProducts->updateCollections(); - } - QWidget::showEvent(event); - } - - void onTagClicked(const QString &tag) - { - const QString text = m_searcher->text(); - m_searcher->setText((text.startsWith("tag:\"") ? text.trimmed() + " " : QString()) - + QString("tag:\"%1\" ").arg(tag)); - } - -private: - SectionedProducts *m_sectionedProducts = nullptr; - QLabel *m_errorLabel = nullptr; - QLineEdit *m_searcher = nullptr; - bool m_initialized = false; -}; - -// QtMarketplaceWelcomePage - -class QtMarketplaceWelcomePage final : public IWelcomePage -{ -public: - QtMarketplaceWelcomePage() = default; - - QString title() const final { return Tr::tr("Marketplace"); } - int priority() const final { return 60; } - Utils::Id id() const final { return "Marketplace"; } - QWidget *createWidget() const final { return new QtMarketplacePageWidget; } -}; - -void setupQtMarketPlaceWelcomePage(QObject *guard) -{ - auto page = new QtMarketplaceWelcomePage; - page->setParent(guard); -} - -} // Marketplace::Internal diff --git a/src/plugins/marketplace/qtmarketplacewelcomepage.h b/src/plugins/marketplace/qtmarketplacewelcomepage.h deleted file mode 100644 index 99deafbefe6..00000000000 --- a/src/plugins/marketplace/qtmarketplacewelcomepage.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2019 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Marketplace::Internal { - -void setupQtMarketPlaceWelcomePage(QObject *guard); - -} // namespace Marketplace::Internal diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index 7293d34d683..cd882fcd1ec 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -56,7 +56,6 @@ Project { "languageclient/lualanguageclient/lualanguageclient.qbs", "lua/lua.qbs", "macros/macros.qbs", - "marketplace/marketplace.qbs", "mcusupport/mcusupport.qbs", "mercurial/mercurial.qbs", "modeleditor/modeleditor.qbs", From baf02224a2aa2dd22c18c7b000a230cd5382edc5 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 21 Nov 2024 16:30:51 +0100 Subject: [PATCH 355/989] Editor: add function to guess tab settings for a document It can be manually triggered from the menu of the tab settings tool button. Task-number: QTCREATORBUG-25628 Change-Id: Icde79f3579a035fddef354cfdd3bf9b594f28bef Reviewed-by: Christian Stenger --- src/plugins/texteditor/tabsettings.cpp | 95 +++++++++++++++++++++++++- src/plugins/texteditor/tabsettings.h | 4 +- src/plugins/texteditor/texteditor.cpp | 7 +- 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp index d3aa8eb40f4..54aa18f3c29 100644 --- a/src/plugins/texteditor/tabsettings.cpp +++ b/src/plugins/texteditor/tabsettings.cpp @@ -4,6 +4,7 @@ #include "tabsettings.h" #include +#include #include #include @@ -50,6 +51,98 @@ void TabSettings::fromMap(const Store &map) map.value(paddingModeKey, m_continuationAlignBehavior).toInt(); } +TabSettings TabSettings::autoDetect(const QTextDocument *document) const +{ + QTC_ASSERT(document, return *this); + + const int blockCount = document->blockCount(); + if (blockCount < 10) + return *this; + + int totalIndentations = 0; + int indentationWithTabs = 0; + QMap indentCount; + + auto checkText = + [this, &totalIndentations, &indentCount, &indentationWithTabs](const QTextBlock &block) { + if (block.length() == 0) + return; + const QTextDocument *doc = block.document(); + int pos = block.position(); + bool hasTabs = false; + int indentation = 0; + // iterate ove the characters in the document is faster since we do not have to allocate + // a string for each block text when we are only interested in the first few characters + QChar c = doc->characterAt(pos); + while (c.isSpace() && c != QChar::ParagraphSeparator) { + if (c == QChar::Tabulation) { + hasTabs = true; + indentation += m_tabSize; + } else { + ++indentation; + } + c = doc->characterAt(++pos); + } + // only track indentations that are at least 2 columns wide + if (indentation > 1) { + if (hasTabs) + ++indentationWithTabs; + ++indentCount[indentation]; + ++totalIndentations; + } + }; + + if (blockCount < 200) { + // check the indentation of all blocks if the document is shorter than 200 lines + for (QTextBlock block = document->firstBlock(); block.isValid(); block = block.next()) + checkText(block); + } else { + // scanning the first and last 25 lines specifically since those most probably contain + // different indentations + const int startEndDelta = 25; + for (int delta = 0; delta < startEndDelta; ++delta) { + checkText(document->findBlockByNumber(delta)); + checkText(document->findBlockByNumber(blockCount - 1 - delta)); + } + + // scan random lines until we have 100 indentations or checked a maximum of 2000 lines + // to limit the number of checks for large documents + QRandomGenerator gen(QDateTime::currentDateTime().toMSecsSinceEpoch()); + int checks = 0; + while (totalIndentations < 100) { + ++checks; + if (checks > 2000) + break; + const int blockNummer = gen.bounded(startEndDelta + 1, blockCount - startEndDelta - 2); + checkText(document->findBlockByNumber(blockNummer)); + } + } + + // find the most common indent + int mostCommonIndent = 0; + int mostCommonIndentCount = 0; + for (auto it = indentCount.cbegin(); it != indentCount.cend(); ++it) { + if (const int count = it.value(); count > mostCommonIndentCount) { + mostCommonIndentCount = count; + mostCommonIndent = it.key(); + } + } + + for (auto it = indentCount.cbegin(); it != indentCount.cend(); ++it) { + // check whether the smallest indent is a fraction of the most common indent + // to filter out some false positives + if (mostCommonIndent % it.key() == 0) { + TabSettings result = *this; + result.m_indentSize = it.key(); + double relativeTabCount = double(indentationWithTabs) / double(totalIndentations); + result.m_tabPolicy = relativeTabCount > 0.5 ? TabSettings::TabsOnlyTabPolicy + : TabSettings::SpacesOnlyTabPolicy; + return result; + } + } + return *this; +} + bool TabSettings::cursorIsAtBeginningOfLine(const QTextCursor &cursor) { QString text = cursor.block().text(); @@ -80,7 +173,7 @@ int TabSettings::firstNonSpace(const QString &text) return i; } -QString TabSettings::indentationString(const QString &text) const +QString TabSettings::indentationString(const QString &text) { return text.left(firstNonSpace(text)); } diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h index 0a8e4305713..4d28a3c05cd 100644 --- a/src/plugins/texteditor/tabsettings.h +++ b/src/plugins/texteditor/tabsettings.h @@ -41,6 +41,8 @@ public: Utils::Store toMap() const; void fromMap(const Utils::Store &map); + TabSettings autoDetect(const QTextDocument *document) const; + int lineIndentPosition(const QString &text) const; int columnAt(const QString &text, int position) const; int columnAtCursorPosition(const QTextCursor &cursor) const; @@ -48,7 +50,6 @@ public: int columnCountForText(const QString &text, int startColumn = 0) const; int indentedColumn(int column, bool doIndent = true) const; QString indentationString(int startColumn, int targetColumn, int padding, const QTextBlock ¤tBlock = QTextBlock()) const; - QString indentationString(const QString &text) const; int indentationColumn(const QString &text) const; static int maximumPadding(const QString &text); @@ -62,6 +63,7 @@ public: friend bool operator!=(const TabSettings &t1, const TabSettings &t2) { return !t1.equals(t2); } static int firstNonSpace(const QString &text); + static QString indentationString(const QString &text); static inline bool onlySpace(const QString &text) { return firstNonSpace(text) == text.length(); } static int spacesLeftFromPosition(const QString &text, int position); static bool cursorIsAtBeginningOfLine(const QTextCursor &cursor); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 056ce0aab95..51fb959b996 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -316,7 +316,6 @@ private: menu->addAction(ActionManager::command(Constants::AUTO_INDENT_SELECTION)->action()); auto documentSettings = menu->addMenu(Tr::tr("Document Settings")); - auto tabSettings = documentSettings->addMenu(Tr::tr("Tab Settings")); auto modifyTabSettings = [this](std::function modifier) { return [this, modifier]() { auto ts = m_doc->tabSettings(); @@ -324,6 +323,12 @@ private: m_doc->setTabSettings(ts); }; }; + documentSettings->addAction( + Tr::tr("Auto detect"), + modifyTabSettings([doc = m_doc->document()](TabSettings &tabSettings) { + tabSettings = tabSettings.autoDetect(doc); + })); + auto tabSettings = documentSettings->addMenu(Tr::tr("Tab Settings")); tabSettings->addAction(Tr::tr("Spaces"), modifyTabSettings([](TabSettings &tabSettings) { tabSettings.m_tabPolicy = TabSettings::SpacesOnlyTabPolicy; })); From d9016f917e562c8d241772263b4dff5a18864ba4 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 26 Nov 2024 12:02:42 +0100 Subject: [PATCH 356/989] Editor: move code setCodeStyle from widget to document The information was only used in the document and it does not make any sense to change it for different widgets in different ways. Change-Id: I1d7c4548c4bd02c3dfa8f27065e440b7469653b1 Reviewed-by: Christian Stenger --- .../cppeditor/cppcodestylesettingspage.cpp | 2 +- src/plugins/cppeditor/cppeditordocument.cpp | 6 ++++ src/plugins/cppeditor/cppeditordocument.h | 1 + src/plugins/cppeditor/cppeditorwidget.cpp | 6 ---- src/plugins/cppeditor/cppeditorwidget.h | 2 -- .../diffeditor/selectabletexteditorwidget.cpp | 2 +- .../projectexplorer/editorconfiguration.cpp | 4 +-- src/plugins/texteditor/codestyleeditor.cpp | 2 +- src/plugins/texteditor/textdocument.cpp | 24 +++++++++++++ src/plugins/texteditor/textdocument.h | 2 ++ src/plugins/texteditor/texteditor.cpp | 36 +++---------------- src/plugins/texteditor/texteditor.h | 3 -- 12 files changed, 42 insertions(+), 48 deletions(-) diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.cpp b/src/plugins/cppeditor/cppcodestylesettingspage.cpp index 55c3e5b8235..500b6ae9bdb 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.cpp +++ b/src/plugins/cppeditor/cppcodestylesettingspage.cpp @@ -507,7 +507,7 @@ void CppCodeStylePreferencesWidget::updatePreview() QtStyleCodeFormatter formatter(ts, ccss); for (SnippetEditorWidget *preview : std::as_const(d->m_previews)) { preview->textDocument()->setTabSettings(ts); - preview->setCodeStyle(cppCodeStylePreferences); + preview->textDocument()->setCodeStyle(cppCodeStylePreferences); QTextDocument *doc = preview->document(); formatter.invalidateCache(doc); diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index 297e1d81462..8b0735e076e 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -171,6 +171,12 @@ void CppEditorDocument::applyFontSettings() m_processor->semanticRehighlight(); } +void CppEditorDocument::slotCodeStyleSettingsChanged() +{ + QtStyleCodeFormatter formatter; + formatter.invalidateCache(document()); +} + void CppEditorDocument::invalidateFormatterCache() { QtStyleCodeFormatter formatter; diff --git a/src/plugins/cppeditor/cppeditordocument.h b/src/plugins/cppeditor/cppeditordocument.h index 02946c60278..60c171c072d 100644 --- a/src/plugins/cppeditor/cppeditordocument.h +++ b/src/plugins/cppeditor/cppeditordocument.h @@ -68,6 +68,7 @@ signals: protected: void applyFontSettings() override; Utils::Result saveImpl(const Utils::FilePath &filePath, bool autoSave) override; + void slotCodeStyleSettingsChanged() override; private: void invalidateFormatterCache(); diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 4a0f1fb429b..e2bd2ef93e5 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -1246,12 +1246,6 @@ bool CppEditorWidget::handleStringSplitting(QKeyEvent *e) const return false; } -void CppEditorWidget::slotCodeStyleSettingsChanged(const QVariant &) -{ - QtStyleCodeFormatter formatter; - formatter.invalidateCache(document()); -} - void CppEditorWidget::updateSemanticInfo() { updateSemanticInfo(d->m_cppEditorDocument->recalculateSemanticInfo(), diff --git a/src/plugins/cppeditor/cppeditorwidget.h b/src/plugins/cppeditor/cppeditorwidget.h index caad6b89d55..d554c4588eb 100644 --- a/src/plugins/cppeditor/cppeditorwidget.h +++ b/src/plugins/cppeditor/cppeditorwidget.h @@ -115,8 +115,6 @@ protected: bool resolveTarget = true, bool inNextSplit = false) override; - void slotCodeStyleSettingsChanged(const QVariant &) override; - private: void updateFunctionDeclDefLink(); void updateFunctionDeclDefLinkNow(); diff --git a/src/plugins/diffeditor/selectabletexteditorwidget.cpp b/src/plugins/diffeditor/selectabletexteditorwidget.cpp index af7ed7f3d16..41662250cd1 100644 --- a/src/plugins/diffeditor/selectabletexteditorwidget.cpp +++ b/src/plugins/diffeditor/selectabletexteditorwidget.cpp @@ -27,7 +27,7 @@ SelectableTextEditorWidget::SelectableTextEditorWidget(Utils::Id id, QWidget *pa this, &SelectableTextEditorWidget::setDisplaySettings); SelectableTextEditorWidget::setDisplaySettings(TextEditorSettings::displaySettings()); - setCodeStyle(TextEditorSettings::codeStyle()); + textDocument()->setCodeStyle(TextEditorSettings::codeStyle()); setCodeFoldingSupported(true); } diff --git a/src/plugins/projectexplorer/editorconfiguration.cpp b/src/plugins/projectexplorer/editorconfiguration.cpp index 2f40e48159d..bb0cc2fe24d 100644 --- a/src/plugins/projectexplorer/editorconfiguration.cpp +++ b/src/plugins/projectexplorer/editorconfiguration.cpp @@ -234,7 +234,7 @@ void EditorConfiguration::configureEditor(BaseTextEditor *textEditor) const { TextEditorWidget *widget = textEditor->editorWidget(); if (widget) - widget->setCodeStyle(codeStyle(widget->languageSettingsId())); + widget->textDocument()->setCodeStyle(codeStyle(widget->languageSettingsId())); if (!d->m_useGlobal) { textEditor->textDocument()->setCodec(d->m_textCodec); if (widget) @@ -250,7 +250,7 @@ void EditorConfiguration::deconfigureEditor(BaseTextEditor *textEditor) const { TextEditorWidget *widget = textEditor->editorWidget(); if (widget) - widget->setCodeStyle(TextEditorSettings::codeStyle(widget->languageSettingsId())); + widget->textDocument()->setCodeStyle(TextEditorSettings::codeStyle(widget->languageSettingsId())); d->m_editors.removeOne(textEditor); diff --git a/src/plugins/texteditor/codestyleeditor.cpp b/src/plugins/texteditor/codestyleeditor.cpp index c740505895b..9ee1f84b37f 100644 --- a/src/plugins/texteditor/codestyleeditor.cpp +++ b/src/plugins/texteditor/codestyleeditor.cpp @@ -86,7 +86,7 @@ CodeStyleEditor::CodeStyleEditor(ICodeStylePreferencesFactory *factory, indenter->setFileName(fileName); m_preview->textDocument()->setIndenter(indenter); } else { - m_preview->setCodeStyle(codeStyle); + m_preview->textDocument()->setCodeStyle(codeStyle); } updatePreview(); diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 0f77c2568da..8cd61342053 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -5,6 +5,7 @@ #include "extraencodingsettings.h" #include "fontsettings.h" +#include "icodestylepreferences.h" #include "storagesettings.h" #include "syntaxhighlighter.h" #include "tabsettings.h" @@ -76,6 +77,7 @@ public: QString m_suggestedFileName; TypingSettings m_typingSettings; StorageSettings m_storageSettings; + ICodeStylePreferences *m_codeStylePreferences = nullptr; TabSettings m_tabSettings; ExtraEncodingSettings m_extraEncodingSettings; FontSettings m_fontSettings; @@ -457,6 +459,26 @@ IAssistProvider *TextDocument::quickFixAssistProvider() const return d->m_quickFixProvider; } +void TextDocument::setCodeStyle(ICodeStylePreferences *preferences) +{ + indenter()->setCodeStylePreferences(preferences); + if (d->m_codeStylePreferences) { + disconnect(d->m_codeStylePreferences, &ICodeStylePreferences::currentTabSettingsChanged, + this, &TextDocument::setTabSettings); + disconnect(d->m_codeStylePreferences, &ICodeStylePreferences::currentValueChanged, + this, &TextDocument::slotCodeStyleSettingsChanged); + } + d->m_codeStylePreferences = preferences; + if (d->m_codeStylePreferences) { + connect(d->m_codeStylePreferences, &ICodeStylePreferences::currentTabSettingsChanged, + this, &TextDocument::setTabSettings); + connect(d->m_codeStylePreferences, &ICodeStylePreferences::currentValueChanged, + this, &TextDocument::slotCodeStyleSettingsChanged); + setTabSettings(d->m_codeStylePreferences->currentTabSettings()); + slotCodeStyleSettingsChanged(); + } +} + void TextDocument::applyFontSettings() { d->m_fontSettingsNeedsApply = false; @@ -470,6 +492,8 @@ void TextDocument::applyFontSettings() d->m_highlighter->setFontSettings(d->m_fontSettings); } +void TextDocument::slotCodeStyleSettingsChanged() { } + const FontSettings &TextDocument::fontSettings() const { return d->m_fontSettings; diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index 72ee5a8b6cc..fb97543a477 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -139,6 +139,7 @@ public: void setQuickFixAssistProvider(IAssistProvider *provider) const; virtual IAssistProvider *quickFixAssistProvider() const; + void setCodeStyle(ICodeStylePreferences *preferences); void setTabSettings(const TextEditor::TabSettings &tabSettings); void setFontSettings(const TextEditor::FontSettings &fontSettings); @@ -163,6 +164,7 @@ signals: protected: virtual void applyFontSettings(); Utils::Result saveImpl(const Utils::FilePath &filePath, bool autoSave) override; + virtual void slotCodeStyleSettingsChanged(); // Used in CppEditorDocumet private: OpenResult openImpl(QString *errorString, diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 51fb959b996..4848386104d 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -359,6 +359,7 @@ private: })); } tabSize->addActions(tabSizeGroup->actions()); + menu->popup(QCursor::pos()); } @@ -896,7 +897,6 @@ public: QWidget *m_extraArea = nullptr; Id m_tabSettingsId; - ICodeStylePreferences *m_codeStylePreferences = nullptr; DisplaySettings m_displaySettings; bool m_annotationsrRight = true; MarginSettings m_marginSettings; @@ -1592,7 +1592,7 @@ void TextEditorWidgetPrivate::setDocument(const QSharedPointer &do q->setDisplaySettings(TextEditorSettings::displaySettings()); q->setCompletionSettings(TextEditorSettings::completionSettings()); q->setExtraEncodingSettings(globalExtraEncodingSettings()); - q->setCodeStyle(TextEditorSettings::codeStyle(m_tabSettingsId)); + q->textDocument()->setCodeStyle(TextEditorSettings::codeStyle(m_tabSettingsId)); m_blockCount = doc->document()->blockCount(); @@ -7707,7 +7707,8 @@ void TextEditorWidgetPrivate::toggleBlockVisible(const QTextBlock &block) void TextEditorWidget::setLanguageSettingsId(Id settingsId) { d->m_tabSettingsId = settingsId; - setCodeStyle(TextEditorSettings::codeStyle(settingsId)); + if (auto doc = textDocument()) + doc->setCodeStyle(TextEditorSettings::codeStyle(settingsId)); } Id TextEditorWidget::languageSettingsId() const @@ -7715,35 +7716,6 @@ Id TextEditorWidget::languageSettingsId() const return d->m_tabSettingsId; } -void TextEditorWidget::setCodeStyle(ICodeStylePreferences *preferences) -{ - TextDocument *document = d->m_document.data(); - // Not fully initialized yet... wait for TextEditorWidgetPrivate::setupDocumentSignals - if (!document) - return; - document->indenter()->setCodeStylePreferences(preferences); - if (d->m_codeStylePreferences) { - disconnect(d->m_codeStylePreferences, &ICodeStylePreferences::currentTabSettingsChanged, - document, &TextDocument::setTabSettings); - disconnect(d->m_codeStylePreferences, &ICodeStylePreferences::currentValueChanged, - this, &TextEditorWidget::slotCodeStyleSettingsChanged); - } - d->m_codeStylePreferences = preferences; - if (d->m_codeStylePreferences) { - connect(d->m_codeStylePreferences, &ICodeStylePreferences::currentTabSettingsChanged, - document, &TextDocument::setTabSettings); - connect(d->m_codeStylePreferences, &ICodeStylePreferences::currentValueChanged, - this, &TextEditorWidget::slotCodeStyleSettingsChanged); - document->setTabSettings(d->m_codeStylePreferences->currentTabSettings()); - slotCodeStyleSettingsChanged(d->m_codeStylePreferences->currentValue()); - } -} - -void TextEditorWidget::slotCodeStyleSettingsChanged(const QVariant &) -{ - -} - const DisplaySettings &TextEditorWidget::displaySettings() const { return d->m_displaySettings; diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index ed2bdf7d775..787ee75a960 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -319,8 +319,6 @@ public: void setLanguageSettingsId(Utils::Id settingsId); Utils::Id languageSettingsId() const; - void setCodeStyle(ICodeStylePreferences *settings); - const DisplaySettings &displaySettings() const; const MarginSettings &marginSettings() const; const BehaviorSettings &behaviorSettings() const; @@ -689,7 +687,6 @@ signals: protected: virtual void slotCursorPositionChanged(); // Used in VcsBase - virtual void slotCodeStyleSettingsChanged(const QVariant &); // Used in CppEditor private: std::unique_ptr d; From 870eb37867ce8dd8df2dff6162dbb6c32683213f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 26 Nov 2024 13:12:28 +0100 Subject: [PATCH 357/989] Editor: link global settings in tab settings button Change-Id: I5ca9f3a2191e9146d5517dc8cccf6932e2c21032 Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppcodestylepreferences.cpp | 2 ++ src/plugins/qmljstools/qmljscodestylepreferences.cpp | 2 ++ src/plugins/texteditor/icodestylepreferences.cpp | 11 +++++++++++ src/plugins/texteditor/icodestylepreferences.h | 4 ++++ src/plugins/texteditor/simplecodestylepreferences.cpp | 3 ++- src/plugins/texteditor/textdocument.cpp | 5 +++++ src/plugins/texteditor/textdocument.h | 1 + src/plugins/texteditor/texteditor.cpp | 9 +++++++++ 8 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppcodestylepreferences.cpp b/src/plugins/cppeditor/cppcodestylepreferences.cpp index 59d2bd232fe..cb04d4e12cb 100644 --- a/src/plugins/cppeditor/cppcodestylepreferences.cpp +++ b/src/plugins/cppeditor/cppcodestylepreferences.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "cppcodestylepreferences.h" +#include "cppeditorconstants.h" using namespace Utils; @@ -11,6 +12,7 @@ CppCodeStylePreferences::CppCodeStylePreferences(QObject *parent) : ICodeStylePreferences(parent) { setSettingsSuffix("CodeStyleSettings"); + setGlobalSettingsCategory(Constants::CPP_CODE_STYLE_SETTINGS_ID); connect(this, &CppCodeStylePreferences::currentValueChanged, this, &CppCodeStylePreferences::slotCurrentValueChanged); diff --git a/src/plugins/qmljstools/qmljscodestylepreferences.cpp b/src/plugins/qmljstools/qmljscodestylepreferences.cpp index f19c40a7b88..679dd561f09 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferences.cpp +++ b/src/plugins/qmljstools/qmljscodestylepreferences.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qmljscodestylepreferences.h" +#include "qmljstoolsconstants.h" using namespace Utils; @@ -11,6 +12,7 @@ QmlJSCodeStylePreferences::QmlJSCodeStylePreferences(QObject *parent) : ICodeStylePreferences(parent) { setSettingsSuffix("CodeStyleSettings"); + setGlobalSettingsCategory(Constants::QML_JS_CODE_STYLE_SETTINGS_ID); connect(this, &QmlJSCodeStylePreferences::currentValueChanged, this, &QmlJSCodeStylePreferences::slotCurrentValueChanged); diff --git a/src/plugins/texteditor/icodestylepreferences.cpp b/src/plugins/texteditor/icodestylepreferences.cpp index 8eae1c4be70..997e67a6be2 100644 --- a/src/plugins/texteditor/icodestylepreferences.cpp +++ b/src/plugins/texteditor/icodestylepreferences.cpp @@ -19,6 +19,7 @@ class ICodeStylePreferencesPrivate public: CodeStylePool *m_pool = nullptr; ICodeStylePreferences *m_currentDelegate = nullptr; + Utils::Id m_globalSettingsCategory; TabSettings m_tabSettings; QByteArray m_id; QString m_displayName; @@ -249,6 +250,16 @@ void ICodeStylePreferences::fromMap(const Store &map) } } +Id ICodeStylePreferences::globalSettingsCategory() +{ + return d->m_globalSettingsCategory; +} + +void ICodeStylePreferences::setGlobalSettingsCategory(const Utils::Id &id) +{ + d->m_globalSettingsCategory = id; +} + void ICodeStylePreferences::codeStyleRemoved(ICodeStylePreferences *preferences) { if (currentDelegate() == preferences) { diff --git a/src/plugins/texteditor/icodestylepreferences.h b/src/plugins/texteditor/icodestylepreferences.h index aab34d3dc25..49f63f2c609 100644 --- a/src/plugins/texteditor/icodestylepreferences.h +++ b/src/plugins/texteditor/icodestylepreferences.h @@ -5,6 +5,7 @@ #include "texteditor_global.h" +#include #include #include @@ -75,6 +76,9 @@ public: virtual Utils::Store toMap() const; virtual void fromMap(const Utils::Store &map); + Utils::Id globalSettingsCategory(); + void setGlobalSettingsCategory(const Utils::Id &id); + signals: void tabSettingsChanged(const TextEditor::TabSettings &settings); void currentTabSettingsChanged(const TextEditor::TabSettings &settings); diff --git a/src/plugins/texteditor/simplecodestylepreferences.cpp b/src/plugins/texteditor/simplecodestylepreferences.cpp index 6a6a76bb64a..57d0dd84345 100644 --- a/src/plugins/texteditor/simplecodestylepreferences.cpp +++ b/src/plugins/texteditor/simplecodestylepreferences.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "simplecodestylepreferences.h" +#include "texteditorconstants.h" #include @@ -11,9 +12,9 @@ SimpleCodeStylePreferences::SimpleCodeStylePreferences(QObject *parent) : ICodeStylePreferences(parent) { setSettingsSuffix("TabPreferences"); + setGlobalSettingsCategory(Constants::TEXT_EDITOR_BEHAVIOR_SETTINGS); } - QVariant SimpleCodeStylePreferences::value() const { return QVariant(); diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 8cd61342053..c375a8f1780 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -479,6 +479,11 @@ void TextDocument::setCodeStyle(ICodeStylePreferences *preferences) } } +ICodeStylePreferences *TextDocument::codeStyle() const +{ + return d->m_codeStylePreferences; +} + void TextDocument::applyFontSettings() { d->m_fontSettingsNeedsApply = false; diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index fb97543a477..55a4e75c0bb 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -140,6 +140,7 @@ public: virtual IAssistProvider *quickFixAssistProvider() const; void setCodeStyle(ICodeStylePreferences *preferences); + ICodeStylePreferences *codeStyle() const; void setTabSettings(const TextEditor::TabSettings &tabSettings); void setFontSettings(const TextEditor::FontSettings &fontSettings); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 4848386104d..ac8e9800b40 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -360,6 +360,15 @@ private: } tabSize->addActions(tabSizeGroup->actions()); + Id globalSettingsCategory; + if (auto codeStyle = m_doc->codeStyle()) + globalSettingsCategory = codeStyle->globalSettingsCategory(); + if (!globalSettingsCategory.isValid()) + globalSettingsCategory = Constants::TEXT_EDITOR_BEHAVIOR_SETTINGS; + menu->addAction(Tr::tr("Global Settings..."), [globalSettingsCategory] { + Core::ICore::showOptionsDialog(globalSettingsCategory); + }); + menu->popup(QCursor::pos()); } From fa6a520e542c48459b158c6b5c365051169038ac Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 27 Nov 2024 12:20:59 +0100 Subject: [PATCH 358/989] RemoteLinux: Use Process's output decoding in the GenericDirectUploadStep ("Upload files via SFTP") Change-Id: I2165460a3af3496279c967c7180c5d8d0b96504b Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/genericdirectuploadstep.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 430f89f552e..37cb75df065 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -22,6 +22,7 @@ #include #include +#include using namespace ProjectExplorer; using namespace Tasking; @@ -110,14 +111,14 @@ QDateTime GenericDirectUploadStep::timestampFromStat(const DeployableFile &file, .arg(file.remoteFilePath(), error)); return {}; } - const QByteArray output = statProc->readAllRawStandardOutput().trimmed(); + const QString output = statProc->readAllStandardOutput().trimmed(); const QString warningString(Tr::tr("Unexpected stat output for remote file \"%1\": %2") - .arg(file.remoteFilePath()).arg(QString::fromUtf8(output))); - if (!output.startsWith(file.remoteFilePath().toUtf8())) { + .arg(file.remoteFilePath()).arg(output)); + if (!output.startsWith(file.remoteFilePath())) { addWarningMessage(warningString); return {}; } - const QByteArrayList columns = output.mid(file.remoteFilePath().toUtf8().size() + 1).split(' '); + const QStringList columns = output.mid(file.remoteFilePath().size() + 1).split(' '); if (columns.size() < 14) { // Normal Linux stat: 16 columns in total, busybox stat: 15 columns addWarningMessage(warningString); return {}; @@ -136,6 +137,7 @@ GroupItem GenericDirectUploadStep::statTask(UploadStorage *storage, StatEndHandler statEndHandler) { const auto onSetup = [this, file](Process &process) { + process.setCodec(QTextCodec::codecForName("UTF-8")); // We'd like to use --format=%Y, but it's not supported by busybox. process.setCommand({deviceConfiguration()->filePath("stat"), {"-t", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); From c8ea58d2707ce22368ae38abb9bebeb64d550e97 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Dec 2024 13:07:18 +0100 Subject: [PATCH 359/989] Utils: Add FilePath::processStd{Out,Err}Codec() Allows in principle each executable to declare their output encoding. For now use the usual codecForLocale() on desktop and UTF-8 everywhere else. Change-Id: I040e9c0fca929fcccce0bf7746864bb9e3dac33b Reviewed-by: Marcus Tillmanns --- src/libs/utils/devicefileaccess.cpp | 25 +++++++++++++++++++++++++ src/libs/utils/devicefileaccess.h | 10 ++++++++++ src/libs/utils/filepath.cpp | 10 ++++++++++ src/libs/utils/filepath.h | 4 ++++ 4 files changed, 49 insertions(+) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 24d69f728b7..b7e7edf24a7 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #ifdef Q_OS_WIN @@ -400,6 +401,18 @@ Utils::expected_str> DeviceFileAccess::watch( return make_unexpected(Tr::tr("watch is not implemented.")); } +QTextCodec *DeviceFileAccess::processStdOutCodec(const FilePath &executable) const +{ + Q_UNUSED(executable) + return QTextCodec::codecForName("UTF-8"); // Good default nowadays. +} + +QTextCodec *DeviceFileAccess::processStdErrCodec(const FilePath &executable) const +{ + Q_UNUSED(executable) + return QTextCodec::codecForName("UTF-8"); // Good default nowadays. +} + // UnavailableDeviceFileAccess UnavailableDeviceFileAccess::UnavailableDeviceFileAccess() = default; @@ -1183,6 +1196,18 @@ Utils::expected_str> DesktopDeviceFileAccess::w return make_unexpected(watcher->error()); } +QTextCodec *DesktopDeviceFileAccess::processStdOutCodec(const FilePath &executable) const +{ + Q_UNUSED(executable); + return QTextCodec::codecForLocale(); +} + +QTextCodec *DesktopDeviceFileAccess::processStdErrCodec(const FilePath &executable) const +{ + Q_UNUSED(executable); + return QTextCodec::codecForLocale(); +} + QDateTime DesktopDeviceFileAccess::lastModified(const FilePath &filePath) const { return QFileInfo(filePath.path()).lastModified(); diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index 04931046472..1a49a48259f 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -10,6 +10,10 @@ class tst_unixdevicefileaccess; // For testing. +QT_BEGIN_NAMESPACE +class QTextCodec; +QT_END_NAMESPACE + namespace Utils { class CommandLine; @@ -77,6 +81,9 @@ protected: virtual expected_str createTempFile(const FilePath &filePath); virtual Utils::expected_str> watch(const FilePath &path) const; + + virtual QTextCodec *processStdOutCodec(const FilePath &executable) const; + virtual QTextCodec *processStdErrCodec(const FilePath &executable) const; }; class QTCREATOR_UTILS_EXPORT UnavailableDeviceFileAccess : public DeviceFileAccess @@ -194,6 +201,9 @@ protected: expected_str createTempFile(const FilePath &filePath) override; Utils::expected_str> watch(const FilePath &path) const override; + + QTextCodec *processStdOutCodec(const FilePath &executable) const override; + QTextCodec *processStdErrCodec(const FilePath &executable) const override; }; class QTCREATOR_UTILS_EXPORT UnixDeviceFileAccess : public DeviceFileAccess diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index e617ddf1eb3..5bfa0a9b0e8 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -2155,6 +2155,16 @@ QChar FilePath::pathListSeparator() const return osType() == OsTypeWindows ? u';' : u':'; } +QTextCodec *FilePath::processStdOutCodec() const +{ + return fileAccess()->processStdOutCodec(*this); +} + +QTextCodec *FilePath::processStdErrCodec() const +{ + return fileAccess()->processStdErrCodec(*this); +} + /*! \brief Recursively resolves symlinks if this is a symlink. diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 36ab6ad532f..07bd00b9d81 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -24,6 +24,7 @@ QT_BEGIN_NAMESPACE class QDateTime; class QDebug; class QFileInfo; +class QTextCodec; class QUrl; QT_END_NAMESPACE @@ -191,6 +192,9 @@ public: QChar pathComponentSeparator() const; QChar pathListSeparator() const; + QTextCodec *processStdOutCodec() const; + QTextCodec *processStdErrCodec() const; + void clear(); bool isEmpty() const; From 8941000decf9e4d7212399fe09d2bb8aea581737 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Dec 2024 13:43:02 +0100 Subject: [PATCH 360/989] Utils: Use FilePath::processCodec as default when starting processes Can still be overridden for special cases. Change-Id: Ic540974812a8c965603bafd1f1fde4c383f3481d Reviewed-by: Marcus Tillmanns --- src/libs/utils/qtcprocess.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 29de1f01759..cb7f21512ef 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -723,8 +723,8 @@ public: qint64 m_applicationMainThreadId = 0; ProcessResultData m_resultData; - QTextCodec *m_stdOutCodec = QTextCodec::codecForLocale(); - QTextCodec *m_stdErrCodec = QTextCodec::codecForLocale(); + QTextCodec *m_stdOutCodec = nullptr; + QTextCodec *m_stdErrCodec = nullptr; ProcessResult m_result = ProcessResult::StartFailed; ChannelBuffer m_stdOut; @@ -983,10 +983,16 @@ void ProcessPrivate::sendControlSignal(ControlSignal controlSignal) void ProcessPrivate::clearForRun() { + if (!m_stdOutCodec) + m_stdOutCodec = m_setup.m_commandLine.executable().processStdOutCodec(); m_stdOut.clearForRun(); m_stdOut.codec = m_stdOutCodec; + + if (!m_stdErrCodec) + m_stdErrCodec = m_setup.m_commandLine.executable().processStdErrCodec(); m_stdErr.clearForRun(); m_stdErr.codec = m_stdErrCodec; + m_result = ProcessResult::StartFailed; m_startTimestamp = {}; m_doneTimestamp = {}; @@ -1622,12 +1628,14 @@ QByteArray Process::rawStdErr() const QString Process::stdOut() const { QTC_CHECK(d->m_stdOut.keepRawData); + QTC_ASSERT(d->m_stdOutCodec, return {}); // Process was not started return d->m_stdOutCodec->toUnicode(d->m_stdOut.rawData); } QString Process::stdErr() const { QTC_CHECK(d->m_stdErr.keepRawData); + QTC_ASSERT(d->m_stdErrCodec, return {}); // Process was not started return d->m_stdErrCodec->toUnicode(d->m_stdErr.rawData); } From fcc921cc5b2f9efbbfe9a9893eb1e909de8f1b7c Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Dec 2024 14:20:57 +0100 Subject: [PATCH 361/989] Core/ProjectExplorer: Reduce some QTextCodec uses in "leaf" code Uses are more centralized via FilePath::codec*() now. Change-Id: Ib0c137a7da38c78bb1826915b121243862efee89 Reviewed-by: Marcus Tillmanns --- src/libs/utils/qtcprocess.cpp | 6 ------ src/libs/utils/qtcprocess.h | 3 +-- src/plugins/coreplugin/locator/executefilter.cpp | 2 -- src/plugins/projectexplorer/abstractprocessstep.cpp | 5 ++--- src/plugins/remotelinux/genericdirectuploadstep.cpp | 1 - 5 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index cb7f21512ef..4799e8adbd0 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -1761,12 +1761,6 @@ void Process::setStdOutCodec(QTextCodec *c) d->m_stdOutCodec = c; } -void Process::setStdErrCodec(QTextCodec *c) -{ - QTC_ASSERT(c, return); - d->m_stdErrCodec = c; -} - void Process::setTimeOutMessageBoxEnabled(bool v) { d->m_timeOutMessageBoxEnabled = v; diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 1de06a359b4..bf79f774c88 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -144,8 +144,7 @@ public: EventLoopMode eventLoopMode = EventLoopMode::Off); void setCodec(QTextCodec *c); // for stdOut and stdErr - void setStdOutCodec(QTextCodec *c); - void setStdErrCodec(QTextCodec *c); + void setStdOutCodec(QTextCodec *c); // for stdOut, stdErr uses executable.processStdErrCodec() void setTimeOutMessageBoxEnabled(bool); diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 863ed8834dd..cada4a6d45d 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -17,7 +17,6 @@ #include #include #include -#include using namespace Tasking; using namespace Utils; @@ -160,7 +159,6 @@ void ExecuteFilter::createProcess() m_process = new Process; m_process->setEnvironment(Environment::systemEnvironment()); - m_process->setCodec(QTextCodec::codecForLocale()); connect(m_process, &Process::done, this, &ExecuteFilter::done); connect(m_process, &Process::readyReadStandardOutput, this, &ExecuteFilter::readStdOutput); connect(m_process, &Process::readyReadStandardError, this, &ExecuteFilter::readStdError); diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index 4f3dc2ffba0..765b4eb877a 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -194,9 +194,8 @@ bool AbstractProcessStep::setupProcess(Process &process) if (d->m_lowPriority && projectExplorerSettings().lowBuildPriority) process.setLowPriority(); - process.setStdOutCodec(buildEnvironment().hasKey("VSLANG") - ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale()); - process.setStdErrCodec(QTextCodec::codecForLocale()); + if (buildEnvironment().hasKey("VSLANG")) + process.setStdOutCodec(QTextCodec::codecForName("UTF-8")); process.setStdOutCallback([this](const QString &s){ emit addOutput(s, OutputFormat::Stdout, DontAppendNewline); diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 37cb75df065..25eb72ca905 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -137,7 +137,6 @@ GroupItem GenericDirectUploadStep::statTask(UploadStorage *storage, StatEndHandler statEndHandler) { const auto onSetup = [this, file](Process &process) { - process.setCodec(QTextCodec::codecForName("UTF-8")); // We'd like to use --format=%Y, but it's not supported by busybox. process.setCommand({deviceConfiguration()->filePath("stat"), {"-t", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); From 015c1475422c10643995b883b40a243e1f1f95ce Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Dec 2024 14:33:48 +0100 Subject: [PATCH 362/989] ProjectExplorer: Remove some explicit QTextCodec use Default in Utils::Process implementation is now good enough. Change-Id: I3840c60b019f10949f0ba625a197cae41e103b8e Reviewed-by: Marcus Tillmanns --- src/plugins/projectexplorer/runcontrol.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 7041a168631..666c734aab1 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -42,7 +42,6 @@ #include #include -#include #include #if defined (WITH_JOURNALD) @@ -1522,15 +1521,14 @@ void SimpleTargetRunnerPrivate::handleStandardError() void SimpleTargetRunnerPrivate::start() { - const bool isLocal = !m_command.executable().needsDevice(); - CommandLine cmdLine = m_command; Environment env = m_environment; m_resultData = {}; QTC_ASSERT(m_state == Inactive, return); - if (isLocal) { + if (!m_command.executable().needsDevice()) { + // Running locally. if (m_runAsRoot) RunControl::provideAskPassEntry(env); @@ -1565,7 +1563,6 @@ void SimpleTargetRunnerPrivate::start() m_state = Run; m_process.setWorkingDirectory(m_workingDirectory); - m_process.setCodec(isLocal ? QTextCodec::codecForLocale() : QTextCodec::codecForName("utf8")); m_process.setForceDefaultErrorModeOnWindows(true); m_process.start(); } From 5fad41873e1fdf205186ea335e62a2eee64df1b8 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Dec 2024 14:53:54 +0100 Subject: [PATCH 363/989] Utils: Add FilePath::isLocal() and use it instead of !needsDevice() "needsDevice()" is an odd name, but keep it for now until downstream has caught up. Change-Id: I1fdb65d55e84e31512edb8f0bea8a0a3f7b2879c Reviewed-by: Marcus Tillmanns --- .../gocmdbridge/client/bridgedfileaccess.cpp | 2 +- src/libs/utils/aspects.cpp | 2 +- src/libs/utils/devicefileaccess.cpp | 2 +- src/libs/utils/elfreader.cpp | 2 +- src/libs/utils/filepath.cpp | 54 +++++++++---------- src/libs/utils/filepath.h | 5 +- src/libs/utils/filestreamer.cpp | 8 +-- src/libs/utils/fileutils.cpp | 14 ++--- src/libs/utils/fsengine/fileiconprovider.cpp | 6 +-- src/libs/utils/fsengine/fsenginehandler.cpp | 2 +- src/libs/utils/mimetypes2/mimeutils.cpp | 2 +- src/libs/utils/pathchooser.cpp | 4 +- src/libs/utils/processinfo.cpp | 2 +- src/libs/utils/qtcprocess.cpp | 12 ++--- src/libs/utils/savefile.cpp | 2 +- src/libs/utils/winutils.cpp | 2 +- src/plugins/axivion/axivionsettings.cpp | 4 +- src/plugins/beautifier/beautifiertool.cpp | 2 +- src/plugins/clangformat/llvmfilesystem.h | 2 +- .../cmakebuildconfiguration.cpp | 2 +- .../cmakeprojectmanager/cmakebuildsystem.cpp | 2 +- .../cmakeprojectmanager/cmakeprocess.cpp | 2 +- src/plugins/cmakeprojectmanager/cmaketool.cpp | 2 +- .../cmakeprojectmanager/cmaketoolmanager.cpp | 4 +- .../cmaketoolsettingsaccessor.cpp | 4 +- .../cmakeprojectmanager/fileapireader.cpp | 2 +- .../coreplugin/locator/filesystemfilter.cpp | 2 +- src/plugins/debugger/dap/pydapengine.cpp | 6 +-- src/plugins/debugger/debuggeritemmanager.cpp | 4 +- src/plugins/debugger/debuggerkitaspect.cpp | 2 +- src/plugins/debugger/gdb/gdbengine.cpp | 6 +-- src/plugins/debugger/moduleshandler.cpp | 2 +- src/plugins/docker/dockerdevice.cpp | 8 +-- src/plugins/docker/dockerdevice.h | 2 +- src/plugins/git/gitclient.cpp | 2 +- src/plugins/projectexplorer/buildaspects.cpp | 2 +- .../desktoprunconfiguration.cpp | 4 +- .../devicesupport/desktopdevice.cpp | 2 +- .../devicesupport/devicemanager.cpp | 2 +- src/plugins/projectexplorer/gcctoolchain.cpp | 4 +- .../jsonwizard/jsonwizardfactory.cpp | 3 +- .../projectexplorer/processparameters.cpp | 2 +- .../projectexplorer/projectexplorer.cpp | 14 ++--- src/plugins/projectexplorer/projectnodes.cpp | 4 +- src/plugins/projectexplorer/runcontrol.cpp | 10 ++-- .../projectexplorer/toolchainmanager.cpp | 4 +- src/plugins/python/pythonkitaspect.cpp | 2 +- src/plugins/python/pythonlanguageclient.cpp | 4 +- src/plugins/python/pythonsettings.cpp | 10 ++-- .../qmakeprojectmanager/qmakeparsernodes.cpp | 2 +- .../qmakeprojectmanager/qmakeproject.cpp | 4 +- src/plugins/qtsupport/baseqtversion.cpp | 6 +-- src/plugins/qtsupport/exampleslistmodel.cpp | 2 +- src/plugins/qtsupport/qtversionmanager.cpp | 2 +- src/plugins/remotelinux/linuxdevice.cpp | 2 +- src/plugins/terminal/shellintegration.cpp | 2 +- src/plugins/terminal/terminalpane.cpp | 2 +- src/plugins/vcsbase/vcsbaseclient.cpp | 2 +- src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 2 +- tests/auto/utils/filepath/tst_filepath.cpp | 8 +-- tests/auto/utils/fsengine/tst_fsengine.cpp | 10 ++-- 61 files changed, 145 insertions(+), 147 deletions(-) diff --git a/src/libs/gocmdbridge/client/bridgedfileaccess.cpp b/src/libs/gocmdbridge/client/bridgedfileaccess.cpp index 387d7ad17de..250f4e9c42e 100644 --- a/src/libs/gocmdbridge/client/bridgedfileaccess.cpp +++ b/src/libs/gocmdbridge/client/bridgedfileaccess.cpp @@ -107,7 +107,7 @@ Result FileAccess::deployAndInit(const FilePath &libExecPath, const FilePath &re qCDebug(faLog) << deco() << "Using cmdbridge at:" << *cmdBridgePath; - if (remoteRootPath.needsDevice()) { + if (!remoteRootPath.isLocal()) { const auto cmdBridgeFileData = cmdBridgePath->fileContents(); if (!cmdBridgeFileData) { diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 1b3bf074d1c..8d7093f921a 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1587,7 +1587,7 @@ FilePath FilePathAspect::effectiveBinary() const if (kind != PathChooser::ExistingCommand && kind != PathChooser::Command) return current; - if (current.needsDevice()) + if (!current.isLocal()) return current; d->m_effectiveBinary.emplace(current.searchInPath()); diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index b7e7edf24a7..690fbf4522a 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -1013,7 +1013,7 @@ static bool checkToRefuseRemoveDirectory(const QDir &dir, QString *error) bool DesktopDeviceFileAccess::removeRecursively(const FilePath &filePath, QString *error) const { - QTC_ASSERT(!filePath.needsDevice(), return false); + QTC_ASSERT(filePath.isLocal(), return false); QFileInfo fileInfo = filePath.toFileInfo(); if (!fileInfo.exists() && !fileInfo.isSymLink()) return true; diff --git a/src/libs/utils/elfreader.cpp b/src/libs/utils/elfreader.cpp index 35c1a38ec12..44f0ed6ef43 100644 --- a/src/libs/utils/elfreader.cpp +++ b/src/libs/utils/elfreader.cpp @@ -86,7 +86,7 @@ ElfMapper::ElfMapper(const ElfReader *reader) bool ElfMapper::map() { - if (binary.needsDevice()) { + if (!binary.isLocal()) { const expected_str contents = binary.fileContents(); QTC_CHECK(contents); raw = contents.value_or(QByteArray()); diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 5bfa0a9b0e8..32118cd56a4 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -234,7 +234,7 @@ FilePath FilePath::currentWorkingPath() bool FilePath::isRootPath() const { - if (needsDevice()) { + if (!isLocal()) { QStringView path = pathView(); if (osType() != OsTypeWindows) return path == QLatin1String("/"); @@ -262,7 +262,7 @@ bool FilePath::isResourceFile() const { if (scheme() == u"qrc") return true; - if (needsDevice()) + if (!isLocal()) return false; return pathView().startsWith(':'); } @@ -297,7 +297,7 @@ QString decodeHost(QString host) */ QString FilePath::toString() const { - if (!needsDevice()) + if (isLocal()) return path(); if (pathView().isEmpty()) @@ -377,7 +377,7 @@ QString FilePath::toFSPathString() const QUrl FilePath::toUrl() const { - if (!needsDevice()) + if (isLocal()) return QUrl::fromLocalFile(toFSPathString()); QUrl url; url.setScheme(scheme().toString()); @@ -395,7 +395,7 @@ QUrl FilePath::toUrl() const QString FilePath::toUserOutput() const { QString tmp = toString(); - if (needsDevice()) + if (!isLocal()) return tmp; if (osType() == OsTypeWindows) @@ -598,7 +598,7 @@ std::optional FilePath::refersToExecutableFile(MatchScope matchScope) expected_str FilePath::tmpDir() const { - if (needsDevice()) { + if (!isLocal()) { const expected_str env = deviceEnvironmentWithError(); if (!env) return make_unexpected(env.error()); @@ -621,7 +621,7 @@ expected_str FilePath::tmpDir() const expected_str FilePath::createTempFile() const { - if (!needsDevice()) { + if (isLocal()) { QTemporaryFile file(path()); file.setAutoRemove(false); if (file.open()) @@ -726,13 +726,11 @@ expected_str FilePath::fileContents(qint64 maxSize, qint64 offset) c bool FilePath::ensureReachable(const FilePath &other) const { - if (needsDevice()) { + if (!isLocal()) { QTC_ASSERT(deviceFileHooks().ensureReachable, return false); return deviceFileHooks().ensureReachable(*this, other); - } else if (!other.needsDevice()) { - return true; } - return false; + return other.isLocal(); } expected_str FilePath::writeFileContents(const QByteArray &data) const @@ -757,16 +755,16 @@ FileStreamHandle FilePath::asyncWrite(const QByteArray &data, QObject *context, return FileStreamerManager::write(*this, data, context, cont); } -bool FilePath::needsDevice() const +bool FilePath::isLocal() const { - return m_schemeLen > 0 && scheme() != u"file"; + return m_schemeLen == 0 || scheme() == u"file"; } bool FilePath::isSameDevice(const FilePath &other) const { - if (needsDevice() != other.needsDevice()) + if (isLocal() != other.isLocal()) return false; - if (!needsDevice() && !other.needsDevice()) + if (isLocal() && other.isLocal()) return true; QTC_ASSERT(deviceFileHooks().isSameDevice, return true); @@ -1084,7 +1082,7 @@ FilePath FilePath::parentDir() const FilePath FilePath::absolutePath() const { - if (!needsDevice() && isEmpty()) + if (!!isLocal() && isEmpty()) return *this; const FilePath parentPath = isAbsolutePath() ? parentDir() @@ -1096,7 +1094,7 @@ FilePath FilePath::absoluteFilePath() const { if (isAbsolutePath()) return cleanPath(); - if (!needsDevice() && isEmpty()) + if (!!isLocal() && isEmpty()) return cleanPath(); return FilePath::currentWorkingPath().resolvePath(*this); @@ -1129,7 +1127,7 @@ const QString &FilePath::specialDeviceRootPath() FilePath FilePath::normalizedPathName() const { FilePath result = *this; - if (!needsDevice()) // FIXME: Assumes no remote Windows and Mac for now. + if (!!isLocal()) // FIXME: Assumes no remote Windows and Mac for now. result.setParts(scheme(), host(), FileUtils::normalizedPathName(path())); return result; } @@ -1146,7 +1144,7 @@ FilePath FilePath::normalizedPathName() const QString FilePath::displayName(const QString &args) const { QString deviceName; - if (needsDevice()) { + if (!isLocal()) { QTC_ASSERT(deviceFileHooks().deviceDisplayName, return nativePath()); deviceName = deviceFileHooks().deviceDisplayName(*this); } @@ -1278,7 +1276,7 @@ void FilePath::setFromString(QStringView fileNameView) static expected_str getFileAccess(const FilePath &filePath) { - if (!filePath.needsDevice()) + if (filePath.isLocal()) return DesktopDeviceFileAccess::instance(); if (!deviceFileHooks().fileAccess) { @@ -1890,7 +1888,7 @@ Environment FilePath::deviceEnvironment() const expected_str FilePath::deviceEnvironmentWithError() const { - if (needsDevice()) { + if (!isLocal()) { QTC_ASSERT(deviceFileHooks().environment, return {}); return deviceFileHooks().environment(*this); } @@ -1900,7 +1898,7 @@ expected_str FilePath::deviceEnvironmentWithError() const FilePaths FilePath::devicePathEnvironmentVariable() const { FilePaths result = deviceEnvironment().path(); - if (needsDevice()) { + if (!isLocal()) { for (FilePath &dir : result) dir.setParts(this->scheme(), this->host(), dir.path()); } @@ -2001,7 +1999,7 @@ bool FilePath::setPermissions(QFile::Permissions permissions) const OsType FilePath::osType() const { - if (!needsDevice()) + if (!!isLocal()) return HostOsInfo::hostOs(); QTC_ASSERT(deviceFileHooks().osType, return HostOsInfo::hostOs()); @@ -2200,7 +2198,7 @@ FilePath FilePath::resolveSymlinks() const */ FilePath FilePath::canonicalPath() const { - if (needsDevice()) { + if (!isLocal()) { // FIXME: Not a full solution, but it stays on the right device. return *this; } @@ -2330,7 +2328,7 @@ FilePath FilePath::resolvePath(const QString &tail) const expected_str FilePath::localSource() const { - if (!needsDevice()) + if (!!isLocal()) return *this; QTC_ASSERT(deviceFileHooks().localSource, @@ -2367,7 +2365,7 @@ QString FilePath::withTildeHomePath() const if (osType() == OsTypeWindows) return toString(); - if (needsDevice()) + if (!isLocal()) return toString(); static const QString homePath = QDir::homePath(); @@ -2486,8 +2484,8 @@ QTCREATOR_UTILS_EXPORT bool operator!=(const FilePath &first, const FilePath &se QTCREATOR_UTILS_EXPORT bool operator<(const FilePath &first, const FilePath &second) { - const bool firstNeedsDevice = first.needsDevice(); - const bool secondNeedsDevice = second.needsDevice(); + const bool firstNeedsDevice = !first.isLocal(); + const bool secondNeedsDevice = !second.isLocal(); // If either needs a device, we have to compare host and scheme first. if (firstNeedsDevice || secondNeedsDevice) { diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 07bd00b9d81..35694346082 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -281,11 +281,12 @@ public: const WriteContinuation &cont = {}) const; // Prefer not to use - // Using needsDevice() in "user" code is likely to result in code that + // Using isLocal() in "user" code is likely to result in code that // makes a local/remote distinction which should be avoided in general. // There are usually other means available. E.g. distinguishing based // on FilePath::osType(). - bool needsDevice() const; + bool isLocal() const; + [[deprecated]] bool needsDevice() const { return !isLocal(); } bool hasFileAccess() const; bool isSameDevice(const FilePath &other) const; diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index 663f505b881..9079081e9ef 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -36,7 +36,7 @@ public: void setFilePath(const FilePath &filePath) { m_filePath = filePath; } void start() { QTC_ASSERT(!m_taskTreeRunner.isRunning(), return); - m_taskTreeRunner.start({m_filePath.needsDevice() ? remoteTask() : localTask()}); + m_taskTreeRunner.start({m_filePath.isLocal() ? localTask() : remoteTask()}); } signals: @@ -307,8 +307,8 @@ using FileStreamWriterTask = CustomTask; static Group sameRemoteDeviceTransferTask(const FilePath &source, const FilePath &destination) { - QTC_CHECK(source.needsDevice()); - QTC_CHECK(destination.needsDevice()); + QTC_CHECK(!source.isLocal()); + QTC_CHECK(!destination.isLocal()); QTC_CHECK(source.isSameDevice(destination)); const auto setup = [source, destination](Process &process) { @@ -359,7 +359,7 @@ static Group interDeviceTransferTask(const FilePath &source, const FilePath &des static Group transferTask(const FilePath &source, const FilePath &destination) { - if (source.needsDevice() && destination.needsDevice() && source.isSameDevice(destination)) + if (!source.isLocal() && !destination.isLocal() && source.isSameDevice(destination)) return sameRemoteDeviceTransferTask(source, destination); return interDeviceTransferTask(source, destination); } diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index a713292c142..e20ebb853d6 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -282,7 +282,7 @@ void TempFileSaver::initFromString(const QString &templ) TempFileSaver::TempFileSaver(const FilePath &templ) { - if (templ.isEmpty() || !templ.needsDevice()) { + if (templ.isEmpty() || templ.isLocal()) { initFromString(templ.path()); } else { expected_str result = templ.createTempFile(); @@ -437,7 +437,7 @@ static QUrl filePathToQUrl(const FilePath &filePath) static void prepareNonNativeDialog(QFileDialog &dialog) { const auto isValidSideBarPath = [](const FilePath &fp) { - return !fp.needsDevice() || fp.hasFileAccess(); + return fp.isLocal() || fp.hasFileAccess(); }; // Checking QFileDialog::itemDelegate() seems to be the only way to determine @@ -524,7 +524,7 @@ FilePath getOpenFilePath(QWidget *parent, bool fromDeviceIfShiftIsPressed, bool forceNonNativeDialog) { - forceNonNativeDialog = forceNonNativeDialog || dir.needsDevice(); + forceNonNativeDialog = forceNonNativeDialog || !dir.isLocal(); #ifdef QT_GUI_LIB if (fromDeviceIfShiftIsPressed && qApp->queryKeyboardModifiers() & Qt::ShiftModifier) { forceNonNativeDialog = true; @@ -552,7 +552,7 @@ FilePath getSaveFilePath(QWidget *parent, QFileDialog::Options options, bool forceNonNativeDialog) { - forceNonNativeDialog = forceNonNativeDialog || dir.needsDevice(); + forceNonNativeDialog = forceNonNativeDialog || !dir.isLocal(); const QStringList schemes = QStringList(QStringLiteral("file")); return firstOrEmpty(getFilePaths(dialogParent(parent), @@ -574,7 +574,7 @@ FilePath getExistingDirectory(QWidget *parent, bool fromDeviceIfShiftIsPressed, bool forceNonNativeDialog) { - forceNonNativeDialog = forceNonNativeDialog || dir.needsDevice(); + forceNonNativeDialog = forceNonNativeDialog || !dir.isLocal(); #ifdef QT_GUI_LIB if (fromDeviceIfShiftIsPressed && qApp->queryKeyboardModifiers() & Qt::ShiftModifier) { @@ -602,7 +602,7 @@ FilePaths getOpenFilePaths(QWidget *parent, QString *selectedFilter, QFileDialog::Options options) { - bool forceNonNativeDialog = dir.needsDevice(); + bool forceNonNativeDialog = !dir.isLocal(); const QStringList schemes = QStringList(QStringLiteral("file")); return getFilePaths(dialogParent(parent), @@ -749,7 +749,7 @@ Result copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath) if (!srcFilePath.exists()) return Result::Error(Tr::tr("File %1 does not exist.").arg(srcFilePath.toUserOutput())); - if (srcFilePath.needsDevice() || tgtFilePath.needsDevice()) + if (!srcFilePath.isLocal() || !tgtFilePath.isLocal()) return srcFilePath.copyFile(tgtFilePath); if (tgtFilePath.exists()) { diff --git a/src/libs/utils/fsengine/fileiconprovider.cpp b/src/libs/utils/fsengine/fileiconprovider.cpp index 9d2a7c8c050..70d7c8b08b2 100644 --- a/src/libs/utils/fsengine/fileiconprovider.cpp +++ b/src/libs/utils/fsengine/fileiconprovider.cpp @@ -164,7 +164,7 @@ QIcon FileIconProviderImplementation::icon(IconType type) const QString FileIconProviderImplementation::type(const QFileInfo &fi) const { const FilePath fPath = FilePath::fromString(fi.filePath()); - if (fPath.needsDevice()) { + if (!fPath.isLocal()) { if (fi.isDir()) { #ifdef Q_OS_WIN return QGuiApplication::translate("QAbstractFileIconProvider", "File Folder", "Match Windows Explorer"); @@ -214,7 +214,7 @@ QIcon FileIconProviderImplementation::icon(const FilePath &filePath) const // Check if its one of the virtual devices directories if (filePath.path().startsWith(FilePath::specialRootPath())) { // If the filepath does not need a device, it is a virtual device directory - if (!filePath.needsDevice()) + if (filePath.isLocal()) return dirIcon(); } @@ -237,7 +237,7 @@ QIcon FileIconProviderImplementation::icon(const FilePath &filePath) const return *icon; } - if (filePath.needsDevice()) + if (!filePath.isLocal()) return isDir ? dirIcon() : unknownFileIcon(); // Get icon from OS (and cache it based on suffix!) diff --git a/src/libs/utils/fsengine/fsenginehandler.cpp b/src/libs/utils/fsengine/fsenginehandler.cpp index f48051bfe44..b9bd8bb810a 100644 --- a/src/libs/utils/fsengine/fsenginehandler.cpp +++ b/src/libs/utils/fsengine/fsenginehandler.cpp @@ -569,7 +569,7 @@ FSEngineHandler::create(const QString &fileName) const FilePath fixedPath = FilePath::fromString(fixedFileName); - if (fixedPath.needsDevice()) { + if (!fixedPath.isLocal()) { #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) return std::make_unique(removeDoubleSlash(fileName)); #else diff --git a/src/libs/utils/mimetypes2/mimeutils.cpp b/src/libs/utils/mimetypes2/mimeutils.cpp index 787353ceb24..9873a57d5fc 100644 --- a/src/libs/utils/mimetypes2/mimeutils.cpp +++ b/src/libs/utils/mimetypes2/mimeutils.cpp @@ -28,7 +28,7 @@ MimeType mimeTypeForFile(const QString &fileName, MimeMatchMode mode) MimeType mimeTypeForFile(const FilePath &filePath, MimeMatchMode mode) { MimeDatabase mdb; - if (filePath.needsDevice() && mode != MimeMatchMode::MatchDefaultAndRemote) + if (!filePath.isLocal() && mode != MimeMatchMode::MatchDefaultAndRemote) return mdb.mimeTypeForUrl(filePath.toUrl()); if (mode == MimeMatchMode::MatchDefaultAndRemote) { mode = MimeMatchMode::MatchDefault; diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index f268d4de2ca..73558995979 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -233,7 +233,7 @@ FilePath PathChooserPrivate::expandedPath(const FilePath &input) const // as 'cD:\\dev\\build-project' is considered is handled as being relative // input = "cD:\\dev\build-project"; // prepended 'c' to change the device letter // m_baseDirectory = "D:\\dev\\project" - if (!fp.needsDevice() && HostOsInfo::isWindowsHost() && fp.toString().count(':') > 1) + if (fp.isLocal() && HostOsInfo::isWindowsHost() && fp.toString().count(':') > 1) return path; return fp; } @@ -401,7 +401,7 @@ void PathChooser::slotBrowse(bool remote) predefined.clear(); } - remote = remote || filePath().needsDevice(); + remote = remote || !filePath().isLocal(); // Prompt for a file/dir FilePath newPath; diff --git a/src/libs/utils/processinfo.cpp b/src/libs/utils/processinfo.cpp index 89f732295c6..8139eba32f0 100644 --- a/src/libs/utils/processinfo.cpp +++ b/src/libs/utils/processinfo.cpp @@ -201,7 +201,7 @@ QList ProcessInfo::processInfoList(const FilePath &deviceRoot) QList ProcessInfo::processInfoList(const FilePath &deviceRoot) { - if (deviceRoot.needsDevice()) + if (!deviceRoot.isLocal()) return processInfoListUnix(deviceRoot); QList processes; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 4799e8adbd0..ea27cab3f2c 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -1087,7 +1087,7 @@ const Environment &Process::controlEnvironment() const void Process::setRunData(const ProcessRunData &data) { - if (data.workingDirectory.needsDevice() && data.command.executable().needsDevice()) { + if (!data.workingDirectory.isLocal() && !data.command.executable().isLocal()) { QTC_CHECK(data.workingDirectory.isSameDevice(data.command.executable())); } d->m_setup.m_commandLine = data.command; @@ -1102,7 +1102,7 @@ ProcessRunData Process::runData() const void Process::setCommand(const CommandLine &cmdLine) { - if (d->m_setup.m_workingDirectory.needsDevice() && cmdLine.executable().needsDevice()) { + if (!d->m_setup.m_workingDirectory.isLocal() && !cmdLine.executable().isLocal()) { QTC_CHECK(d->m_setup.m_workingDirectory.isSameDevice(cmdLine.executable())); } d->m_setup.m_commandLine = cmdLine; @@ -1120,7 +1120,7 @@ FilePath Process::workingDirectory() const void Process::setWorkingDirectory(const FilePath &dir) { - if (dir.needsDevice() && d->m_setup.m_commandLine.executable().needsDevice()) { + if (!dir.isLocal() && !d->m_setup.m_commandLine.executable().isLocal()) { QTC_CHECK(dir.isSameDevice(d->m_setup.m_commandLine.executable())); } d->m_setup.m_workingDirectory = dir; @@ -1139,11 +1139,11 @@ void Process::start() "lead to crash! Consider calling close() prior to direct restart.")); d->clearForRun(); ProcessInterface *processImpl = nullptr; - if (d->m_setup.m_commandLine.executable().needsDevice()) { + if (d->m_setup.m_commandLine.executable().isLocal()) { + processImpl = d->createProcessInterface(); + } else { QTC_ASSERT(s_deviceHooks.processImplHook, return); processImpl = s_deviceHooks.processImplHook(commandLine().executable()); - } else { - processImpl = d->createProcessInterface(); } if (!processImpl) { diff --git a/src/libs/utils/savefile.cpp b/src/libs/utils/savefile.cpp index 9ccdf1cea52..49bc4e40560 100644 --- a/src/libs/utils/savefile.cpp +++ b/src/libs/utils/savefile.cpp @@ -130,7 +130,7 @@ bool SaveFile::commit() if constexpr (HostOsInfo::isWindowsHost()) { static const bool disableWinSpecialCode = !qEnvironmentVariableIsEmpty( "QTC_DISABLE_SPECIAL_WIN_SAVEFILE"); - if (!m_finalFilePath.needsDevice() && !disableWinSpecialCode) { + if (m_finalFilePath.isLocal() && !disableWinSpecialCode) { // Release the file lock m_tempFile.reset(); bool result = ReplaceFile( diff --git a/src/libs/utils/winutils.cpp b/src/libs/utils/winutils.cpp index ce896aa4bd8..6cff39f57c7 100644 --- a/src/libs/utils/winutils.cpp +++ b/src/libs/utils/winutils.cpp @@ -132,7 +132,7 @@ QTCREATOR_UTILS_EXPORT bool is64BitWindowsSystem() QTCREATOR_UTILS_EXPORT bool is64BitWindowsBinary(const FilePath &binaryIn) { - QTC_ASSERT(!binaryIn.isEmpty() && !binaryIn.needsDevice(), return false); + QTC_ASSERT(!binaryIn.isEmpty() && binaryIn.isLocal(), return false); #ifdef Q_OS_WIN32 # ifdef __GNUC__ // MinGW lacking some definitions/winbase.h # define SCS_64BIT_BINARY 6 diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 834d2602cd0..b29423c844e 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -90,7 +90,7 @@ static bool analysisPathValid(const FilePath &analysisPath, QString *error) { if (analysisPath.isEmpty()) return true; - if (analysisPath.needsDevice() || analysisPath.isAbsolutePath()) { + if (!analysisPath.isLocal() || analysisPath.isAbsolutePath()) { if (error) *error = QString("Path must be relative."); return false; @@ -107,7 +107,7 @@ static bool analysisPathValid(const FilePath &analysisPath, QString *error) bool PathMapping::isValid() const { return !projectName.isEmpty() && !localPath.isEmpty() - && !localPath.needsDevice() && localPath.isAbsolutePath() + && localPath.isLocal() && localPath.isAbsolutePath() && analysisPathValid(analysisPath, nullptr); } diff --git a/src/plugins/beautifier/beautifiertool.cpp b/src/plugins/beautifier/beautifiertool.cpp index 9e55cf18363..8160c6289a9 100644 --- a/src/plugins/beautifier/beautifiertool.cpp +++ b/src/plugins/beautifier/beautifiertool.cpp @@ -302,7 +302,7 @@ void AbstractSettings::save() FilePath filePath = styleFileName(key); filePath.removeFile(); QTC_ASSERT(m_styleDir.isAbsolutePath(), break); - QTC_ASSERT(!m_styleDir.needsDevice(), break); + QTC_ASSERT(m_styleDir.isLocal(), break); const FilePath parentDir = filePath.parentDir(); if (parentDir != m_styleDir) { // FIXME: Missing in FilePath diff --git a/src/plugins/clangformat/llvmfilesystem.h b/src/plugins/clangformat/llvmfilesystem.h index b2d1c5de7e7..57b375c5900 100644 --- a/src/plugins/clangformat/llvmfilesystem.h +++ b/src/plugins/clangformat/llvmfilesystem.h @@ -144,7 +144,7 @@ public: std::error_code isLocal(const Twine &Path, bool &Result) override { const FilePath filePath = FilePath::fromString(QString::fromStdString(Path.str())); - Result = !filePath.needsDevice(); + Result = filePath.isLocal(); return {}; } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 786a5e9493e..80b249620b9 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -2152,7 +2152,7 @@ void CMakeBuildConfiguration::addToEnvironment(Utils::Environment &env) const const CMakeTool *tool = CMakeKitAspect::cmakeTool(kit()); // The hack further down is only relevant for desktop - if (tool && tool->cmakeExecutable().needsDevice()) + if (tool && !tool->cmakeExecutable().isLocal()) return; const FilePath ninja = settings(nullptr).ninjaPath(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index c3bce2741cc..8f593089169 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -1948,7 +1948,7 @@ void CMakeBuildSystem::ensureBuildDirectory(const BuildDirParameters ¶meters return; } - if (tool->cmakeExecutable().needsDevice()) { + if (!tool->cmakeExecutable().isLocal()) { if (!tool->cmakeExecutable().ensureReachable(bdir)) { // Make sure that the build directory is available on the device. handleParsingFailed( diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index ea5fdb11416..5130ab00ce6 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -93,7 +93,7 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & return; } - if (buildDirectory.needsDevice()) { + if (!buildDirectory.isLocal()) { if (!cmake->cmakeExecutable().isSameDevice(buildDirectory)) { const QString msg = ::CMakeProjectManager::Tr::tr( "CMake executable \"%1\" and build directory \"%2\" must be on the same device.") diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index 22712536c4f..75b9f981edd 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -380,7 +380,7 @@ std::optional CMakeTool::readerType() const FilePath CMakeTool::searchQchFile(const FilePath &executable) { - if (executable.isEmpty() || executable.needsDevice()) // do not register docs from devices + if (executable.isEmpty() || !executable.isLocal()) // do not register docs from devices return {}; FilePath prefixDir = executable.parentDir().parentDir(); diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp index 113021b3d7f..ab188b307e2 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp @@ -441,7 +441,7 @@ FilePath CMakeToolManager::mappedFilePath(Project *project, const FilePath &path if (!HostOsInfo::isWindowsHost()) return path; - if (path.needsDevice()) + if (!path.isLocal()) return path; auto environment = Environment::systemEnvironment(); @@ -560,7 +560,7 @@ void CMakeToolManager::ensureDefaultCMakeToolIsValid() if (findById(d->m_defaultCMake)) return; auto cmakeTool = Utils::findOrDefault(cmakeTools(), [](CMakeTool *tool) { - return tool->detectionSource().isEmpty() && !tool->cmakeExecutable().needsDevice(); + return tool->detectionSource().isEmpty() && tool->cmakeExecutable().isLocal(); }); if (cmakeTool) d->m_defaultCMake = cmakeTool->id(); diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp index e8e5a8a64ea..3b3a5e57d3c 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp @@ -176,7 +176,7 @@ void CMakeToolSettingsAccessor::saveCMakeTools(const QList &cmakeTo int count = 0; for (CMakeTool *item : cmakeTools) { Utils::FilePath fi = item->cmakeExecutable(); - if (fi.needsDevice() || fi.isExecutableFile()) { // be graceful for device related stuff + if (!fi.isLocal() || fi.isExecutableFile()) { // be graceful for device related stuff Store tmp = item->toMap(); if (tmp.isEmpty()) continue; @@ -203,7 +203,7 @@ CMakeToolSettingsAccessor::cmakeTools(const Store &data, bool fromSdk) const const Store dbMap = storeFromVariant(data.value(key)); auto item = std::make_unique(dbMap, fromSdk); const FilePath cmakeExecutable = item->cmakeExecutable(); - if (item->isAutoDetected() && !cmakeExecutable.needsDevice() && !cmakeExecutable.isExecutableFile()) { + if (item->isAutoDetected() && cmakeExecutable.isLocal() && !cmakeExecutable.isExecutableFile()) { qWarning() << QString("CMakeTool \"%1\" (%2) dropped since the command is not executable.") .arg(cmakeExecutable.toUserOutput(), item->id().toString()); continue; diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index bcfb12e13c4..c109fece0b8 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -421,7 +421,7 @@ void FileApiReader::replyDirectoryHasChanged(const QString &directory) const const FilePath dir = reply.absolutePath(); if (dir.isEmpty()) return; // CMake started to fill the result dir, but has not written a result file yet - QTC_CHECK(!dir.needsDevice()); + QTC_CHECK(dir.isLocal()); QTC_ASSERT(dir.path() == directory, return); if (m_lastReplyTimestamp.isValid() && reply.lastModified() > m_lastReplyTimestamp) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 2bc451dcf70..3213d32504b 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -141,7 +141,7 @@ static void matches(QPromise &promise, const LocatorStorage &storage, ? expandedEntryPath : currentDocumentDir.resolvePath(expandedEntryPath); // The case of e.g. "ssh://", "ssh://*p", etc - const bool isPartOfDeviceRoot = expandedEntryPath.needsDevice() + const bool isPartOfDeviceRoot = !expandedEntryPath.isLocal() && expandedEntryPath.path().isEmpty(); // Consider the entered path a directory if it ends with slash/backslash. diff --git a/src/plugins/debugger/dap/pydapengine.cpp b/src/plugins/debugger/dap/pydapengine.cpp index 666750b3e66..43a58bac9b1 100644 --- a/src/plugins/debugger/dap/pydapengine.cpp +++ b/src/plugins/debugger/dap/pydapengine.cpp @@ -40,8 +40,8 @@ const char installDebugPyInfoBarId[] = "Python::InstallDebugPy"; static FilePath packageDir(const FilePath &python, const QString &packageName) { - expected_str baseDir = python.needsDevice() ? python.tmpDir() - : Core::ICore::userResourcePath(); + expected_str baseDir = python.isLocal() ? Core::ICore::userResourcePath() + : python.tmpDir(); return baseDir ? baseDir->pathAppended(packageName) : FilePath(); } @@ -243,7 +243,7 @@ void PyDapEngine::setupEngine() "pip", "install", "-t", - target.needsDevice() ? target.path() : target.toUserOutput(), + target.isLocal() ? target.toUserOutput() : target.path(), "debugpy", "--upgrade"}}); m_installProcess->setTerminalMode(TerminalMode::Run); diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 94f5a6199f5..6a162757bb3 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -629,7 +629,7 @@ void DebuggerItemModel::autoDetectGdbOrLldbDebuggers(const FilePaths &searchPath } FilePaths paths = searchPaths; - if (!searchPaths.front().needsDevice()) { + if (searchPaths.front().isLocal()) { paths.append(searchGdbPathsFromRegistry()); const expected_str lldb = Core::ICore::lldbExecutable(CLANG_BINDIR); @@ -777,7 +777,7 @@ void DebuggerItemModel::readDebuggers(const FilePath &fileName, bool isSystem) continue; } // FIXME: During startup, devices are not yet available, so we cannot check if the file still exists. - if (!item.command().needsDevice() && !item.command().isExecutableFile()) { + if (item.command().isLocal() && !item.command().isExecutableFile()) { qWarning() << QString("DebuggerItem \"%1\" (%2) read from \"%3\" dropped since the command is not executable.") .arg(item.command().toUserOutput(), item.id().toString(), fileName.toUserOutput()); continue; diff --git a/src/plugins/debugger/debuggerkitaspect.cpp b/src/plugins/debugger/debuggerkitaspect.cpp index 946f1e1ca3e..40294f56986 100644 --- a/src/plugins/debugger/debuggerkitaspect.cpp +++ b/src/plugins/debugger/debuggerkitaspect.cpp @@ -285,7 +285,7 @@ public: // This improves the situation a bit if a cross-compilation tool chain has the // same ABI as the host. if (level == DebuggerItem::MatchesPerfectly - && !item.command().needsDevice() + && item.command().isLocal() && systemEnvironment.path().contains(item.command().parentDir())) { level = DebuggerItem::MatchesPerfectlyInPath; } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index d8bfdfb2a6a..a3b16abdd60 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3999,7 +3999,7 @@ void GdbEngine::handleGdbStarted() // runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())}); const FilePath dumperPath = ICore::resourcePath("debugger"); - if (rp.debugger.command.executable().needsDevice()) { + if (!rp.debugger.command.executable().isLocal()) { // Gdb itself running remotely. const FilePath loadOrderFile = dumperPath / "loadorder.txt"; const expected_str toLoad = loadOrderFile.fileContents(); @@ -4411,7 +4411,7 @@ bool GdbEngine::isTermEngine() const bool GdbEngine::usesOutputCollector() const { - return isPlainEngine() && !runParameters().debugger.command.executable().needsDevice(); + return isPlainEngine() && runParameters().debugger.command.executable().isLocal(); } void GdbEngine::claimInitialBreakpoints() @@ -4740,7 +4740,7 @@ void GdbEngine::interruptInferior2() interruptLocalInferior(runParameters().attachPID.pid()); } else if (isRemoteEngine() || runParameters().startMode == AttachToRemoteProcess - || m_gdbProc.commandLine().executable().needsDevice()) { + || !m_gdbProc.commandLine().executable().isLocal()) { CHECK_STATE(InferiorStopRequested); if (usesTargetAsync()) { diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index 3d72f704576..a6b10b59ffe 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -171,7 +171,7 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) addAction(this, menu, Tr::tr("Show Dependencies of \"%1\"").arg(moduleName), Tr::tr("Show Dependencies"), - moduleNameValid && !modulePath.needsDevice() && modulePath.exists() + moduleNameValid && modulePath.isLocal() && modulePath.exists() && dependsCanBeFound(), [modulePath] { Process::startDetached({{"depends"}, {modulePath.toString()}}); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 8f6e839ba35..73f8c59da6b 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -215,7 +215,7 @@ public: { if (q->clangdExecutableAspect().isEmpty()) return std::nullopt; - if (!q->clangdExecutableAspect().needsDevice()) + if (q->clangdExecutableAspect().isLocal()) return q->rootPath().withNewMappedPath(q->clangdExecutableAspect()); return q->clangdExecutableAspect(); } @@ -611,7 +611,7 @@ DockerDevice::DockerDevice() return asyncRun([rootPath, newValue]() -> expected_str { QString changedValue = newValue; FilePath path = FilePath::fromUserInput(newValue); - if (!path.needsDevice()) { + if (path.isLocal()) { const FilePath onDevicePath = rootPath.withNewMappedPath(path); if (onDevicePath.exists()) { changedValue = onDevicePath.toUserOutput(); @@ -827,7 +827,7 @@ QStringList toMountArg(const DockerDevicePrivate::MountPair &mi) expected_str isValidMountInfo(const DockerDevicePrivate::MountPair &mi) { - if (mi.path.needsDevice()) + if (!mi.path.isLocal()) return make_unexpected(QString("The path \"%1\" is not local.").arg(mi.path.toUserOutput())); if (mi.path.isEmpty() && mi.containerPath.isEmpty()) @@ -1105,7 +1105,7 @@ bool DockerDevice::ensureReachable(const FilePath &other) const if (other.isSameDevice(rootPath())) return true; - if (other.needsDevice()) + if (!other.isLocal()) return false; if (other.isDir()) diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index b738ac41b05..0f929bdaf6c 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -41,7 +41,7 @@ public: bool canMount(const Utils::FilePath &filePath) const override { - return !filePath.needsDevice() || filePath.isSameDevice(rootPath()); + return filePath.isLocal() || filePath.isSameDevice(rootPath()); } bool handlesFile(const Utils::FilePath &filePath) const override; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 6bb1301f40b..1e8b5c05bbf 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2629,7 +2629,7 @@ bool GitClient::launchGitBash(const FilePath &workingDirectory) FilePath GitClient::vcsBinary(const FilePath &forDirectory) const { - if (forDirectory.needsDevice()) { + if (!forDirectory.isLocal()) { auto it = m_gitExecutableCache.find(forDirectory.withNewPath({})); if (it == m_gitExecutableCache.end()) { const FilePath gitBin = forDirectory.withNewPath("git").searchInPath(); diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp index dfaf86205dd..ae8eeb83b78 100644 --- a/src/plugins/projectexplorer/buildaspects.cpp +++ b/src/plugins/projectexplorer/buildaspects.cpp @@ -159,7 +159,7 @@ void BuildDirectoryAspect::addToLayoutImpl(Layouting::Layout &parent) FilePath BuildDirectoryAspect::fixupDir(const FilePath &dir) { - if (dir.needsDevice()) + if (!dir.isLocal()) return dir; if (HostOsInfo::isWindowsHost() && !dir.startsWithDriveLetter()) return {}; diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.cpp b/src/plugins/projectexplorer/desktoprunconfiguration.cpp index 3cbe11125b9..3582dad2bf8 100644 --- a/src/plugins/projectexplorer/desktoprunconfiguration.cpp +++ b/src/plugins/projectexplorer/desktoprunconfiguration.cpp @@ -100,8 +100,8 @@ void DesktopRunConfiguration::updateTargetInformation() BuildTargetInfo bti = buildTargetInfo(); auto terminalAspect = aspect(); - terminalAspect->setUseTerminalHint(bti.targetFilePath.needsDevice() ? false : bti.usesTerminal); - terminalAspect->setEnabled(!bti.targetFilePath.needsDevice()); + terminalAspect->setUseTerminalHint(!bti.targetFilePath.isLocal() ? false : bti.usesTerminal); + terminalAspect->setEnabled(bti.targetFilePath.isLocal()); auto launcherAspect = aspect(); launcherAspect->setVisible(false); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index b055cb399a4..b1299403486 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -105,7 +105,7 @@ QUrl DesktopDevice::toolControlChannel(const ControlChannelHint &) const bool DesktopDevice::handlesFile(const FilePath &filePath) const { - return !filePath.needsDevice(); + return filePath.isLocal(); } FilePath DesktopDevice::filePath(const QString &pathOnDevice) const diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index 4af922fae0a..cad72ceaf3e 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -417,7 +417,7 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique expected_str { - if (!filePath.needsDevice()) + if (filePath.isLocal()) return DesktopDeviceFileAccess::instance(); IDevice::ConstPtr device = DeviceManager::deviceForPath(filePath); if (!device) { diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 9b4513e203b..c4dadedef01 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1668,8 +1668,8 @@ Toolchains GccToolchainFactory::autoDetectToolchains(const FilePaths &compilerPa existingTcMatches = existingCommand.isSameExecutable(compilerPath); if (!existingTcMatches && HostOsInfo::isWindowsHost() - && !existingCommand.needsDevice() - && !compilerPath.needsDevice()) { + && existingCommand.isLocal() + && compilerPath.isLocal()) { existingTcMatches = existingCommand.fileSize() == compilerPath.fileSize(); } } diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index 0d74f2fbf27..6cb79cef777 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -600,9 +600,8 @@ FilePaths &JsonWizardFactory::searchPaths() const auto values = plugin->metaData().value("JsonWizardPaths").toArray(); for (const QJsonValue &v : values) { const auto path = FilePath::fromString(v.toString()); - if (!path.isEmpty() && !path.needsDevice()) { + if (!path.isEmpty() && path.isLocal()) m_searchPaths << base.resolvePath(path); - } } } } diff --git a/src/plugins/projectexplorer/processparameters.cpp b/src/plugins/projectexplorer/processparameters.cpp index 54a5dffcdb0..07d0a2788de 100644 --- a/src/plugins/projectexplorer/processparameters.cpp +++ b/src/plugins/projectexplorer/processparameters.cpp @@ -99,7 +99,7 @@ FilePath ProcessParameters::effectiveCommand() const FilePath cmd = m_runData.command.executable(); if (m_macroExpander) cmd = m_macroExpander->expand(cmd); - if (cmd.needsDevice()) { + if (!cmd.isLocal()) { // Assume this is already good. FIXME: It is possibly not, so better fix searchInPath. m_effectiveCommand = cmd; } else { diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 437ba6b4101..f3451b92ca3 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2234,7 +2234,7 @@ void ProjectExplorerPluginPrivate::checkRecentProjectsAsync() m_recentProjectsFuture = QtConcurrent::mapped(&m_recentProjectsPool, m_recentProjects, [](RecentProjectsEntry p) { // check if project is available, but avoid querying devices - p.exists = p.filePath.needsDevice() || p.filePath.exists(); + p.exists = !p.filePath.isLocal() || p.filePath.exists(); return p; }); Utils::futureSynchronizer()->addFuture(m_recentProjectsFuture); @@ -3845,10 +3845,10 @@ void ProjectExplorerPluginPrivate::openTerminalHere(const EnvironmentGetter &env return; } - if (buildDevice->rootPath().needsDevice()) - Terminal::Hooks::instance().openTerminal({CommandLine{*shell}, workingDir, environment}); - else + if (buildDevice->rootPath().isLocal()) Terminal::Hooks::instance().openTerminal({workingDir, environment}); + else + Terminal::Hooks::instance().openTerminal({CommandLine{*shell}, workingDir, environment}); } void ProjectExplorerPluginPrivate::openTerminalHereWithRunEnv() @@ -3885,11 +3885,11 @@ void ProjectExplorerPluginPrivate::openTerminalHereWithRunEnv() return; } - if (device->rootPath().needsDevice()) { + if (!device->rootPath().isLocal()) { + Terminal::Hooks::instance().openTerminal({workingDir, runnable.environment}); + } else { Terminal::Hooks::instance().openTerminal({CommandLine{*shell}, workingDir, runnable.environment}); - } else { - Terminal::Hooks::instance().openTerminal({workingDir, runnable.environment}); } } diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index 42e1d604741..414c123086c 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -375,7 +375,7 @@ FilePath Node::pathOrDirectory(bool dir) const if (m_filePath.isEmpty()) return {}; - if (m_filePath.needsDevice()) { + if (!m_filePath.isLocal()) { if (dir) return m_filePath.isDir() ? m_filePath.absoluteFilePath() : m_filePath.absolutePath(); return m_filePath; @@ -413,7 +413,7 @@ FileNode::FileNode(const Utils::FilePath &filePath, const FileType fileType) : setFilePath(filePath); const bool ignored = (fileType == FileType::Project || fileType == FileType::App || fileType == FileType::Lib); - setUseUnavailableMarker(!ignored && !filePath.needsDevice() && !filePath.exists()); + setUseUnavailableMarker(!ignored && filePath.isLocal() && !filePath.exists()); setListInProject(true); if (fileType == FileType::Project) setPriority(DefaultProjectFilePriority); diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 666c734aab1..9a0893737c8 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1436,7 +1436,7 @@ SimpleTargetRunnerPrivate::SimpleTargetRunnerPrivate(SimpleTargetRunner *parent) m_waitForDoneTimer.setSingleShot(true); connect(&m_waitForDoneTimer, &QTimer::timeout, this, [this] { q->appendMessage(Tr::tr("Process unexpectedly did not finish."), ErrorMessageFormat); - if (m_command.executable().needsDevice()) + if (!m_command.executable().isLocal()) q->appendMessage(Tr::tr("Connectivity lost?"), ErrorMessageFormat); m_process.close(); forwardDone(); @@ -1527,7 +1527,7 @@ void SimpleTargetRunnerPrivate::start() m_resultData = {}; QTC_ASSERT(m_state == Inactive, return); - if (!m_command.executable().needsDevice()) { + if (m_command.executable().isLocal()) { // Running locally. if (m_runAsRoot) RunControl::provideAskPassEntry(env); @@ -1609,7 +1609,7 @@ void SimpleTargetRunnerPrivate::forwardDone() void SimpleTargetRunnerPrivate::forwardStarted() { - const bool isDesktop = !m_command.executable().needsDevice(); + const bool isDesktop = m_command.executable().isLocal(); if (isDesktop) { // Console processes only know their pid after being started ProcessHandle pid{privateApplicationPID()}; @@ -1657,7 +1657,7 @@ void SimpleTargetRunner::start() appendMessage({}, StdOutFormat); } - const bool isDesktop = !d->m_command.executable().needsDevice(); + const bool isDesktop = d->m_command.executable().isLocal(); if (isDesktop && d->m_command.isEmpty()) { reportFailure(Tr::tr("No executable specified.")); return; @@ -1714,7 +1714,7 @@ void SimpleTargetRunner::suppressDefaultStdOutHandling() void SimpleTargetRunner::forceRunOnHost() { const FilePath executable = d->m_command.executable(); - if (executable.needsDevice()) { + if (!executable.isLocal()) { QTC_CHECK(false); d->m_command.setExecutable(FilePath::fromString(executable.path())); } diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp index 8e59ec7a505..c7d7ce786cf 100644 --- a/src/plugins/projectexplorer/toolchainmanager.cpp +++ b/src/plugins/projectexplorer/toolchainmanager.cpp @@ -373,7 +373,7 @@ bool ToolchainManager::isBetterToolchain( // Hack to prefer a tool chain from PATH (e.g. autodetected) over other matches. // This improves the situation a bit if a cross-compilation tool chain has the // same ABI as the host. - if (!bundle1.get(&Toolchain::compilerCommand).needsDevice()) { + if (bundle1.get(&Toolchain::compilerCommand).isLocal()) { const FilePaths envPathVar = Environment::systemEnvironment().path(); const auto toolchainIsInPath = [&envPathVar](const ToolchainBundle &b) { return Utils::contains(b.toolchains(), [&envPathVar](const Toolchain *tc) { @@ -390,7 +390,7 @@ bool ToolchainManager::isBetterToolchain( } } - if (!path1.needsDevice() && !path2.needsDevice()) { + if (path1.isLocal() && path2.isLocal()) { const QVersionNumber v1 = bundle1.get(&Toolchain::version); const QVersionNumber v2 = bundle2.get(&Toolchain::version); if (!v1.isNull() && !v2.isNull()) { diff --git a/src/plugins/python/pythonkitaspect.cpp b/src/plugins/python/pythonkitaspect.cpp index 62bb10e5b00..548c99b1b13 100644 --- a/src/plugins/python/pythonkitaspect.cpp +++ b/src/plugins/python/pythonkitaspect.cpp @@ -92,7 +92,7 @@ public: if (!python) return result; const FilePath path = python->command; - if (path.needsDevice()) + if (!path.isLocal()) return result; if (path.isEmpty()) { result << BuildSystemTask(Task::Error, Tr::tr("No Python setup.")); diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index bbfb5c75474..ea92b20d451 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -70,7 +70,7 @@ static QHash &pythonClients() static FilePath pyLspPath(const FilePath &python) { const QString version = pythonVersion(python); - if (!python.needsDevice()) + if (python.isLocal()) return Core::ICore::userResourcePath() / "pylsp" / version; if (const expected_str tmpDir = python.tmpDir()) return *tmpDir / "qc-pylsp" / version; @@ -136,7 +136,7 @@ protected: if (!lspPath.isEmpty() && lspPath.exists() && QTC_GUARD(lspPath.isSameDevice(python))) { env.appendOrSet("PYTHONPATH", lspPath.path()); } - if (!python.needsDevice()) { + if (python.isLocal()) { // todo check where to put this tempdir in remote setups env.appendOrSet("PYTHONPATH", m_extraPythonPath.path().toString()); } diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 58e5d11f81b..20eae05906b 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -287,7 +287,7 @@ void InterpreterOptionsWidget::updateCleanButton() void InterpreterOptionsWidget::updateGenerateKitButton(const Interpreter &interpreter) { bool enabled = !KitManager::kit(Id::fromString(interpreter.id)) - && (interpreter.command.needsDevice() || interpreter.command.isExecutableFile()); + && (!interpreter.command.isLocal() || interpreter.command.isExecutableFile()); m_generateKitButton->setEnabled(enabled); } @@ -806,7 +806,7 @@ void PythonSettings::removeKitsForInterpreter(const Interpreter &interpreter) bool PythonSettings::interpreterIsValid(const Interpreter &interpreter) { - return interpreter.command.needsDevice() || interpreter.command.isExecutableFile(); + return !interpreter.command.isLocal() || interpreter.command.isExecutableFile(); } void PythonSettings::setInterpreter(const QList &interpreters, const QString &defaultId) @@ -1019,7 +1019,7 @@ void PythonSettings::initFromSettings(QtcSettings *settings) const auto keepInterpreter = [](const Interpreter &interpreter) { return !interpreter.autoDetected // always keep user added interpreters - || interpreter.command.needsDevice() // remote devices might not be reachable at startup + || !interpreter.command.isLocal() // remote devices might not be reachable at startup || interpreter.command.isExecutableFile(); }; @@ -1030,7 +1030,7 @@ void PythonSettings::initFromSettings(QtcSettings *settings) for (const Interpreter &interpreter : m_interpreters) { if (interpreter.autoDetected) { const FilePath &cmd = interpreter.command; - if (cmd.needsDevice() || cmd.parentDir().pathAppended("activate").exists()) + if (!cmd.isLocal() || cmd.parentDir().pathAppended("activate").exists()) continue; } addKitsForInterpreter(interpreter, false); @@ -1186,7 +1186,7 @@ Utils::ListModel *createInterpreterModel(QObject * return f; } case Qt::ToolTipRole: - if (interpreter.command.needsDevice()) + if (!interpreter.command.isLocal()) break; if (interpreter.command.isEmpty()) return Tr::tr("Executable is empty."); diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index 5204334ecd7..6e804f70b30 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -144,7 +144,7 @@ FilePath QmakePriFile::directoryPath() const QString QmakePriFile::deviceRoot() const { - if (m_filePath.needsDevice()) + if (!m_filePath.isLocal()) return m_filePath.withNewPath("/").toFSPathString(); return {}; } diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index ffd219cd164..e3cb45c7673 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -813,7 +813,7 @@ FilePath QmakeBuildSystem::buildDir(const FilePath &proFilePath) const // the convoluted existing local version for now. // For starters, compute a 'new' version to check what it would look like, // but don't use it. - if (!proFilePath.needsDevice()) { + if (proFilePath.isLocal()) { // This branch should not exist. const QDir srcDirRoot = QDir(projectDirectory().toString()); const QString relativeDir = srcDirRoot.relativeFilePath(proFilePath.parentDir().toString()); @@ -1457,7 +1457,7 @@ QString QmakeBuildSystem::deviceRoot() const IDeviceConstPtr device = BuildDeviceKitAspect::device(target()->kit()); QTC_ASSERT(device, return {}); FilePath deviceRoot = device->rootPath(); - if (deviceRoot.needsDevice()) + if (!deviceRoot.isLocal()) return deviceRoot.toFSPathString(); return {}; diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 2e19566b983..1bbf74f96ad 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -275,7 +275,7 @@ QString QtVersion::defaultUnexpandedDisplayName() const ? Tr::tr("Qt %{Qt:Version} in PATH (%2)").arg(location) : Tr::tr("Qt %{Qt:Version} (%2)").arg(location); - if (qmakeFilePath().needsDevice()) + if (!qmakeFilePath().isLocal()) result += QString(Tr::tr(" (on %1)")).arg(qmakeFilePath().host().toString()); return result; @@ -631,7 +631,7 @@ void QtVersion::fromMap(const Store &map, const FilePath &filePath) if (string.startsWith('~')) string.remove(0, 1).prepend(QDir::homePath()); qmake = qmake.withNewPath(string); - if (!d->m_qmakeCommand.needsDevice()) { + if (d->m_qmakeCommand.isLocal()) { if (BuildableHelperLibrary::isQtChooser(qmake)) { // we don't want to treat qtchooser as a normal qmake // see e.g. QTCREATORBUG-9841, also this lead to users changing what @@ -1115,7 +1115,7 @@ void QtVersion::ensureMkSpecParsed() const Environment env = d->m_qmakeCommand.deviceEnvironment(); setupQmakeRunEnvironment(env); option.environment = env.toProcessEnvironment(); - if (d->m_qmakeCommand.needsDevice()) + if (!d->m_qmakeCommand.isLocal()) option.device_root = d->m_qmakeCommand.withNewPath("/").toFSPathString(); // Empty for host! ProMessageHandler msgHandler(true); ProFileCacheManager::instance()->incRefCount(); diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index b5199047177..6d1bcd38404 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -487,7 +487,7 @@ void ExampleSetModel::updateQtVersionList() { QtVersions versions = QtVersionManager::sortVersions( QtVersionManager::versions([](const QtVersion *v) { - return !v->qmakeFilePath().needsDevice() && (v->hasExamples() || v->hasDemos()); + return v->qmakeFilePath().isLocal() && (v->hasExamples() || v->hasDemos()); })); // prioritize default qt version diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index 987b647d871..0ab378f5e6b 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -531,7 +531,7 @@ static AllDocumentationFiles allDocumentationFiles(const QtVersions &versions) { QList> versionsWithDocPath; for (QtVersion *v : versions) { - if (v->hasDocs() && !v->docsPath().needsDevice()) + if (v->hasDocs() && v->docsPath().isLocal()) versionsWithDocPath << qMakePair(v, v->docsPath().path()); } QFuture> future = QtConcurrent::mapped( diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 82821747682..6975372d4b6 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1656,7 +1656,7 @@ FileTransferInterface *LinuxDevice::createFileTransferInterface( const FileTransferSetupData &setup) const { if (Utils::anyOf(setup.m_files, - [](const FileToTransfer &f) { return f.m_source.needsDevice(); })) { + [](const FileToTransfer &f) { return !f.m_source.isLocal(); })) { return new GenericTransferImpl(setup); } diff --git a/src/plugins/terminal/shellintegration.cpp b/src/plugins/terminal/shellintegration.cpp index 11dce74eca3..1a70bacc395 100644 --- a/src/plugins/terminal/shellintegration.cpp +++ b/src/plugins/terminal/shellintegration.cpp @@ -58,7 +58,7 @@ struct bool ShellIntegration::canIntegrate(const Utils::CommandLine &cmdLine) { - if (cmdLine.executable().needsDevice()) + if (!cmdLine.executable().isLocal()) return false; // TODO: Allow integration for remote shells if (cmdLine.executable().baseName() == "zsh") diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 8b6699ef77e..e107f55b3d1 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -106,7 +106,7 @@ void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) } } - if (parametersCopy.workingDirectory && parametersCopy.workingDirectory->needsDevice() + if (parametersCopy.workingDirectory && !parametersCopy.workingDirectory->isLocal() && !parametersCopy.shellCommand) { const FilePath shell = parametersCopy.workingDirectory->withNewPath( parametersCopy.environment diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index 2b5a59cebcc..d2ee214109d 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -64,7 +64,7 @@ VcsBaseClientImpl::VcsBaseClientImpl(VcsBaseSettings *baseSettings) FilePath VcsBaseClientImpl::vcsBinary(const Utils::FilePath &forDirectory) const { - if (forDirectory.needsDevice()) + if (!forDirectory.isLocal()) return {}; return m_baseSettings->binaryPath(); diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 49f58bb0687..995fb5c848c 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -535,7 +535,7 @@ static QString msgCheckScript(const FilePath &workingDir, const FilePath &cmd) bool VcsBaseSubmitEditor::runSubmitMessageCheckScript(const FilePath &checkScript, QString *errorMessage) const { - QTC_ASSERT(!checkScript.needsDevice(), return false); // Not supported below. + QTC_ASSERT(checkScript.isLocal(), return false); // Not supported below. // Write out message TempFileSaver saver(TemporaryDirectory::masterDirectoryPath() + "/msgXXXXXX.txt"); saver.write(fileContents()); diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index 917f3c2246a..cf7a7efd562 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -662,8 +662,8 @@ void tst_filepath::toString() FilePath filePath = FilePath::fromParts(scheme, host, path); QCOMPARE(filePath.toString(), result); - QString cleanedOutput = filePath.needsDevice() ? filePath.toUserOutput() - : QDir::cleanPath(filePath.toUserOutput()); + QString cleanedOutput = filePath.isLocal() ? QDir::cleanPath(filePath.toUserOutput()) + : filePath.toUserOutput(); QCOMPARE(cleanedOutput, userResult); } @@ -728,8 +728,8 @@ void tst_filepath::toFSPathString() FilePath filePath = FilePath::fromParts(scheme, host, path); QCOMPARE(filePath.toFSPathString(), result); - QString cleanedOutput = filePath.needsDevice() ? filePath.toUserOutput() - : QDir::cleanPath(filePath.toUserOutput()); + QString cleanedOutput = filePath.isLocal() ? QDir::cleanPath(filePath.toUserOutput()) + : filePath.toUserOutput(); QCOMPARE(cleanedOutput, userResult); } diff --git a/tests/auto/utils/fsengine/tst_fsengine.cpp b/tests/auto/utils/fsengine/tst_fsengine.cpp index d516bda8c21..9f030188311 100644 --- a/tests/auto/utils/fsengine/tst_fsengine.cpp +++ b/tests/auto/utils/fsengine/tst_fsengine.cpp @@ -158,19 +158,19 @@ void tst_fsengine::testListDir() void tst_fsengine::testWindowsPaths() { // Test upper-case "C:" - QVERIFY(FilePath::fromString("C:/__qtc_devices__/device/{cd6c7e4b-12fd-43ca-9bb2-053a38e6b7c5}") - .needsDevice()); + QVERIFY(!FilePath::fromString("C:/__qtc_devices__/device/{cd6c7e4b-12fd-43ca-9bb2-053a38e6b7c5}") + .isLocal()); // Test lower-case "C:" - QVERIFY(FilePath::fromString("c:/__qtc_devices__/device/{cd6c7e4b-12fd-43ca-9bb2-053a38e6b7c5}") - .needsDevice()); + QVERIFY(!FilePath::fromString("c:/__qtc_devices__/device/{cd6c7e4b-12fd-43ca-9bb2-053a38e6b7c5}") + .isLocal()); } void tst_fsengine::testUrl() { FilePath p = FilePath::fromString(makeTestPath("", true)); - QVERIFY(p.needsDevice()); + QVERIFY(!p.isLocal()); } void tst_fsengine::testBrokenWindowsPath() From 3a56be45a25fb3ea0180299b0c1fc5930eb831a1 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Dec 2024 17:15:19 +0100 Subject: [PATCH 364/989] Utils: Add a Process::setUtf8Codec helper function Allows us to get rid of direct includes of in a few places. Change-Id: I9e3ec953c71f78ce31230cd299c6875696445bdc Reviewed-by: Marcus Tillmanns --- src/libs/utils/qtcprocess.cpp | 20 ++++++++++++------- src/libs/utils/qtcprocess.h | 5 +++-- .../projectexplorer/abstractprocessstep.cpp | 4 +--- src/plugins/projectexplorer/msvctoolchain.cpp | 5 ++--- src/plugins/squish/objectsmapdocument.cpp | 4 +--- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index ea27cab3f2c..b7881ae57ba 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -1748,17 +1748,23 @@ void ChannelBuffer::handleRest() } } -void Process::setCodec(QTextCodec *c) +void Process::setCodec(QTextCodec *codec) { - QTC_ASSERT(c, return); - d->m_stdOutCodec = c; - d->m_stdErrCodec = c; + QTC_ASSERT(codec, return); + d->m_stdOutCodec = codec; + d->m_stdErrCodec = codec; } -void Process::setStdOutCodec(QTextCodec *c) +void Process::setUtf8Codec() { - QTC_ASSERT(c, return); - d->m_stdOutCodec = c; + QTextCodec *codec = QTextCodec::codecForName("UTF-8"); + d->m_stdOutCodec = codec; + d->m_stdErrCodec = codec; +} + +void Process::setUtf8StdOutCodec() +{ + d->m_stdOutCodec = QTextCodec::codecForName("UTF-8"); } void Process::setTimeOutMessageBoxEnabled(bool v) diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index bf79f774c88..6288cd396c5 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -143,8 +143,9 @@ public: void runBlocking(std::chrono::seconds timeout = std::chrono::seconds(10), EventLoopMode eventLoopMode = EventLoopMode::Off); - void setCodec(QTextCodec *c); // for stdOut and stdErr - void setStdOutCodec(QTextCodec *c); // for stdOut, stdErr uses executable.processStdErrCodec() + void setCodec(QTextCodec *codec); // for stdOut and stdErr + void setUtf8Codec(); // for stdOut and stdErr + void setUtf8StdOutCodec(); // for stdOut, stdErr uses executable.processStdErrCodec() void setTimeOutMessageBoxEnabled(bool); diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index 765b4eb877a..1795c062d41 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -13,8 +13,6 @@ #include #include -#include - using namespace Tasking; using namespace Utils; @@ -195,7 +193,7 @@ bool AbstractProcessStep::setupProcess(Process &process) process.setLowPriority(); if (buildEnvironment().hasKey("VSLANG")) - process.setStdOutCodec(QTextCodec::codecForName("UTF-8")); + process.setUtf8StdOutCodec(); process.setStdOutCallback([this](const QString &s){ emit addOutput(s, OutputFormat::Stdout, DontAppendNewline); diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index e977f776f8c..ab4d75521f3 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -260,7 +259,7 @@ static QVector detectVisualStudioFromVsWhere(const QSt { QVector installations; Process vsWhereProcess; - vsWhereProcess.setCodec(QTextCodec::codecForName("UTF-8")); + vsWhereProcess.setUtf8Codec(); vsWhereProcess.setCommand({FilePath::fromString(vswhere), {"-products", "*", "-prerelease", "-legacy", "-format", "json", "-utf8"}}); vsWhereProcess.runBlocking(5s); @@ -2114,7 +2113,7 @@ std::optional MsvcToolchain::generateEnvironmentSettings(const Utils::E CommandLine cmd(cmdPath, {"/D", "/E:ON", "/V:ON", "/c", saver.filePath().toUserOutput()}); qCDebug(Log) << "readEnvironmentSetting: " << call << cmd.toUserOutput() << " Env: " << runEnv.toStringList().size(); - run.setCodec(QTextCodec::codecForName("UTF-8")); + run.setUtf8Codec(); run.setCommand(cmd); run.runBlocking(1min); diff --git a/src/plugins/squish/objectsmapdocument.cpp b/src/plugins/squish/objectsmapdocument.cpp index 4e373eead2a..3cb7b5fd7c5 100644 --- a/src/plugins/squish/objectsmapdocument.cpp +++ b/src/plugins/squish/objectsmapdocument.cpp @@ -11,8 +11,6 @@ #include #include -#include - using namespace Utils; namespace Squish { @@ -209,7 +207,7 @@ Core::IDocument::OpenResult ObjectsMapDocument::openImpl(QString *error, Utils::Process objectMapReader; objectMapReader.setCommand({exe, {"--scriptMap", "--mode", "read", "--scriptedObjectMapPath", realFileName.toUserOutput()}}); - objectMapReader.setCodec(QTextCodec::codecForName("UTF-8")); + objectMapReader.setUtf8Codec(); objectMapReader.start(); objectMapReader.waitForFinished(); text = objectMapReader.cleanedStdOut().toUtf8(); From a5f97ed58939ecf2b82eadb6339bd898b8063f27 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 9 Dec 2024 11:56:32 +0100 Subject: [PATCH 365/989] Docker: Fix deadlock Change-Id: I065a28f8a824901a72bb98b60b3d3a75c36d8b0c Reviewed-by: hjk --- src/libs/gocmdbridge/client/cmdbridgeclient.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/gocmdbridge/client/cmdbridgeclient.cpp b/src/libs/gocmdbridge/client/cmdbridgeclient.cpp index a88ab332bcd..754aac2251c 100644 --- a/src/libs/gocmdbridge/client/cmdbridgeclient.cpp +++ b/src/libs/gocmdbridge/client/cmdbridgeclient.cpp @@ -292,6 +292,9 @@ expected_str> Client::start() d->process->setCommand({d->remoteCmdBridgePath, {}}); d->process->setProcessMode(ProcessMode::Writer); d->process->setProcessChannelMode(QProcess::ProcessChannelMode::SeparateChannels); + // Make sure the process has a codec, otherwise it will try to ask us recursively + // and dead lock. + d->process->setUtf8Codec(); connect(d->process, &Process::done, d->process, [this] { if (d->process->resultData().m_exitCode != 0) { From 5ec07b368bb948585a01a8a52a014a5bc29632bd Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Tue, 26 Nov 2024 17:35:34 +0100 Subject: [PATCH 366/989] QML Debug: Remove timer connection "optimization" Trying to connect ot host while there's another connection in progress leads to the latter being dropped and `QmlDebugConnection::connectionFailed` signal getting emitted (see `QmlDebugConnection::connectToHost` and `QmlDebugConnection::socketDisconnected`). This signal initiates the destruction of the connection itself (see `QmlDebugConnectionManager::qmlDebugConnectionFailed`). Fixes: QTCREATORBUG-32062 Change-Id: Ibf4a33ac87db0d62d81177c508ae68db337e9f82 Reviewed-by: hjk Reviewed-by: Marcus Tillmanns --- src/libs/qmldebug/qmldebugconnectionmanager.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/libs/qmldebug/qmldebugconnectionmanager.cpp b/src/libs/qmldebug/qmldebugconnectionmanager.cpp index eb706b3dbbb..ddd8995c5af 100644 --- a/src/libs/qmldebug/qmldebugconnectionmanager.cpp +++ b/src/libs/qmldebug/qmldebugconnectionmanager.cpp @@ -71,15 +71,6 @@ void QmlDebugConnectionManager::connectToTcpServer() // If the previous connection failed, recreate it. createConnection(); m_connection->connectToHost(m_server.host(), port16(m_server)); - } else if (m_numRetries < 3 - && m_connection->socketState() != QAbstractSocket::ConnectedState) { - // If we don't get connected in the first retry interval, drop the socket and try - // with a new one. On some operating systems (maxOS) the very first connection to a - // TCP server takes a very long time to get established and this helps. - // On other operating systems (windows) every connection takes forever to get - // established. So, after tearing down and rebuilding the socket twice, just - // keep trying with the same one. - m_connection->connectToHost(m_server.host(), port16(m_server)); } // Else leave it alone and wait for hello. } else { // On final timeout, clear the connection. From 8fedcb6ba9a8b63d8d749f8de46524151078bffa Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 3 Dec 2024 10:10:43 +0100 Subject: [PATCH 367/989] ProjectExplorer: Create a thin DeviceRef wrapper class ... around a weak pointer to IDevice to pass around device identity. The idea is to ramp down the direct use, especially storage, of IDevice::{Const,}Ptr outside the DeviceManager and use DeviceRef instead, in order to avoid the problem of device shared pointers not dying when copies are held in dormant dialogs or similar. The separate class effectively acts as a weak pointer with somewhat nicer syntax. Change-Id: If735ed8af9589137640b73b023d04c063ea876be Reviewed-by: Christian Kandeler --- .../projectexplorer/devicesupport/idevice.cpp | 53 +++++++++++++++++++ .../projectexplorer/devicesupport/idevice.h | 27 ++++++++++ .../devicesupport/idevicefwd.h | 3 ++ .../remotelinux/publickeydeploymentdialog.cpp | 14 ++--- .../remotelinux/publickeydeploymentdialog.h | 9 ++-- src/plugins/remotelinux/sshdevicewizard.cpp | 28 +++++----- src/plugins/remotelinux/sshdevicewizard.h | 5 +- 7 files changed, 113 insertions(+), 26 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 96b9c2e0ca6..bb5479539f6 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -794,4 +794,57 @@ void DeviceProcessKillerTaskAdapter::start() task()->start(); } +// DeviceConstRef + +DeviceConstRef::DeviceConstRef(const IDevice::ConstPtr &device) + : m_constDevice(device) +{} + +DeviceConstRef::DeviceConstRef(const IDevice::Ptr &device) + : m_constDevice(device) +{} + +DeviceConstRef::~DeviceConstRef() = default; + +Id DeviceConstRef::id() const +{ + const IDevice::ConstPtr device = m_constDevice.lock(); + QTC_ASSERT(device, return {}); + return device->id(); +} + +QString DeviceConstRef::displayName() const +{ + const IDevice::ConstPtr device = m_constDevice.lock(); + QTC_ASSERT(device, return {}); + return device->displayName(); +} + +SshParameters DeviceConstRef::sshParameters() const +{ + const IDevice::ConstPtr device = m_constDevice.lock(); + QTC_ASSERT(device, return {}); + return device->sshParameters(); +} + +// DeviceRef, mutable + +DeviceRef::DeviceRef(const IDevice::Ptr &device) + : DeviceConstRef(device), m_mutableDevice(device) +{} + +void DeviceRef::setDisplayName(const QString &displayName) +{ + const IDevice::Ptr device = m_mutableDevice.lock(); + QTC_ASSERT(device, return); + device->setDisplayName(displayName); +} + +void DeviceRef::setSshParameters(const SshParameters ¶ms) +{ + const IDevice::Ptr device = m_mutableDevice.lock(); + QTC_ASSERT(device, return); + device->setSshParameters(params); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index ec6220d30b1..58737ec6c7a 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -245,6 +245,33 @@ private: friend class DeviceManager; }; +class PROJECTEXPLORER_EXPORT DeviceConstRef +{ +public: + DeviceConstRef(const IDevice::ConstPtr &device); + DeviceConstRef(const IDevice::Ptr &device); + virtual ~DeviceConstRef(); + + Utils::Id id() const; + QString displayName() const; + SshParameters sshParameters() const; + +private: + std::weak_ptr m_constDevice; +}; + +class PROJECTEXPLORER_EXPORT DeviceRef : public DeviceConstRef +{ +public: + DeviceRef(const IDevice::Ptr &device); + + void setDisplayName(const QString &displayName); + void setSshParameters(const SshParameters ¶ms); + +private: + std::weak_ptr m_mutableDevice; +}; + class PROJECTEXPLORER_EXPORT DeviceTester : public QObject { Q_OBJECT diff --git a/src/plugins/projectexplorer/devicesupport/idevicefwd.h b/src/plugins/projectexplorer/devicesupport/idevicefwd.h index 533e88beb1c..236c10f2d31 100644 --- a/src/plugins/projectexplorer/devicesupport/idevicefwd.h +++ b/src/plugins/projectexplorer/devicesupport/idevicefwd.h @@ -7,6 +7,9 @@ namespace ProjectExplorer { +class DeviceRef; +class DeviceConstRef; + class IDevice; using IDevicePtr = std::shared_ptr; diff --git a/src/plugins/remotelinux/publickeydeploymentdialog.cpp b/src/plugins/remotelinux/publickeydeploymentdialog.cpp index b0da7f2b1d0..c7fdaaf50f9 100644 --- a/src/plugins/remotelinux/publickeydeploymentdialog.cpp +++ b/src/plugins/remotelinux/publickeydeploymentdialog.cpp @@ -28,19 +28,21 @@ public: }; PublicKeyDeploymentDialog *PublicKeyDeploymentDialog::createDialog( - const IDevice::ConstPtr &deviceConfig, QWidget *parent) + const DeviceConstRef &device, QWidget *parent) { - const FilePath dir = deviceConfig->sshParameters().privateKeyFile.parentDir(); + const FilePath dir = device.sshParameters().privateKeyFile.parentDir(); const FilePath publicKeyFileName = FileUtils::getOpenFilePath(nullptr, Tr::tr("Choose Public Key File"), dir, Tr::tr("Public Key Files (*.pub);;All Files (*)")); if (publicKeyFileName.isEmpty()) return nullptr; - return new PublicKeyDeploymentDialog(deviceConfig, publicKeyFileName, parent); + return new PublicKeyDeploymentDialog(device, publicKeyFileName, parent); } -PublicKeyDeploymentDialog::PublicKeyDeploymentDialog(const IDevice::ConstPtr &deviceConfig, - const FilePath &publicKeyFileName, QWidget *parent) +PublicKeyDeploymentDialog::PublicKeyDeploymentDialog( + const DeviceConstRef &device, + const FilePath &publicKeyFileName, + QWidget *parent) : QProgressDialog(parent), d(new PublicKeyDeploymentDialogPrivate) { setAutoReset(false); @@ -76,7 +78,7 @@ PublicKeyDeploymentDialog::PublicKeyDeploymentDialog(const IDevice::ConstPtr &de + QString::fromLocal8Bit(reader.data()) + "' >> .ssh/authorized_keys && chmod 0600 .ssh/authorized_keys"; - const SshParameters params = deviceConfig->sshParameters(); + const SshParameters params = device.sshParameters(); const QString hostKeyCheckingString = params.hostKeyCheckingMode == SshHostKeyCheckingStrict ? QLatin1String("yes") : QLatin1String("no"); const bool isWindows = HostOsInfo::isWindowsHost() diff --git a/src/plugins/remotelinux/publickeydeploymentdialog.h b/src/plugins/remotelinux/publickeydeploymentdialog.h index 8177e58935e..68b023e8133 100644 --- a/src/plugins/remotelinux/publickeydeploymentdialog.h +++ b/src/plugins/remotelinux/publickeydeploymentdialog.h @@ -18,11 +18,12 @@ class PublicKeyDeploymentDialog : public QProgressDialog Q_OBJECT public: // Asks for public key and returns null if the file dialog is canceled. - static PublicKeyDeploymentDialog *createDialog( - const ProjectExplorer::IDeviceConstPtr &deviceConfig, QWidget *parent = nullptr); + static PublicKeyDeploymentDialog *createDialog(const ProjectExplorer::DeviceConstRef &device, + QWidget *parent = nullptr); - PublicKeyDeploymentDialog(const ProjectExplorer::IDeviceConstPtr &deviceConfig, - const Utils::FilePath &publicKeyFileName, QWidget *parent = nullptr); + PublicKeyDeploymentDialog(const ProjectExplorer::DeviceConstRef &device, + const Utils::FilePath &publicKeyFileName, + QWidget *parent = nullptr); ~PublicKeyDeploymentDialog() override; diff --git a/src/plugins/remotelinux/sshdevicewizard.cpp b/src/plugins/remotelinux/sshdevicewizard.cpp index 1bea0cfa950..b1f41777fca 100644 --- a/src/plugins/remotelinux/sshdevicewizard.cpp +++ b/src/plugins/remotelinux/sshdevicewizard.cpp @@ -31,7 +31,7 @@ namespace RemoteLinux { class SetupPage : public QWizardPage { public: - explicit SetupPage(const ProjectExplorer::IDevicePtr &device) + explicit SetupPage(const DeviceRef &device) : m_device(device) { setTitle(Tr::tr("Connection")); @@ -65,11 +65,11 @@ public: private: void initializePage() final { - m_nameLineEdit->setText(m_device->displayName()); - m_hostNameLineEdit->setText(m_device->sshParameters().host()); + m_nameLineEdit->setText(m_device.displayName()); + m_hostNameLineEdit->setText(m_device.sshParameters().host()); m_sshPortSpinBox->setValue(22); m_sshPortSpinBox->setRange(1, 65535); - m_userNameLineEdit->setText(m_device->sshParameters().userName()); + m_userNameLineEdit->setText(m_device.sshParameters().userName()); } bool isComplete() const final { return !m_nameLineEdit->text().trimmed().isEmpty() @@ -77,12 +77,12 @@ private: && !m_userNameLineEdit->text().trimmed().isEmpty(); } bool validatePage() final { - m_device->setDisplayName(m_nameLineEdit->text().trimmed()); - SshParameters sshParams = m_device->sshParameters(); + m_device.setDisplayName(m_nameLineEdit->text().trimmed()); + SshParameters sshParams = m_device.sshParameters(); sshParams.setHost(m_hostNameLineEdit->text().trimmed()); sshParams.setUserName(m_userNameLineEdit->text().trimmed()); sshParams.setPort(m_sshPortSpinBox->value()); - m_device->setSshParameters(sshParams); + m_device.setSshParameters(sshParams); return true; } @@ -90,13 +90,13 @@ private: FancyLineEdit *m_hostNameLineEdit; QSpinBox *m_sshPortSpinBox; FancyLineEdit *m_userNameLineEdit; - IDevicePtr m_device; + DeviceRef m_device; }; class KeyDeploymentPage : public QWizardPage { public: - explicit KeyDeploymentPage(const ProjectExplorer::IDevicePtr &device) + explicit KeyDeploymentPage(const DeviceRef &device) : m_device(device) { setTitle(Tr::tr("Key Deployment")); @@ -150,7 +150,7 @@ public: private: void initializePage() final { - if (!m_device->sshParameters().privateKeyFile.isEmpty()) + if (!m_device.sshParameters().privateKeyFile.isEmpty()) m_keyFileChooser.setFilePath(m_keyFileChooser.filePath()); m_iconLabel.clear(); } @@ -160,10 +160,10 @@ private: } bool validatePage() final { if (!defaultKeys().contains(m_keyFileChooser.filePath())) { - SshParameters sshParams = m_device->sshParameters(); + SshParameters sshParams = m_device.sshParameters(); sshParams.authenticationType = SshParameters::AuthenticationTypeSpecificKey; sshParams.privateKeyFile = m_keyFileChooser.filePath(); - m_device->setSshParameters(sshParams); + m_device.setSshParameters(sshParams); } return true; } @@ -174,7 +174,7 @@ private: PathChooser m_keyFileChooser; QLabel m_iconLabel; - IDevicePtr m_device; + DeviceRef m_device; }; class FinalPage final : public QWizardPage @@ -193,7 +193,7 @@ public: } }; -SshDeviceWizard::SshDeviceWizard(const QString &title, const ProjectExplorer::IDevicePtr &device) +SshDeviceWizard::SshDeviceWizard(const QString &title, const DeviceRef &device) : Wizard(Core::ICore::dialogParent()) { setWindowTitle(title); diff --git a/src/plugins/remotelinux/sshdevicewizard.h b/src/plugins/remotelinux/sshdevicewizard.h index 3bd2af1ab22..319904b1234 100644 --- a/src/plugins/remotelinux/sshdevicewizard.h +++ b/src/plugins/remotelinux/sshdevicewizard.h @@ -5,15 +5,16 @@ #include "remotelinux_export.h" -#include #include +namespace ProjectExplorer { class DeviceRef; } + namespace RemoteLinux { class REMOTELINUX_EXPORT SshDeviceWizard : public Utils::Wizard { public: - SshDeviceWizard(const QString &title, const ProjectExplorer::IDevicePtr &device); + SshDeviceWizard(const QString &title, const ProjectExplorer::DeviceRef &device); }; } // namespace RemoteLinux From c1db4f6accd91de5ccd780b6bb8d5dc89c472f24 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 9 Dec 2024 13:14:48 +0100 Subject: [PATCH 368/989] QbsProjectManager: Fix cross-compiling with clang In order to use a generic clang as a cross-compiler, we have to pass "- target" in the "platform codegen flags" in the toolchain settings. However, qbs errors out when that flag is used directly, so we need to filter it out along with "-arch". Change-Id: Ide83115b046bc53c330e86b5d5715640a4c5ed98 Reviewed-by: Christian Stenger --- src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index 0ea8d83e55d..ebf6d5e80e2 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -233,8 +233,7 @@ static void filterCompilerLinkerFlags(const ProjectExplorer::Abi &targetAbi, QSt { for (int i = 0; i < flags.size(); ) { if (targetAbi.architecture() != ProjectExplorer::Abi::UnknownArchitecture - && flags[i] == QStringLiteral("-arch") - && i + 1 < flags.size()) { + && (flags[i] == "-arch" || flags[i] == "-target") && i + 1 < flags.size()) { flags.removeAt(i); flags.removeAt(i); } else { From dc16286bb48a82fdb67f965b9526a8dc79153437 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 18 Nov 2024 08:54:15 +0100 Subject: [PATCH 369/989] KArchive: Add KArchive library and its dependencies We want to include a reliable way to extract archives. KArchive is a library that provides a simple API for reading and writing archives. It will allow us to replace the current implementation of archive extraction which relies on the necessary tools (7zip, unzip, tar etc.) to be available on the users system. Since karchive is built on top of QFile if will also allow us to use it for reading and writing archives on remote devices. Change-Id: I390e0e786f2dd20ae85d16dab34f43510cdf82a6 Reviewed-by: Eike Ziller --- qt_attributions.json | 44 +- src/libs/3rdparty/CMakeLists.txt | 2 + .../karchive/3rdparty/bzip2/.gitattributes | 1 + .../karchive/3rdparty/bzip2/.gitignore | 9 + .../3rdparty/karchive/3rdparty/bzip2/CHANGES | 356 ++ .../3rdparty/karchive/3rdparty/bzip2/LICENSE | 42 + .../3rdparty/karchive/3rdparty/bzip2/README | 196 ++ .../bzip2/README.COMPILATION.PROBLEMS | 58 + .../karchive/3rdparty/bzip2/README.XML.STUFF | 45 + .../karchive/3rdparty/bzip2/README.qtcreator | 4 + .../karchive/3rdparty/bzip2/blocksort.c | 1094 ++++++ .../3rdparty/karchive/3rdparty/bzip2/bzip2.c | 2036 +++++++++++ .../karchive/3rdparty/bzip2/bzip2recover.c | 516 +++ .../3rdparty/karchive/3rdparty/bzip2/bzlib.c | 1572 +++++++++ .../3rdparty/karchive/3rdparty/bzip2/bzlib.h | 281 ++ .../karchive/3rdparty/bzip2/bzlib_private.h | 509 +++ .../karchive/3rdparty/bzip2/compress.c | 672 ++++ .../karchive/3rdparty/bzip2/crctable.c | 104 + .../karchive/3rdparty/bzip2/decompress.c | 652 ++++ .../karchive/3rdparty/bzip2/huffman.c | 205 ++ .../3rdparty/karchive/3rdparty/bzip2/mk251.c | 31 + .../karchive/3rdparty/bzip2/randtable.c | 84 + .../3rdparty/karchive/3rdparty/xz/AUTHORS | 58 + .../3rdparty/karchive/3rdparty/xz/COPYING | 83 + .../karchive/3rdparty/xz/COPYING.0BSD | 11 + .../karchive/3rdparty/xz/COPYING.GPLv2 | 339 ++ .../karchive/3rdparty/xz/COPYING.GPLv3 | 674 ++++ .../karchive/3rdparty/xz/COPYING.LGPLv2.1 | 502 +++ src/libs/3rdparty/karchive/3rdparty/xz/README | 310 ++ .../karchive/3rdparty/xz/README.qtcreator | 4 + src/libs/3rdparty/karchive/3rdparty/xz/THANKS | 202 ++ src/libs/3rdparty/karchive/3rdparty/xz/TODO | 105 + .../3rdparty/xz/src/common/mythread.h | 548 +++ .../karchive/3rdparty/xz/src/common/sysdefs.h | 199 ++ .../3rdparty/xz/src/common/tuklib_common.h | 90 + .../3rdparty/xz/src/common/tuklib_config.h | 12 + .../3rdparty/xz/src/common/tuklib_cpucores.c | 108 + .../3rdparty/xz/src/common/tuklib_cpucores.h | 22 + .../3rdparty/xz/src/common/tuklib_exit.c | 57 + .../3rdparty/xz/src/common/tuklib_exit.h | 24 + .../3rdparty/xz/src/common/tuklib_gettext.h | 43 + .../3rdparty/xz/src/common/tuklib_integer.h | 954 ++++++ .../3rdparty/xz/src/common/tuklib_mbstr.h | 65 + .../3rdparty/xz/src/common/tuklib_mbstr_fw.c | 30 + .../xz/src/common/tuklib_mbstr_width.c | 64 + .../xz/src/common/tuklib_open_stdxxx.c | 56 + .../xz/src/common/tuklib_open_stdxxx.h | 22 + .../3rdparty/xz/src/common/tuklib_physmem.c | 231 ++ .../3rdparty/xz/src/common/tuklib_physmem.h | 27 + .../3rdparty/xz/src/common/tuklib_progname.c | 49 + .../3rdparty/xz/src/common/tuklib_progname.h | 31 + .../xz/src/common/w32_application.manifest | 28 + .../w32_application.manifest.comments.txt | 178 + .../3rdparty/xz/src/liblzma/api/lzma.h | 327 ++ .../3rdparty/xz/src/liblzma/api/lzma/base.h | 747 ++++ .../3rdparty/xz/src/liblzma/api/lzma/bcj.h | 98 + .../3rdparty/xz/src/liblzma/api/lzma/block.h | 694 ++++ .../3rdparty/xz/src/liblzma/api/lzma/check.h | 163 + .../xz/src/liblzma/api/lzma/container.h | 995 ++++++ .../3rdparty/xz/src/liblzma/api/lzma/delta.h | 95 + .../3rdparty/xz/src/liblzma/api/lzma/filter.h | 769 +++++ .../xz/src/liblzma/api/lzma/hardware.h | 62 + .../3rdparty/xz/src/liblzma/api/lzma/index.h | 882 +++++ .../xz/src/liblzma/api/lzma/index_hash.h | 123 + .../3rdparty/xz/src/liblzma/api/lzma/lzma12.h | 568 ++++ .../xz/src/liblzma/api/lzma/stream_flags.h | 265 ++ .../xz/src/liblzma/api/lzma/version.h | 134 + .../3rdparty/xz/src/liblzma/api/lzma/vli.h | 166 + .../3rdparty/xz/src/liblzma/check/check.c | 173 + .../3rdparty/xz/src/liblzma/check/check.h | 174 + .../xz/src/liblzma/check/crc32_arm64.h | 122 + .../xz/src/liblzma/check/crc32_fast.c | 204 ++ .../xz/src/liblzma/check/crc32_small.c | 67 + .../xz/src/liblzma/check/crc32_table.c | 42 + .../xz/src/liblzma/check/crc32_table_be.h | 527 +++ .../xz/src/liblzma/check/crc32_table_le.h | 527 +++ .../xz/src/liblzma/check/crc32_tablegen.c | 120 + .../3rdparty/xz/src/liblzma/check/crc32_x86.S | 312 ++ .../xz/src/liblzma/check/crc64_fast.c | 156 + .../xz/src/liblzma/check/crc64_small.c | 57 + .../xz/src/liblzma/check/crc64_table.c | 37 + .../xz/src/liblzma/check/crc64_table_be.h | 523 +++ .../xz/src/liblzma/check/crc64_table_le.h | 523 +++ .../xz/src/liblzma/check/crc64_tablegen.c | 89 + .../3rdparty/xz/src/liblzma/check/crc64_x86.S | 295 ++ .../xz/src/liblzma/check/crc_common.h | 137 + .../xz/src/liblzma/check/crc_x86_clmul.h | 432 +++ .../3rdparty/xz/src/liblzma/check/sha256.c | 189 + .../xz/src/liblzma/common/alone_decoder.c | 248 ++ .../xz/src/liblzma/common/alone_decoder.h | 22 + .../xz/src/liblzma/common/alone_encoder.c | 151 + .../xz/src/liblzma/common/auto_decoder.c | 205 ++ .../src/liblzma/common/block_buffer_decoder.c | 79 + .../src/liblzma/common/block_buffer_encoder.c | 354 ++ .../src/liblzma/common/block_buffer_encoder.h | 23 + .../xz/src/liblzma/common/block_decoder.c | 288 ++ .../xz/src/liblzma/common/block_decoder.h | 21 + .../xz/src/liblzma/common/block_encoder.c | 226 ++ .../xz/src/liblzma/common/block_encoder.h | 46 + .../src/liblzma/common/block_header_decoder.c | 114 + .../src/liblzma/common/block_header_encoder.c | 131 + .../xz/src/liblzma/common/block_util.c | 89 + .../3rdparty/xz/src/liblzma/common/common.c | 480 +++ .../3rdparty/xz/src/liblzma/common/common.h | 412 +++ .../src/liblzma/common/easy_buffer_encoder.c | 26 + .../liblzma/common/easy_decoder_memusage.c | 23 + .../xz/src/liblzma/common/easy_encoder.c | 23 + .../liblzma/common/easy_encoder_memusage.c | 23 + .../xz/src/liblzma/common/easy_preset.c | 26 + .../xz/src/liblzma/common/easy_preset.h | 36 + .../xz/src/liblzma/common/file_info.c | 854 +++++ .../liblzma/common/filter_buffer_decoder.c | 87 + .../liblzma/common/filter_buffer_encoder.c | 54 + .../xz/src/liblzma/common/filter_common.c | 393 +++ .../xz/src/liblzma/common/filter_common.h | 50 + .../xz/src/liblzma/common/filter_decoder.c | 214 ++ .../xz/src/liblzma/common/filter_decoder.h | 22 + .../xz/src/liblzma/common/filter_encoder.c | 330 ++ .../xz/src/liblzma/common/filter_encoder.h | 22 + .../src/liblzma/common/filter_flags_decoder.c | 45 + .../src/liblzma/common/filter_flags_encoder.c | 55 + .../src/liblzma/common/hardware_cputhreads.c | 33 + .../xz/src/liblzma/common/hardware_physmem.c | 24 + .../3rdparty/xz/src/liblzma/common/index.c | 1268 +++++++ .../3rdparty/xz/src/liblzma/common/index.h | 80 + .../xz/src/liblzma/common/index_decoder.c | 372 ++ .../xz/src/liblzma/common/index_decoder.h | 24 + .../xz/src/liblzma/common/index_encoder.c | 262 ++ .../xz/src/liblzma/common/index_encoder.h | 22 + .../xz/src/liblzma/common/index_hash.c | 342 ++ .../xz/src/liblzma/common/lzip_decoder.c | 417 +++ .../xz/src/liblzma/common/lzip_decoder.h | 21 + .../xz/src/liblzma/common/memcmplen.h | 188 + .../xz/src/liblzma/common/microlzma_decoder.c | 220 ++ .../xz/src/liblzma/common/microlzma_encoder.c | 140 + .../3rdparty/xz/src/liblzma/common/outqueue.c | 286 ++ .../3rdparty/xz/src/liblzma/common/outqueue.h | 258 ++ .../liblzma/common/stream_buffer_decoder.c | 90 + .../liblzma/common/stream_buffer_encoder.c | 141 + .../xz/src/liblzma/common/stream_decoder.c | 473 +++ .../xz/src/liblzma/common/stream_decoder.h | 21 + .../xz/src/liblzma/common/stream_decoder_mt.c | 2017 +++++++++++ .../xz/src/liblzma/common/stream_encoder.c | 354 ++ .../xz/src/liblzma/common/stream_encoder_mt.c | 1280 +++++++ .../src/liblzma/common/stream_flags_common.c | 46 + .../src/liblzma/common/stream_flags_common.h | 35 + .../src/liblzma/common/stream_flags_decoder.c | 87 + .../src/liblzma/common/stream_flags_encoder.c | 85 + .../xz/src/liblzma/common/string_conversion.c | 1338 ++++++++ .../xz/src/liblzma/common/vli_decoder.c | 85 + .../xz/src/liblzma/common/vli_encoder.c | 68 + .../3rdparty/xz/src/liblzma/common/vli_size.c | 29 + .../xz/src/liblzma/delta/delta_common.c | 72 + .../xz/src/liblzma/delta/delta_common.h | 19 + .../xz/src/liblzma/delta/delta_decoder.c | 87 + .../xz/src/liblzma/delta/delta_decoder.h | 25 + .../xz/src/liblzma/delta/delta_encoder.c | 132 + .../xz/src/liblzma/delta/delta_encoder.h | 23 + .../xz/src/liblzma/delta/delta_private.h | 36 + .../3rdparty/xz/src/liblzma/liblzma.pc.in | 16 + .../xz/src/liblzma/liblzma_generic.map | 128 + .../3rdparty/xz/src/liblzma/liblzma_linux.map | 143 + .../3rdparty/xz/src/liblzma/lz/lz_decoder.c | 324 ++ .../3rdparty/xz/src/liblzma/lz/lz_decoder.h | 250 ++ .../3rdparty/xz/src/liblzma/lz/lz_encoder.c | 632 ++++ .../3rdparty/xz/src/liblzma/lz/lz_encoder.h | 352 ++ .../xz/src/liblzma/lz/lz_encoder_hash.h | 108 + .../xz/src/liblzma/lz/lz_encoder_hash_table.h | 70 + .../xz/src/liblzma/lz/lz_encoder_mf.c | 744 ++++ .../3rdparty/xz/src/liblzma/lzma/fastpos.h | 141 + .../xz/src/liblzma/lzma/fastpos_table.c | 521 +++ .../xz/src/liblzma/lzma/fastpos_tablegen.c | 58 + .../xz/src/liblzma/lzma/lzma2_decoder.c | 310 ++ .../xz/src/liblzma/lzma/lzma2_decoder.h | 28 + .../xz/src/liblzma/lzma/lzma2_encoder.c | 416 +++ .../xz/src/liblzma/lzma/lzma2_encoder.h | 42 + .../xz/src/liblzma/lzma/lzma_common.h | 240 ++ .../xz/src/liblzma/lzma/lzma_decoder.c | 1263 +++++++ .../xz/src/liblzma/lzma/lzma_decoder.h | 52 + .../xz/src/liblzma/lzma/lzma_encoder.c | 786 +++++ .../xz/src/liblzma/lzma/lzma_encoder.h | 58 + .../liblzma/lzma/lzma_encoder_optimum_fast.c | 169 + .../lzma/lzma_encoder_optimum_normal.c | 858 +++++ .../src/liblzma/lzma/lzma_encoder_presets.c | 63 + .../src/liblzma/lzma/lzma_encoder_private.h | 161 + .../xz/src/liblzma/rangecoder/price.h | 92 + .../xz/src/liblzma/rangecoder/price_table.c | 24 + .../src/liblzma/rangecoder/price_tablegen.c | 93 + .../xz/src/liblzma/rangecoder/range_common.h | 77 + .../xz/src/liblzma/rangecoder/range_decoder.h | 966 ++++++ .../xz/src/liblzma/rangecoder/range_encoder.h | 349 ++ .../3rdparty/xz/src/liblzma/simple/arm.c | 74 + .../3rdparty/xz/src/liblzma/simple/arm64.c | 136 + .../3rdparty/xz/src/liblzma/simple/armthumb.c | 79 + .../3rdparty/xz/src/liblzma/simple/ia64.c | 115 + .../3rdparty/xz/src/liblzma/simple/powerpc.c | 79 + .../3rdparty/xz/src/liblzma/simple/riscv.c | 755 ++++ .../xz/src/liblzma/simple/simple_coder.c | 291 ++ .../xz/src/liblzma/simple/simple_coder.h | 89 + .../xz/src/liblzma/simple/simple_decoder.c | 39 + .../xz/src/liblzma/simple/simple_decoder.h | 21 + .../xz/src/liblzma/simple/simple_encoder.c | 37 + .../xz/src/liblzma/simple/simple_encoder.h | 22 + .../xz/src/liblzma/simple/simple_private.h | 73 + .../3rdparty/xz/src/liblzma/simple/sparc.c | 86 + .../3rdparty/xz/src/liblzma/simple/x86.c | 157 + .../3rdparty/xz/src/liblzma/validate_map.sh | 163 + src/libs/3rdparty/karchive/AUTHORS | 10 + src/libs/3rdparty/karchive/CMakeLists.txt | 152 + .../karchive/LICENSES/BSD-2-Clause.txt | 22 + .../3rdparty/karchive/LICENSES/CC0-1.0.txt | 121 + .../karchive/LICENSES/LGPL-2.0-or-later.txt | 446 +++ src/libs/3rdparty/karchive/README.md | 33 + src/libs/3rdparty/karchive/src/k7zip.cpp | 3028 +++++++++++++++++ src/libs/3rdparty/karchive/src/k7zip.h | 100 + src/libs/3rdparty/karchive/src/kar.cpp | 195 ++ src/libs/3rdparty/karchive/src/kar.h | 106 + src/libs/3rdparty/karchive/src/karchive.cpp | 1062 ++++++ src/libs/3rdparty/karchive/src/karchive.h | 433 +++ .../3rdparty/karchive/src/karchive_export.h | 14 + src/libs/3rdparty/karchive/src/karchive_p.h | 59 + .../3rdparty/karchive/src/karchivedirectory.h | 131 + .../3rdparty/karchive/src/karchiveentry.h | 111 + src/libs/3rdparty/karchive/src/karchivefile.h | 110 + .../3rdparty/karchive/src/kbzip2filter.cpp | 198 ++ src/libs/3rdparty/karchive/src/kbzip2filter.h | 47 + .../karchive/src/kcompressiondevice.cpp | 519 +++ .../karchive/src/kcompressiondevice.h | 146 + .../karchive/src/kcompressiondevice_p.h | 13 + .../3rdparty/karchive/src/kfilterbase.cpp | 81 + src/libs/3rdparty/karchive/src/kfilterbase.h | 109 + .../3rdparty/karchive/src/kgzipfilter.cpp | 366 ++ src/libs/3rdparty/karchive/src/kgzipfilter.h | 59 + .../karchive/src/klimitediodevice.cpp | 73 + .../karchive/src/klimitediodevice_p.h | 58 + .../3rdparty/karchive/src/knonefilter.cpp | 127 + src/libs/3rdparty/karchive/src/knonefilter.h | 48 + src/libs/3rdparty/karchive/src/krcc.cpp | 162 + src/libs/3rdparty/karchive/src/krcc.h | 103 + src/libs/3rdparty/karchive/src/ktar.cpp | 975 ++++++ src/libs/3rdparty/karchive/src/ktar.h | 117 + src/libs/3rdparty/karchive/src/kxzfilter.cpp | 279 ++ src/libs/3rdparty/karchive/src/kxzfilter.h | 67 + src/libs/3rdparty/karchive/src/kzip.cpp | 1477 ++++++++ src/libs/3rdparty/karchive/src/kzip.h | 178 + .../3rdparty/karchive/src/kzipfileentry.h | 79 + .../3rdparty/karchive/src/kzstdfilter.cpp | 134 + src/libs/3rdparty/karchive/src/kzstdfilter.h | 46 + .../3rdparty/karchive/src/loggingcategory.cpp | 3 + .../3rdparty/karchive/src/loggingcategory.h | 5 + 250 files changed, 63456 insertions(+), 1 deletion(-) create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/.gitattributes create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/.gitignore create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/CHANGES create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/README create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/README.COMPILATION.PROBLEMS create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/README.XML.STUFF create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/README.qtcreator create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/blocksort.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2recover.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib_private.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/compress.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/crctable.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/decompress.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/huffman.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/mk251.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/randtable.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/AUTHORS create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING.0BSD create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv2 create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv3 create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING.LGPLv2.1 create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/README create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/README.qtcreator create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/THANKS create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/TODO create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/mythread.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/sysdefs.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_config.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_gettext.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_integer.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_fw.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_width.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest.comments.txt create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/base.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/bcj.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/block.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/check.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/container.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/delta.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/filter.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/hardware.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index_hash.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/lzma12.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/stream_flags.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/version.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/vli.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_arm64.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_fast.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_small.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_be.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_le.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_tablegen.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_x86.S create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_fast.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_small.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_be.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_le.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_tablegen.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_x86.S create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_x86_clmul.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/sha256.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/auto_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_util.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_buffer_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_decoder_memusage.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder_memusage.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/file_info.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_cputhreads.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_physmem.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_hash.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/memcmplen.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder_mt.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder_mt.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/string_conversion.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_size.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_private.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma.pc.in create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_generic.map create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_linux.map create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash_table.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_mf.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_table.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_tablegen.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_presets.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_private.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_table.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_tablegen.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm64.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/armthumb.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/ia64.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/powerpc.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/riscv.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_private.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/sparc.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/x86.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/validate_map.sh create mode 100644 src/libs/3rdparty/karchive/AUTHORS create mode 100644 src/libs/3rdparty/karchive/CMakeLists.txt create mode 100644 src/libs/3rdparty/karchive/LICENSES/BSD-2-Clause.txt create mode 100644 src/libs/3rdparty/karchive/LICENSES/CC0-1.0.txt create mode 100644 src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt create mode 100644 src/libs/3rdparty/karchive/README.md create mode 100644 src/libs/3rdparty/karchive/src/k7zip.cpp create mode 100644 src/libs/3rdparty/karchive/src/k7zip.h create mode 100644 src/libs/3rdparty/karchive/src/kar.cpp create mode 100644 src/libs/3rdparty/karchive/src/kar.h create mode 100644 src/libs/3rdparty/karchive/src/karchive.cpp create mode 100644 src/libs/3rdparty/karchive/src/karchive.h create mode 100644 src/libs/3rdparty/karchive/src/karchive_export.h create mode 100644 src/libs/3rdparty/karchive/src/karchive_p.h create mode 100644 src/libs/3rdparty/karchive/src/karchivedirectory.h create mode 100644 src/libs/3rdparty/karchive/src/karchiveentry.h create mode 100644 src/libs/3rdparty/karchive/src/karchivefile.h create mode 100644 src/libs/3rdparty/karchive/src/kbzip2filter.cpp create mode 100644 src/libs/3rdparty/karchive/src/kbzip2filter.h create mode 100644 src/libs/3rdparty/karchive/src/kcompressiondevice.cpp create mode 100644 src/libs/3rdparty/karchive/src/kcompressiondevice.h create mode 100644 src/libs/3rdparty/karchive/src/kcompressiondevice_p.h create mode 100644 src/libs/3rdparty/karchive/src/kfilterbase.cpp create mode 100644 src/libs/3rdparty/karchive/src/kfilterbase.h create mode 100644 src/libs/3rdparty/karchive/src/kgzipfilter.cpp create mode 100644 src/libs/3rdparty/karchive/src/kgzipfilter.h create mode 100644 src/libs/3rdparty/karchive/src/klimitediodevice.cpp create mode 100644 src/libs/3rdparty/karchive/src/klimitediodevice_p.h create mode 100644 src/libs/3rdparty/karchive/src/knonefilter.cpp create mode 100644 src/libs/3rdparty/karchive/src/knonefilter.h create mode 100644 src/libs/3rdparty/karchive/src/krcc.cpp create mode 100644 src/libs/3rdparty/karchive/src/krcc.h create mode 100644 src/libs/3rdparty/karchive/src/ktar.cpp create mode 100644 src/libs/3rdparty/karchive/src/ktar.h create mode 100644 src/libs/3rdparty/karchive/src/kxzfilter.cpp create mode 100644 src/libs/3rdparty/karchive/src/kxzfilter.h create mode 100644 src/libs/3rdparty/karchive/src/kzip.cpp create mode 100644 src/libs/3rdparty/karchive/src/kzip.h create mode 100644 src/libs/3rdparty/karchive/src/kzipfileentry.h create mode 100644 src/libs/3rdparty/karchive/src/kzstdfilter.cpp create mode 100644 src/libs/3rdparty/karchive/src/kzstdfilter.h create mode 100644 src/libs/3rdparty/karchive/src/loggingcategory.cpp create mode 100644 src/libs/3rdparty/karchive/src/loggingcategory.h diff --git a/qt_attributions.json b/qt_attributions.json index 008ff353943..888782be407 100644 --- a/qt_attributions.json +++ b/qt_attributions.json @@ -40,6 +40,20 @@ "LicenseFile": "src/libs/3rdparty/syntax-highlighting/COPYING", "Copyright": "Author: Dominik Haumann (dhaumann@kde.org)." }, + { + "Id": "karchive", + "Name": "KArchive", + "QDocModule": "qtcreator", + "QtParts": ["tools"], + "QtUsage": "Used for reading and writing archives.", + "Path": "src/libs/3rdparty/karchive", + "Description": "KArchive provides classes for easy reading, creation and manipulation of 'archive' formats like ZIP and TAR.", + "Homepage": "https://invent.kde.org/frameworks/karchive", + "Version": "6.9.0", + "License": "GNU Lesser General Public License v2.1", + "LicenseFile": "src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt", + "Copyright": "Copyright The KDE project contributors" + }, { "Id": "ksyntaxhighlighting-bash", "Name": "KSyntaxHighlighting: bash.xml", @@ -637,7 +651,7 @@ "Name": "ZLib", "QDocModule": "qtcreator", "QtParts": ["tools"], - "QtUsage": "Used by ZipWriter/ZipReader to support compress and uncompress operations.", + "QtUsage": "Used by KArchive/ZipWriter/ZipReader to support compress and uncompress operations.", "Path": "src/libs/3rdparty/zlib", "Description": "Zlib is a lossless data-compression library.", "Homepage": "https://www.zlib.net", @@ -646,6 +660,34 @@ "LicenseFile": "src/libs/3rdparty/zlib/LICENSE", "Copyright": "Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler" }, + { + "Id": "bzip2", + "Name": "bzip2", + "QDocModule": "qtcreator", + "QtParts": ["tools"], + "QtUsage": "Used by KArchive to support compress and uncompress operations.", + "Path": "src/libs/3rdparty/karchive/3rdparty/bzip2", + "Description": "BZip2 is a lossless data-compression library.", + "Homepage": "https://sourceware.org/bzip2/", + "Version": "1.0.8", + "License": "bzip2 and libbzip2 License v1.0.6", + "LicenseFile": "src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE", + "Copyright": "copyright (C) 1996-2019 Julian R Seward." + }, + { + "Id": "xz", + "Name": "xz", + "QDocModule": "qtcreator", + "QtParts": ["tools"], + "QtUsage": "Used by KArchive to support compress and uncompress operations.", + "Path": "src/libs/3rdparty/karchive/3rdparty/xz", + "Description": "XZ is a lossless data-compression library.", + "Homepage": "https://tukaani.org/xz/", + "Version": "5.6.3", + "License": "BSD Zero Clause License (0BSD)", + "LicenseFile": "src/libs/3rdparty/karchive/3rdparty/xz/COPYING", + "Copyright": "Copyright (C) The XZ Utils authors and contributors" + }, { "Id": "tika-mimetypes", "Name": "Apache Tika MimeType Definitions", diff --git a/src/libs/3rdparty/CMakeLists.txt b/src/libs/3rdparty/CMakeLists.txt index 4a9ec9d4904..3c28a28afd1 100644 --- a/src/libs/3rdparty/CMakeLists.txt +++ b/src/libs/3rdparty/CMakeLists.txt @@ -5,6 +5,8 @@ add_subdirectory(libptyqt) add_subdirectory(qtkeychain) add_subdirectory(lua) add_subdirectory(sol2) +# Do not enable it yet, as the necessary changes are only introduced with the next patch. +#add_subdirectory(karchive) if(WIN32) add_subdirectory(winpty) diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitattributes b/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitattributes new file mode 100644 index 00000000000..f3af893933f --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitattributes @@ -0,0 +1 @@ +*.ref binary diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitignore b/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitignore new file mode 100644 index 00000000000..da23814dc7b --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitignore @@ -0,0 +1,9 @@ +*.o +*.obj +*.rb2 +*.tst +*.a +*.lib +*.exe +bzip2 +bzip2recover diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/CHANGES b/src/libs/3rdparty/karchive/3rdparty/bzip2/CHANGES new file mode 100644 index 00000000000..30afead2586 --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/CHANGES @@ -0,0 +1,356 @@ + ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.8 of 13 July 2019 + Copyright (C) 1996-2019 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ + + +0.9.0 +~~~~~ +First version. + + +0.9.0a +~~~~~~ +Removed 'ranlib' from Makefile, since most modern Unix-es +don't need it, or even know about it. + + +0.9.0b +~~~~~~ +Fixed a problem with error reporting in bzip2.c. This does not effect +the library in any way. Problem is: versions 0.9.0 and 0.9.0a (of the +program proper) compress and decompress correctly, but give misleading +error messages (internal panics) when an I/O error occurs, instead of +reporting the problem correctly. This shouldn't give any data loss +(as far as I can see), but is confusing. + +Made the inline declarations disappear for non-GCC compilers. + + +0.9.0c +~~~~~~ +Fixed some problems in the library pertaining to some boundary cases. +This makes the library behave more correctly in those situations. The +fixes apply only to features (calls and parameters) not used by +bzip2.c, so the non-fixedness of them in previous versions has no +effect on reliability of bzip2.c. + +In bzlib.c: + * made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. + +In compress.c: + * changed setting of nGroups in sendMTFValues() so as to + do a bit better on small files. This _does_ effect + bzip2.c. + + +0.9.5a +~~~~~~ +Major change: add a fallback sorting algorithm (blocksort.c) +to give reasonable behaviour even for very repetitive inputs. +Nuked --repetitive-best and --repetitive-fast since they are +no longer useful. + +Minor changes: mostly a whole bunch of small changes/ +bugfixes in the driver (bzip2.c). Changes pertaining to the +user interface are: + + allow decompression of symlink'd files to stdout + decompress/test files even without .bz2 extension + give more accurate error messages for I/O errors + when compressing/decompressing to stdout, don't catch control-C + read flags from BZIP2 and BZIP environment variables + decline to break hard links to a file unless forced with -f + allow -c flag even with no filenames + preserve file ownerships as far as possible + make -s -1 give the expected block size (100k) + add a flag -q --quiet to suppress nonessential warnings + stop decoding flags after --, so files beginning in - can be handled + resolved inconsistent naming: bzcat or bz2cat ? + bzip2 --help now returns 0 + +Programming-level changes are: + + fixed syntax error in GET_LL4 for Borland C++ 5.02 + let bzBuffToBuffDecompress return BZ_DATA_ERROR{_MAGIC} + fix overshoot of mode-string end in bzopen_or_bzdopen + wrapped bzlib.h in #ifdef __cplusplus ... extern "C" { ... } + close file handles under all error conditions + added minor mods so it compiles with DJGPP out of the box + fixed Makefile so it doesn't give problems with BSD make + fix uninitialised memory reads in dlltest.c + +0.9.5b +~~~~~~ +Open stdin/stdout in binary mode for DJGPP. + +0.9.5c +~~~~~~ +Changed BZ_N_OVERSHOOT to be ... + 2 instead of ... + 1. The + 1 +version could cause the sorted order to be wrong in some extremely +obscure cases. Also changed setting of quadrant in blocksort.c. + +0.9.5d +~~~~~~ +The only functional change is to make bzlibVersion() in the library +return the correct string. This has no effect whatsoever on the +functioning of the bzip2 program or library. Added a couple of casts +so the library compiles without warnings at level 3 in MS Visual +Studio 6.0. Included a Y2K statement in the file Y2K_INFO. All other +changes are minor documentation changes. + +1.0 +~~~ +Several minor bugfixes and enhancements: + +* Large file support. The library uses 64-bit counters to + count the volume of data passing through it. bzip2.c + is now compiled with -D_FILE_OFFSET_BITS=64 to get large + file support from the C library. -v correctly prints out + file sizes greater than 4 gigabytes. All these changes have + been made without assuming a 64-bit platform or a C compiler + which supports 64-bit ints, so, except for the C library + aspect, they are fully portable. + +* Decompression robustness. The library/program should be + robust to any corruption of compressed data, detecting and + handling _all_ corruption, instead of merely relying on + the CRCs. What this means is that the program should + never crash, given corrupted data, and the library should + always return BZ_DATA_ERROR. + +* Fixed an obscure race-condition bug only ever observed on + Solaris, in which, if you were very unlucky and issued + control-C at exactly the wrong time, both input and output + files would be deleted. + +* Don't run out of file handles on test/decompression when + large numbers of files have invalid magic numbers. + +* Avoid library namespace pollution. Prefix all exported + symbols with BZ2_. + +* Minor sorting enhancements from my DCC2000 paper. + +* Advance the version number to 1.0, so as to counteract the + (false-in-this-case) impression some people have that programs + with version numbers less than 1.0 are in some way, experimental, + pre-release versions. + +* Create an initial Makefile-libbz2_so to build a shared library. + Yes, I know I should really use libtool et al ... + +* Make the program exit with 2 instead of 0 when decompression + fails due to a bad magic number (ie, an invalid bzip2 header). + Also exit with 1 (as the manual claims :-) whenever a diagnostic + message would have been printed AND the corresponding operation + is aborted, for example + bzip2: Output file xx already exists. + When a diagnostic message is printed but the operation is not + aborted, for example + bzip2: Can't guess original name for wurble -- using wurble.out + then the exit value 0 is returned, unless some other problem is + also detected. + + I think it corresponds more closely to what the manual claims now. + + +1.0.1 +~~~~~ +* Modified dlltest.c so it uses the new BZ2_ naming scheme. +* Modified makefile-msc to fix minor build probs on Win2k. +* Updated README.COMPILATION.PROBLEMS. + +There are no functionality changes or bug fixes relative to version +1.0.0. This is just a documentation update + a fix for minor Win32 +build problems. For almost everyone, upgrading from 1.0.0 to 1.0.1 is +utterly pointless. Don't bother. + + +1.0.2 +~~~~~ +A bug fix release, addressing various minor issues which have appeared +in the 18 or so months since 1.0.1 was released. Most of the fixes +are to do with file-handling or documentation bugs. To the best of my +knowledge, there have been no data-loss-causing bugs reported in the +compression/decompression engine of 1.0.0 or 1.0.1. + +Note that this release does not improve the rather crude build system +for Unix platforms. The general plan here is to autoconfiscate/ +libtoolise 1.0.2 soon after release, and release the result as 1.1.0 +or perhaps 1.2.0. That, however, is still just a plan at this point. + +Here are the changes in 1.0.2. Bug-reporters and/or patch-senders in +parentheses. + +* Fix an infinite segfault loop in 1.0.1 when a directory is + encountered in -f (force) mode. + (Trond Eivind Glomsrod, Nicholas Nethercote, Volker Schmidt) + +* Avoid double fclose() of output file on certain I/O error paths. + (Solar Designer) + +* Don't fail with internal error 1007 when fed a long stream (> 48MB) + of byte 251. Also print useful message suggesting that 1007s may be + caused by bad memory. + (noticed by Juan Pedro Vallejo, fixed by me) + +* Fix uninitialised variable silly bug in demo prog dlltest.c. + (Jorj Bauer) + +* Remove 512-MB limitation on recovered file size for bzip2recover + on selected platforms which support 64-bit ints. At the moment + all GCC supported platforms, and Win32. + (me, Alson van der Meulen) + +* Hard-code header byte values, to give correct operation on platforms + using EBCDIC as their native character set (IBM's OS/390). + (Leland Lucius) + +* Copy file access times correctly. + (Marty Leisner) + +* Add distclean and check targets to Makefile. + (Michael Carmack) + +* Parameterise use of ar and ranlib in Makefile. Also add $(LDFLAGS). + (Rich Ireland, Bo Thorsen) + +* Pass -p (create parent dirs as needed) to mkdir during make install. + (Jeremy Fusco) + +* Dereference symlinks when copying file permissions in -f mode. + (Volker Schmidt) + +* Majorly simplify implementation of uInt64_qrm10. + (Bo Lindbergh) + +* Check the input file still exists before deleting the output one, + when aborting in cleanUpAndFail(). + (Joerg Prante, Robert Linden, Matthias Krings) + +Also a bunch of patches courtesy of Philippe Troin, the Debian maintainer +of bzip2: + +* Wrapper scripts (with manpages): bzdiff, bzgrep, bzmore. + +* Spelling changes and minor enhancements in bzip2.1. + +* Avoid race condition between creating the output file and setting its + interim permissions safely, by using fopen_output_safely(). + No changes to bzip2recover since there is no issue with file + permissions there. + +* do not print senseless report with -v when compressing an empty + file. + +* bzcat -f works on non-bzip2 files. + +* do not try to escape shell meta-characters on unix (the shell takes + care of these). + +* added --fast and --best aliases for -1 -9 for gzip compatibility. + + +1.0.3 (15 Feb 05) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.2. + +* Further robustification against corrupted compressed data. + There are currently no known bitstreams which can cause the + decompressor to crash, loop or access memory which does not + belong to it. If you are using bzip2 or the library to + decompress bitstreams from untrusted sources, an upgrade + to 1.0.3 is recommended. This fixes CAN-2005-1260. + +* The documentation has been converted to XML, from which html + and pdf can be derived. + +* Various minor bugs in the documentation have been fixed. + +* Fixes for various compilation warnings with newer versions of + gcc, and on 64-bit platforms. + +* The BZ_NO_STDIO cpp symbol was not properly observed in 1.0.2. + This has been fixed. + + +1.0.4 (20 Dec 06) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.3. + +* Fix file permissions race problem (CAN-2005-0953). + +* Avoid possible segfault in BZ2_bzclose. From Coverity's NetBSD + scan. + +* 'const'/prototype cleanups in the C code. + +* Change default install location to /usr/local, and handle multiple + 'make install's without error. + +* Sanitise file names more carefully in bzgrep. Fixes CAN-2005-0758 + to the extent that applies to bzgrep. + +* Use 'mktemp' rather than 'tempfile' in bzdiff. + +* Tighten up a couple of assertions in blocksort.c following automated + analysis. + +* Fix minor doc/comment bugs. + + +1.0.5 (10 Dec 07) +~~~~~~~~~~~~~~~~~ +Security fix only. Fixes CERT-FI 20469 as it applies to bzip2. + + +1.0.6 (6 Sept 10) +~~~~~~~~~~~~~~~~~ + +* Security fix for CVE-2010-0405. This was reported by Mikolaj + Izdebski. + +* Make the documentation build on Ubuntu 10.04 + +1.0.7 (27 Jun 19) +~~~~~~~~~~~~~~~~~ + +* Fix undefined behavior in the macros SET_BH, CLEAR_BH, & ISSET_BH + +* bzip2: Fix return value when combining --test,-t and -q. + +* bzip2recover: Fix buffer overflow for large argv[0] + +* bzip2recover: Fix use after free issue with outFile (CVE-2016-3189) + +* Make sure nSelectors is not out of range (CVE-2019-12900) + +1.0.8 (13 Jul 19) +~~~~~~~~~~~~~~~~~ + +* Accept as many selectors as the file format allows. + This relaxes the fix for CVE-2019-12900 from 1.0.7 + so that bzip2 allows decompression of bz2 files that + use (too) many selectors again. + +* Fix handling of large (> 4GB) files on Windows. + +* Cleanup of bzdiff and bzgrep scripts so they don't use + any bash extensions and handle multiple archives correctly. + +* There is now a bz2-files testsuite at + https://sourceware.org/git/bzip2-tests.git diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE b/src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE new file mode 100644 index 00000000000..81a37eab7a5 --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE @@ -0,0 +1,42 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2019 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@acm.org +bzip2/libbzip2 version 1.0.8 of 13 July 2019 + +-------------------------------------------------------------------------- diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/README b/src/libs/3rdparty/karchive/3rdparty/bzip2/README new file mode 100644 index 00000000000..b9c6099fd1c --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/README @@ -0,0 +1,196 @@ + +This is the README for bzip2/libzip2. +This version is fully compatible with the previous public releases. + +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.8 of 13 July 2019 +Copyright (C) 1996-2019 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in this file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +Complete documentation is available in Postscript form (manual.ps), +PDF (manual.pdf) or html (manual.html). A plain-text version of the +manual page is available as bzip2.txt. + + +HOW TO BUILD -- UNIX + +Type 'make'. This builds the library libbz2.a and then the programs +bzip2 and bzip2recover. Six self-tests are run. If the self-tests +complete ok, carry on to installation: + +To install in /usr/local/bin, /usr/local/lib, /usr/local/man and +/usr/local/include, type + + make install + +To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type + + make install PREFIX=/xxx/yyy + +If you are (justifiably) paranoid and want to see what 'make install' +is going to do, you can first do + + make -n install or + make -n install PREFIX=/xxx/yyy respectively. + +The -n instructs make to show the commands it would execute, but not +actually execute them. + + +HOW TO BUILD -- UNIX, shared library libbz2.so. + +Do 'make -f Makefile-libbz2_so'. This Makefile seems to work for +Linux-ELF (RedHat 7.2 on an x86 box), with gcc. I make no claims +that it works for any other platform, though I suspect it probably +will work for most platforms employing both ELF and gcc. + +bzip2-shared, a client of the shared library, is also built, but not +self-tested. So I suggest you also build using the normal Makefile, +since that conducts a self-test. A second reason to prefer the +version statically linked to the library is that, on x86 platforms, +building shared objects makes a valuable register (%ebx) unavailable +to gcc, resulting in a slowdown of 10%-20%, at least for bzip2. + +Important note for people upgrading .so's from 0.9.0/0.9.5 to version +1.0.X. All the functions in the library have been renamed, from (eg) +bzCompress to BZ2_bzCompress, to avoid namespace pollution. +Unfortunately this means that the libbz2.so created by +Makefile-libbz2_so will not work with any program which used an older +version of the library. I do encourage library clients to make the +effort to upgrade to use version 1.0, since it is both faster and more +robust than previous versions. + + +HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc. + +It's difficult for me to support compilation on all these platforms. +My approach is to collect binaries for these platforms, and put them +on the master web site (https://sourceware.org/bzip2/). Look there. However +(FWIW), bzip2-1.0.X is very standard ANSI C and should compile +unmodified with MS Visual C. If you have difficulties building, you +might want to read README.COMPILATION.PROBLEMS. + +At least using MS Visual C++ 6, you can build from the unmodified +sources by issuing, in a command shell: + + nmake -f makefile.msc + +(you may need to first run the MSVC-provided script VCVARS32.BAT + so as to set up paths to the MSVC tools correctly). + + +VALIDATION + +Correct operation, in the sense that a compressed file can always be +decompressed to reproduce the original, is obviously of paramount +importance. To validate bzip2, I used a modified version of Mark +Nelson's churn program. Churn is an automated test driver which +recursively traverses a directory structure, using bzip2 to compress +and then decompress each file it encounters, and checking that the +decompressed data is the same as the original. + + + +Please read and be aware of the following: + +WARNING: + + This program and library (attempts to) compress data by + performing several non-trivial transformations on it. + Unless you are 100% familiar with *all* the algorithms + contained herein, and with the consequences of modifying them, + you should NOT meddle with the compression or decompression + machinery. Incorrect changes can and very likely *will* + lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2/libbzip2 + has been carefully constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2/libbzip2 does not use any + patented algorithms. However, I do not have the resources + to carry out a patent search. Therefore I cannot give any + guarantee of the above statement. + + + +WHAT'S NEW IN 0.9.0 (as compared to 0.1pl2) ? + + * Approx 10% faster compression, 30% faster decompression + * -t (test mode) is a lot quicker + * Can decompress concatenated compressed files + * Programming interface, so programs can directly read/write .bz2 files + * Less restrictive (BSD-style) licensing + * Flag handling more compatible with GNU gzip + * Much more documentation, i.e., a proper user manual + * Hopefully, improved portability (at least of the library) + +WHAT'S NEW IN 0.9.5 ? + + * Compression speed is much less sensitive to the input + data than in previous versions. Specifically, the very + slow performance caused by repetitive data is fixed. + * Many small improvements in file and flag handling. + * A Y2K statement. + +WHAT'S NEW IN 1.0.x ? + + See the CHANGES file. + +I hope you find bzip2 useful. Feel free to contact the developers at + bzip2-devel@sourceware.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, +1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this +feedback. I thank you for your comments. + +bzip2's "home" is https://sourceware.org/bzip2/ + +Julian Seward +jseward@acm.org +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) +20 December 2006 (bzip2, version 1.0.4) +10 December 2007 (bzip2, version 1.0.5) + 6 Sept 2010 (bzip2, version 1.0.6) +27 June 2019 (bzip2, version 1.0.7) +13 July 2019 (bzip2, version 1.0.8) diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/README.COMPILATION.PROBLEMS b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.COMPILATION.PROBLEMS new file mode 100644 index 00000000000..fa317a50c81 --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.COMPILATION.PROBLEMS @@ -0,0 +1,58 @@ +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.8 of 13 July 2019 +Copyright (C) 1996-2019 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +bzip2 should compile without problems on the vast majority of +platforms. Using the supplied Makefile, I've built and tested it +myself for x86-linux and amd64-linux. With makefile.msc, Visual C++ +6.0 and nmake, you can build a native Win32 version too. Large file +support seems to work correctly on at least on amd64-linux. + +When I say "large file" I mean a file of size 2,147,483,648 (2^31) +bytes or above. Many older OSs can't handle files above this size, +but many newer ones can. Large files are pretty huge -- most files +you'll encounter are not Large Files. + +Early versions of bzip2 (0.1, 0.9.0, 0.9.5) compiled on a wide variety +of platforms without difficulty, and I hope this version will continue +in that tradition. However, in order to support large files, I've had +to include the define -D_FILE_OFFSET_BITS=64 in the Makefile. This +can cause problems. + +The technique of adding -D_FILE_OFFSET_BITS=64 to get large file +support is, as far as I know, the Recommended Way to get correct large +file support. For more details, see the Large File Support +Specification, published by the Large File Summit, at + + http://ftp.sas.com/standards/large.file + +As a general comment, if you get compilation errors which you think +are related to large file support, try removing the above define from +the Makefile, ie, delete the line + + BIGFILES=-D_FILE_OFFSET_BITS=64 + +from the Makefile, and do 'make clean ; make'. This will give you a +version of bzip2 without large file support, which, for most +applications, is probably not a problem. + +Alternatively, try some of the platform-specific hints listed below. + +You can use the spewG.c program to generate huge files to test bzip2's +large file support, if you are feeling paranoid. Be aware though that +any compilation problems which affect bzip2 will also affect spewG.c, +alas. + +AIX: I have reports that for large file support, you need to specify +-D_LARGE_FILES rather than -D_FILE_OFFSET_BITS=64. I have not tested +this myself. diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/README.XML.STUFF b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.XML.STUFF new file mode 100644 index 00000000000..1503476ebe6 --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.XML.STUFF @@ -0,0 +1,45 @@ + ---------------------------------------------------------------- + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.8 of 13 July 2019 + Copyright (C) 1996-2019 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ---------------------------------------------------------------- + +The script xmlproc.sh takes an xml file as input, +and processes it to create .pdf, .html or .ps output. +It uses format.pl, a perl script to format
     blocks nicely,
    + and add CDATA tags so writers do not have to use eg. < 
    +
    +The file "entities.xml" must be edited to reflect current
    +version, year, etc.
    +
    +
    +Usage:
    +
    +  ./xmlproc.sh -v manual.xml
    +  Validates an xml file to ensure no dtd-compliance errors
    +
    +  ./xmlproc.sh -html manual.xml
    +  Output: manual.html
    +
    +  ./xmlproc.sh -pdf manual.xml
    +  Output: manual.pdf
    +
    +  ./xmlproc.sh -ps manual.xml
    +  Output: manual.ps
    +
    +
    +Notum bene: 
    +- pdfxmltex barfs if given a filename with an underscore in it
    +
    +- xmltex won't work yet - there's a bug in passivetex
    +    which we are all waiting for Sebastian to fix.
    +  So we are going the xml -> pdf -> ps route for the time being,
    +    using pdfxmltex.
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/README.qtcreator b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.qtcreator
    new file mode 100644
    index 00000000000..b523a5153c5
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.qtcreator
    @@ -0,0 +1,4 @@
    +This directory contains a stripped down version of `git://sourceware.org/git/bzip2.git` with the following modifications:
    +
    +* Branch bzip2-1.0.8 was checked out (6a8690fc8d26c815e798c588f796eabe9d684cf0)
    +* All unnecessary files have been removed.
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/blocksort.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/blocksort.c
    new file mode 100644
    index 00000000000..92d81fe287e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/blocksort.c
    @@ -0,0 +1,1094 @@
    +
    +/*-------------------------------------------------------------*/
    +/*--- Block sorting machinery                               ---*/
    +/*---                                           blocksort.c ---*/
    +/*-------------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +
    +#include "bzlib_private.h"
    +
    +/*---------------------------------------------*/
    +/*--- Fallback O(N log(N)^2) sorting        ---*/
    +/*--- algorithm, for repetitive blocks      ---*/
    +/*---------------------------------------------*/
    +
    +/*---------------------------------------------*/
    +static 
    +__inline__
    +void fallbackSimpleSort ( UInt32* fmap, 
    +                          UInt32* eclass, 
    +                          Int32   lo, 
    +                          Int32   hi )
    +{
    +   Int32 i, j, tmp;
    +   UInt32 ec_tmp;
    +
    +   if (lo == hi) return;
    +
    +   if (hi - lo > 3) {
    +      for ( i = hi-4; i >= lo; i-- ) {
    +         tmp = fmap[i];
    +         ec_tmp = eclass[tmp];
    +         for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 )
    +            fmap[j-4] = fmap[j];
    +         fmap[j-4] = tmp;
    +      }
    +   }
    +
    +   for ( i = hi-1; i >= lo; i-- ) {
    +      tmp = fmap[i];
    +      ec_tmp = eclass[tmp];
    +      for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ )
    +         fmap[j-1] = fmap[j];
    +      fmap[j-1] = tmp;
    +   }
    +}
    +
    +
    +/*---------------------------------------------*/
    +#define fswap(zz1, zz2) \
    +   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
    +
    +#define fvswap(zzp1, zzp2, zzn)       \
    +{                                     \
    +   Int32 yyp1 = (zzp1);               \
    +   Int32 yyp2 = (zzp2);               \
    +   Int32 yyn  = (zzn);                \
    +   while (yyn > 0) {                  \
    +      fswap(fmap[yyp1], fmap[yyp2]);  \
    +      yyp1++; yyp2++; yyn--;          \
    +   }                                  \
    +}
    +
    +
    +#define fmin(a,b) ((a) < (b)) ? (a) : (b)
    +
    +#define fpush(lz,hz) { stackLo[sp] = lz; \
    +                       stackHi[sp] = hz; \
    +                       sp++; }
    +
    +#define fpop(lz,hz) { sp--;              \
    +                      lz = stackLo[sp];  \
    +                      hz = stackHi[sp]; }
    +
    +#define FALLBACK_QSORT_SMALL_THRESH 10
    +#define FALLBACK_QSORT_STACK_SIZE   100
    +
    +
    +static
    +void fallbackQSort3 ( UInt32* fmap, 
    +                      UInt32* eclass,
    +                      Int32   loSt, 
    +                      Int32   hiSt )
    +{
    +   Int32 unLo, unHi, ltLo, gtHi, n, m;
    +   Int32 sp, lo, hi;
    +   UInt32 med, r, r3;
    +   Int32 stackLo[FALLBACK_QSORT_STACK_SIZE];
    +   Int32 stackHi[FALLBACK_QSORT_STACK_SIZE];
    +
    +   r = 0;
    +
    +   sp = 0;
    +   fpush ( loSt, hiSt );
    +
    +   while (sp > 0) {
    +
    +      AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 );
    +
    +      fpop ( lo, hi );
    +      if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
    +         fallbackSimpleSort ( fmap, eclass, lo, hi );
    +         continue;
    +      }
    +
    +      /* Random partitioning.  Median of 3 sometimes fails to
    +         avoid bad cases.  Median of 9 seems to help but 
    +         looks rather expensive.  This too seems to work but
    +         is cheaper.  Guidance for the magic constants 
    +         7621 and 32768 is taken from Sedgewick's algorithms
    +         book, chapter 35.
    +      */
    +      r = ((r * 7621) + 1) % 32768;
    +      r3 = r % 3;
    +      if (r3 == 0) med = eclass[fmap[lo]]; else
    +      if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else
    +                   med = eclass[fmap[hi]];
    +
    +      unLo = ltLo = lo;
    +      unHi = gtHi = hi;
    +
    +      while (1) {
    +         while (1) {
    +            if (unLo > unHi) break;
    +            n = (Int32)eclass[fmap[unLo]] - (Int32)med;
    +            if (n == 0) { 
    +               fswap(fmap[unLo], fmap[ltLo]); 
    +               ltLo++; unLo++; 
    +               continue; 
    +            };
    +            if (n > 0) break;
    +            unLo++;
    +         }
    +         while (1) {
    +            if (unLo > unHi) break;
    +            n = (Int32)eclass[fmap[unHi]] - (Int32)med;
    +            if (n == 0) { 
    +               fswap(fmap[unHi], fmap[gtHi]); 
    +               gtHi--; unHi--; 
    +               continue; 
    +            };
    +            if (n < 0) break;
    +            unHi--;
    +         }
    +         if (unLo > unHi) break;
    +         fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
    +      }
    +
    +      AssertD ( unHi == unLo-1, "fallbackQSort3(2)" );
    +
    +      if (gtHi < ltLo) continue;
    +
    +      n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n);
    +      m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m);
    +
    +      n = lo + unLo - ltLo - 1;
    +      m = hi - (gtHi - unHi) + 1;
    +
    +      if (n - lo > hi - m) {
    +         fpush ( lo, n );
    +         fpush ( m, hi );
    +      } else {
    +         fpush ( m, hi );
    +         fpush ( lo, n );
    +      }
    +   }
    +}
    +
    +#undef fmin
    +#undef fpush
    +#undef fpop
    +#undef fswap
    +#undef fvswap
    +#undef FALLBACK_QSORT_SMALL_THRESH
    +#undef FALLBACK_QSORT_STACK_SIZE
    +
    +
    +/*---------------------------------------------*/
    +/* Pre:
    +      nblock > 0
    +      eclass exists for [0 .. nblock-1]
    +      ((UChar*)eclass) [0 .. nblock-1] holds block
    +      ptr exists for [0 .. nblock-1]
    +
    +   Post:
    +      ((UChar*)eclass) [0 .. nblock-1] holds block
    +      All other areas of eclass destroyed
    +      fmap [0 .. nblock-1] holds sorted order
    +      bhtab [ 0 .. 2+(nblock/32) ] destroyed
    +*/
    +
    +#define       SET_BH(zz)  bhtab[(zz) >> 5] |= ((UInt32)1 << ((zz) & 31))
    +#define     CLEAR_BH(zz)  bhtab[(zz) >> 5] &= ~((UInt32)1 << ((zz) & 31))
    +#define     ISSET_BH(zz)  (bhtab[(zz) >> 5] & ((UInt32)1 << ((zz) & 31)))
    +#define      WORD_BH(zz)  bhtab[(zz) >> 5]
    +#define UNALIGNED_BH(zz)  ((zz) & 0x01f)
    +
    +static
    +void fallbackSort ( UInt32* fmap, 
    +                    UInt32* eclass, 
    +                    UInt32* bhtab,
    +                    Int32   nblock,
    +                    Int32   verb )
    +{
    +   Int32 ftab[257];
    +   Int32 ftabCopy[256];
    +   Int32 H, i, j, k, l, r, cc, cc1;
    +   Int32 nNotDone;
    +   Int32 nBhtab;
    +   UChar* eclass8 = (UChar*)eclass;
    +
    +   /*--
    +      Initial 1-char radix sort to generate
    +      initial fmap and initial BH bits.
    +   --*/
    +   if (verb >= 4)
    +      VPrintf0 ( "        bucket sorting ...\n" );
    +   for (i = 0; i < 257;    i++) ftab[i] = 0;
    +   for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
    +   for (i = 0; i < 256;    i++) ftabCopy[i] = ftab[i];
    +   for (i = 1; i < 257;    i++) ftab[i] += ftab[i-1];
    +
    +   for (i = 0; i < nblock; i++) {
    +      j = eclass8[i];
    +      k = ftab[j] - 1;
    +      ftab[j] = k;
    +      fmap[k] = i;
    +   }
    +
    +   nBhtab = 2 + (nblock / 32);
    +   for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
    +   for (i = 0; i < 256; i++) SET_BH(ftab[i]);
    +
    +   /*--
    +      Inductively refine the buckets.  Kind-of an
    +      "exponential radix sort" (!), inspired by the
    +      Manber-Myers suffix array construction algorithm.
    +   --*/
    +
    +   /*-- set sentinel bits for block-end detection --*/
    +   for (i = 0; i < 32; i++) { 
    +      SET_BH(nblock + 2*i);
    +      CLEAR_BH(nblock + 2*i + 1);
    +   }
    +
    +   /*-- the log(N) loop --*/
    +   H = 1;
    +   while (1) {
    +
    +      if (verb >= 4) 
    +         VPrintf1 ( "        depth %6d has ", H );
    +
    +      j = 0;
    +      for (i = 0; i < nblock; i++) {
    +         if (ISSET_BH(i)) j = i;
    +         k = fmap[i] - H; if (k < 0) k += nblock;
    +         eclass[k] = j;
    +      }
    +
    +      nNotDone = 0;
    +      r = -1;
    +      while (1) {
    +
    +	 /*-- find the next non-singleton bucket --*/
    +         k = r + 1;
    +         while (ISSET_BH(k) && UNALIGNED_BH(k)) k++;
    +         if (ISSET_BH(k)) {
    +            while (WORD_BH(k) == 0xffffffff) k += 32;
    +            while (ISSET_BH(k)) k++;
    +         }
    +         l = k - 1;
    +         if (l >= nblock) break;
    +         while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++;
    +         if (!ISSET_BH(k)) {
    +            while (WORD_BH(k) == 0x00000000) k += 32;
    +            while (!ISSET_BH(k)) k++;
    +         }
    +         r = k - 1;
    +         if (r >= nblock) break;
    +
    +         /*-- now [l, r] bracket current bucket --*/
    +         if (r > l) {
    +            nNotDone += (r - l + 1);
    +            fallbackQSort3 ( fmap, eclass, l, r );
    +
    +            /*-- scan bucket and generate header bits-- */
    +            cc = -1;
    +            for (i = l; i <= r; i++) {
    +               cc1 = eclass[fmap[i]];
    +               if (cc != cc1) { SET_BH(i); cc = cc1; };
    +            }
    +         }
    +      }
    +
    +      if (verb >= 4) 
    +         VPrintf1 ( "%6d unresolved strings\n", nNotDone );
    +
    +      H *= 2;
    +      if (H > nblock || nNotDone == 0) break;
    +   }
    +
    +   /*-- 
    +      Reconstruct the original block in
    +      eclass8 [0 .. nblock-1], since the
    +      previous phase destroyed it.
    +   --*/
    +   if (verb >= 4)
    +      VPrintf0 ( "        reconstructing block ...\n" );
    +   j = 0;
    +   for (i = 0; i < nblock; i++) {
    +      while (ftabCopy[j] == 0) j++;
    +      ftabCopy[j]--;
    +      eclass8[fmap[i]] = (UChar)j;
    +   }
    +   AssertH ( j < 256, 1005 );
    +}
    +
    +#undef       SET_BH
    +#undef     CLEAR_BH
    +#undef     ISSET_BH
    +#undef      WORD_BH
    +#undef UNALIGNED_BH
    +
    +
    +/*---------------------------------------------*/
    +/*--- The main, O(N^2 log(N)) sorting       ---*/
    +/*--- algorithm.  Faster for "normal"       ---*/
    +/*--- non-repetitive blocks.                ---*/
    +/*---------------------------------------------*/
    +
    +/*---------------------------------------------*/
    +static
    +__inline__
    +Bool mainGtU ( UInt32  i1, 
    +               UInt32  i2,
    +               UChar*  block, 
    +               UInt16* quadrant,
    +               UInt32  nblock,
    +               Int32*  budget )
    +{
    +   Int32  k;
    +   UChar  c1, c2;
    +   UInt16 s1, s2;
    +
    +   AssertD ( i1 != i2, "mainGtU" );
    +   /* 1 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 2 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 3 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 4 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 5 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 6 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 7 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 8 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 9 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 10 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 11 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +   /* 12 */
    +   c1 = block[i1]; c2 = block[i2];
    +   if (c1 != c2) return (c1 > c2);
    +   i1++; i2++;
    +
    +   k = nblock + 8;
    +
    +   do {
    +      /* 1 */
    +      c1 = block[i1]; c2 = block[i2];
    +      if (c1 != c2) return (c1 > c2);
    +      s1 = quadrant[i1]; s2 = quadrant[i2];
    +      if (s1 != s2) return (s1 > s2);
    +      i1++; i2++;
    +      /* 2 */
    +      c1 = block[i1]; c2 = block[i2];
    +      if (c1 != c2) return (c1 > c2);
    +      s1 = quadrant[i1]; s2 = quadrant[i2];
    +      if (s1 != s2) return (s1 > s2);
    +      i1++; i2++;
    +      /* 3 */
    +      c1 = block[i1]; c2 = block[i2];
    +      if (c1 != c2) return (c1 > c2);
    +      s1 = quadrant[i1]; s2 = quadrant[i2];
    +      if (s1 != s2) return (s1 > s2);
    +      i1++; i2++;
    +      /* 4 */
    +      c1 = block[i1]; c2 = block[i2];
    +      if (c1 != c2) return (c1 > c2);
    +      s1 = quadrant[i1]; s2 = quadrant[i2];
    +      if (s1 != s2) return (s1 > s2);
    +      i1++; i2++;
    +      /* 5 */
    +      c1 = block[i1]; c2 = block[i2];
    +      if (c1 != c2) return (c1 > c2);
    +      s1 = quadrant[i1]; s2 = quadrant[i2];
    +      if (s1 != s2) return (s1 > s2);
    +      i1++; i2++;
    +      /* 6 */
    +      c1 = block[i1]; c2 = block[i2];
    +      if (c1 != c2) return (c1 > c2);
    +      s1 = quadrant[i1]; s2 = quadrant[i2];
    +      if (s1 != s2) return (s1 > s2);
    +      i1++; i2++;
    +      /* 7 */
    +      c1 = block[i1]; c2 = block[i2];
    +      if (c1 != c2) return (c1 > c2);
    +      s1 = quadrant[i1]; s2 = quadrant[i2];
    +      if (s1 != s2) return (s1 > s2);
    +      i1++; i2++;
    +      /* 8 */
    +      c1 = block[i1]; c2 = block[i2];
    +      if (c1 != c2) return (c1 > c2);
    +      s1 = quadrant[i1]; s2 = quadrant[i2];
    +      if (s1 != s2) return (s1 > s2);
    +      i1++; i2++;
    +
    +      if (i1 >= nblock) i1 -= nblock;
    +      if (i2 >= nblock) i2 -= nblock;
    +
    +      k -= 8;
    +      (*budget)--;
    +   }
    +      while (k >= 0);
    +
    +   return False;
    +}
    +
    +
    +/*---------------------------------------------*/
    +/*--
    +   Knuth's increments seem to work better
    +   than Incerpi-Sedgewick here.  Possibly
    +   because the number of elems to sort is
    +   usually small, typically <= 20.
    +--*/
    +static
    +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
    +                   9841, 29524, 88573, 265720,
    +                   797161, 2391484 };
    +
    +static
    +void mainSimpleSort ( UInt32* ptr,
    +                      UChar*  block,
    +                      UInt16* quadrant,
    +                      Int32   nblock,
    +                      Int32   lo, 
    +                      Int32   hi, 
    +                      Int32   d,
    +                      Int32*  budget )
    +{
    +   Int32 i, j, h, bigN, hp;
    +   UInt32 v;
    +
    +   bigN = hi - lo + 1;
    +   if (bigN < 2) return;
    +
    +   hp = 0;
    +   while (incs[hp] < bigN) hp++;
    +   hp--;
    +
    +   for (; hp >= 0; hp--) {
    +      h = incs[hp];
    +
    +      i = lo + h;
    +      while (True) {
    +
    +         /*-- copy 1 --*/
    +         if (i > hi) break;
    +         v = ptr[i];
    +         j = i;
    +         while ( mainGtU ( 
    +                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
    +                 ) ) {
    +            ptr[j] = ptr[j-h];
    +            j = j - h;
    +            if (j <= (lo + h - 1)) break;
    +         }
    +         ptr[j] = v;
    +         i++;
    +
    +         /*-- copy 2 --*/
    +         if (i > hi) break;
    +         v = ptr[i];
    +         j = i;
    +         while ( mainGtU ( 
    +                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
    +                 ) ) {
    +            ptr[j] = ptr[j-h];
    +            j = j - h;
    +            if (j <= (lo + h - 1)) break;
    +         }
    +         ptr[j] = v;
    +         i++;
    +
    +         /*-- copy 3 --*/
    +         if (i > hi) break;
    +         v = ptr[i];
    +         j = i;
    +         while ( mainGtU ( 
    +                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
    +                 ) ) {
    +            ptr[j] = ptr[j-h];
    +            j = j - h;
    +            if (j <= (lo + h - 1)) break;
    +         }
    +         ptr[j] = v;
    +         i++;
    +
    +         if (*budget < 0) return;
    +      }
    +   }
    +}
    +
    +
    +/*---------------------------------------------*/
    +/*--
    +   The following is an implementation of
    +   an elegant 3-way quicksort for strings,
    +   described in a paper "Fast Algorithms for
    +   Sorting and Searching Strings", by Robert
    +   Sedgewick and Jon L. Bentley.
    +--*/
    +
    +#define mswap(zz1, zz2) \
    +   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
    +
    +#define mvswap(zzp1, zzp2, zzn)       \
    +{                                     \
    +   Int32 yyp1 = (zzp1);               \
    +   Int32 yyp2 = (zzp2);               \
    +   Int32 yyn  = (zzn);                \
    +   while (yyn > 0) {                  \
    +      mswap(ptr[yyp1], ptr[yyp2]);    \
    +      yyp1++; yyp2++; yyn--;          \
    +   }                                  \
    +}
    +
    +static 
    +__inline__
    +UChar mmed3 ( UChar a, UChar b, UChar c )
    +{
    +   UChar t;
    +   if (a > b) { t = a; a = b; b = t; };
    +   if (b > c) { 
    +      b = c;
    +      if (a > b) b = a;
    +   }
    +   return b;
    +}
    +
    +#define mmin(a,b) ((a) < (b)) ? (a) : (b)
    +
    +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \
    +                          stackHi[sp] = hz; \
    +                          stackD [sp] = dz; \
    +                          sp++; }
    +
    +#define mpop(lz,hz,dz) { sp--;             \
    +                         lz = stackLo[sp]; \
    +                         hz = stackHi[sp]; \
    +                         dz = stackD [sp]; }
    +
    +
    +#define mnextsize(az) (nextHi[az]-nextLo[az])
    +
    +#define mnextswap(az,bz)                                        \
    +   { Int32 tz;                                                  \
    +     tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
    +     tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
    +     tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; }
    +
    +
    +#define MAIN_QSORT_SMALL_THRESH 20
    +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
    +#define MAIN_QSORT_STACK_SIZE 100
    +
    +static
    +void mainQSort3 ( UInt32* ptr,
    +                  UChar*  block,
    +                  UInt16* quadrant,
    +                  Int32   nblock,
    +                  Int32   loSt, 
    +                  Int32   hiSt, 
    +                  Int32   dSt,
    +                  Int32*  budget )
    +{
    +   Int32 unLo, unHi, ltLo, gtHi, n, m, med;
    +   Int32 sp, lo, hi, d;
    +
    +   Int32 stackLo[MAIN_QSORT_STACK_SIZE];
    +   Int32 stackHi[MAIN_QSORT_STACK_SIZE];
    +   Int32 stackD [MAIN_QSORT_STACK_SIZE];
    +
    +   Int32 nextLo[3];
    +   Int32 nextHi[3];
    +   Int32 nextD [3];
    +
    +   sp = 0;
    +   mpush ( loSt, hiSt, dSt );
    +
    +   while (sp > 0) {
    +
    +      AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 );
    +
    +      mpop ( lo, hi, d );
    +      if (hi - lo < MAIN_QSORT_SMALL_THRESH || 
    +          d > MAIN_QSORT_DEPTH_THRESH) {
    +         mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget );
    +         if (*budget < 0) return;
    +         continue;
    +      }
    +
    +      med = (Int32) 
    +            mmed3 ( block[ptr[ lo         ]+d],
    +                    block[ptr[ hi         ]+d],
    +                    block[ptr[ (lo+hi)>>1 ]+d] );
    +
    +      unLo = ltLo = lo;
    +      unHi = gtHi = hi;
    +
    +      while (True) {
    +         while (True) {
    +            if (unLo > unHi) break;
    +            n = ((Int32)block[ptr[unLo]+d]) - med;
    +            if (n == 0) { 
    +               mswap(ptr[unLo], ptr[ltLo]); 
    +               ltLo++; unLo++; continue; 
    +            };
    +            if (n >  0) break;
    +            unLo++;
    +         }
    +         while (True) {
    +            if (unLo > unHi) break;
    +            n = ((Int32)block[ptr[unHi]+d]) - med;
    +            if (n == 0) { 
    +               mswap(ptr[unHi], ptr[gtHi]); 
    +               gtHi--; unHi--; continue; 
    +            };
    +            if (n <  0) break;
    +            unHi--;
    +         }
    +         if (unLo > unHi) break;
    +         mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--;
    +      }
    +
    +      AssertD ( unHi == unLo-1, "mainQSort3(2)" );
    +
    +      if (gtHi < ltLo) {
    +         mpush(lo, hi, d+1 );
    +         continue;
    +      }
    +
    +      n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n);
    +      m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m);
    +
    +      n = lo + unLo - ltLo - 1;
    +      m = hi - (gtHi - unHi) + 1;
    +
    +      nextLo[0] = lo;  nextHi[0] = n;   nextD[0] = d;
    +      nextLo[1] = m;   nextHi[1] = hi;  nextD[1] = d;
    +      nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
    +
    +      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
    +      if (mnextsize(1) < mnextsize(2)) mnextswap(1,2);
    +      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
    +
    +      AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" );
    +      AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" );
    +
    +      mpush (nextLo[0], nextHi[0], nextD[0]);
    +      mpush (nextLo[1], nextHi[1], nextD[1]);
    +      mpush (nextLo[2], nextHi[2], nextD[2]);
    +   }
    +}
    +
    +#undef mswap
    +#undef mvswap
    +#undef mpush
    +#undef mpop
    +#undef mmin
    +#undef mnextsize
    +#undef mnextswap
    +#undef MAIN_QSORT_SMALL_THRESH
    +#undef MAIN_QSORT_DEPTH_THRESH
    +#undef MAIN_QSORT_STACK_SIZE
    +
    +
    +/*---------------------------------------------*/
    +/* Pre:
    +      nblock > N_OVERSHOOT
    +      block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
    +      ((UChar*)block32) [0 .. nblock-1] holds block
    +      ptr exists for [0 .. nblock-1]
    +
    +   Post:
    +      ((UChar*)block32) [0 .. nblock-1] holds block
    +      All other areas of block32 destroyed
    +      ftab [0 .. 65536 ] destroyed
    +      ptr [0 .. nblock-1] holds sorted order
    +      if (*budget < 0), sorting was abandoned
    +*/
    +
    +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
    +#define SETMASK (1 << 21)
    +#define CLEARMASK (~(SETMASK))
    +
    +static
    +void mainSort ( UInt32* ptr, 
    +                UChar*  block,
    +                UInt16* quadrant, 
    +                UInt32* ftab,
    +                Int32   nblock,
    +                Int32   verb,
    +                Int32*  budget )
    +{
    +   Int32  i, j, k, ss, sb;
    +   Int32  runningOrder[256];
    +   Bool   bigDone[256];
    +   Int32  copyStart[256];
    +   Int32  copyEnd  [256];
    +   UChar  c1;
    +   Int32  numQSorted;
    +   UInt16 s;
    +   if (verb >= 4) VPrintf0 ( "        main sort initialise ...\n" );
    +
    +   /*-- set up the 2-byte frequency table --*/
    +   for (i = 65536; i >= 0; i--) ftab[i] = 0;
    +
    +   j = block[0] << 8;
    +   i = nblock-1;
    +   for (; i >= 3; i -= 4) {
    +      quadrant[i] = 0;
    +      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
    +      ftab[j]++;
    +      quadrant[i-1] = 0;
    +      j = (j >> 8) | ( ((UInt16)block[i-1]) << 8);
    +      ftab[j]++;
    +      quadrant[i-2] = 0;
    +      j = (j >> 8) | ( ((UInt16)block[i-2]) << 8);
    +      ftab[j]++;
    +      quadrant[i-3] = 0;
    +      j = (j >> 8) | ( ((UInt16)block[i-3]) << 8);
    +      ftab[j]++;
    +   }
    +   for (; i >= 0; i--) {
    +      quadrant[i] = 0;
    +      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
    +      ftab[j]++;
    +   }
    +
    +   /*-- (emphasises close relationship of block & quadrant) --*/
    +   for (i = 0; i < BZ_N_OVERSHOOT; i++) {
    +      block   [nblock+i] = block[i];
    +      quadrant[nblock+i] = 0;
    +   }
    +
    +   if (verb >= 4) VPrintf0 ( "        bucket sorting ...\n" );
    +
    +   /*-- Complete the initial radix sort --*/
    +   for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1];
    +
    +   s = block[0] << 8;
    +   i = nblock-1;
    +   for (; i >= 3; i -= 4) {
    +      s = (s >> 8) | (block[i] << 8);
    +      j = ftab[s] -1;
    +      ftab[s] = j;
    +      ptr[j] = i;
    +      s = (s >> 8) | (block[i-1] << 8);
    +      j = ftab[s] -1;
    +      ftab[s] = j;
    +      ptr[j] = i-1;
    +      s = (s >> 8) | (block[i-2] << 8);
    +      j = ftab[s] -1;
    +      ftab[s] = j;
    +      ptr[j] = i-2;
    +      s = (s >> 8) | (block[i-3] << 8);
    +      j = ftab[s] -1;
    +      ftab[s] = j;
    +      ptr[j] = i-3;
    +   }
    +   for (; i >= 0; i--) {
    +      s = (s >> 8) | (block[i] << 8);
    +      j = ftab[s] -1;
    +      ftab[s] = j;
    +      ptr[j] = i;
    +   }
    +
    +   /*--
    +      Now ftab contains the first loc of every small bucket.
    +      Calculate the running order, from smallest to largest
    +      big bucket.
    +   --*/
    +   for (i = 0; i <= 255; i++) {
    +      bigDone     [i] = False;
    +      runningOrder[i] = i;
    +   }
    +
    +   {
    +      Int32 vv;
    +      Int32 h = 1;
    +      do h = 3 * h + 1; while (h <= 256);
    +      do {
    +         h = h / 3;
    +         for (i = h; i <= 255; i++) {
    +            vv = runningOrder[i];
    +            j = i;
    +            while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) {
    +               runningOrder[j] = runningOrder[j-h];
    +               j = j - h;
    +               if (j <= (h - 1)) goto zero;
    +            }
    +            zero:
    +            runningOrder[j] = vv;
    +         }
    +      } while (h != 1);
    +   }
    +
    +   /*--
    +      The main sorting loop.
    +   --*/
    +
    +   numQSorted = 0;
    +
    +   for (i = 0; i <= 255; i++) {
    +
    +      /*--
    +         Process big buckets, starting with the least full.
    +         Basically this is a 3-step process in which we call
    +         mainQSort3 to sort the small buckets [ss, j], but
    +         also make a big effort to avoid the calls if we can.
    +      --*/
    +      ss = runningOrder[i];
    +
    +      /*--
    +         Step 1:
    +         Complete the big bucket [ss] by quicksorting
    +         any unsorted small buckets [ss, j], for j != ss.  
    +         Hopefully previous pointer-scanning phases have already
    +         completed many of the small buckets [ss, j], so
    +         we don't have to sort them at all.
    +      --*/
    +      for (j = 0; j <= 255; j++) {
    +         if (j != ss) {
    +            sb = (ss << 8) + j;
    +            if ( ! (ftab[sb] & SETMASK) ) {
    +               Int32 lo = ftab[sb]   & CLEARMASK;
    +               Int32 hi = (ftab[sb+1] & CLEARMASK) - 1;
    +               if (hi > lo) {
    +                  if (verb >= 4)
    +                     VPrintf4 ( "        qsort [0x%x, 0x%x]   "
    +                                "done %d   this %d\n",
    +                                ss, j, numQSorted, hi - lo + 1 );
    +                  mainQSort3 ( 
    +                     ptr, block, quadrant, nblock, 
    +                     lo, hi, BZ_N_RADIX, budget 
    +                  );   
    +                  numQSorted += (hi - lo + 1);
    +                  if (*budget < 0) return;
    +               }
    +            }
    +            ftab[sb] |= SETMASK;
    +         }
    +      }
    +
    +      AssertH ( !bigDone[ss], 1006 );
    +
    +      /*--
    +         Step 2:
    +         Now scan this big bucket [ss] so as to synthesise the
    +         sorted order for small buckets [t, ss] for all t,
    +         including, magically, the bucket [ss,ss] too.
    +         This will avoid doing Real Work in subsequent Step 1's.
    +      --*/
    +      {
    +         for (j = 0; j <= 255; j++) {
    +            copyStart[j] =  ftab[(j << 8) + ss]     & CLEARMASK;
    +            copyEnd  [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
    +         }
    +         for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
    +            k = ptr[j]-1; if (k < 0) k += nblock;
    +            c1 = block[k];
    +            if (!bigDone[c1])
    +               ptr[ copyStart[c1]++ ] = k;
    +         }
    +         for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
    +            k = ptr[j]-1; if (k < 0) k += nblock;
    +            c1 = block[k];
    +            if (!bigDone[c1]) 
    +               ptr[ copyEnd[c1]-- ] = k;
    +         }
    +      }
    +
    +      AssertH ( (copyStart[ss]-1 == copyEnd[ss])
    +                || 
    +                /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
    +                   Necessity for this case is demonstrated by compressing 
    +                   a sequence of approximately 48.5 million of character 
    +                   251; 1.0.0/1.0.1 will then die here. */
    +                (copyStart[ss] == 0 && copyEnd[ss] == nblock-1),
    +                1007 )
    +
    +      for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK;
    +
    +      /*--
    +         Step 3:
    +         The [ss] big bucket is now done.  Record this fact,
    +         and update the quadrant descriptors.  Remember to
    +         update quadrants in the overshoot area too, if
    +         necessary.  The "if (i < 255)" test merely skips
    +         this updating for the last bucket processed, since
    +         updating for the last bucket is pointless.
    +
    +         The quadrant array provides a way to incrementally
    +         cache sort orderings, as they appear, so as to 
    +         make subsequent comparisons in fullGtU() complete
    +         faster.  For repetitive blocks this makes a big
    +         difference (but not big enough to be able to avoid
    +         the fallback sorting mechanism, exponential radix sort).
    +
    +         The precise meaning is: at all times:
    +
    +            for 0 <= i < nblock and 0 <= j <= nblock
    +
    +            if block[i] != block[j], 
    +
    +               then the relative values of quadrant[i] and 
    +                    quadrant[j] are meaningless.
    +
    +               else {
    +                  if quadrant[i] < quadrant[j]
    +                     then the string starting at i lexicographically
    +                     precedes the string starting at j
    +
    +                  else if quadrant[i] > quadrant[j]
    +                     then the string starting at j lexicographically
    +                     precedes the string starting at i
    +
    +                  else
    +                     the relative ordering of the strings starting
    +                     at i and j has not yet been determined.
    +               }
    +      --*/
    +      bigDone[ss] = True;
    +
    +      if (i < 255) {
    +         Int32 bbStart  = ftab[ss << 8] & CLEARMASK;
    +         Int32 bbSize   = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
    +         Int32 shifts   = 0;
    +
    +         while ((bbSize >> shifts) > 65534) shifts++;
    +
    +         for (j = bbSize-1; j >= 0; j--) {
    +            Int32 a2update     = ptr[bbStart + j];
    +            UInt16 qVal        = (UInt16)(j >> shifts);
    +            quadrant[a2update] = qVal;
    +            if (a2update < BZ_N_OVERSHOOT)
    +               quadrant[a2update + nblock] = qVal;
    +         }
    +         AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 );
    +      }
    +
    +   }
    +
    +   if (verb >= 4)
    +      VPrintf3 ( "        %d pointers, %d sorted, %d scanned\n",
    +                 nblock, numQSorted, nblock - numQSorted );
    +}
    +
    +#undef BIGFREQ
    +#undef SETMASK
    +#undef CLEARMASK
    +
    +
    +/*---------------------------------------------*/
    +/* Pre:
    +      nblock > 0
    +      arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
    +      ((UChar*)arr2)  [0 .. nblock-1] holds block
    +      arr1 exists for [0 .. nblock-1]
    +
    +   Post:
    +      ((UChar*)arr2) [0 .. nblock-1] holds block
    +      All other areas of block destroyed
    +      ftab [ 0 .. 65536 ] destroyed
    +      arr1 [0 .. nblock-1] holds sorted order
    +*/
    +void BZ2_blockSort ( EState* s )
    +{
    +   UInt32* ptr    = s->ptr; 
    +   UChar*  block  = s->block;
    +   UInt32* ftab   = s->ftab;
    +   Int32   nblock = s->nblock;
    +   Int32   verb   = s->verbosity;
    +   Int32   wfact  = s->workFactor;
    +   UInt16* quadrant;
    +   Int32   budget;
    +   Int32   budgetInit;
    +   Int32   i;
    +
    +   if (nblock < 10000) {
    +      fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
    +   } else {
    +      /* Calculate the location for quadrant, remembering to get
    +         the alignment right.  Assumes that &(block[0]) is at least
    +         2-byte aligned -- this should be ok since block is really
    +         the first section of arr2.
    +      */
    +      i = nblock+BZ_N_OVERSHOOT;
    +      if (i & 1) i++;
    +      quadrant = (UInt16*)(&(block[i]));
    +
    +      /* (wfact-1) / 3 puts the default-factor-30
    +         transition point at very roughly the same place as 
    +         with v0.1 and v0.9.0.  
    +         Not that it particularly matters any more, since the
    +         resulting compressed stream is now the same regardless
    +         of whether or not we use the main sort or fallback sort.
    +      */
    +      if (wfact < 1  ) wfact = 1;
    +      if (wfact > 100) wfact = 100;
    +      budgetInit = nblock * ((wfact-1) / 3);
    +      budget = budgetInit;
    +
    +      mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget );
    +      if (verb >= 3) 
    +         VPrintf3 ( "      %d work, %d block, ratio %5.2f\n",
    +                    budgetInit - budget,
    +                    nblock, 
    +                    (float)(budgetInit - budget) /
    +                    (float)(nblock==0 ? 1 : nblock) ); 
    +      if (budget < 0) {
    +         if (verb >= 2) 
    +            VPrintf0 ( "    too repetitive; using fallback"
    +                       " sorting algorithm\n" );
    +         fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
    +      }
    +   }
    +
    +   s->origPtr = -1;
    +   for (i = 0; i < s->nblock; i++)
    +      if (ptr[i] == 0)
    +         { s->origPtr = i; break; };
    +
    +   AssertH( s->origPtr != -1, 1003 );
    +}
    +
    +
    +/*-------------------------------------------------------------*/
    +/*--- end                                       blocksort.c ---*/
    +/*-------------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2.c
    new file mode 100644
    index 00000000000..d95d280619a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2.c
    @@ -0,0 +1,2036 @@
    +
    +/*-----------------------------------------------------------*/
    +/*--- A block-sorting, lossless compressor        bzip2.c ---*/
    +/*-----------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +
    +/* Place a 1 beside your platform, and 0 elsewhere.
    +   Generic 32-bit Unix.
    +   Also works on 64-bit Unix boxes.
    +   This is the default.
    +*/
    +#define BZ_UNIX      1
    +
    +/*--
    +  Win32, as seen by Jacob Navia's excellent
    +  port of (Chris Fraser & David Hanson)'s excellent
    +  lcc compiler.  Or with MS Visual C.
    +  This is selected automatically if compiled by a compiler which
    +  defines _WIN32, not including the Cygwin GCC.
    +--*/
    +#define BZ_LCCWIN32  0
    +
    +#if defined(_WIN32) && !defined(__CYGWIN__)
    +#undef  BZ_LCCWIN32
    +#define BZ_LCCWIN32 1
    +#undef  BZ_UNIX
    +#define BZ_UNIX 0
    +#endif
    +
    +
    +/*---------------------------------------------*/
    +/*--
    +  Some stuff for all platforms.
    +--*/
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include "bzlib.h"
    +
    +#define ERROR_IF_EOF(i)       { if ((i) == EOF)  ioError(); }
    +#define ERROR_IF_NOT_ZERO(i)  { if ((i) != 0)    ioError(); }
    +#define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
    +
    +
    +/*---------------------------------------------*/
    +/*--
    +   Platform-specific stuff.
    +--*/
    +
    +#if BZ_UNIX
    +#   include 
    +#   include 
    +#   include 
    +#   include 
    +#   include 
    +#   include 
    +
    +#   define PATH_SEP    '/'
    +#   define MY_LSTAT    lstat
    +#   define MY_STAT     stat
    +#   define MY_S_ISREG  S_ISREG
    +#   define MY_S_ISDIR  S_ISDIR
    +
    +#   define APPEND_FILESPEC(root, name) \
    +      root=snocString((root), (name))
    +
    +#   define APPEND_FLAG(root, name) \
    +      root=snocString((root), (name))
    +
    +#   define SET_BINARY_MODE(fd) /**/
    +
    +#   ifdef __GNUC__
    +#      define NORETURN __attribute__ ((noreturn))
    +#   else
    +#      define NORETURN /**/
    +#   endif
    +
    +#   ifdef __DJGPP__
    +#     include 
    +#     include 
    +#     undef MY_LSTAT
    +#     undef MY_STAT
    +#     define MY_LSTAT stat
    +#     define MY_STAT stat
    +#     undef SET_BINARY_MODE
    +#     define SET_BINARY_MODE(fd)                        \
    +        do {                                            \
    +           int retVal = setmode ( fileno ( fd ),        \
    +                                  O_BINARY );           \
    +           ERROR_IF_MINUS_ONE ( retVal );               \
    +        } while ( 0 )
    +#   endif
    +
    +#   ifdef __CYGWIN__
    +#     include 
    +#     include 
    +#     undef SET_BINARY_MODE
    +#     define SET_BINARY_MODE(fd)                        \
    +        do {                                            \
    +           int retVal = setmode ( fileno ( fd ),        \
    +                                  O_BINARY );           \
    +           ERROR_IF_MINUS_ONE ( retVal );               \
    +        } while ( 0 )
    +#   endif
    +#endif /* BZ_UNIX */
    +
    +
    +
    +#if BZ_LCCWIN32
    +#   include 
    +#   include 
    +#   include 
    +
    +#   define NORETURN       /**/
    +#   define PATH_SEP       '\\'
    +#   define MY_LSTAT       _stati64
    +#   define MY_STAT        _stati64
    +#   define MY_S_ISREG(x)  ((x) & _S_IFREG)
    +#   define MY_S_ISDIR(x)  ((x) & _S_IFDIR)
    +
    +#   define APPEND_FLAG(root, name) \
    +      root=snocString((root), (name))
    +
    +#   define APPEND_FILESPEC(root, name)                \
    +      root = snocString ((root), (name))
    +
    +#   define SET_BINARY_MODE(fd)                        \
    +      do {                                            \
    +         int retVal = setmode ( fileno ( fd ),        \
    +                                O_BINARY );           \
    +         ERROR_IF_MINUS_ONE ( retVal );               \
    +      } while ( 0 )
    +
    +#endif /* BZ_LCCWIN32 */
    +
    +
    +/*---------------------------------------------*/
    +/*--
    +  Some more stuff for all platforms :-)
    +--*/
    +
    +typedef char            Char;
    +typedef unsigned char   Bool;
    +typedef unsigned char   UChar;
    +typedef int             Int32;
    +typedef unsigned int    UInt32;
    +typedef short           Int16;
    +typedef unsigned short  UInt16;
    +                                       
    +#define True  ((Bool)1)
    +#define False ((Bool)0)
    +
    +/*--
    +  IntNative is your platform's `native' int size.
    +  Only here to avoid probs with 64-bit platforms.
    +--*/
    +typedef int IntNative;
    +
    +
    +/*---------------------------------------------------*/
    +/*--- Misc (file handling) data decls             ---*/
    +/*---------------------------------------------------*/
    +
    +Int32   verbosity;
    +Bool    keepInputFiles, smallMode, deleteOutputOnInterrupt;
    +Bool    forceOverwrite, testFailsExist, unzFailsExist, noisy;
    +Int32   numFileNames, numFilesProcessed, blockSize100k;
    +Int32   exitValue;
    +
    +/*-- source modes; F==file, I==stdin, O==stdout --*/
    +#define SM_I2O           1
    +#define SM_F2O           2
    +#define SM_F2F           3
    +
    +/*-- operation modes --*/
    +#define OM_Z             1
    +#define OM_UNZ           2
    +#define OM_TEST          3
    +
    +Int32   opMode;
    +Int32   srcMode;
    +
    +#define FILE_NAME_LEN 1034
    +
    +Int32   longestFileName;
    +Char    inName [FILE_NAME_LEN];
    +Char    outName[FILE_NAME_LEN];
    +Char    tmpName[FILE_NAME_LEN];
    +Char    *progName;
    +Char    progNameReally[FILE_NAME_LEN];
    +FILE    *outputHandleJustInCase;
    +Int32   workFactor;
    +
    +static void    panic                 ( const Char* ) NORETURN;
    +static void    ioError               ( void )        NORETURN;
    +static void    outOfMemory           ( void )        NORETURN;
    +static void    configError           ( void )        NORETURN;
    +static void    crcError              ( void )        NORETURN;
    +static void    cleanUpAndFail        ( Int32 )       NORETURN;
    +static void    compressedStreamEOF   ( void )        NORETURN;
    +
    +static void    copyFileName ( Char*, Char* );
    +static void*   myMalloc     ( Int32 );
    +static void    applySavedFileAttrToOutputFile ( IntNative fd );
    +
    +
    +
    +/*---------------------------------------------------*/
    +/*--- An implementation of 64-bit ints.  Sigh.    ---*/
    +/*--- Roll on widespread deployment of ANSI C9X ! ---*/
    +/*---------------------------------------------------*/
    +
    +typedef
    +   struct { UChar b[8]; } 
    +   UInt64;
    +
    +
    +static
    +void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 )
    +{
    +   n->b[7] = (UChar)((hi32 >> 24) & 0xFF);
    +   n->b[6] = (UChar)((hi32 >> 16) & 0xFF);
    +   n->b[5] = (UChar)((hi32 >> 8)  & 0xFF);
    +   n->b[4] = (UChar) (hi32        & 0xFF);
    +   n->b[3] = (UChar)((lo32 >> 24) & 0xFF);
    +   n->b[2] = (UChar)((lo32 >> 16) & 0xFF);
    +   n->b[1] = (UChar)((lo32 >> 8)  & 0xFF);
    +   n->b[0] = (UChar) (lo32        & 0xFF);
    +}
    +
    +
    +static
    +double uInt64_to_double ( UInt64* n )
    +{
    +   Int32  i;
    +   double base = 1.0;
    +   double sum  = 0.0;
    +   for (i = 0; i < 8; i++) {
    +      sum  += base * (double)(n->b[i]);
    +      base *= 256.0;
    +   }
    +   return sum;
    +}
    +
    +
    +static
    +Bool uInt64_isZero ( UInt64* n )
    +{
    +   Int32 i;
    +   for (i = 0; i < 8; i++)
    +      if (n->b[i] != 0) return 0;
    +   return 1;
    +}
    +
    +
    +/* Divide *n by 10, and return the remainder.  */
    +static 
    +Int32 uInt64_qrm10 ( UInt64* n )
    +{
    +   UInt32 rem, tmp;
    +   Int32  i;
    +   rem = 0;
    +   for (i = 7; i >= 0; i--) {
    +      tmp = rem * 256 + n->b[i];
    +      n->b[i] = tmp / 10;
    +      rem = tmp % 10;
    +   }
    +   return rem;
    +}
    +
    +
    +/* ... and the Whole Entire Point of all this UInt64 stuff is
    +   so that we can supply the following function.
    +*/
    +static
    +void uInt64_toAscii ( char* outbuf, UInt64* n )
    +{
    +   Int32  i, q;
    +   UChar  buf[32];
    +   Int32  nBuf   = 0;
    +   UInt64 n_copy = *n;
    +   do {
    +      q = uInt64_qrm10 ( &n_copy );
    +      buf[nBuf] = q + '0';
    +      nBuf++;
    +   } while (!uInt64_isZero(&n_copy));
    +   outbuf[nBuf] = 0;
    +   for (i = 0; i < nBuf; i++) 
    +      outbuf[i] = buf[nBuf-i-1];
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/*--- Processing of complete files and streams    ---*/
    +/*---------------------------------------------------*/
    +
    +/*---------------------------------------------*/
    +static 
    +Bool myfeof ( FILE* f )
    +{
    +   Int32 c = fgetc ( f );
    +   if (c == EOF) return True;
    +   ungetc ( c, f );
    +   return False;
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void compressStream ( FILE *stream, FILE *zStream )
    +{
    +   BZFILE* bzf = NULL;
    +   UChar   ibuf[5000];
    +   Int32   nIbuf;
    +   UInt32  nbytes_in_lo32, nbytes_in_hi32;
    +   UInt32  nbytes_out_lo32, nbytes_out_hi32;
    +   Int32   bzerr, bzerr_dummy, ret;
    +
    +   SET_BINARY_MODE(stream);
    +   SET_BINARY_MODE(zStream);
    +
    +   if (ferror(stream)) goto errhandler_io;
    +   if (ferror(zStream)) goto errhandler_io;
    +
    +   bzf = BZ2_bzWriteOpen ( &bzerr, zStream, 
    +                           blockSize100k, verbosity, workFactor );   
    +   if (bzerr != BZ_OK) goto errhandler;
    +
    +   if (verbosity >= 2) fprintf ( stderr, "\n" );
    +
    +   while (True) {
    +
    +      if (myfeof(stream)) break;
    +      nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
    +      if (ferror(stream)) goto errhandler_io;
    +      if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
    +      if (bzerr != BZ_OK) goto errhandler;
    +
    +   }
    +
    +   BZ2_bzWriteClose64 ( &bzerr, bzf, 0, 
    +                        &nbytes_in_lo32, &nbytes_in_hi32,
    +                        &nbytes_out_lo32, &nbytes_out_hi32 );
    +   if (bzerr != BZ_OK) goto errhandler;
    +
    +   if (ferror(zStream)) goto errhandler_io;
    +   ret = fflush ( zStream );
    +   if (ret == EOF) goto errhandler_io;
    +   if (zStream != stdout) {
    +      Int32 fd = fileno ( zStream );
    +      if (fd < 0) goto errhandler_io;
    +      applySavedFileAttrToOutputFile ( fd );
    +      ret = fclose ( zStream );
    +      outputHandleJustInCase = NULL;
    +      if (ret == EOF) goto errhandler_io;
    +   }
    +   outputHandleJustInCase = NULL;
    +   if (ferror(stream)) goto errhandler_io;
    +   ret = fclose ( stream );
    +   if (ret == EOF) goto errhandler_io;
    +
    +   if (verbosity >= 1) {
    +      if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) {
    +	 fprintf ( stderr, " no data compressed.\n");
    +      } else {
    +	 Char   buf_nin[32], buf_nout[32];
    +	 UInt64 nbytes_in,   nbytes_out;
    +	 double nbytes_in_d, nbytes_out_d;
    +	 uInt64_from_UInt32s ( &nbytes_in, 
    +			       nbytes_in_lo32, nbytes_in_hi32 );
    +	 uInt64_from_UInt32s ( &nbytes_out, 
    +			       nbytes_out_lo32, nbytes_out_hi32 );
    +	 nbytes_in_d  = uInt64_to_double ( &nbytes_in );
    +	 nbytes_out_d = uInt64_to_double ( &nbytes_out );
    +	 uInt64_toAscii ( buf_nin, &nbytes_in );
    +	 uInt64_toAscii ( buf_nout, &nbytes_out );
    +	 fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
    +		   "%5.2f%% saved, %s in, %s out.\n",
    +		   nbytes_in_d / nbytes_out_d,
    +		   (8.0 * nbytes_out_d) / nbytes_in_d,
    +		   100.0 * (1.0 - nbytes_out_d / nbytes_in_d),
    +		   buf_nin,
    +		   buf_nout
    +		 );
    +      }
    +   }
    +
    +   return;
    +
    +   errhandler:
    +   BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1, 
    +                        &nbytes_in_lo32, &nbytes_in_hi32,
    +                        &nbytes_out_lo32, &nbytes_out_hi32 );
    +   switch (bzerr) {
    +      case BZ_CONFIG_ERROR:
    +         configError(); break;
    +      case BZ_MEM_ERROR:
    +         outOfMemory (); break;
    +      case BZ_IO_ERROR:
    +         errhandler_io:
    +         ioError(); break;
    +      default:
    +         panic ( "compress:unexpected error" );
    +   }
    +
    +   panic ( "compress:end" );
    +   /*notreached*/
    +}
    +
    +
    +
    +/*---------------------------------------------*/
    +static 
    +Bool uncompressStream ( FILE *zStream, FILE *stream )
    +{
    +   BZFILE* bzf = NULL;
    +   Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
    +   UChar   obuf[5000];
    +   UChar   unused[BZ_MAX_UNUSED];
    +   Int32   nUnused;
    +   void*   unusedTmpV;
    +   UChar*  unusedTmp;
    +
    +   nUnused = 0;
    +   streamNo = 0;
    +
    +   SET_BINARY_MODE(stream);
    +   SET_BINARY_MODE(zStream);
    +
    +   if (ferror(stream)) goto errhandler_io;
    +   if (ferror(zStream)) goto errhandler_io;
    +
    +   while (True) {
    +
    +      bzf = BZ2_bzReadOpen ( 
    +               &bzerr, zStream, verbosity, 
    +               (int)smallMode, unused, nUnused
    +            );
    +      if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
    +      streamNo++;
    +
    +      while (bzerr == BZ_OK) {
    +         nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
    +         if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat;
    +         if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
    +            fwrite ( obuf, sizeof(UChar), nread, stream );
    +         if (ferror(stream)) goto errhandler_io;
    +      }
    +      if (bzerr != BZ_STREAM_END) goto errhandler;
    +
    +      BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
    +      if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
    +
    +      unusedTmp = (UChar*)unusedTmpV;
    +      for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
    +
    +      BZ2_bzReadClose ( &bzerr, bzf );
    +      if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
    +
    +      if (nUnused == 0 && myfeof(zStream)) break;
    +   }
    +
    +   closeok:
    +   if (ferror(zStream)) goto errhandler_io;
    +   if (stream != stdout) {
    +      Int32 fd = fileno ( stream );
    +      if (fd < 0) goto errhandler_io;
    +      applySavedFileAttrToOutputFile ( fd );
    +   }
    +   ret = fclose ( zStream );
    +   if (ret == EOF) goto errhandler_io;
    +
    +   if (ferror(stream)) goto errhandler_io;
    +   ret = fflush ( stream );
    +   if (ret != 0) goto errhandler_io;
    +   if (stream != stdout) {
    +      ret = fclose ( stream );
    +      outputHandleJustInCase = NULL;
    +      if (ret == EOF) goto errhandler_io;
    +   }
    +   outputHandleJustInCase = NULL;
    +   if (verbosity >= 2) fprintf ( stderr, "\n    " );
    +   return True;
    +
    +   trycat: 
    +   if (forceOverwrite) {
    +      rewind(zStream);
    +      while (True) {
    +      	 if (myfeof(zStream)) break;
    +      	 nread = fread ( obuf, sizeof(UChar), 5000, zStream );
    +      	 if (ferror(zStream)) goto errhandler_io;
    +      	 if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream );
    +      	 if (ferror(stream)) goto errhandler_io;
    +      }
    +      goto closeok;
    +   }
    +  
    +   errhandler:
    +   BZ2_bzReadClose ( &bzerr_dummy, bzf );
    +   switch (bzerr) {
    +      case BZ_CONFIG_ERROR:
    +         configError(); break;
    +      case BZ_IO_ERROR:
    +         errhandler_io:
    +         ioError(); break;
    +      case BZ_DATA_ERROR:
    +         crcError();
    +      case BZ_MEM_ERROR:
    +         outOfMemory();
    +      case BZ_UNEXPECTED_EOF:
    +         compressedStreamEOF();
    +      case BZ_DATA_ERROR_MAGIC:
    +         if (zStream != stdin) fclose(zStream);
    +         if (stream != stdout) fclose(stream);
    +         if (streamNo == 1) {
    +            return False;
    +         } else {
    +            if (noisy)
    +            fprintf ( stderr, 
    +                      "\n%s: %s: trailing garbage after EOF ignored\n",
    +                      progName, inName );
    +            return True;       
    +         }
    +      default:
    +         panic ( "decompress:unexpected error" );
    +   }
    +
    +   panic ( "decompress:end" );
    +   return True; /*notreached*/
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +Bool testStream ( FILE *zStream )
    +{
    +   BZFILE* bzf = NULL;
    +   Int32   bzerr, bzerr_dummy, ret, streamNo, i;
    +   UChar   obuf[5000];
    +   UChar   unused[BZ_MAX_UNUSED];
    +   Int32   nUnused;
    +   void*   unusedTmpV;
    +   UChar*  unusedTmp;
    +
    +   nUnused = 0;
    +   streamNo = 0;
    +
    +   SET_BINARY_MODE(zStream);
    +   if (ferror(zStream)) goto errhandler_io;
    +
    +   while (True) {
    +
    +      bzf = BZ2_bzReadOpen ( 
    +               &bzerr, zStream, verbosity, 
    +               (int)smallMode, unused, nUnused
    +            );
    +      if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
    +      streamNo++;
    +
    +      while (bzerr == BZ_OK) {
    +         BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
    +         if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
    +      }
    +      if (bzerr != BZ_STREAM_END) goto errhandler;
    +
    +      BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
    +      if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
    +
    +      unusedTmp = (UChar*)unusedTmpV;
    +      for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
    +
    +      BZ2_bzReadClose ( &bzerr, bzf );
    +      if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
    +      if (nUnused == 0 && myfeof(zStream)) break;
    +
    +   }
    +
    +   if (ferror(zStream)) goto errhandler_io;
    +   ret = fclose ( zStream );
    +   if (ret == EOF) goto errhandler_io;
    +
    +   if (verbosity >= 2) fprintf ( stderr, "\n    " );
    +   return True;
    +
    +   errhandler:
    +   BZ2_bzReadClose ( &bzerr_dummy, bzf );
    +   if (verbosity == 0) 
    +      fprintf ( stderr, "%s: %s: ", progName, inName );
    +   switch (bzerr) {
    +      case BZ_CONFIG_ERROR:
    +         configError(); break;
    +      case BZ_IO_ERROR:
    +         errhandler_io:
    +         ioError(); break;
    +      case BZ_DATA_ERROR:
    +         fprintf ( stderr,
    +                   "data integrity (CRC) error in data\n" );
    +         return False;
    +      case BZ_MEM_ERROR:
    +         outOfMemory();
    +      case BZ_UNEXPECTED_EOF:
    +         fprintf ( stderr,
    +                   "file ends unexpectedly\n" );
    +         return False;
    +      case BZ_DATA_ERROR_MAGIC:
    +         if (zStream != stdin) fclose(zStream);
    +         if (streamNo == 1) {
    +          fprintf ( stderr, 
    +                    "bad magic number (file not created by bzip2)\n" );
    +            return False;
    +         } else {
    +            if (noisy)
    +            fprintf ( stderr, 
    +                      "trailing garbage after EOF ignored\n" );
    +            return True;       
    +         }
    +      default:
    +         panic ( "test:unexpected error" );
    +   }
    +
    +   panic ( "test:end" );
    +   return True; /*notreached*/
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/*--- Error [non-] handling grunge                ---*/
    +/*---------------------------------------------------*/
    +
    +/*---------------------------------------------*/
    +static
    +void setExit ( Int32 v )
    +{
    +   if (v > exitValue) exitValue = v;
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void cadvise ( void )
    +{
    +   if (noisy)
    +   fprintf (
    +      stderr,
    +      "\nIt is possible that the compressed file(s) have become corrupted.\n"
    +        "You can use the -tvv option to test integrity of such files.\n\n"
    +        "You can use the `bzip2recover' program to attempt to recover\n"
    +        "data from undamaged sections of corrupted files.\n\n"
    +    );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void showFileNames ( void )
    +{
    +   if (noisy)
    +   fprintf (
    +      stderr,
    +      "\tInput file = %s, output file = %s\n",
    +      inName, outName 
    +   );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void cleanUpAndFail ( Int32 ec )
    +{
    +   IntNative      retVal;
    +   struct MY_STAT statBuf;
    +
    +   if ( srcMode == SM_F2F 
    +        && opMode != OM_TEST
    +        && deleteOutputOnInterrupt ) {
    +
    +      /* Check whether input file still exists.  Delete output file
    +         only if input exists to avoid loss of data.  Joerg Prante, 5
    +         January 2002.  (JRS 06-Jan-2002: other changes in 1.0.2 mean
    +         this is less likely to happen.  But to be ultra-paranoid, we
    +         do the check anyway.)  */
    +      retVal = MY_STAT ( inName, &statBuf );
    +      if (retVal == 0) {
    +         if (noisy)
    +            fprintf ( stderr, 
    +                      "%s: Deleting output file %s, if it exists.\n",
    +                      progName, outName );
    +         if (outputHandleJustInCase != NULL)
    +            fclose ( outputHandleJustInCase );
    +         retVal = remove ( outName );
    +         if (retVal != 0)
    +            fprintf ( stderr,
    +                      "%s: WARNING: deletion of output file "
    +                      "(apparently) failed.\n",
    +                      progName );
    +      } else {
    +         fprintf ( stderr,
    +                   "%s: WARNING: deletion of output file suppressed\n",
    +                    progName );
    +         fprintf ( stderr,
    +                   "%s:    since input file no longer exists.  Output file\n",
    +                   progName );
    +         fprintf ( stderr,
    +                   "%s:    `%s' may be incomplete.\n",
    +                   progName, outName );
    +         fprintf ( stderr, 
    +                   "%s:    I suggest doing an integrity test (bzip2 -tv)"
    +                   " of it.\n",
    +                   progName );
    +      }
    +   }
    +
    +   if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
    +      fprintf ( stderr, 
    +                "%s: WARNING: some files have not been processed:\n"
    +                "%s:    %d specified on command line, %d not processed yet.\n\n",
    +                progName, progName,
    +                numFileNames, numFileNames - numFilesProcessed );
    +   }
    +   setExit(ec);
    +   exit(exitValue);
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void panic ( const Char* s )
    +{
    +   fprintf ( stderr,
    +             "\n%s: PANIC -- internal consistency error:\n"
    +             "\t%s\n"
    +             "\tThis is a BUG.  Please report it to:\n"
    +             "\tbzip2-devel@sourceware.org\n",
    +             progName, s );
    +   showFileNames();
    +   cleanUpAndFail( 3 );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void crcError ( void )
    +{
    +   fprintf ( stderr,
    +             "\n%s: Data integrity error when decompressing.\n",
    +             progName );
    +   showFileNames();
    +   cadvise();
    +   cleanUpAndFail( 2 );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void compressedStreamEOF ( void )
    +{
    +  if (noisy) {
    +    fprintf ( stderr,
    +	      "\n%s: Compressed file ends unexpectedly;\n\t"
    +	      "perhaps it is corrupted?  *Possible* reason follows.\n",
    +	      progName );
    +    perror ( progName );
    +    showFileNames();
    +    cadvise();
    +  }
    +  cleanUpAndFail( 2 );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void ioError ( void )
    +{
    +   fprintf ( stderr,
    +             "\n%s: I/O or other error, bailing out.  "
    +             "Possible reason follows.\n",
    +             progName );
    +   perror ( progName );
    +   showFileNames();
    +   cleanUpAndFail( 1 );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void mySignalCatcher ( IntNative n )
    +{
    +   fprintf ( stderr,
    +             "\n%s: Control-C or similar caught, quitting.\n",
    +             progName );
    +   cleanUpAndFail(1);
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void mySIGSEGVorSIGBUScatcher ( IntNative n )
    +{
    +   if (opMode == OM_Z)
    +      fprintf ( 
    +      stderr,
    +      "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
    +      "\n"
    +      "   Possible causes are (most likely first):\n"
    +      "   (1) This computer has unreliable memory or cache hardware\n"
    +      "       (a surprisingly common problem; try a different machine.)\n"
    +      "   (2) A bug in the compiler used to create this executable\n"
    +      "       (unlikely, if you didn't compile bzip2 yourself.)\n"
    +      "   (3) A real bug in bzip2 -- I hope this should never be the case.\n"
    +      "   The user's manual, Section 4.3, has more info on (1) and (2).\n"
    +      "   \n"
    +      "   If you suspect this is a bug in bzip2, or are unsure about (1)\n"
    +      "   or (2), feel free to report it to: bzip2-devel@sourceware.org.\n"
    +      "   Section 4.3 of the user's manual describes the info a useful\n"
    +      "   bug report should have.  If the manual is available on your\n"
    +      "   system, please try and read it before mailing me.  If you don't\n"
    +      "   have the manual or can't be bothered to read it, mail me anyway.\n"
    +      "\n",
    +      progName );
    +      else
    +      fprintf ( 
    +      stderr,
    +      "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
    +      "\n"
    +      "   Possible causes are (most likely first):\n"
    +      "   (1) The compressed data is corrupted, and bzip2's usual checks\n"
    +      "       failed to detect this.  Try bzip2 -tvv my_file.bz2.\n"
    +      "   (2) This computer has unreliable memory or cache hardware\n"
    +      "       (a surprisingly common problem; try a different machine.)\n"
    +      "   (3) A bug in the compiler used to create this executable\n"
    +      "       (unlikely, if you didn't compile bzip2 yourself.)\n"
    +      "   (4) A real bug in bzip2 -- I hope this should never be the case.\n"
    +      "   The user's manual, Section 4.3, has more info on (2) and (3).\n"
    +      "   \n"
    +      "   If you suspect this is a bug in bzip2, or are unsure about (2)\n"
    +      "   or (3), feel free to report it to: bzip2-devel@sourceware.org.\n"
    +      "   Section 4.3 of the user's manual describes the info a useful\n"
    +      "   bug report should have.  If the manual is available on your\n"
    +      "   system, please try and read it before mailing me.  If you don't\n"
    +      "   have the manual or can't be bothered to read it, mail me anyway.\n"
    +      "\n",
    +      progName );
    +
    +   showFileNames();
    +   if (opMode == OM_Z)
    +      cleanUpAndFail( 3 ); else
    +      { cadvise(); cleanUpAndFail( 2 ); }
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void outOfMemory ( void )
    +{
    +   fprintf ( stderr,
    +             "\n%s: couldn't allocate enough memory\n",
    +             progName );
    +   showFileNames();
    +   cleanUpAndFail(1);
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void configError ( void )
    +{
    +   fprintf ( stderr,
    +             "bzip2: I'm not configured correctly for this platform!\n"
    +             "\tI require Int32, Int16 and Char to have sizes\n"
    +             "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
    +             "\tProbably you can fix this by defining them correctly,\n"
    +             "\tand recompiling.  Bye!\n" );
    +   setExit(3);
    +   exit(exitValue);
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/*--- The main driver machinery                   ---*/
    +/*---------------------------------------------------*/
    +
    +/* All rather crufty.  The main problem is that input files
    +   are stat()d multiple times before use.  This should be
    +   cleaned up. 
    +*/
    +
    +/*---------------------------------------------*/
    +static 
    +void pad ( Char *s )
    +{
    +   Int32 i;
    +   if ( (Int32)strlen(s) >= longestFileName ) return;
    +   for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
    +      fprintf ( stderr, " " );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void copyFileName ( Char* to, Char* from ) 
    +{
    +   if ( strlen(from) > FILE_NAME_LEN-10 )  {
    +      fprintf (
    +         stderr,
    +         "bzip2: file name\n`%s'\n"
    +         "is suspiciously (more than %d chars) long.\n"
    +         "Try using a reasonable file name instead.  Sorry! :-)\n",
    +         from, FILE_NAME_LEN-10
    +      );
    +      setExit(1);
    +      exit(exitValue);
    +   }
    +
    +  strncpy(to,from,FILE_NAME_LEN-10);
    +  to[FILE_NAME_LEN-10]='\0';
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +Bool fileExists ( Char* name )
    +{
    +   FILE *tmp   = fopen ( name, "rb" );
    +   Bool exists = (tmp != NULL);
    +   if (tmp != NULL) fclose ( tmp );
    +   return exists;
    +}
    +
    +
    +/*---------------------------------------------*/
    +/* Open an output file safely with O_EXCL and good permissions.
    +   This avoids a race condition in versions < 1.0.2, in which
    +   the file was first opened and then had its interim permissions
    +   set safely.  We instead use open() to create the file with
    +   the interim permissions required. (--- --- rw-).
    +
    +   For non-Unix platforms, if we are not worrying about
    +   security issues, simple this simply behaves like fopen.
    +*/
    +static
    +FILE* fopen_output_safely ( Char* name, const char* mode )
    +{
    +#  if BZ_UNIX
    +   FILE*     fp;
    +   IntNative fh;
    +   fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
    +   if (fh == -1) return NULL;
    +   fp = fdopen(fh, mode);
    +   if (fp == NULL) close(fh);
    +   return fp;
    +#  else
    +   return fopen(name, mode);
    +#  endif
    +}
    +
    +
    +/*---------------------------------------------*/
    +/*--
    +  if in doubt, return True
    +--*/
    +static 
    +Bool notAStandardFile ( Char* name )
    +{
    +   IntNative      i;
    +   struct MY_STAT statBuf;
    +
    +   i = MY_LSTAT ( name, &statBuf );
    +   if (i != 0) return True;
    +   if (MY_S_ISREG(statBuf.st_mode)) return False;
    +   return True;
    +}
    +
    +
    +/*---------------------------------------------*/
    +/*--
    +  rac 11/21/98 see if file has hard links to it
    +--*/
    +static 
    +Int32 countHardLinks ( Char* name )
    +{  
    +   IntNative      i;
    +   struct MY_STAT statBuf;
    +
    +   i = MY_LSTAT ( name, &statBuf );
    +   if (i != 0) return 0;
    +   return (statBuf.st_nlink - 1);
    +}
    +
    +
    +/*---------------------------------------------*/
    +/* Copy modification date, access date, permissions and owner from the
    +   source to destination file.  We have to copy this meta-info off
    +   into fileMetaInfo before starting to compress / decompress it,
    +   because doing it afterwards means we get the wrong access time.
    +
    +   To complicate matters, in compress() and decompress() below, the
    +   sequence of tests preceding the call to saveInputFileMetaInfo()
    +   involves calling fileExists(), which in turn establishes its result
    +   by attempting to fopen() the file, and if successful, immediately
    +   fclose()ing it again.  So we have to assume that the fopen() call
    +   does not cause the access time field to be updated.
    +
    +   Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems
    +   to imply that merely doing open() will not affect the access time.
    +   Therefore we merely need to hope that the C library only does
    +   open() as a result of fopen(), and not any kind of read()-ahead
    +   cleverness.
    +
    +   It sounds pretty fragile to me.  Whether this carries across
    +   robustly to arbitrary Unix-like platforms (or even works robustly
    +   on this one, RedHat 7.2) is unknown to me.  Nevertheless ...  
    +*/
    +#if BZ_UNIX
    +static 
    +struct MY_STAT fileMetaInfo;
    +#endif
    +
    +static 
    +void saveInputFileMetaInfo ( Char *srcName )
    +{
    +#  if BZ_UNIX
    +   IntNative retVal;
    +   /* Note use of stat here, not lstat. */
    +   retVal = MY_STAT( srcName, &fileMetaInfo );
    +   ERROR_IF_NOT_ZERO ( retVal );
    +#  endif
    +}
    +
    +
    +static 
    +void applySavedTimeInfoToOutputFile ( Char *dstName )
    +{
    +#  if BZ_UNIX
    +   IntNative      retVal;
    +   struct utimbuf uTimBuf;
    +
    +   uTimBuf.actime = fileMetaInfo.st_atime;
    +   uTimBuf.modtime = fileMetaInfo.st_mtime;
    +
    +   retVal = utime ( dstName, &uTimBuf );
    +   ERROR_IF_NOT_ZERO ( retVal );
    +#  endif
    +}
    +
    +static 
    +void applySavedFileAttrToOutputFile ( IntNative fd )
    +{
    +#  if BZ_UNIX
    +   IntNative retVal;
    +
    +   retVal = fchmod ( fd, fileMetaInfo.st_mode );
    +   ERROR_IF_NOT_ZERO ( retVal );
    +
    +   (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
    +   /* chown() will in many cases return with EPERM, which can
    +      be safely ignored.
    +   */
    +#  endif
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +Bool containsDubiousChars ( Char* name )
    +{
    +#  if BZ_UNIX
    +   /* On unix, files can contain any characters and the file expansion
    +    * is performed by the shell.
    +    */
    +   return False;
    +#  else /* ! BZ_UNIX */
    +   /* On non-unix (Win* platforms), wildcard characters are not allowed in 
    +    * filenames.
    +    */
    +   for (; *name != '\0'; name++)
    +      if (*name == '?' || *name == '*') return True;
    +   return False;
    +#  endif /* BZ_UNIX */
    +}
    +
    +
    +/*---------------------------------------------*/
    +#define BZ_N_SUFFIX_PAIRS 4
    +
    +const Char* zSuffix[BZ_N_SUFFIX_PAIRS] 
    +   = { ".bz2", ".bz", ".tbz2", ".tbz" };
    +const Char* unzSuffix[BZ_N_SUFFIX_PAIRS] 
    +   = { "", "", ".tar", ".tar" };
    +
    +static 
    +Bool hasSuffix ( Char* s, const Char* suffix )
    +{
    +   Int32 ns = strlen(s);
    +   Int32 nx = strlen(suffix);
    +   if (ns < nx) return False;
    +   if (strcmp(s + ns - nx, suffix) == 0) return True;
    +   return False;
    +}
    +
    +static 
    +Bool mapSuffix ( Char* name, 
    +                 const Char* oldSuffix, 
    +                 const Char* newSuffix )
    +{
    +   if (!hasSuffix(name,oldSuffix)) return False;
    +   name[strlen(name)-strlen(oldSuffix)] = 0;
    +   strcat ( name, newSuffix );
    +   return True;
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void compress ( Char *name )
    +{
    +   FILE  *inStr;
    +   FILE  *outStr;
    +   Int32 n, i;
    +   struct MY_STAT statBuf;
    +
    +   deleteOutputOnInterrupt = False;
    +
    +   if (name == NULL && srcMode != SM_I2O)
    +      panic ( "compress: bad modes\n" );
    +
    +   switch (srcMode) {
    +      case SM_I2O: 
    +         copyFileName ( inName, (Char*)"(stdin)" );
    +         copyFileName ( outName, (Char*)"(stdout)" ); 
    +         break;
    +      case SM_F2F: 
    +         copyFileName ( inName, name );
    +         copyFileName ( outName, name );
    +         strcat ( outName, ".bz2" ); 
    +         break;
    +      case SM_F2O: 
    +         copyFileName ( inName, name );
    +         copyFileName ( outName, (Char*)"(stdout)" ); 
    +         break;
    +   }
    +
    +   if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
    +      if (noisy)
    +      fprintf ( stderr, "%s: There are no files matching `%s'.\n",
    +                progName, inName );
    +      setExit(1);
    +      return;
    +   }
    +   if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
    +      fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
    +                progName, inName, strerror(errno) );
    +      setExit(1);
    +      return;
    +   }
    +   for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
    +      if (hasSuffix(inName, zSuffix[i])) {
    +         if (noisy)
    +         fprintf ( stderr, 
    +                   "%s: Input file %s already has %s suffix.\n",
    +                   progName, inName, zSuffix[i] );
    +         setExit(1);
    +         return;
    +      }
    +   }
    +   if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
    +      MY_STAT(inName, &statBuf);
    +      if ( MY_S_ISDIR(statBuf.st_mode) ) {
    +         fprintf( stderr,
    +                  "%s: Input file %s is a directory.\n",
    +                  progName,inName);
    +         setExit(1);
    +         return;
    +      }
    +   }
    +   if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
    +      if (noisy)
    +      fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
    +                progName, inName );
    +      setExit(1);
    +      return;
    +   }
    +   if ( srcMode == SM_F2F && fileExists ( outName ) ) {
    +      if (forceOverwrite) {
    +	 remove(outName);
    +      } else {
    +	 fprintf ( stderr, "%s: Output file %s already exists.\n",
    +		   progName, outName );
    +	 setExit(1);
    +	 return;
    +      }
    +   }
    +   if ( srcMode == SM_F2F && !forceOverwrite &&
    +        (n=countHardLinks ( inName )) > 0) {
    +      fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
    +                progName, inName, n, n > 1 ? "s" : "" );
    +      setExit(1);
    +      return;
    +   }
    +
    +   if ( srcMode == SM_F2F ) {
    +      /* Save the file's meta-info before we open it.  Doing it later
    +         means we mess up the access times. */
    +      saveInputFileMetaInfo ( inName );
    +   }
    +
    +   switch ( srcMode ) {
    +
    +      case SM_I2O:
    +         inStr = stdin;
    +         outStr = stdout;
    +         if ( isatty ( fileno ( stdout ) ) ) {
    +            fprintf ( stderr,
    +                      "%s: I won't write compressed data to a terminal.\n",
    +                      progName );
    +            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
    +                              progName, progName );
    +            setExit(1);
    +            return;
    +         };
    +         break;
    +
    +      case SM_F2O:
    +         inStr = fopen ( inName, "rb" );
    +         outStr = stdout;
    +         if ( isatty ( fileno ( stdout ) ) ) {
    +            fprintf ( stderr,
    +                      "%s: I won't write compressed data to a terminal.\n",
    +                      progName );
    +            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
    +                              progName, progName );
    +            if ( inStr != NULL ) fclose ( inStr );
    +            setExit(1);
    +            return;
    +         };
    +         if ( inStr == NULL ) {
    +            fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
    +                      progName, inName, strerror(errno) );
    +            setExit(1);
    +            return;
    +         };
    +         break;
    +
    +      case SM_F2F:
    +         inStr = fopen ( inName, "rb" );
    +         outStr = fopen_output_safely ( outName, "wb" );
    +         if ( outStr == NULL) {
    +            fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
    +                      progName, outName, strerror(errno) );
    +            if ( inStr != NULL ) fclose ( inStr );
    +            setExit(1);
    +            return;
    +         }
    +         if ( inStr == NULL ) {
    +            fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
    +                      progName, inName, strerror(errno) );
    +            if ( outStr != NULL ) fclose ( outStr );
    +            setExit(1);
    +            return;
    +         };
    +         break;
    +
    +      default:
    +         panic ( "compress: bad srcMode" );
    +         break;
    +   }
    +
    +   if (verbosity >= 1) {
    +      fprintf ( stderr,  "  %s: ", inName );
    +      pad ( inName );
    +      fflush ( stderr );
    +   }
    +
    +   /*--- Now the input and output handles are sane.  Do the Biz. ---*/
    +   outputHandleJustInCase = outStr;
    +   deleteOutputOnInterrupt = True;
    +   compressStream ( inStr, outStr );
    +   outputHandleJustInCase = NULL;
    +
    +   /*--- If there was an I/O error, we won't get here. ---*/
    +   if ( srcMode == SM_F2F ) {
    +      applySavedTimeInfoToOutputFile ( outName );
    +      deleteOutputOnInterrupt = False;
    +      if ( !keepInputFiles ) {
    +         IntNative retVal = remove ( inName );
    +         ERROR_IF_NOT_ZERO ( retVal );
    +      }
    +   }
    +
    +   deleteOutputOnInterrupt = False;
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void uncompress ( Char *name )
    +{
    +   FILE  *inStr;
    +   FILE  *outStr;
    +   Int32 n, i;
    +   Bool  magicNumberOK;
    +   Bool  cantGuess;
    +   struct MY_STAT statBuf;
    +
    +   deleteOutputOnInterrupt = False;
    +
    +   if (name == NULL && srcMode != SM_I2O)
    +      panic ( "uncompress: bad modes\n" );
    +
    +   cantGuess = False;
    +   switch (srcMode) {
    +      case SM_I2O: 
    +         copyFileName ( inName, (Char*)"(stdin)" );
    +         copyFileName ( outName, (Char*)"(stdout)" ); 
    +         break;
    +      case SM_F2F: 
    +         copyFileName ( inName, name );
    +         copyFileName ( outName, name );
    +         for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
    +            if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
    +               goto zzz; 
    +         cantGuess = True;
    +         strcat ( outName, ".out" );
    +         break;
    +      case SM_F2O: 
    +         copyFileName ( inName, name );
    +         copyFileName ( outName, (Char*)"(stdout)" ); 
    +         break;
    +   }
    +
    +   zzz:
    +   if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
    +      if (noisy)
    +      fprintf ( stderr, "%s: There are no files matching `%s'.\n",
    +                progName, inName );
    +      setExit(1);
    +      return;
    +   }
    +   if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
    +      fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
    +                progName, inName, strerror(errno) );
    +      setExit(1);
    +      return;
    +   }
    +   if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
    +      MY_STAT(inName, &statBuf);
    +      if ( MY_S_ISDIR(statBuf.st_mode) ) {
    +         fprintf( stderr,
    +                  "%s: Input file %s is a directory.\n",
    +                  progName,inName);
    +         setExit(1);
    +         return;
    +      }
    +   }
    +   if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
    +      if (noisy)
    +      fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
    +                progName, inName );
    +      setExit(1);
    +      return;
    +   }
    +   if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
    +      if (noisy)
    +      fprintf ( stderr, 
    +                "%s: Can't guess original name for %s -- using %s\n",
    +                progName, inName, outName );
    +      /* just a warning, no return */
    +   }   
    +   if ( srcMode == SM_F2F && fileExists ( outName ) ) {
    +      if (forceOverwrite) {
    +	remove(outName);
    +      } else {
    +        fprintf ( stderr, "%s: Output file %s already exists.\n",
    +                  progName, outName );
    +        setExit(1);
    +        return;
    +      }
    +   }
    +   if ( srcMode == SM_F2F && !forceOverwrite &&
    +        (n=countHardLinks ( inName ) ) > 0) {
    +      fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
    +                progName, inName, n, n > 1 ? "s" : "" );
    +      setExit(1);
    +      return;
    +   }
    +
    +   if ( srcMode == SM_F2F ) {
    +      /* Save the file's meta-info before we open it.  Doing it later
    +         means we mess up the access times. */
    +      saveInputFileMetaInfo ( inName );
    +   }
    +
    +   switch ( srcMode ) {
    +
    +      case SM_I2O:
    +         inStr = stdin;
    +         outStr = stdout;
    +         if ( isatty ( fileno ( stdin ) ) ) {
    +            fprintf ( stderr,
    +                      "%s: I won't read compressed data from a terminal.\n",
    +                      progName );
    +            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
    +                              progName, progName );
    +            setExit(1);
    +            return;
    +         };
    +         break;
    +
    +      case SM_F2O:
    +         inStr = fopen ( inName, "rb" );
    +         outStr = stdout;
    +         if ( inStr == NULL ) {
    +            fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
    +                      progName, inName, strerror(errno) );
    +            if ( inStr != NULL ) fclose ( inStr );
    +            setExit(1);
    +            return;
    +         };
    +         break;
    +
    +      case SM_F2F:
    +         inStr = fopen ( inName, "rb" );
    +         outStr = fopen_output_safely ( outName, "wb" );
    +         if ( outStr == NULL) {
    +            fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
    +                      progName, outName, strerror(errno) );
    +            if ( inStr != NULL ) fclose ( inStr );
    +            setExit(1);
    +            return;
    +         }
    +         if ( inStr == NULL ) {
    +            fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
    +                      progName, inName, strerror(errno) );
    +            if ( outStr != NULL ) fclose ( outStr );
    +            setExit(1);
    +            return;
    +         };
    +         break;
    +
    +      default:
    +         panic ( "uncompress: bad srcMode" );
    +         break;
    +   }
    +
    +   if (verbosity >= 1) {
    +      fprintf ( stderr, "  %s: ", inName );
    +      pad ( inName );
    +      fflush ( stderr );
    +   }
    +
    +   /*--- Now the input and output handles are sane.  Do the Biz. ---*/
    +   outputHandleJustInCase = outStr;
    +   deleteOutputOnInterrupt = True;
    +   magicNumberOK = uncompressStream ( inStr, outStr );
    +   outputHandleJustInCase = NULL;
    +
    +   /*--- If there was an I/O error, we won't get here. ---*/
    +   if ( magicNumberOK ) {
    +      if ( srcMode == SM_F2F ) {
    +         applySavedTimeInfoToOutputFile ( outName );
    +         deleteOutputOnInterrupt = False;
    +         if ( !keepInputFiles ) {
    +            IntNative retVal = remove ( inName );
    +            ERROR_IF_NOT_ZERO ( retVal );
    +         }
    +      }
    +   } else {
    +      unzFailsExist = True;
    +      deleteOutputOnInterrupt = False;
    +      if ( srcMode == SM_F2F ) {
    +         IntNative retVal = remove ( outName );
    +         ERROR_IF_NOT_ZERO ( retVal );
    +      }
    +   }
    +   deleteOutputOnInterrupt = False;
    +
    +   if ( magicNumberOK ) {
    +      if (verbosity >= 1)
    +         fprintf ( stderr, "done\n" );
    +   } else {
    +      setExit(2);
    +      if (verbosity >= 1)
    +         fprintf ( stderr, "not a bzip2 file.\n" ); else
    +         fprintf ( stderr,
    +                   "%s: %s is not a bzip2 file.\n",
    +                   progName, inName );
    +   }
    +
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void testf ( Char *name )
    +{
    +   FILE *inStr;
    +   Bool allOK;
    +   struct MY_STAT statBuf;
    +
    +   deleteOutputOnInterrupt = False;
    +
    +   if (name == NULL && srcMode != SM_I2O)
    +      panic ( "testf: bad modes\n" );
    +
    +   copyFileName ( outName, (Char*)"(none)" );
    +   switch (srcMode) {
    +      case SM_I2O: copyFileName ( inName, (Char*)"(stdin)" ); break;
    +      case SM_F2F: copyFileName ( inName, name ); break;
    +      case SM_F2O: copyFileName ( inName, name ); break;
    +   }
    +
    +   if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
    +      if (noisy)
    +      fprintf ( stderr, "%s: There are no files matching `%s'.\n",
    +                progName, inName );
    +      setExit(1);
    +      return;
    +   }
    +   if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
    +      fprintf ( stderr, "%s: Can't open input %s: %s.\n",
    +                progName, inName, strerror(errno) );
    +      setExit(1);
    +      return;
    +   }
    +   if ( srcMode != SM_I2O ) {
    +      MY_STAT(inName, &statBuf);
    +      if ( MY_S_ISDIR(statBuf.st_mode) ) {
    +         fprintf( stderr,
    +                  "%s: Input file %s is a directory.\n",
    +                  progName,inName);
    +         setExit(1);
    +         return;
    +      }
    +   }
    +
    +   switch ( srcMode ) {
    +
    +      case SM_I2O:
    +         if ( isatty ( fileno ( stdin ) ) ) {
    +            fprintf ( stderr,
    +                      "%s: I won't read compressed data from a terminal.\n",
    +                      progName );
    +            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
    +                              progName, progName );
    +            setExit(1);
    +            return;
    +         };
    +         inStr = stdin;
    +         break;
    +
    +      case SM_F2O: case SM_F2F:
    +         inStr = fopen ( inName, "rb" );
    +         if ( inStr == NULL ) {
    +            fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
    +                      progName, inName, strerror(errno) );
    +            setExit(1);
    +            return;
    +         };
    +         break;
    +
    +      default:
    +         panic ( "testf: bad srcMode" );
    +         break;
    +   }
    +
    +   if (verbosity >= 1) {
    +      fprintf ( stderr, "  %s: ", inName );
    +      pad ( inName );
    +      fflush ( stderr );
    +   }
    +
    +   /*--- Now the input handle is sane.  Do the Biz. ---*/
    +   outputHandleJustInCase = NULL;
    +   allOK = testStream ( inStr );
    +
    +   if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
    +   if (!allOK) testFailsExist = True;
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void license ( void )
    +{
    +   fprintf ( stderr,
    +
    +    "bzip2, a block-sorting file compressor.  "
    +    "Version %s.\n"
    +    "   \n"
    +    "   Copyright (C) 1996-2019 by Julian Seward.\n"
    +    "   \n"
    +    "   This program is free software; you can redistribute it and/or modify\n"
    +    "   it under the terms set out in the LICENSE file, which is included\n"
    +    "   in the bzip2 source distribution.\n"
    +    "   \n"
    +    "   This program is distributed in the hope that it will be useful,\n"
    +    "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    +    "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    +    "   LICENSE file for more details.\n"
    +    "   \n",
    +    BZ2_bzlibVersion()
    +   );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void usage ( Char *fullProgName )
    +{
    +   fprintf (
    +      stderr,
    +      "bzip2, a block-sorting file compressor.  "
    +      "Version %s.\n"
    +      "\n   usage: %s [flags and input files in any order]\n"
    +      "\n"
    +      "   -h --help           print this message\n"
    +      "   -d --decompress     force decompression\n"
    +      "   -z --compress       force compression\n"
    +      "   -k --keep           keep (don't delete) input files\n"
    +      "   -f --force          overwrite existing output files\n"
    +      "   -t --test           test compressed file integrity\n"
    +      "   -c --stdout         output to standard out\n"
    +      "   -q --quiet          suppress noncritical error messages\n"
    +      "   -v --verbose        be verbose (a 2nd -v gives more)\n"
    +      "   -L --license        display software version & license\n"
    +      "   -V --version        display software version & license\n"
    +      "   -s --small          use less memory (at most 2500k)\n"
    +      "   -1 .. -9            set block size to 100k .. 900k\n"
    +      "   --fast              alias for -1\n"
    +      "   --best              alias for -9\n"
    +      "\n"
    +      "   If invoked as `bzip2', default action is to compress.\n"
    +      "              as `bunzip2',  default action is to decompress.\n"
    +      "              as `bzcat', default action is to decompress to stdout.\n"
    +      "\n"
    +      "   If no file names are given, bzip2 compresses or decompresses\n"
    +      "   from standard input to standard output.  You can combine\n"
    +      "   short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
    +#     if BZ_UNIX
    +      "\n"
    +#     endif
    +      ,
    +
    +      BZ2_bzlibVersion(),
    +      fullProgName
    +   );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void redundant ( Char* flag )
    +{
    +   fprintf ( 
    +      stderr, 
    +      "%s: %s is redundant in versions 0.9.5 and above\n",
    +      progName, flag );
    +}
    +
    +
    +/*---------------------------------------------*/
    +/*--
    +  All the garbage from here to main() is purely to
    +  implement a linked list of command-line arguments,
    +  into which main() copies argv[1 .. argc-1].
    +
    +  The purpose of this exercise is to facilitate 
    +  the expansion of wildcard characters * and ? in 
    +  filenames for OSs which don't know how to do it
    +  themselves, like MSDOS, Windows 95 and NT.
    +
    +  The actual Dirty Work is done by the platform-
    +  specific macro APPEND_FILESPEC.
    +--*/
    +
    +typedef
    +   struct zzzz {
    +      Char        *name;
    +      struct zzzz *link;
    +   }
    +   Cell;
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void *myMalloc ( Int32 n )
    +{
    +   void* p;
    +
    +   p = malloc ( (size_t)n );
    +   if (p == NULL) outOfMemory ();
    +   return p;
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +Cell *mkCell ( void )
    +{
    +   Cell *c;
    +
    +   c = (Cell*) myMalloc ( sizeof ( Cell ) );
    +   c->name = NULL;
    +   c->link = NULL;
    +   return c;
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +Cell *snocString ( Cell *root, Char *name )
    +{
    +   if (root == NULL) {
    +      Cell *tmp = mkCell();
    +      tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
    +      strcpy ( tmp->name, name );
    +      return tmp;
    +   } else {
    +      Cell *tmp = root;
    +      while (tmp->link != NULL) tmp = tmp->link;
    +      tmp->link = snocString ( tmp->link, name );
    +      return root;
    +   }
    +}
    +
    +
    +/*---------------------------------------------*/
    +static 
    +void addFlagsFromEnvVar ( Cell** argList, Char* varName ) 
    +{
    +   Int32 i, j, k;
    +   Char *envbase, *p;
    +
    +   envbase = getenv(varName);
    +   if (envbase != NULL) {
    +      p = envbase;
    +      i = 0;
    +      while (True) {
    +         if (p[i] == 0) break;
    +         p += i;
    +         i = 0;
    +         while (isspace((Int32)(p[0]))) p++;
    +         while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
    +         if (i > 0) {
    +            k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
    +            for (j = 0; j < k; j++) tmpName[j] = p[j];
    +            tmpName[k] = 0;
    +            APPEND_FLAG(*argList, tmpName);
    +         }
    +      }
    +   }
    +}
    +
    +
    +/*---------------------------------------------*/
    +#define ISFLAG(s) (strcmp(aa->name, (s))==0)
    +
    +IntNative main ( IntNative argc, Char *argv[] )
    +{
    +   Int32  i, j;
    +   Char   *tmp;
    +   Cell   *argList;
    +   Cell   *aa;
    +   Bool   decode;
    +
    +   /*-- Be really really really paranoid :-) --*/
    +   if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
    +       sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
    +       sizeof(Char)  != 1 || sizeof(UChar)  != 1)
    +      configError();
    +
    +   /*-- Initialise --*/
    +   outputHandleJustInCase  = NULL;
    +   smallMode               = False;
    +   keepInputFiles          = False;
    +   forceOverwrite          = False;
    +   noisy                   = True;
    +   verbosity               = 0;
    +   blockSize100k           = 9;
    +   testFailsExist          = False;
    +   unzFailsExist           = False;
    +   numFileNames            = 0;
    +   numFilesProcessed       = 0;
    +   workFactor              = 30;
    +   deleteOutputOnInterrupt = False;
    +   exitValue               = 0;
    +   i = j = 0; /* avoid bogus warning from egcs-1.1.X */
    +
    +   /*-- Set up signal handlers for mem access errors --*/
    +   signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
    +#  if BZ_UNIX
    +#  ifndef __DJGPP__
    +   signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
    +#  endif
    +#  endif
    +
    +   copyFileName ( inName,  (Char*)"(none)" );
    +   copyFileName ( outName, (Char*)"(none)" );
    +
    +   copyFileName ( progNameReally, argv[0] );
    +   progName = &progNameReally[0];
    +   for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
    +      if (*tmp == PATH_SEP) progName = tmp + 1;
    +
    +
    +   /*-- Copy flags from env var BZIP2, and 
    +        expand filename wildcards in arg list.
    +   --*/
    +   argList = NULL;
    +   addFlagsFromEnvVar ( &argList,  (Char*)"BZIP2" );
    +   addFlagsFromEnvVar ( &argList,  (Char*)"BZIP" );
    +   for (i = 1; i <= argc-1; i++)
    +      APPEND_FILESPEC(argList, argv[i]);
    +
    +
    +   /*-- Find the length of the longest filename --*/
    +   longestFileName = 7;
    +   numFileNames    = 0;
    +   decode          = True;
    +   for (aa = argList; aa != NULL; aa = aa->link) {
    +      if (ISFLAG("--")) { decode = False; continue; }
    +      if (aa->name[0] == '-' && decode) continue;
    +      numFileNames++;
    +      if (longestFileName < (Int32)strlen(aa->name) )
    +         longestFileName = (Int32)strlen(aa->name);
    +   }
    +
    +
    +   /*-- Determine source modes; flag handling may change this too. --*/
    +   if (numFileNames == 0)
    +      srcMode = SM_I2O; else srcMode = SM_F2F;
    +
    +
    +   /*-- Determine what to do (compress/uncompress/test/cat). --*/
    +   /*-- Note that subsequent flag handling may change this. --*/
    +   opMode = OM_Z;
    +
    +   if ( (strstr ( progName, "unzip" ) != 0) ||
    +        (strstr ( progName, "UNZIP" ) != 0) )
    +      opMode = OM_UNZ;
    +
    +   if ( (strstr ( progName, "z2cat" ) != 0) ||
    +        (strstr ( progName, "Z2CAT" ) != 0) ||
    +        (strstr ( progName, "zcat" ) != 0)  ||
    +        (strstr ( progName, "ZCAT" ) != 0) )  {
    +      opMode = OM_UNZ;
    +      srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
    +   }
    +
    +
    +   /*-- Look at the flags. --*/
    +   for (aa = argList; aa != NULL; aa = aa->link) {
    +      if (ISFLAG("--")) break;
    +      if (aa->name[0] == '-' && aa->name[1] != '-') {
    +         for (j = 1; aa->name[j] != '\0'; j++) {
    +            switch (aa->name[j]) {
    +               case 'c': srcMode          = SM_F2O; break;
    +               case 'd': opMode           = OM_UNZ; break;
    +               case 'z': opMode           = OM_Z; break;
    +               case 'f': forceOverwrite   = True; break;
    +               case 't': opMode           = OM_TEST; break;
    +               case 'k': keepInputFiles   = True; break;
    +               case 's': smallMode        = True; break;
    +               case 'q': noisy            = False; break;
    +               case '1': blockSize100k    = 1; break;
    +               case '2': blockSize100k    = 2; break;
    +               case '3': blockSize100k    = 3; break;
    +               case '4': blockSize100k    = 4; break;
    +               case '5': blockSize100k    = 5; break;
    +               case '6': blockSize100k    = 6; break;
    +               case '7': blockSize100k    = 7; break;
    +               case '8': blockSize100k    = 8; break;
    +               case '9': blockSize100k    = 9; break;
    +               case 'V':
    +               case 'L': license();            break;
    +               case 'v': verbosity++; break;
    +               case 'h': usage ( progName );
    +                         exit ( 0 );
    +                         break;
    +               default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
    +                                   progName, aa->name );
    +                         usage ( progName );
    +                         exit ( 1 );
    +                         break;
    +            }
    +         }
    +      }
    +   }
    +   
    +   /*-- And again ... --*/
    +   for (aa = argList; aa != NULL; aa = aa->link) {
    +      if (ISFLAG("--")) break;
    +      if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
    +      if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
    +      if (ISFLAG("--compress"))          opMode           = OM_Z;    else
    +      if (ISFLAG("--force"))             forceOverwrite   = True;    else
    +      if (ISFLAG("--test"))              opMode           = OM_TEST; else
    +      if (ISFLAG("--keep"))              keepInputFiles   = True;    else
    +      if (ISFLAG("--small"))             smallMode        = True;    else
    +      if (ISFLAG("--quiet"))             noisy            = False;   else
    +      if (ISFLAG("--version"))           license();                  else
    +      if (ISFLAG("--license"))           license();                  else
    +      if (ISFLAG("--exponential"))       workFactor = 1;             else 
    +      if (ISFLAG("--repetitive-best"))   redundant(aa->name);        else
    +      if (ISFLAG("--repetitive-fast"))   redundant(aa->name);        else
    +      if (ISFLAG("--fast"))              blockSize100k = 1;          else
    +      if (ISFLAG("--best"))              blockSize100k = 9;          else
    +      if (ISFLAG("--verbose"))           verbosity++;                else
    +      if (ISFLAG("--help"))              { usage ( progName ); exit ( 0 ); }
    +         else
    +         if (strncmp ( aa->name, "--", 2) == 0) {
    +            fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
    +            usage ( progName );
    +            exit ( 1 );
    +         }
    +   }
    +
    +   if (verbosity > 4) verbosity = 4;
    +   if (opMode == OM_Z && smallMode && blockSize100k > 2) 
    +      blockSize100k = 2;
    +
    +   if (opMode == OM_TEST && srcMode == SM_F2O) {
    +      fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
    +                progName );
    +      exit ( 1 );
    +   }
    +
    +   if (srcMode == SM_F2O && numFileNames == 0)
    +      srcMode = SM_I2O;
    +
    +   if (opMode != OM_Z) blockSize100k = 0;
    +
    +   if (srcMode == SM_F2F) {
    +      signal (SIGINT,  mySignalCatcher);
    +      signal (SIGTERM, mySignalCatcher);
    +#     if BZ_UNIX
    +      signal (SIGHUP,  mySignalCatcher);
    +#     endif
    +   }
    +
    +   if (opMode == OM_Z) {
    +     if (srcMode == SM_I2O) {
    +        compress ( NULL );
    +     } else {
    +        decode = True;
    +        for (aa = argList; aa != NULL; aa = aa->link) {
    +           if (ISFLAG("--")) { decode = False; continue; }
    +           if (aa->name[0] == '-' && decode) continue;
    +           numFilesProcessed++;
    +           compress ( aa->name );
    +        }
    +     }
    +   } 
    +   else
    +
    +   if (opMode == OM_UNZ) {
    +      unzFailsExist = False;
    +      if (srcMode == SM_I2O) {
    +         uncompress ( NULL );
    +      } else {
    +         decode = True;
    +         for (aa = argList; aa != NULL; aa = aa->link) {
    +            if (ISFLAG("--")) { decode = False; continue; }
    +            if (aa->name[0] == '-' && decode) continue;
    +            numFilesProcessed++;
    +            uncompress ( aa->name );
    +         }      
    +      }
    +      if (unzFailsExist) { 
    +         setExit(2); 
    +         exit(exitValue);
    +      }
    +   } 
    +
    +   else {
    +      testFailsExist = False;
    +      if (srcMode == SM_I2O) {
    +         testf ( NULL );
    +      } else {
    +         decode = True;
    +         for (aa = argList; aa != NULL; aa = aa->link) {
    +	    if (ISFLAG("--")) { decode = False; continue; }
    +            if (aa->name[0] == '-' && decode) continue;
    +            numFilesProcessed++;
    +            testf ( aa->name );
    +	 }
    +      }
    +      if (testFailsExist) {
    +	 if (noisy) {
    +            fprintf ( stderr,
    +               "\n"
    +               "You can use the `bzip2recover' program to attempt to recover\n"
    +               "data from undamaged sections of corrupted files.\n\n"
    +            );
    +	 }
    +         setExit(2);
    +         exit(exitValue);
    +      }
    +   }
    +
    +   /* Free the argument list memory to mollify leak detectors 
    +      (eg) Purify, Checker.  Serves no other useful purpose.
    +   */
    +   aa = argList;
    +   while (aa != NULL) {
    +      Cell* aa2 = aa->link;
    +      if (aa->name != NULL) free(aa->name);
    +      free(aa);
    +      aa = aa2;
    +   }
    +
    +   return exitValue;
    +}
    +
    +
    +/*-----------------------------------------------------------*/
    +/*--- end                                         bzip2.c ---*/
    +/*-----------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2recover.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2recover.c
    new file mode 100644
    index 00000000000..a8131e0611e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2recover.c
    @@ -0,0 +1,516 @@
    +/*-----------------------------------------------------------*/
    +/*--- Block recoverer program for bzip2                   ---*/
    +/*---                                      bzip2recover.c ---*/
    +/*-----------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +/* This program is a complete hack and should be rewritten properly.
    +	 It isn't very complicated. */
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +
    +/* This program records bit locations in the file to be recovered.
    +   That means that if 64-bit ints are not supported, we will not
    +   be able to recover .bz2 files over 512MB (2^32 bits) long.
    +   On GNU supported platforms, we take advantage of the 64-bit
    +   int support to circumvent this problem.  Ditto MSVC.
    +
    +   This change occurred in version 1.0.2; all prior versions have
    +   the 512MB limitation.
    +*/
    +#ifdef __GNUC__
    +   typedef  unsigned long long int  MaybeUInt64;
    +#  define MaybeUInt64_FMT "%Lu"
    +#else
    +#ifdef _MSC_VER
    +   typedef  unsigned __int64  MaybeUInt64;
    +#  define MaybeUInt64_FMT "%I64u"
    +#else
    +   typedef  unsigned int   MaybeUInt64;
    +#  define MaybeUInt64_FMT "%u"
    +#endif
    +#endif
    +
    +typedef  unsigned int   UInt32;
    +typedef  int            Int32;
    +typedef  unsigned char  UChar;
    +typedef  char           Char;
    +typedef  unsigned char  Bool;
    +#define True    ((Bool)1)
    +#define False   ((Bool)0)
    +
    +
    +#define BZ_MAX_FILENAME 2000
    +
    +Char inFileName[BZ_MAX_FILENAME];
    +Char outFileName[BZ_MAX_FILENAME];
    +Char progName[BZ_MAX_FILENAME];
    +
    +MaybeUInt64 bytesOut = 0;
    +MaybeUInt64 bytesIn  = 0;
    +
    +
    +/*---------------------------------------------------*/
    +/*--- Header bytes                                ---*/
    +/*---------------------------------------------------*/
    +
    +#define BZ_HDR_B 0x42                         /* 'B' */
    +#define BZ_HDR_Z 0x5a                         /* 'Z' */
    +#define BZ_HDR_h 0x68                         /* 'h' */
    +#define BZ_HDR_0 0x30                         /* '0' */
    + 
    +
    +/*---------------------------------------------------*/
    +/*--- I/O errors                                  ---*/
    +/*---------------------------------------------------*/
    +
    +/*---------------------------------------------*/
    +static void readError ( void )
    +{
    +   fprintf ( stderr,
    +             "%s: I/O error reading `%s', possible reason follows.\n",
    +            progName, inFileName );
    +   perror ( progName );
    +   fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
    +             progName );
    +   exit ( 1 );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static void writeError ( void )
    +{
    +   fprintf ( stderr,
    +             "%s: I/O error reading `%s', possible reason follows.\n",
    +            progName, inFileName );
    +   perror ( progName );
    +   fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
    +             progName );
    +   exit ( 1 );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static void mallocFail ( Int32 n )
    +{
    +   fprintf ( stderr,
    +             "%s: malloc failed on request for %d bytes.\n",
    +            progName, n );
    +   fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
    +             progName );
    +   exit ( 1 );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static void tooManyBlocks ( Int32 max_handled_blocks )
    +{
    +   fprintf ( stderr,
    +             "%s: `%s' appears to contain more than %d blocks\n",
    +            progName, inFileName, max_handled_blocks );
    +   fprintf ( stderr,
    +             "%s: and cannot be handled.  To fix, increase\n",
    +             progName );
    +   fprintf ( stderr, 
    +             "%s: BZ_MAX_HANDLED_BLOCKS in bzip2recover.c, and recompile.\n",
    +             progName );
    +   exit ( 1 );
    +}
    +
    +
    +
    +/*---------------------------------------------------*/
    +/*--- Bit stream I/O                              ---*/
    +/*---------------------------------------------------*/
    +
    +typedef
    +   struct {
    +      FILE*  handle;
    +      Int32  buffer;
    +      Int32  buffLive;
    +      Char   mode;
    +   }
    +   BitStream;
    +
    +
    +/*---------------------------------------------*/
    +static BitStream* bsOpenReadStream ( FILE* stream )
    +{
    +   BitStream *bs = malloc ( sizeof(BitStream) );
    +   if (bs == NULL) mallocFail ( sizeof(BitStream) );
    +   bs->handle = stream;
    +   bs->buffer = 0;
    +   bs->buffLive = 0;
    +   bs->mode = 'r';
    +   return bs;
    +}
    +
    +
    +/*---------------------------------------------*/
    +static BitStream* bsOpenWriteStream ( FILE* stream )
    +{
    +   BitStream *bs = malloc ( sizeof(BitStream) );
    +   if (bs == NULL) mallocFail ( sizeof(BitStream) );
    +   bs->handle = stream;
    +   bs->buffer = 0;
    +   bs->buffLive = 0;
    +   bs->mode = 'w';
    +   return bs;
    +}
    +
    +
    +/*---------------------------------------------*/
    +static void bsPutBit ( BitStream* bs, Int32 bit )
    +{
    +   if (bs->buffLive == 8) {
    +      Int32 retVal = putc ( (UChar) bs->buffer, bs->handle );
    +      if (retVal == EOF) writeError();
    +      bytesOut++;
    +      bs->buffLive = 1;
    +      bs->buffer = bit & 0x1;
    +   } else {
    +      bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) );
    +      bs->buffLive++;
    +   };
    +}
    +
    +
    +/*---------------------------------------------*/
    +/*--
    +   Returns 0 or 1, or 2 to indicate EOF.
    +--*/
    +static Int32 bsGetBit ( BitStream* bs )
    +{
    +   if (bs->buffLive > 0) {
    +      bs->buffLive --;
    +      return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 );
    +   } else {
    +      Int32 retVal = getc ( bs->handle );
    +      if ( retVal == EOF ) {
    +         if (errno != 0) readError();
    +         return 2;
    +      }
    +      bs->buffLive = 7;
    +      bs->buffer = retVal;
    +      return ( ((bs->buffer) >> 7) & 0x1 );
    +   }
    +}
    +
    +
    +/*---------------------------------------------*/
    +static void bsClose ( BitStream* bs )
    +{
    +   Int32 retVal;
    +
    +   if ( bs->mode == 'w' ) {
    +      while ( bs->buffLive < 8 ) {
    +         bs->buffLive++;
    +         bs->buffer <<= 1;
    +      };
    +      retVal = putc ( (UChar) (bs->buffer), bs->handle );
    +      if (retVal == EOF) writeError();
    +      bytesOut++;
    +      retVal = fflush ( bs->handle );
    +      if (retVal == EOF) writeError();
    +   }
    +   retVal = fclose ( bs->handle );
    +   if (retVal == EOF) {
    +      if (bs->mode == 'w') writeError(); else readError();
    +   }
    +   free ( bs );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static void bsPutUChar ( BitStream* bs, UChar c )
    +{
    +   Int32 i;
    +   for (i = 7; i >= 0; i--)
    +      bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static void bsPutUInt32 ( BitStream* bs, UInt32 c )
    +{
    +   Int32 i;
    +
    +   for (i = 31; i >= 0; i--)
    +      bsPutBit ( bs, (c >> i) & 0x1 );
    +}
    +
    +
    +/*---------------------------------------------*/
    +static Bool endsInBz2 ( Char* name )
    +{
    +   Int32 n = strlen ( name );
    +   if (n <= 4) return False;
    +   return
    +      (name[n-4] == '.' &&
    +       name[n-3] == 'b' &&
    +       name[n-2] == 'z' &&
    +       name[n-1] == '2');
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/*---                                             ---*/
    +/*---------------------------------------------------*/
    +
    +/* This logic isn't really right when it comes to Cygwin. */
    +#ifdef _WIN32
    +#  define  BZ_SPLIT_SYM  '\\'  /* path splitter on Windows platform */
    +#else
    +#  define  BZ_SPLIT_SYM  '/'   /* path splitter on Unix platform */
    +#endif
    +
    +#define BLOCK_HEADER_HI  0x00003141UL
    +#define BLOCK_HEADER_LO  0x59265359UL
    +
    +#define BLOCK_ENDMARK_HI 0x00001772UL
    +#define BLOCK_ENDMARK_LO 0x45385090UL
    +
    +/* Increase if necessary.  However, a .bz2 file with > 50000 blocks
    +   would have an uncompressed size of at least 40GB, so the chances
    +   are low you'll need to up this.
    +*/
    +#define BZ_MAX_HANDLED_BLOCKS 50000
    +
    +MaybeUInt64 bStart [BZ_MAX_HANDLED_BLOCKS];
    +MaybeUInt64 bEnd   [BZ_MAX_HANDLED_BLOCKS];
    +MaybeUInt64 rbStart[BZ_MAX_HANDLED_BLOCKS];
    +MaybeUInt64 rbEnd  [BZ_MAX_HANDLED_BLOCKS];
    +
    +Int32 main ( Int32 argc, Char** argv )
    +{
    +   FILE*       inFile;
    +   FILE*       outFile;
    +   BitStream*  bsIn, *bsWr;
    +   Int32       b, wrBlock, currBlock, rbCtr;
    +   MaybeUInt64 bitsRead;
    +
    +   UInt32      buffHi, buffLo, blockCRC;
    +   Char*       p;
    +
    +   strncpy ( progName, argv[0], BZ_MAX_FILENAME-1);
    +   progName[BZ_MAX_FILENAME-1]='\0';
    +   inFileName[0] = outFileName[0] = 0;
    +
    +   fprintf ( stderr, 
    +             "bzip2recover 1.0.8: extracts blocks from damaged .bz2 files.\n" );
    +
    +   if (argc != 2) {
    +      fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
    +                        progName, progName );
    +      switch (sizeof(MaybeUInt64)) {
    +         case 8:
    +            fprintf(stderr, 
    +                    "\trestrictions on size of recovered file: None\n");
    +            break;
    +         case 4:
    +            fprintf(stderr, 
    +                    "\trestrictions on size of recovered file: 512 MB\n");
    +            fprintf(stderr, 
    +                    "\tto circumvent, recompile with MaybeUInt64 as an\n"
    +                    "\tunsigned 64-bit int.\n");
    +            break;
    +         default:
    +            fprintf(stderr, 
    +                    "\tsizeof(MaybeUInt64) is not 4 or 8 -- "
    +                    "configuration error.\n");
    +            break;
    +      }
    +      exit(1);
    +   }
    +
    +   if (strlen(argv[1]) >= BZ_MAX_FILENAME-20) {
    +      fprintf ( stderr, 
    +                "%s: supplied filename is suspiciously (>= %d chars) long.  Bye!\n",
    +                progName, (int)strlen(argv[1]) );
    +      exit(1);
    +   }
    +
    +   strcpy ( inFileName, argv[1] );
    +
    +   inFile = fopen ( inFileName, "rb" );
    +   if (inFile == NULL) {
    +      fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName );
    +      exit(1);
    +   }
    +
    +   bsIn = bsOpenReadStream ( inFile );
    +   fprintf ( stderr, "%s: searching for block boundaries ...\n", progName );
    +
    +   bitsRead = 0;
    +   buffHi = buffLo = 0;
    +   currBlock = 0;
    +   bStart[currBlock] = 0;
    +
    +   rbCtr = 0;
    +
    +   while (True) {
    +      b = bsGetBit ( bsIn );
    +      bitsRead++;
    +      if (b == 2) {
    +         if (bitsRead >= bStart[currBlock] &&
    +            (bitsRead - bStart[currBlock]) >= 40) {
    +            bEnd[currBlock] = bitsRead-1;
    +            if (currBlock > 0)
    +               fprintf ( stderr, "   block %d runs from " MaybeUInt64_FMT 
    +                                 " to " MaybeUInt64_FMT " (incomplete)\n",
    +                         currBlock,  bStart[currBlock], bEnd[currBlock] );
    +         } else
    +            currBlock--;
    +         break;
    +      }
    +      buffHi = (buffHi << 1) | (buffLo >> 31);
    +      buffLo = (buffLo << 1) | (b & 1);
    +      if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI 
    +             && buffLo == BLOCK_HEADER_LO)
    +           || 
    +           ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI 
    +             && buffLo == BLOCK_ENDMARK_LO)
    +         ) {
    +         if (bitsRead > 49) {
    +            bEnd[currBlock] = bitsRead-49;
    +         } else {
    +            bEnd[currBlock] = 0;
    +         }
    +         if (currBlock > 0 &&
    +	     (bEnd[currBlock] - bStart[currBlock]) >= 130) {
    +            fprintf ( stderr, "   block %d runs from " MaybeUInt64_FMT 
    +                              " to " MaybeUInt64_FMT "\n",
    +                      rbCtr+1,  bStart[currBlock], bEnd[currBlock] );
    +            rbStart[rbCtr] = bStart[currBlock];
    +            rbEnd[rbCtr] = bEnd[currBlock];
    +            rbCtr++;
    +         }
    +         if (currBlock >= BZ_MAX_HANDLED_BLOCKS)
    +            tooManyBlocks(BZ_MAX_HANDLED_BLOCKS);
    +         currBlock++;
    +
    +         bStart[currBlock] = bitsRead;
    +      }
    +   }
    +
    +   bsClose ( bsIn );
    +
    +   /*-- identified blocks run from 1 to rbCtr inclusive. --*/
    +
    +   if (rbCtr < 1) {
    +      fprintf ( stderr,
    +                "%s: sorry, I couldn't find any block boundaries.\n",
    +                progName );
    +      exit(1);
    +   };
    +
    +   fprintf ( stderr, "%s: splitting into blocks\n", progName );
    +
    +   inFile = fopen ( inFileName, "rb" );
    +   if (inFile == NULL) {
    +      fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName );
    +      exit(1);
    +   }
    +   bsIn = bsOpenReadStream ( inFile );
    +
    +   /*-- placate gcc's dataflow analyser --*/
    +   blockCRC = 0; bsWr = 0;
    +
    +   bitsRead = 0;
    +   outFile = NULL;
    +   wrBlock = 0;
    +   while (True) {
    +      b = bsGetBit(bsIn);
    +      if (b == 2) break;
    +      buffHi = (buffHi << 1) | (buffLo >> 31);
    +      buffLo = (buffLo << 1) | (b & 1);
    +      if (bitsRead == 47+rbStart[wrBlock]) 
    +         blockCRC = (buffHi << 16) | (buffLo >> 16);
    +
    +      if (outFile != NULL && bitsRead >= rbStart[wrBlock]
    +                          && bitsRead <= rbEnd[wrBlock]) {
    +         bsPutBit ( bsWr, b );
    +      }
    +
    +      bitsRead++;
    +
    +      if (bitsRead == rbEnd[wrBlock]+1) {
    +         if (outFile != NULL) {
    +            bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 );
    +            bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 );
    +            bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 );
    +            bsPutUInt32 ( bsWr, blockCRC );
    +            bsClose ( bsWr );
    +            outFile = NULL;
    +         }
    +         if (wrBlock >= rbCtr) break;
    +         wrBlock++;
    +      } else
    +      if (bitsRead == rbStart[wrBlock]) {
    +         /* Create the output file name, correctly handling leading paths. 
    +            (31.10.2001 by Sergey E. Kusikov) */
    +         Char* split;
    +         Int32 ofs, k;
    +         for (k = 0; k < BZ_MAX_FILENAME; k++) 
    +            outFileName[k] = 0;
    +         strcpy (outFileName, inFileName);
    +         split = strrchr (outFileName, BZ_SPLIT_SYM);
    +         if (split == NULL) {
    +            split = outFileName;
    +         } else {
    +            ++split;
    +	 }
    +	 /* Now split points to the start of the basename. */
    +         ofs  = split - outFileName;
    +         sprintf (split, "rec%5d", wrBlock+1);
    +         for (p = split; *p != 0; p++) if (*p == ' ') *p = '0';
    +         strcat (outFileName, inFileName + ofs);
    +
    +         if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" );
    +
    +         fprintf ( stderr, "   writing block %d to `%s' ...\n",
    +                           wrBlock+1, outFileName );
    +
    +         outFile = fopen ( outFileName, "wb" );
    +         if (outFile == NULL) {
    +            fprintf ( stderr, "%s: can't write `%s'\n",
    +                      progName, outFileName );
    +            exit(1);
    +         }
    +         bsWr = bsOpenWriteStream ( outFile );
    +         bsPutUChar ( bsWr, BZ_HDR_B );    
    +         bsPutUChar ( bsWr, BZ_HDR_Z );    
    +         bsPutUChar ( bsWr, BZ_HDR_h );    
    +         bsPutUChar ( bsWr, BZ_HDR_0 + 9 );
    +         bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 );
    +         bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 );
    +         bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 );
    +      }
    +   }
    +
    +   fprintf ( stderr, "%s: finished\n", progName );
    +   return 0;
    +}
    +
    +
    +
    +/*-----------------------------------------------------------*/
    +/*--- end                                  bzip2recover.c ---*/
    +/*-----------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.c
    new file mode 100644
    index 00000000000..21786551b60
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.c
    @@ -0,0 +1,1572 @@
    +
    +/*-------------------------------------------------------------*/
    +/*--- Library top-level functions.                          ---*/
    +/*---                                               bzlib.c ---*/
    +/*-------------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +/* CHANGES
    +   0.9.0    -- original version.
    +   0.9.0a/b -- no changes in this file.
    +   0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
    +     fixed bzWrite/bzRead to ignore zero-length requests.
    +     fixed bzread to correctly handle read requests after EOF.
    +     wrong parameter order in call to bzDecompressInit in
    +     bzBuffToBuffDecompress.  Fixed.
    +*/
    +
    +#include "bzlib_private.h"
    +
    +
    +/*---------------------------------------------------*/
    +/*--- Compression stuff                           ---*/
    +/*---------------------------------------------------*/
    +
    +
    +/*---------------------------------------------------*/
    +#ifndef BZ_NO_STDIO
    +void BZ2_bz__AssertH__fail ( int errcode )
    +{
    +   fprintf(stderr, 
    +      "\n\nbzip2/libbzip2: internal error number %d.\n"
    +      "This is a bug in bzip2/libbzip2, %s.\n"
    +      "Please report it to: bzip2-devel@sourceware.org.  If this happened\n"
    +      "when you were using some program which uses libbzip2 as a\n"
    +      "component, you should also report this bug to the author(s)\n"
    +      "of that program.  Please make an effort to report this bug;\n"
    +      "timely and accurate bug reports eventually lead to higher\n"
    +      "quality software.  Thanks.\n\n",
    +      errcode,
    +      BZ2_bzlibVersion()
    +   );
    +
    +   if (errcode == 1007) {
    +   fprintf(stderr,
    +      "\n*** A special note about internal error number 1007 ***\n"
    +      "\n"
    +      "Experience suggests that a common cause of i.e. 1007\n"
    +      "is unreliable memory or other hardware.  The 1007 assertion\n"
    +      "just happens to cross-check the results of huge numbers of\n"
    +      "memory reads/writes, and so acts (unintendedly) as a stress\n"
    +      "test of your memory system.\n"
    +      "\n"
    +      "I suggest the following: try compressing the file again,\n"
    +      "possibly monitoring progress in detail with the -vv flag.\n"
    +      "\n"
    +      "* If the error cannot be reproduced, and/or happens at different\n"
    +      "  points in compression, you may have a flaky memory system.\n"
    +      "  Try a memory-test program.  I have used Memtest86\n"
    +      "  (www.memtest86.com).  At the time of writing it is free (GPLd).\n"
    +      "  Memtest86 tests memory much more thorougly than your BIOSs\n"
    +      "  power-on test, and may find failures that the BIOS doesn't.\n"
    +      "\n"
    +      "* If the error can be repeatably reproduced, this is a bug in\n"
    +      "  bzip2, and I would very much like to hear about it.  Please\n"
    +      "  let me know, and, ideally, save a copy of the file causing the\n"
    +      "  problem -- without which I will be unable to investigate it.\n"
    +      "\n"
    +   );
    +   }
    +
    +   exit(3);
    +}
    +#endif
    +
    +
    +/*---------------------------------------------------*/
    +static
    +int bz_config_ok ( void )
    +{
    +   if (sizeof(int)   != 4) return 0;
    +   if (sizeof(short) != 2) return 0;
    +   if (sizeof(char)  != 1) return 0;
    +   return 1;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
    +{
    +   void* v = malloc ( items * size );
    +   return v;
    +}
    +
    +static
    +void default_bzfree ( void* opaque, void* addr )
    +{
    +   if (addr != NULL) free ( addr );
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void prepare_new_block ( EState* s )
    +{
    +   Int32 i;
    +   s->nblock = 0;
    +   s->numZ = 0;
    +   s->state_out_pos = 0;
    +   BZ_INITIALISE_CRC ( s->blockCRC );
    +   for (i = 0; i < 256; i++) s->inUse[i] = False;
    +   s->blockNo++;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void init_RL ( EState* s )
    +{
    +   s->state_in_ch  = 256;
    +   s->state_in_len = 0;
    +}
    +
    +
    +static
    +Bool isempty_RL ( EState* s )
    +{
    +   if (s->state_in_ch < 256 && s->state_in_len > 0)
    +      return False; else
    +      return True;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzCompressInit) 
    +                    ( bz_stream* strm, 
    +                     int        blockSize100k,
    +                     int        verbosity,
    +                     int        workFactor )
    +{
    +   Int32   n;
    +   EState* s;
    +
    +   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
    +
    +   if (strm == NULL || 
    +       blockSize100k < 1 || blockSize100k > 9 ||
    +       workFactor < 0 || workFactor > 250)
    +     return BZ_PARAM_ERROR;
    +
    +   if (workFactor == 0) workFactor = 30;
    +   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
    +   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
    +
    +   s = BZALLOC( sizeof(EState) );
    +   if (s == NULL) return BZ_MEM_ERROR;
    +   s->strm = strm;
    +
    +   s->arr1 = NULL;
    +   s->arr2 = NULL;
    +   s->ftab = NULL;
    +
    +   n       = 100000 * blockSize100k;
    +   s->arr1 = BZALLOC( n                  * sizeof(UInt32) );
    +   s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
    +   s->ftab = BZALLOC( 65537              * sizeof(UInt32) );
    +
    +   if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
    +      if (s->arr1 != NULL) BZFREE(s->arr1);
    +      if (s->arr2 != NULL) BZFREE(s->arr2);
    +      if (s->ftab != NULL) BZFREE(s->ftab);
    +      if (s       != NULL) BZFREE(s);
    +      return BZ_MEM_ERROR;
    +   }
    +
    +   s->blockNo           = 0;
    +   s->state             = BZ_S_INPUT;
    +   s->mode              = BZ_M_RUNNING;
    +   s->combinedCRC       = 0;
    +   s->blockSize100k     = blockSize100k;
    +   s->nblockMAX         = 100000 * blockSize100k - 19;
    +   s->verbosity         = verbosity;
    +   s->workFactor        = workFactor;
    +
    +   s->block             = (UChar*)s->arr2;
    +   s->mtfv              = (UInt16*)s->arr1;
    +   s->zbits             = NULL;
    +   s->ptr               = (UInt32*)s->arr1;
    +
    +   strm->state          = s;
    +   strm->total_in_lo32  = 0;
    +   strm->total_in_hi32  = 0;
    +   strm->total_out_lo32 = 0;
    +   strm->total_out_hi32 = 0;
    +   init_RL ( s );
    +   prepare_new_block ( s );
    +   return BZ_OK;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void add_pair_to_block ( EState* s )
    +{
    +   Int32 i;
    +   UChar ch = (UChar)(s->state_in_ch);
    +   for (i = 0; i < s->state_in_len; i++) {
    +      BZ_UPDATE_CRC( s->blockCRC, ch );
    +   }
    +   s->inUse[s->state_in_ch] = True;
    +   switch (s->state_in_len) {
    +      case 1:
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         break;
    +      case 2:
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         break;
    +      case 3:
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         break;
    +      default:
    +         s->inUse[s->state_in_len-4] = True;
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         s->block[s->nblock] = (UChar)ch; s->nblock++;
    +         s->block[s->nblock] = ((UChar)(s->state_in_len-4));
    +         s->nblock++;
    +         break;
    +   }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void flush_RL ( EState* s )
    +{
    +   if (s->state_in_ch < 256) add_pair_to_block ( s );
    +   init_RL ( s );
    +}
    +
    +
    +/*---------------------------------------------------*/
    +#define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
    +{                                                 \
    +   UInt32 zchh = (UInt32)(zchh0);                 \
    +   /*-- fast track the common case --*/           \
    +   if (zchh != zs->state_in_ch &&                 \
    +       zs->state_in_len == 1) {                   \
    +      UChar ch = (UChar)(zs->state_in_ch);        \
    +      BZ_UPDATE_CRC( zs->blockCRC, ch );          \
    +      zs->inUse[zs->state_in_ch] = True;          \
    +      zs->block[zs->nblock] = (UChar)ch;          \
    +      zs->nblock++;                               \
    +      zs->state_in_ch = zchh;                     \
    +   }                                              \
    +   else                                           \
    +   /*-- general, uncommon cases --*/              \
    +   if (zchh != zs->state_in_ch ||                 \
    +      zs->state_in_len == 255) {                  \
    +      if (zs->state_in_ch < 256)                  \
    +         add_pair_to_block ( zs );                \
    +      zs->state_in_ch = zchh;                     \
    +      zs->state_in_len = 1;                       \
    +   } else {                                       \
    +      zs->state_in_len++;                         \
    +   }                                              \
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +Bool copy_input_until_stop ( EState* s )
    +{
    +   Bool progress_in = False;
    +
    +   if (s->mode == BZ_M_RUNNING) {
    +
    +      /*-- fast track the common case --*/
    +      while (True) {
    +         /*-- block full? --*/
    +         if (s->nblock >= s->nblockMAX) break;
    +         /*-- no input? --*/
    +         if (s->strm->avail_in == 0) break;
    +         progress_in = True;
    +         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
    +         s->strm->next_in++;
    +         s->strm->avail_in--;
    +         s->strm->total_in_lo32++;
    +         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
    +      }
    +
    +   } else {
    +
    +      /*-- general, uncommon case --*/
    +      while (True) {
    +         /*-- block full? --*/
    +         if (s->nblock >= s->nblockMAX) break;
    +         /*-- no input? --*/
    +         if (s->strm->avail_in == 0) break;
    +         /*-- flush/finish end? --*/
    +         if (s->avail_in_expect == 0) break;
    +         progress_in = True;
    +         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
    +         s->strm->next_in++;
    +         s->strm->avail_in--;
    +         s->strm->total_in_lo32++;
    +         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
    +         s->avail_in_expect--;
    +      }
    +   }
    +   return progress_in;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +Bool copy_output_until_stop ( EState* s )
    +{
    +   Bool progress_out = False;
    +
    +   while (True) {
    +
    +      /*-- no output space? --*/
    +      if (s->strm->avail_out == 0) break;
    +
    +      /*-- block done? --*/
    +      if (s->state_out_pos >= s->numZ) break;
    +
    +      progress_out = True;
    +      *(s->strm->next_out) = s->zbits[s->state_out_pos];
    +      s->state_out_pos++;
    +      s->strm->avail_out--;
    +      s->strm->next_out++;
    +      s->strm->total_out_lo32++;
    +      if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
    +   }
    +
    +   return progress_out;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +Bool handle_compress ( bz_stream* strm )
    +{
    +   Bool progress_in  = False;
    +   Bool progress_out = False;
    +   EState* s = strm->state;
    +   
    +   while (True) {
    +
    +      if (s->state == BZ_S_OUTPUT) {
    +         progress_out |= copy_output_until_stop ( s );
    +         if (s->state_out_pos < s->numZ) break;
    +         if (s->mode == BZ_M_FINISHING && 
    +             s->avail_in_expect == 0 &&
    +             isempty_RL(s)) break;
    +         prepare_new_block ( s );
    +         s->state = BZ_S_INPUT;
    +         if (s->mode == BZ_M_FLUSHING && 
    +             s->avail_in_expect == 0 &&
    +             isempty_RL(s)) break;
    +      }
    +
    +      if (s->state == BZ_S_INPUT) {
    +         progress_in |= copy_input_until_stop ( s );
    +         if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
    +            flush_RL ( s );
    +            BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
    +            s->state = BZ_S_OUTPUT;
    +         }
    +         else
    +         if (s->nblock >= s->nblockMAX) {
    +            BZ2_compressBlock ( s, False );
    +            s->state = BZ_S_OUTPUT;
    +         }
    +         else
    +         if (s->strm->avail_in == 0) {
    +            break;
    +         }
    +      }
    +
    +   }
    +
    +   return progress_in || progress_out;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
    +{
    +   Bool progress;
    +   EState* s;
    +   if (strm == NULL) return BZ_PARAM_ERROR;
    +   s = strm->state;
    +   if (s == NULL) return BZ_PARAM_ERROR;
    +   if (s->strm != strm) return BZ_PARAM_ERROR;
    +
    +   preswitch:
    +   switch (s->mode) {
    +
    +      case BZ_M_IDLE:
    +         return BZ_SEQUENCE_ERROR;
    +
    +      case BZ_M_RUNNING:
    +         if (action == BZ_RUN) {
    +            progress = handle_compress ( strm );
    +            return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
    +         } 
    +         else
    +	 if (action == BZ_FLUSH) {
    +            s->avail_in_expect = strm->avail_in;
    +            s->mode = BZ_M_FLUSHING;
    +            goto preswitch;
    +         }
    +         else
    +         if (action == BZ_FINISH) {
    +            s->avail_in_expect = strm->avail_in;
    +            s->mode = BZ_M_FINISHING;
    +            goto preswitch;
    +         }
    +         else 
    +            return BZ_PARAM_ERROR;
    +
    +      case BZ_M_FLUSHING:
    +         if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
    +         if (s->avail_in_expect != s->strm->avail_in) 
    +            return BZ_SEQUENCE_ERROR;
    +         progress = handle_compress ( strm );
    +         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
    +             s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
    +         s->mode = BZ_M_RUNNING;
    +         return BZ_RUN_OK;
    +
    +      case BZ_M_FINISHING:
    +         if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
    +         if (s->avail_in_expect != s->strm->avail_in) 
    +            return BZ_SEQUENCE_ERROR;
    +         progress = handle_compress ( strm );
    +         if (!progress) return BZ_SEQUENCE_ERROR;
    +         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
    +             s->state_out_pos < s->numZ) return BZ_FINISH_OK;
    +         s->mode = BZ_M_IDLE;
    +         return BZ_STREAM_END;
    +   }
    +   return BZ_OK; /*--not reached--*/
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzCompressEnd)  ( bz_stream *strm )
    +{
    +   EState* s;
    +   if (strm == NULL) return BZ_PARAM_ERROR;
    +   s = strm->state;
    +   if (s == NULL) return BZ_PARAM_ERROR;
    +   if (s->strm != strm) return BZ_PARAM_ERROR;
    +
    +   if (s->arr1 != NULL) BZFREE(s->arr1);
    +   if (s->arr2 != NULL) BZFREE(s->arr2);
    +   if (s->ftab != NULL) BZFREE(s->ftab);
    +   BZFREE(strm->state);
    +
    +   strm->state = NULL;   
    +
    +   return BZ_OK;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/*--- Decompression stuff                         ---*/
    +/*---------------------------------------------------*/
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzDecompressInit) 
    +                     ( bz_stream* strm, 
    +                       int        verbosity,
    +                       int        small )
    +{
    +   DState* s;
    +
    +   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
    +
    +   if (strm == NULL) return BZ_PARAM_ERROR;
    +   if (small != 0 && small != 1) return BZ_PARAM_ERROR;
    +   if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
    +
    +   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
    +   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
    +
    +   s = BZALLOC( sizeof(DState) );
    +   if (s == NULL) return BZ_MEM_ERROR;
    +   s->strm                  = strm;
    +   strm->state              = s;
    +   s->state                 = BZ_X_MAGIC_1;
    +   s->bsLive                = 0;
    +   s->bsBuff                = 0;
    +   s->calculatedCombinedCRC = 0;
    +   strm->total_in_lo32      = 0;
    +   strm->total_in_hi32      = 0;
    +   strm->total_out_lo32     = 0;
    +   strm->total_out_hi32     = 0;
    +   s->smallDecompress       = (Bool)small;
    +   s->ll4                   = NULL;
    +   s->ll16                  = NULL;
    +   s->tt                    = NULL;
    +   s->currBlockNo           = 0;
    +   s->verbosity             = verbosity;
    +
    +   return BZ_OK;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/* Return  True iff data corruption is discovered.
    +   Returns False if there is no problem.
    +*/
    +static
    +Bool unRLE_obuf_to_output_FAST ( DState* s )
    +{
    +   UChar k1;
    +
    +   if (s->blockRandomised) {
    +
    +      while (True) {
    +         /* try to finish existing run */
    +         while (True) {
    +            if (s->strm->avail_out == 0) return False;
    +            if (s->state_out_len == 0) break;
    +            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
    +            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
    +            s->state_out_len--;
    +            s->strm->next_out++;
    +            s->strm->avail_out--;
    +            s->strm->total_out_lo32++;
    +            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
    +         }
    +
    +         /* can a new run be started? */
    +         if (s->nblock_used == s->save_nblock+1) return False;
    +               
    +         /* Only caused by corrupt data stream? */
    +         if (s->nblock_used > s->save_nblock+1)
    +            return True;
    +   
    +         s->state_out_len = 1;
    +         s->state_out_ch = s->k0;
    +         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
    +         k1 ^= BZ_RAND_MASK; s->nblock_used++;
    +         if (s->nblock_used == s->save_nblock+1) continue;
    +         if (k1 != s->k0) { s->k0 = k1; continue; };
    +   
    +         s->state_out_len = 2;
    +         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
    +         k1 ^= BZ_RAND_MASK; s->nblock_used++;
    +         if (s->nblock_used == s->save_nblock+1) continue;
    +         if (k1 != s->k0) { s->k0 = k1; continue; };
    +   
    +         s->state_out_len = 3;
    +         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
    +         k1 ^= BZ_RAND_MASK; s->nblock_used++;
    +         if (s->nblock_used == s->save_nblock+1) continue;
    +         if (k1 != s->k0) { s->k0 = k1; continue; };
    +   
    +         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
    +         k1 ^= BZ_RAND_MASK; s->nblock_used++;
    +         s->state_out_len = ((Int32)k1) + 4;
    +         BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; 
    +         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
    +      }
    +
    +   } else {
    +
    +      /* restore */
    +      UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
    +      UChar         c_state_out_ch       = s->state_out_ch;
    +      Int32         c_state_out_len      = s->state_out_len;
    +      Int32         c_nblock_used        = s->nblock_used;
    +      Int32         c_k0                 = s->k0;
    +      UInt32*       c_tt                 = s->tt;
    +      UInt32        c_tPos               = s->tPos;
    +      char*         cs_next_out          = s->strm->next_out;
    +      unsigned int  cs_avail_out         = s->strm->avail_out;
    +      Int32         ro_blockSize100k     = s->blockSize100k;
    +      /* end restore */
    +
    +      UInt32       avail_out_INIT = cs_avail_out;
    +      Int32        s_save_nblockPP = s->save_nblock+1;
    +      unsigned int total_out_lo32_old;
    +
    +      while (True) {
    +
    +         /* try to finish existing run */
    +         if (c_state_out_len > 0) {
    +            while (True) {
    +               if (cs_avail_out == 0) goto return_notr;
    +               if (c_state_out_len == 1) break;
    +               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
    +               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
    +               c_state_out_len--;
    +               cs_next_out++;
    +               cs_avail_out--;
    +            }
    +            s_state_out_len_eq_one:
    +            {
    +               if (cs_avail_out == 0) { 
    +                  c_state_out_len = 1; goto return_notr;
    +               };
    +               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
    +               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
    +               cs_next_out++;
    +               cs_avail_out--;
    +            }
    +         }   
    +         /* Only caused by corrupt data stream? */
    +         if (c_nblock_used > s_save_nblockPP)
    +            return True;
    +
    +         /* can a new run be started? */
    +         if (c_nblock_used == s_save_nblockPP) {
    +            c_state_out_len = 0; goto return_notr;
    +         };   
    +         c_state_out_ch = c_k0;
    +         BZ_GET_FAST_C(k1); c_nblock_used++;
    +         if (k1 != c_k0) { 
    +            c_k0 = k1; goto s_state_out_len_eq_one; 
    +         };
    +         if (c_nblock_used == s_save_nblockPP) 
    +            goto s_state_out_len_eq_one;
    +   
    +         c_state_out_len = 2;
    +         BZ_GET_FAST_C(k1); c_nblock_used++;
    +         if (c_nblock_used == s_save_nblockPP) continue;
    +         if (k1 != c_k0) { c_k0 = k1; continue; };
    +   
    +         c_state_out_len = 3;
    +         BZ_GET_FAST_C(k1); c_nblock_used++;
    +         if (c_nblock_used == s_save_nblockPP) continue;
    +         if (k1 != c_k0) { c_k0 = k1; continue; };
    +   
    +         BZ_GET_FAST_C(k1); c_nblock_used++;
    +         c_state_out_len = ((Int32)k1) + 4;
    +         BZ_GET_FAST_C(c_k0); c_nblock_used++;
    +      }
    +
    +      return_notr:
    +      total_out_lo32_old = s->strm->total_out_lo32;
    +      s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
    +      if (s->strm->total_out_lo32 < total_out_lo32_old)
    +         s->strm->total_out_hi32++;
    +
    +      /* save */
    +      s->calculatedBlockCRC = c_calculatedBlockCRC;
    +      s->state_out_ch       = c_state_out_ch;
    +      s->state_out_len      = c_state_out_len;
    +      s->nblock_used        = c_nblock_used;
    +      s->k0                 = c_k0;
    +      s->tt                 = c_tt;
    +      s->tPos               = c_tPos;
    +      s->strm->next_out     = cs_next_out;
    +      s->strm->avail_out    = cs_avail_out;
    +      /* end save */
    +   }
    +   return False;
    +}
    +
    +
    +
    +/*---------------------------------------------------*/
    +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
    +{
    +   Int32 nb, na, mid;
    +   nb = 0;
    +   na = 256;
    +   do {
    +      mid = (nb + na) >> 1;
    +      if (indx >= cftab[mid]) nb = mid; else na = mid;
    +   }
    +   while (na - nb != 1);
    +   return nb;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/* Return  True iff data corruption is discovered.
    +   Returns False if there is no problem.
    +*/
    +static
    +Bool unRLE_obuf_to_output_SMALL ( DState* s )
    +{
    +   UChar k1;
    +
    +   if (s->blockRandomised) {
    +
    +      while (True) {
    +         /* try to finish existing run */
    +         while (True) {
    +            if (s->strm->avail_out == 0) return False;
    +            if (s->state_out_len == 0) break;
    +            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
    +            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
    +            s->state_out_len--;
    +            s->strm->next_out++;
    +            s->strm->avail_out--;
    +            s->strm->total_out_lo32++;
    +            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
    +         }
    +   
    +         /* can a new run be started? */
    +         if (s->nblock_used == s->save_nblock+1) return False;
    +
    +         /* Only caused by corrupt data stream? */
    +         if (s->nblock_used > s->save_nblock+1)
    +            return True;
    +   
    +         s->state_out_len = 1;
    +         s->state_out_ch = s->k0;
    +         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
    +         k1 ^= BZ_RAND_MASK; s->nblock_used++;
    +         if (s->nblock_used == s->save_nblock+1) continue;
    +         if (k1 != s->k0) { s->k0 = k1; continue; };
    +   
    +         s->state_out_len = 2;
    +         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
    +         k1 ^= BZ_RAND_MASK; s->nblock_used++;
    +         if (s->nblock_used == s->save_nblock+1) continue;
    +         if (k1 != s->k0) { s->k0 = k1; continue; };
    +   
    +         s->state_out_len = 3;
    +         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
    +         k1 ^= BZ_RAND_MASK; s->nblock_used++;
    +         if (s->nblock_used == s->save_nblock+1) continue;
    +         if (k1 != s->k0) { s->k0 = k1; continue; };
    +   
    +         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
    +         k1 ^= BZ_RAND_MASK; s->nblock_used++;
    +         s->state_out_len = ((Int32)k1) + 4;
    +         BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; 
    +         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
    +      }
    +
    +   } else {
    +
    +      while (True) {
    +         /* try to finish existing run */
    +         while (True) {
    +            if (s->strm->avail_out == 0) return False;
    +            if (s->state_out_len == 0) break;
    +            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
    +            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
    +            s->state_out_len--;
    +            s->strm->next_out++;
    +            s->strm->avail_out--;
    +            s->strm->total_out_lo32++;
    +            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
    +         }
    +   
    +         /* can a new run be started? */
    +         if (s->nblock_used == s->save_nblock+1) return False;
    +
    +         /* Only caused by corrupt data stream? */
    +         if (s->nblock_used > s->save_nblock+1)
    +            return True;
    +   
    +         s->state_out_len = 1;
    +         s->state_out_ch = s->k0;
    +         BZ_GET_SMALL(k1); s->nblock_used++;
    +         if (s->nblock_used == s->save_nblock+1) continue;
    +         if (k1 != s->k0) { s->k0 = k1; continue; };
    +   
    +         s->state_out_len = 2;
    +         BZ_GET_SMALL(k1); s->nblock_used++;
    +         if (s->nblock_used == s->save_nblock+1) continue;
    +         if (k1 != s->k0) { s->k0 = k1; continue; };
    +   
    +         s->state_out_len = 3;
    +         BZ_GET_SMALL(k1); s->nblock_used++;
    +         if (s->nblock_used == s->save_nblock+1) continue;
    +         if (k1 != s->k0) { s->k0 = k1; continue; };
    +   
    +         BZ_GET_SMALL(k1); s->nblock_used++;
    +         s->state_out_len = ((Int32)k1) + 4;
    +         BZ_GET_SMALL(s->k0); s->nblock_used++;
    +      }
    +
    +   }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
    +{
    +   Bool    corrupt;
    +   DState* s;
    +   if (strm == NULL) return BZ_PARAM_ERROR;
    +   s = strm->state;
    +   if (s == NULL) return BZ_PARAM_ERROR;
    +   if (s->strm != strm) return BZ_PARAM_ERROR;
    +
    +   while (True) {
    +      if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
    +      if (s->state == BZ_X_OUTPUT) {
    +         if (s->smallDecompress)
    +            corrupt = unRLE_obuf_to_output_SMALL ( s ); else
    +            corrupt = unRLE_obuf_to_output_FAST  ( s );
    +         if (corrupt) return BZ_DATA_ERROR;
    +         if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
    +            BZ_FINALISE_CRC ( s->calculatedBlockCRC );
    +            if (s->verbosity >= 3) 
    +               VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, 
    +                          s->calculatedBlockCRC );
    +            if (s->verbosity >= 2) VPrintf0 ( "]" );
    +            if (s->calculatedBlockCRC != s->storedBlockCRC)
    +               return BZ_DATA_ERROR;
    +            s->calculatedCombinedCRC 
    +               = (s->calculatedCombinedCRC << 1) | 
    +                    (s->calculatedCombinedCRC >> 31);
    +            s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
    +            s->state = BZ_X_BLKHDR_1;
    +         } else {
    +            return BZ_OK;
    +         }
    +      }
    +      if (s->state >= BZ_X_MAGIC_1) {
    +         Int32 r = BZ2_decompress ( s );
    +         if (r == BZ_STREAM_END) {
    +            if (s->verbosity >= 3)
    +               VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x", 
    +                          s->storedCombinedCRC, s->calculatedCombinedCRC );
    +            if (s->calculatedCombinedCRC != s->storedCombinedCRC)
    +               return BZ_DATA_ERROR;
    +            return r;
    +         }
    +         if (s->state != BZ_X_OUTPUT) return r;
    +      }
    +   }
    +
    +   AssertH ( 0, 6001 );
    +
    +   return 0;  /*NOTREACHED*/
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
    +{
    +   DState* s;
    +   if (strm == NULL) return BZ_PARAM_ERROR;
    +   s = strm->state;
    +   if (s == NULL) return BZ_PARAM_ERROR;
    +   if (s->strm != strm) return BZ_PARAM_ERROR;
    +
    +   if (s->tt   != NULL) BZFREE(s->tt);
    +   if (s->ll16 != NULL) BZFREE(s->ll16);
    +   if (s->ll4  != NULL) BZFREE(s->ll4);
    +
    +   BZFREE(strm->state);
    +   strm->state = NULL;
    +
    +   return BZ_OK;
    +}
    +
    +
    +#ifndef BZ_NO_STDIO
    +/*---------------------------------------------------*/
    +/*--- File I/O stuff                              ---*/
    +/*---------------------------------------------------*/
    +
    +#define BZ_SETERR(eee)                    \
    +{                                         \
    +   if (bzerror != NULL) *bzerror = eee;   \
    +   if (bzf != NULL) bzf->lastErr = eee;   \
    +}
    +
    +typedef 
    +   struct {
    +      FILE*     handle;
    +      Char      buf[BZ_MAX_UNUSED];
    +      Int32     bufN;
    +      Bool      writing;
    +      bz_stream strm;
    +      Int32     lastErr;
    +      Bool      initialisedOk;
    +   }
    +   bzFile;
    +
    +
    +/*---------------------------------------------*/
    +static Bool myfeof ( FILE* f )
    +{
    +   Int32 c = fgetc ( f );
    +   if (c == EOF) return True;
    +   ungetc ( c, f );
    +   return False;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +BZFILE* BZ_API(BZ2_bzWriteOpen) 
    +                    ( int*  bzerror,      
    +                      FILE* f, 
    +                      int   blockSize100k, 
    +                      int   verbosity,
    +                      int   workFactor )
    +{
    +   Int32   ret;
    +   bzFile* bzf = NULL;
    +
    +   BZ_SETERR(BZ_OK);
    +
    +   if (f == NULL ||
    +       (blockSize100k < 1 || blockSize100k > 9) ||
    +       (workFactor < 0 || workFactor > 250) ||
    +       (verbosity < 0 || verbosity > 4))
    +      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
    +
    +   if (ferror(f))
    +      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
    +
    +   bzf = malloc ( sizeof(bzFile) );
    +   if (bzf == NULL)
    +      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
    +
    +   BZ_SETERR(BZ_OK);
    +   bzf->initialisedOk = False;
    +   bzf->bufN          = 0;
    +   bzf->handle        = f;
    +   bzf->writing       = True;
    +   bzf->strm.bzalloc  = NULL;
    +   bzf->strm.bzfree   = NULL;
    +   bzf->strm.opaque   = NULL;
    +
    +   if (workFactor == 0) workFactor = 30;
    +   ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, 
    +                              verbosity, workFactor );
    +   if (ret != BZ_OK)
    +      { BZ_SETERR(ret); free(bzf); return NULL; };
    +
    +   bzf->strm.avail_in = 0;
    +   bzf->initialisedOk = True;
    +   return bzf;   
    +}
    +
    +
    +
    +/*---------------------------------------------------*/
    +void BZ_API(BZ2_bzWrite)
    +             ( int*    bzerror, 
    +               BZFILE* b, 
    +               void*   buf, 
    +               int     len )
    +{
    +   Int32 n, n2, ret;
    +   bzFile* bzf = (bzFile*)b;
    +
    +   BZ_SETERR(BZ_OK);
    +   if (bzf == NULL || buf == NULL || len < 0)
    +      { BZ_SETERR(BZ_PARAM_ERROR); return; };
    +   if (!(bzf->writing))
    +      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
    +   if (ferror(bzf->handle))
    +      { BZ_SETERR(BZ_IO_ERROR); return; };
    +
    +   if (len == 0)
    +      { BZ_SETERR(BZ_OK); return; };
    +
    +   bzf->strm.avail_in = len;
    +   bzf->strm.next_in  = buf;
    +
    +   while (True) {
    +      bzf->strm.avail_out = BZ_MAX_UNUSED;
    +      bzf->strm.next_out = bzf->buf;
    +      ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
    +      if (ret != BZ_RUN_OK)
    +         { BZ_SETERR(ret); return; };
    +
    +      if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
    +         n = BZ_MAX_UNUSED - bzf->strm.avail_out;
    +         n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
    +                       n, bzf->handle );
    +         if (n != n2 || ferror(bzf->handle))
    +            { BZ_SETERR(BZ_IO_ERROR); return; };
    +      }
    +
    +      if (bzf->strm.avail_in == 0)
    +         { BZ_SETERR(BZ_OK); return; };
    +   }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +void BZ_API(BZ2_bzWriteClose)
    +                  ( int*          bzerror, 
    +                    BZFILE*       b, 
    +                    int           abandon,
    +                    unsigned int* nbytes_in,
    +                    unsigned int* nbytes_out )
    +{
    +   BZ2_bzWriteClose64 ( bzerror, b, abandon, 
    +                        nbytes_in, NULL, nbytes_out, NULL );
    +}
    +
    +
    +void BZ_API(BZ2_bzWriteClose64)
    +                  ( int*          bzerror, 
    +                    BZFILE*       b, 
    +                    int           abandon,
    +                    unsigned int* nbytes_in_lo32,
    +                    unsigned int* nbytes_in_hi32,
    +                    unsigned int* nbytes_out_lo32,
    +                    unsigned int* nbytes_out_hi32 )
    +{
    +   Int32   n, n2, ret;
    +   bzFile* bzf = (bzFile*)b;
    +
    +   if (bzf == NULL)
    +      { BZ_SETERR(BZ_OK); return; };
    +   if (!(bzf->writing))
    +      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
    +   if (ferror(bzf->handle))
    +      { BZ_SETERR(BZ_IO_ERROR); return; };
    +
    +   if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
    +   if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
    +   if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
    +   if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
    +
    +   if ((!abandon) && bzf->lastErr == BZ_OK) {
    +      while (True) {
    +         bzf->strm.avail_out = BZ_MAX_UNUSED;
    +         bzf->strm.next_out = bzf->buf;
    +         ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
    +         if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
    +            { BZ_SETERR(ret); return; };
    +
    +         if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
    +            n = BZ_MAX_UNUSED - bzf->strm.avail_out;
    +            n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
    +                          n, bzf->handle );
    +            if (n != n2 || ferror(bzf->handle))
    +               { BZ_SETERR(BZ_IO_ERROR); return; };
    +         }
    +
    +         if (ret == BZ_STREAM_END) break;
    +      }
    +   }
    +
    +   if ( !abandon && !ferror ( bzf->handle ) ) {
    +      fflush ( bzf->handle );
    +      if (ferror(bzf->handle))
    +         { BZ_SETERR(BZ_IO_ERROR); return; };
    +   }
    +
    +   if (nbytes_in_lo32 != NULL)
    +      *nbytes_in_lo32 = bzf->strm.total_in_lo32;
    +   if (nbytes_in_hi32 != NULL)
    +      *nbytes_in_hi32 = bzf->strm.total_in_hi32;
    +   if (nbytes_out_lo32 != NULL)
    +      *nbytes_out_lo32 = bzf->strm.total_out_lo32;
    +   if (nbytes_out_hi32 != NULL)
    +      *nbytes_out_hi32 = bzf->strm.total_out_hi32;
    +
    +   BZ_SETERR(BZ_OK);
    +   BZ2_bzCompressEnd ( &(bzf->strm) );
    +   free ( bzf );
    +}
    +
    +
    +/*---------------------------------------------------*/
    +BZFILE* BZ_API(BZ2_bzReadOpen) 
    +                   ( int*  bzerror, 
    +                     FILE* f, 
    +                     int   verbosity,
    +                     int   small,
    +                     void* unused,
    +                     int   nUnused )
    +{
    +   bzFile* bzf = NULL;
    +   int     ret;
    +
    +   BZ_SETERR(BZ_OK);
    +
    +   if (f == NULL || 
    +       (small != 0 && small != 1) ||
    +       (verbosity < 0 || verbosity > 4) ||
    +       (unused == NULL && nUnused != 0) ||
    +       (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
    +      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
    +
    +   if (ferror(f))
    +      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
    +
    +   bzf = malloc ( sizeof(bzFile) );
    +   if (bzf == NULL) 
    +      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
    +
    +   BZ_SETERR(BZ_OK);
    +
    +   bzf->initialisedOk = False;
    +   bzf->handle        = f;
    +   bzf->bufN          = 0;
    +   bzf->writing       = False;
    +   bzf->strm.bzalloc  = NULL;
    +   bzf->strm.bzfree   = NULL;
    +   bzf->strm.opaque   = NULL;
    +   
    +   while (nUnused > 0) {
    +      bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
    +      unused = ((void*)( 1 + ((UChar*)(unused))  ));
    +      nUnused--;
    +   }
    +
    +   ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
    +   if (ret != BZ_OK)
    +      { BZ_SETERR(ret); free(bzf); return NULL; };
    +
    +   bzf->strm.avail_in = bzf->bufN;
    +   bzf->strm.next_in  = bzf->buf;
    +
    +   bzf->initialisedOk = True;
    +   return bzf;   
    +}
    +
    +
    +/*---------------------------------------------------*/
    +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
    +{
    +   bzFile* bzf = (bzFile*)b;
    +
    +   BZ_SETERR(BZ_OK);
    +   if (bzf == NULL)
    +      { BZ_SETERR(BZ_OK); return; };
    +
    +   if (bzf->writing)
    +      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
    +
    +   if (bzf->initialisedOk)
    +      (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
    +   free ( bzf );
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzRead) 
    +           ( int*    bzerror, 
    +             BZFILE* b, 
    +             void*   buf, 
    +             int     len )
    +{
    +   Int32   n, ret;
    +   bzFile* bzf = (bzFile*)b;
    +
    +   BZ_SETERR(BZ_OK);
    +
    +   if (bzf == NULL || buf == NULL || len < 0)
    +      { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
    +
    +   if (bzf->writing)
    +      { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
    +
    +   if (len == 0)
    +      { BZ_SETERR(BZ_OK); return 0; };
    +
    +   bzf->strm.avail_out = len;
    +   bzf->strm.next_out = buf;
    +
    +   while (True) {
    +
    +      if (ferror(bzf->handle)) 
    +         { BZ_SETERR(BZ_IO_ERROR); return 0; };
    +
    +      if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
    +         n = fread ( bzf->buf, sizeof(UChar), 
    +                     BZ_MAX_UNUSED, bzf->handle );
    +         if (ferror(bzf->handle))
    +            { BZ_SETERR(BZ_IO_ERROR); return 0; };
    +         bzf->bufN = n;
    +         bzf->strm.avail_in = bzf->bufN;
    +         bzf->strm.next_in = bzf->buf;
    +      }
    +
    +      ret = BZ2_bzDecompress ( &(bzf->strm) );
    +
    +      if (ret != BZ_OK && ret != BZ_STREAM_END)
    +         { BZ_SETERR(ret); return 0; };
    +
    +      if (ret == BZ_OK && myfeof(bzf->handle) && 
    +          bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
    +         { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
    +
    +      if (ret == BZ_STREAM_END)
    +         { BZ_SETERR(BZ_STREAM_END);
    +           return len - bzf->strm.avail_out; };
    +      if (bzf->strm.avail_out == 0)
    +         { BZ_SETERR(BZ_OK); return len; };
    +      
    +   }
    +
    +   return 0; /*not reached*/
    +}
    +
    +
    +/*---------------------------------------------------*/
    +void BZ_API(BZ2_bzReadGetUnused) 
    +                     ( int*    bzerror, 
    +                       BZFILE* b, 
    +                       void**  unused, 
    +                       int*    nUnused )
    +{
    +   bzFile* bzf = (bzFile*)b;
    +   if (bzf == NULL)
    +      { BZ_SETERR(BZ_PARAM_ERROR); return; };
    +   if (bzf->lastErr != BZ_STREAM_END)
    +      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
    +   if (unused == NULL || nUnused == NULL)
    +      { BZ_SETERR(BZ_PARAM_ERROR); return; };
    +
    +   BZ_SETERR(BZ_OK);
    +   *nUnused = bzf->strm.avail_in;
    +   *unused = bzf->strm.next_in;
    +}
    +#endif
    +
    +
    +/*---------------------------------------------------*/
    +/*--- Misc convenience stuff                      ---*/
    +/*---------------------------------------------------*/
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzBuffToBuffCompress) 
    +                         ( char*         dest, 
    +                           unsigned int* destLen,
    +                           char*         source, 
    +                           unsigned int  sourceLen,
    +                           int           blockSize100k, 
    +                           int           verbosity, 
    +                           int           workFactor )
    +{
    +   bz_stream strm;
    +   int ret;
    +
    +   if (dest == NULL || destLen == NULL || 
    +       source == NULL ||
    +       blockSize100k < 1 || blockSize100k > 9 ||
    +       verbosity < 0 || verbosity > 4 ||
    +       workFactor < 0 || workFactor > 250) 
    +      return BZ_PARAM_ERROR;
    +
    +   if (workFactor == 0) workFactor = 30;
    +   strm.bzalloc = NULL;
    +   strm.bzfree = NULL;
    +   strm.opaque = NULL;
    +   ret = BZ2_bzCompressInit ( &strm, blockSize100k, 
    +                              verbosity, workFactor );
    +   if (ret != BZ_OK) return ret;
    +
    +   strm.next_in = source;
    +   strm.next_out = dest;
    +   strm.avail_in = sourceLen;
    +   strm.avail_out = *destLen;
    +
    +   ret = BZ2_bzCompress ( &strm, BZ_FINISH );
    +   if (ret == BZ_FINISH_OK) goto output_overflow;
    +   if (ret != BZ_STREAM_END) goto errhandler;
    +
    +   /* normal termination */
    +   *destLen -= strm.avail_out;   
    +   BZ2_bzCompressEnd ( &strm );
    +   return BZ_OK;
    +
    +   output_overflow:
    +   BZ2_bzCompressEnd ( &strm );
    +   return BZ_OUTBUFF_FULL;
    +
    +   errhandler:
    +   BZ2_bzCompressEnd ( &strm );
    +   return ret;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzBuffToBuffDecompress) 
    +                           ( char*         dest, 
    +                             unsigned int* destLen,
    +                             char*         source, 
    +                             unsigned int  sourceLen,
    +                             int           small,
    +                             int           verbosity )
    +{
    +   bz_stream strm;
    +   int ret;
    +
    +   if (dest == NULL || destLen == NULL || 
    +       source == NULL ||
    +       (small != 0 && small != 1) ||
    +       verbosity < 0 || verbosity > 4) 
    +          return BZ_PARAM_ERROR;
    +
    +   strm.bzalloc = NULL;
    +   strm.bzfree = NULL;
    +   strm.opaque = NULL;
    +   ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
    +   if (ret != BZ_OK) return ret;
    +
    +   strm.next_in = source;
    +   strm.next_out = dest;
    +   strm.avail_in = sourceLen;
    +   strm.avail_out = *destLen;
    +
    +   ret = BZ2_bzDecompress ( &strm );
    +   if (ret == BZ_OK) goto output_overflow_or_eof;
    +   if (ret != BZ_STREAM_END) goto errhandler;
    +
    +   /* normal termination */
    +   *destLen -= strm.avail_out;
    +   BZ2_bzDecompressEnd ( &strm );
    +   return BZ_OK;
    +
    +   output_overflow_or_eof:
    +   if (strm.avail_out > 0) {
    +      BZ2_bzDecompressEnd ( &strm );
    +      return BZ_UNEXPECTED_EOF;
    +   } else {
    +      BZ2_bzDecompressEnd ( &strm );
    +      return BZ_OUTBUFF_FULL;
    +   };      
    +
    +   errhandler:
    +   BZ2_bzDecompressEnd ( &strm );
    +   return ret; 
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/*--
    +   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
    +   to support better zlib compatibility.
    +   This code is not _officially_ part of libbzip2 (yet);
    +   I haven't tested it, documented it, or considered the
    +   threading-safeness of it.
    +   If this code breaks, please contact both Yoshioka and me.
    +--*/
    +/*---------------------------------------------------*/
    +
    +/*---------------------------------------------------*/
    +/*--
    +   return version like "0.9.5d, 4-Sept-1999".
    +--*/
    +const char * BZ_API(BZ2_bzlibVersion)(void)
    +{
    +   return BZ_VERSION;
    +}
    +
    +
    +#ifndef BZ_NO_STDIO
    +/*---------------------------------------------------*/
    +
    +#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
    +#   include 
    +#   include 
    +#   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
    +#else
    +#   define SET_BINARY_MODE(file)
    +#endif
    +static
    +BZFILE * bzopen_or_bzdopen
    +               ( const char *path,   /* no use when bzdopen */
    +                 int fd,             /* no use when bzdopen */
    +                 const char *mode,
    +                 int open_mode)      /* bzopen: 0, bzdopen:1 */
    +{
    +   int    bzerr;
    +   char   unused[BZ_MAX_UNUSED];
    +   int    blockSize100k = 9;
    +   int    writing       = 0;
    +   char   mode2[10]     = "";
    +   FILE   *fp           = NULL;
    +   BZFILE *bzfp         = NULL;
    +   int    verbosity     = 0;
    +   int    workFactor    = 30;
    +   int    smallMode     = 0;
    +   int    nUnused       = 0; 
    +
    +   if (mode == NULL) return NULL;
    +   while (*mode) {
    +      switch (*mode) {
    +      case 'r':
    +         writing = 0; break;
    +      case 'w':
    +         writing = 1; break;
    +      case 's':
    +         smallMode = 1; break;
    +      default:
    +         if (isdigit((int)(*mode))) {
    +            blockSize100k = *mode-BZ_HDR_0;
    +         }
    +      }
    +      mode++;
    +   }
    +   strcat(mode2, writing ? "w" : "r" );
    +   strcat(mode2,"b");   /* binary mode */
    +
    +   if (open_mode==0) {
    +      if (path==NULL || strcmp(path,"")==0) {
    +        fp = (writing ? stdout : stdin);
    +        SET_BINARY_MODE(fp);
    +      } else {
    +        fp = fopen(path,mode2);
    +      }
    +   } else {
    +#ifdef BZ_STRICT_ANSI
    +      fp = NULL;
    +#else
    +      fp = fdopen(fd,mode2);
    +#endif
    +   }
    +   if (fp == NULL) return NULL;
    +
    +   if (writing) {
    +      /* Guard against total chaos and anarchy -- JRS */
    +      if (blockSize100k < 1) blockSize100k = 1;
    +      if (blockSize100k > 9) blockSize100k = 9; 
    +      bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
    +                             verbosity,workFactor);
    +   } else {
    +      bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
    +                            unused,nUnused);
    +   }
    +   if (bzfp == NULL) {
    +      if (fp != stdin && fp != stdout) fclose(fp);
    +      return NULL;
    +   }
    +   return bzfp;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/*--
    +   open file for read or write.
    +      ex) bzopen("file","w9")
    +      case path="" or NULL => use stdin or stdout.
    +--*/
    +BZFILE * BZ_API(BZ2_bzopen)
    +               ( const char *path,
    +                 const char *mode )
    +{
    +   return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
    +}
    +
    +
    +/*---------------------------------------------------*/
    +BZFILE * BZ_API(BZ2_bzdopen)
    +               ( int fd,
    +                 const char *mode )
    +{
    +   return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
    +{
    +   int bzerr, nread;
    +   if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
    +   nread = BZ2_bzRead(&bzerr,b,buf,len);
    +   if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
    +      return nread;
    +   } else {
    +      return -1;
    +   }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
    +{
    +   int bzerr;
    +
    +   BZ2_bzWrite(&bzerr,b,buf,len);
    +   if(bzerr == BZ_OK){
    +      return len;
    +   }else{
    +      return -1;
    +   }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +int BZ_API(BZ2_bzflush) (BZFILE *b)
    +{
    +   /* do nothing now... */
    +   return 0;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +void BZ_API(BZ2_bzclose) (BZFILE* b)
    +{
    +   int bzerr;
    +   FILE *fp;
    +   
    +   if (b==NULL) {return;}
    +   fp = ((bzFile *)b)->handle;
    +   if(((bzFile*)b)->writing){
    +      BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
    +      if(bzerr != BZ_OK){
    +         BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
    +      }
    +   }else{
    +      BZ2_bzReadClose(&bzerr,b);
    +   }
    +   if(fp!=stdin && fp!=stdout){
    +      fclose(fp);
    +   }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/*--
    +   return last error code 
    +--*/
    +static const char *bzerrorstrings[] = {
    +       "OK"
    +      ,"SEQUENCE_ERROR"
    +      ,"PARAM_ERROR"
    +      ,"MEM_ERROR"
    +      ,"DATA_ERROR"
    +      ,"DATA_ERROR_MAGIC"
    +      ,"IO_ERROR"
    +      ,"UNEXPECTED_EOF"
    +      ,"OUTBUFF_FULL"
    +      ,"CONFIG_ERROR"
    +      ,"???"   /* for future */
    +      ,"???"   /* for future */
    +      ,"???"   /* for future */
    +      ,"???"   /* for future */
    +      ,"???"   /* for future */
    +      ,"???"   /* for future */
    +};
    +
    +
    +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
    +{
    +   int err = ((bzFile *)b)->lastErr;
    +
    +   if(err>0) err = 0;
    +   *errnum = err;
    +   return bzerrorstrings[err*-1];
    +}
    +#endif
    +
    +
    +/*-------------------------------------------------------------*/
    +/*--- end                                           bzlib.c ---*/
    +/*-------------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.h b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.h
    new file mode 100644
    index 00000000000..b68a3f4c163
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.h
    @@ -0,0 +1,281 @@
    +
    +/*-------------------------------------------------------------*/
    +/*--- Public header file for the library.                   ---*/
    +/*---                                               bzlib.h ---*/
    +/*-------------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +#ifndef _BZLIB_H
    +#define _BZLIB_H
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +#define BZ_RUN               0
    +#define BZ_FLUSH             1
    +#define BZ_FINISH            2
    +
    +#define BZ_OK                0
    +#define BZ_RUN_OK            1
    +#define BZ_FLUSH_OK          2
    +#define BZ_FINISH_OK         3
    +#define BZ_STREAM_END        4
    +#define BZ_SEQUENCE_ERROR    (-1)
    +#define BZ_PARAM_ERROR       (-2)
    +#define BZ_MEM_ERROR         (-3)
    +#define BZ_DATA_ERROR        (-4)
    +#define BZ_DATA_ERROR_MAGIC  (-5)
    +#define BZ_IO_ERROR          (-6)
    +#define BZ_UNEXPECTED_EOF    (-7)
    +#define BZ_OUTBUFF_FULL      (-8)
    +#define BZ_CONFIG_ERROR      (-9)
    +
    +typedef 
    +   struct {
    +      char *next_in;
    +      unsigned int avail_in;
    +      unsigned int total_in_lo32;
    +      unsigned int total_in_hi32;
    +
    +      char *next_out;
    +      unsigned int avail_out;
    +      unsigned int total_out_lo32;
    +      unsigned int total_out_hi32;
    +
    +      void *state;
    +
    +      void *(*bzalloc)(void *,int,int);
    +      void (*bzfree)(void *,void *);
    +      void *opaque;
    +   } 
    +   bz_stream;
    +
    +
    +#ifndef BZ_IMPORT
    +#define BZ_EXPORT
    +#endif
    +
    +#ifndef BZ_NO_STDIO
    +/* Need a definitition for FILE */
    +#include 
    +#endif
    +
    +#ifdef _WIN32
    +#   include 
    +#   ifdef small
    +      /* windows.h define small to char */
    +#      undef small
    +#   endif
    +#   ifdef BZ_EXPORT
    +#   define BZ_API(func) WINAPI func
    +#   define BZ_EXTERN extern
    +#   else
    +   /* import windows dll dynamically */
    +#   define BZ_API(func) (WINAPI * func)
    +#   define BZ_EXTERN
    +#   endif
    +#else
    +#   define BZ_API(func) func
    +#   define BZ_EXTERN extern
    +#endif
    +
    +
    +/*-- Core (low-level) library functions --*/
    +
    +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( 
    +      bz_stream* strm, 
    +      int        blockSize100k, 
    +      int        verbosity, 
    +      int        workFactor 
    +   );
    +
    +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( 
    +      bz_stream* strm, 
    +      int action 
    +   );
    +
    +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( 
    +      bz_stream* strm 
    +   );
    +
    +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( 
    +      bz_stream *strm, 
    +      int       verbosity, 
    +      int       small
    +   );
    +
    +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( 
    +      bz_stream* strm 
    +   );
    +
    +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( 
    +      bz_stream *strm 
    +   );
    +
    +
    +
    +/*-- High(er) level library functions --*/
    +
    +#ifndef BZ_NO_STDIO
    +#define BZ_MAX_UNUSED 5000
    +
    +typedef void BZFILE;
    +
    +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( 
    +      int*  bzerror,   
    +      FILE* f, 
    +      int   verbosity, 
    +      int   small,
    +      void* unused,    
    +      int   nUnused 
    +   );
    +
    +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( 
    +      int*    bzerror, 
    +      BZFILE* b 
    +   );
    +
    +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( 
    +      int*    bzerror, 
    +      BZFILE* b, 
    +      void**  unused,  
    +      int*    nUnused 
    +   );
    +
    +BZ_EXTERN int BZ_API(BZ2_bzRead) ( 
    +      int*    bzerror, 
    +      BZFILE* b, 
    +      void*   buf, 
    +      int     len 
    +   );
    +
    +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( 
    +      int*  bzerror,      
    +      FILE* f, 
    +      int   blockSize100k, 
    +      int   verbosity, 
    +      int   workFactor 
    +   );
    +
    +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( 
    +      int*    bzerror, 
    +      BZFILE* b, 
    +      void*   buf, 
    +      int     len 
    +   );
    +
    +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( 
    +      int*          bzerror, 
    +      BZFILE*       b, 
    +      int           abandon, 
    +      unsigned int* nbytes_in, 
    +      unsigned int* nbytes_out 
    +   );
    +
    +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( 
    +      int*          bzerror, 
    +      BZFILE*       b, 
    +      int           abandon, 
    +      unsigned int* nbytes_in_lo32, 
    +      unsigned int* nbytes_in_hi32, 
    +      unsigned int* nbytes_out_lo32, 
    +      unsigned int* nbytes_out_hi32
    +   );
    +#endif
    +
    +
    +/*-- Utility functions --*/
    +
    +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( 
    +      char*         dest, 
    +      unsigned int* destLen,
    +      char*         source, 
    +      unsigned int  sourceLen,
    +      int           blockSize100k, 
    +      int           verbosity, 
    +      int           workFactor 
    +   );
    +
    +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( 
    +      char*         dest, 
    +      unsigned int* destLen,
    +      char*         source, 
    +      unsigned int  sourceLen,
    +      int           small, 
    +      int           verbosity 
    +   );
    +
    +
    +/*--
    +   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
    +   to support better zlib compatibility.
    +   This code is not _officially_ part of libbzip2 (yet);
    +   I haven't tested it, documented it, or considered the
    +   threading-safeness of it.
    +   If this code breaks, please contact both Yoshioka and me.
    +--*/
    +
    +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
    +      void
    +   );
    +
    +#ifndef BZ_NO_STDIO
    +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
    +      const char *path,
    +      const char *mode
    +   );
    +
    +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
    +      int        fd,
    +      const char *mode
    +   );
    +         
    +BZ_EXTERN int BZ_API(BZ2_bzread) (
    +      BZFILE* b, 
    +      void* buf, 
    +      int len 
    +   );
    +
    +BZ_EXTERN int BZ_API(BZ2_bzwrite) (
    +      BZFILE* b, 
    +      void*   buf, 
    +      int     len 
    +   );
    +
    +BZ_EXTERN int BZ_API(BZ2_bzflush) (
    +      BZFILE* b
    +   );
    +
    +BZ_EXTERN void BZ_API(BZ2_bzclose) (
    +      BZFILE* b
    +   );
    +
    +BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
    +      BZFILE *b, 
    +      int    *errnum
    +   );
    +#endif
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    +
    +/*-------------------------------------------------------------*/
    +/*--- end                                           bzlib.h ---*/
    +/*-------------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib_private.h b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib_private.h
    new file mode 100644
    index 00000000000..3755a6f701e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib_private.h
    @@ -0,0 +1,509 @@
    +
    +/*-------------------------------------------------------------*/
    +/*--- Private header file for the library.                  ---*/
    +/*---                                       bzlib_private.h ---*/
    +/*-------------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +
    +#ifndef _BZLIB_PRIVATE_H
    +#define _BZLIB_PRIVATE_H
    +
    +#include 
    +
    +#ifndef BZ_NO_STDIO
    +#include 
    +#include 
    +#include 
    +#endif
    +
    +#include "bzlib.h"
    +
    +
    +
    +/*-- General stuff. --*/
    +
    +#define BZ_VERSION  "1.0.8, 13-Jul-2019"
    +
    +typedef char            Char;
    +typedef unsigned char   Bool;
    +typedef unsigned char   UChar;
    +typedef int             Int32;
    +typedef unsigned int    UInt32;
    +typedef short           Int16;
    +typedef unsigned short  UInt16;
    +
    +#define True  ((Bool)1)
    +#define False ((Bool)0)
    +
    +#ifndef __GNUC__
    +#define __inline__  /* */
    +#endif 
    +
    +#ifndef BZ_NO_STDIO
    +
    +extern void BZ2_bz__AssertH__fail ( int errcode );
    +#define AssertH(cond,errcode) \
    +   { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
    +
    +#if BZ_DEBUG
    +#define AssertD(cond,msg) \
    +   { if (!(cond)) {       \
    +      fprintf ( stderr,   \
    +        "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
    +      exit(1); \
    +   }}
    +#else
    +#define AssertD(cond,msg) /* */
    +#endif
    +
    +#define VPrintf0(zf) \
    +   fprintf(stderr,zf)
    +#define VPrintf1(zf,za1) \
    +   fprintf(stderr,zf,za1)
    +#define VPrintf2(zf,za1,za2) \
    +   fprintf(stderr,zf,za1,za2)
    +#define VPrintf3(zf,za1,za2,za3) \
    +   fprintf(stderr,zf,za1,za2,za3)
    +#define VPrintf4(zf,za1,za2,za3,za4) \
    +   fprintf(stderr,zf,za1,za2,za3,za4)
    +#define VPrintf5(zf,za1,za2,za3,za4,za5) \
    +   fprintf(stderr,zf,za1,za2,za3,za4,za5)
    +
    +#else
    +
    +extern void bz_internal_error ( int errcode );
    +#define AssertH(cond,errcode) \
    +   { if (!(cond)) bz_internal_error ( errcode ); }
    +#define AssertD(cond,msg)                do { } while (0)
    +#define VPrintf0(zf)                     do { } while (0)
    +#define VPrintf1(zf,za1)                 do { } while (0)
    +#define VPrintf2(zf,za1,za2)             do { } while (0)
    +#define VPrintf3(zf,za1,za2,za3)         do { } while (0)
    +#define VPrintf4(zf,za1,za2,za3,za4)     do { } while (0)
    +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
    +
    +#endif
    +
    +
    +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
    +#define BZFREE(ppp)  (strm->bzfree)(strm->opaque,(ppp))
    +
    +
    +/*-- Header bytes. --*/
    +
    +#define BZ_HDR_B 0x42   /* 'B' */
    +#define BZ_HDR_Z 0x5a   /* 'Z' */
    +#define BZ_HDR_h 0x68   /* 'h' */
    +#define BZ_HDR_0 0x30   /* '0' */
    +  
    +/*-- Constants for the back end. --*/
    +
    +#define BZ_MAX_ALPHA_SIZE 258
    +#define BZ_MAX_CODE_LEN    23
    +
    +#define BZ_RUNA 0
    +#define BZ_RUNB 1
    +
    +#define BZ_N_GROUPS 6
    +#define BZ_G_SIZE   50
    +#define BZ_N_ITERS  4
    +
    +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
    +
    +
    +
    +/*-- Stuff for randomising repetitive blocks. --*/
    +
    +extern Int32 BZ2_rNums[512];
    +
    +#define BZ_RAND_DECLS                          \
    +   Int32 rNToGo;                               \
    +   Int32 rTPos                                 \
    +
    +#define BZ_RAND_INIT_MASK                      \
    +   s->rNToGo = 0;                              \
    +   s->rTPos  = 0                               \
    +
    +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
    +
    +#define BZ_RAND_UPD_MASK                       \
    +   if (s->rNToGo == 0) {                       \
    +      s->rNToGo = BZ2_rNums[s->rTPos];         \
    +      s->rTPos++;                              \
    +      if (s->rTPos == 512) s->rTPos = 0;       \
    +   }                                           \
    +   s->rNToGo--;
    +
    +
    +
    +/*-- Stuff for doing CRCs. --*/
    +
    +extern UInt32 BZ2_crc32Table[256];
    +
    +#define BZ_INITIALISE_CRC(crcVar)              \
    +{                                              \
    +   crcVar = 0xffffffffL;                       \
    +}
    +
    +#define BZ_FINALISE_CRC(crcVar)                \
    +{                                              \
    +   crcVar = ~(crcVar);                         \
    +}
    +
    +#define BZ_UPDATE_CRC(crcVar,cha)              \
    +{                                              \
    +   crcVar = (crcVar << 8) ^                    \
    +            BZ2_crc32Table[(crcVar >> 24) ^    \
    +                           ((UChar)cha)];      \
    +}
    +
    +
    +
    +/*-- States and modes for compression. --*/
    +
    +#define BZ_M_IDLE      1
    +#define BZ_M_RUNNING   2
    +#define BZ_M_FLUSHING  3
    +#define BZ_M_FINISHING 4
    +
    +#define BZ_S_OUTPUT    1
    +#define BZ_S_INPUT     2
    +
    +#define BZ_N_RADIX 2
    +#define BZ_N_QSORT 12
    +#define BZ_N_SHELL 18
    +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
    +
    +
    +
    +
    +/*-- Structure holding all the compression-side stuff. --*/
    +
    +typedef
    +   struct {
    +      /* pointer back to the struct bz_stream */
    +      bz_stream* strm;
    +
    +      /* mode this stream is in, and whether inputting */
    +      /* or outputting data */
    +      Int32    mode;
    +      Int32    state;
    +
    +      /* remembers avail_in when flush/finish requested */
    +      UInt32   avail_in_expect;
    +
    +      /* for doing the block sorting */
    +      UInt32*  arr1;
    +      UInt32*  arr2;
    +      UInt32*  ftab;
    +      Int32    origPtr;
    +
    +      /* aliases for arr1 and arr2 */
    +      UInt32*  ptr;
    +      UChar*   block;
    +      UInt16*  mtfv;
    +      UChar*   zbits;
    +
    +      /* for deciding when to use the fallback sorting algorithm */
    +      Int32    workFactor;
    +
    +      /* run-length-encoding of the input */
    +      UInt32   state_in_ch;
    +      Int32    state_in_len;
    +      BZ_RAND_DECLS;
    +
    +      /* input and output limits and current posns */
    +      Int32    nblock;
    +      Int32    nblockMAX;
    +      Int32    numZ;
    +      Int32    state_out_pos;
    +
    +      /* map of bytes used in block */
    +      Int32    nInUse;
    +      Bool     inUse[256];
    +      UChar    unseqToSeq[256];
    +
    +      /* the buffer for bit stream creation */
    +      UInt32   bsBuff;
    +      Int32    bsLive;
    +
    +      /* block and combined CRCs */
    +      UInt32   blockCRC;
    +      UInt32   combinedCRC;
    +
    +      /* misc administratium */
    +      Int32    verbosity;
    +      Int32    blockNo;
    +      Int32    blockSize100k;
    +
    +      /* stuff for coding the MTF values */
    +      Int32    nMTF;
    +      Int32    mtfFreq    [BZ_MAX_ALPHA_SIZE];
    +      UChar    selector   [BZ_MAX_SELECTORS];
    +      UChar    selectorMtf[BZ_MAX_SELECTORS];
    +
    +      UChar    len     [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +      Int32    code    [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +      Int32    rfreq   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +      /* second dimension: only 3 needed; 4 makes index calculations faster */
    +      UInt32   len_pack[BZ_MAX_ALPHA_SIZE][4];
    +
    +   }
    +   EState;
    +
    +
    +
    +/*-- externs for compression. --*/
    +
    +extern void 
    +BZ2_blockSort ( EState* );
    +
    +extern void 
    +BZ2_compressBlock ( EState*, Bool );
    +
    +extern void 
    +BZ2_bsInitWrite ( EState* );
    +
    +extern void 
    +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
    +
    +extern void 
    +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
    +
    +
    +
    +/*-- states for decompression. --*/
    +
    +#define BZ_X_IDLE        1
    +#define BZ_X_OUTPUT      2
    +
    +#define BZ_X_MAGIC_1     10
    +#define BZ_X_MAGIC_2     11
    +#define BZ_X_MAGIC_3     12
    +#define BZ_X_MAGIC_4     13
    +#define BZ_X_BLKHDR_1    14
    +#define BZ_X_BLKHDR_2    15
    +#define BZ_X_BLKHDR_3    16
    +#define BZ_X_BLKHDR_4    17
    +#define BZ_X_BLKHDR_5    18
    +#define BZ_X_BLKHDR_6    19
    +#define BZ_X_BCRC_1      20
    +#define BZ_X_BCRC_2      21
    +#define BZ_X_BCRC_3      22
    +#define BZ_X_BCRC_4      23
    +#define BZ_X_RANDBIT     24
    +#define BZ_X_ORIGPTR_1   25
    +#define BZ_X_ORIGPTR_2   26
    +#define BZ_X_ORIGPTR_3   27
    +#define BZ_X_MAPPING_1   28
    +#define BZ_X_MAPPING_2   29
    +#define BZ_X_SELECTOR_1  30
    +#define BZ_X_SELECTOR_2  31
    +#define BZ_X_SELECTOR_3  32
    +#define BZ_X_CODING_1    33
    +#define BZ_X_CODING_2    34
    +#define BZ_X_CODING_3    35
    +#define BZ_X_MTF_1       36
    +#define BZ_X_MTF_2       37
    +#define BZ_X_MTF_3       38
    +#define BZ_X_MTF_4       39
    +#define BZ_X_MTF_5       40
    +#define BZ_X_MTF_6       41
    +#define BZ_X_ENDHDR_2    42
    +#define BZ_X_ENDHDR_3    43
    +#define BZ_X_ENDHDR_4    44
    +#define BZ_X_ENDHDR_5    45
    +#define BZ_X_ENDHDR_6    46
    +#define BZ_X_CCRC_1      47
    +#define BZ_X_CCRC_2      48
    +#define BZ_X_CCRC_3      49
    +#define BZ_X_CCRC_4      50
    +
    +
    +
    +/*-- Constants for the fast MTF decoder. --*/
    +
    +#define MTFA_SIZE 4096
    +#define MTFL_SIZE 16
    +
    +
    +
    +/*-- Structure holding all the decompression-side stuff. --*/
    +
    +typedef
    +   struct {
    +      /* pointer back to the struct bz_stream */
    +      bz_stream* strm;
    +
    +      /* state indicator for this stream */
    +      Int32    state;
    +
    +      /* for doing the final run-length decoding */
    +      UChar    state_out_ch;
    +      Int32    state_out_len;
    +      Bool     blockRandomised;
    +      BZ_RAND_DECLS;
    +
    +      /* the buffer for bit stream reading */
    +      UInt32   bsBuff;
    +      Int32    bsLive;
    +
    +      /* misc administratium */
    +      Int32    blockSize100k;
    +      Bool     smallDecompress;
    +      Int32    currBlockNo;
    +      Int32    verbosity;
    +
    +      /* for undoing the Burrows-Wheeler transform */
    +      Int32    origPtr;
    +      UInt32   tPos;
    +      Int32    k0;
    +      Int32    unzftab[256];
    +      Int32    nblock_used;
    +      Int32    cftab[257];
    +      Int32    cftabCopy[257];
    +
    +      /* for undoing the Burrows-Wheeler transform (FAST) */
    +      UInt32   *tt;
    +
    +      /* for undoing the Burrows-Wheeler transform (SMALL) */
    +      UInt16   *ll16;
    +      UChar    *ll4;
    +
    +      /* stored and calculated CRCs */
    +      UInt32   storedBlockCRC;
    +      UInt32   storedCombinedCRC;
    +      UInt32   calculatedBlockCRC;
    +      UInt32   calculatedCombinedCRC;
    +
    +      /* map of bytes used in block */
    +      Int32    nInUse;
    +      Bool     inUse[256];
    +      Bool     inUse16[16];
    +      UChar    seqToUnseq[256];
    +
    +      /* for decoding the MTF values */
    +      UChar    mtfa   [MTFA_SIZE];
    +      Int32    mtfbase[256 / MTFL_SIZE];
    +      UChar    selector   [BZ_MAX_SELECTORS];
    +      UChar    selectorMtf[BZ_MAX_SELECTORS];
    +      UChar    len  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +
    +      Int32    limit  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +      Int32    base   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +      Int32    perm   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +      Int32    minLens[BZ_N_GROUPS];
    +
    +      /* save area for scalars in the main decompress code */
    +      Int32    save_i;
    +      Int32    save_j;
    +      Int32    save_t;
    +      Int32    save_alphaSize;
    +      Int32    save_nGroups;
    +      Int32    save_nSelectors;
    +      Int32    save_EOB;
    +      Int32    save_groupNo;
    +      Int32    save_groupPos;
    +      Int32    save_nextSym;
    +      Int32    save_nblockMAX;
    +      Int32    save_nblock;
    +      Int32    save_es;
    +      Int32    save_N;
    +      Int32    save_curr;
    +      Int32    save_zt;
    +      Int32    save_zn; 
    +      Int32    save_zvec;
    +      Int32    save_zj;
    +      Int32    save_gSel;
    +      Int32    save_gMinlen;
    +      Int32*   save_gLimit;
    +      Int32*   save_gBase;
    +      Int32*   save_gPerm;
    +
    +   }
    +   DState;
    +
    +
    +
    +/*-- Macros for decompression. --*/
    +
    +#define BZ_GET_FAST(cccc)                     \
    +    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
    +    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
    +    s->tPos = s->tt[s->tPos];                 \
    +    cccc = (UChar)(s->tPos & 0xff);           \
    +    s->tPos >>= 8;
    +
    +#define BZ_GET_FAST_C(cccc)                   \
    +    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
    +    if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
    +    c_tPos = c_tt[c_tPos];                    \
    +    cccc = (UChar)(c_tPos & 0xff);            \
    +    c_tPos >>= 8;
    +
    +#define SET_LL4(i,n)                                          \
    +   { if (((i) & 0x1) == 0)                                    \
    +        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else    \
    +        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4);  \
    +   }
    +
    +#define GET_LL4(i)                             \
    +   ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
    +
    +#define SET_LL(i,n)                          \
    +   { s->ll16[i] = (UInt16)(n & 0x0000ffff);  \
    +     SET_LL4(i, n >> 16);                    \
    +   }
    +
    +#define GET_LL(i) \
    +   (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
    +
    +#define BZ_GET_SMALL(cccc)                            \
    +    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
    +    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
    +    cccc = BZ2_indexIntoF ( s->tPos, s->cftab );    \
    +    s->tPos = GET_LL(s->tPos);
    +
    +
    +/*-- externs for decompression. --*/
    +
    +extern Int32 
    +BZ2_indexIntoF ( Int32, Int32* );
    +
    +extern Int32 
    +BZ2_decompress ( DState* );
    +
    +extern void 
    +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
    +                           Int32,  Int32, Int32 );
    +
    +
    +#endif
    +
    +
    +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
    +
    +#ifdef BZ_NO_STDIO
    +#ifndef NULL
    +#define NULL 0
    +#endif
    +#endif
    +
    +
    +/*-------------------------------------------------------------*/
    +/*--- end                                   bzlib_private.h ---*/
    +/*-------------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/compress.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/compress.c
    new file mode 100644
    index 00000000000..5dfa00231b0
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/compress.c
    @@ -0,0 +1,672 @@
    +
    +/*-------------------------------------------------------------*/
    +/*--- Compression machinery (not incl block sorting)        ---*/
    +/*---                                            compress.c ---*/
    +/*-------------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +
    +/* CHANGES
    +    0.9.0    -- original version.
    +    0.9.0a/b -- no changes in this file.
    +    0.9.0c   -- changed setting of nGroups in sendMTFValues() 
    +                so as to do a bit better on small files
    +*/
    +
    +#include "bzlib_private.h"
    +
    +
    +/*---------------------------------------------------*/
    +/*--- Bit stream I/O                              ---*/
    +/*---------------------------------------------------*/
    +
    +/*---------------------------------------------------*/
    +void BZ2_bsInitWrite ( EState* s )
    +{
    +   s->bsLive = 0;
    +   s->bsBuff = 0;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void bsFinishWrite ( EState* s )
    +{
    +   while (s->bsLive > 0) {
    +      s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
    +      s->numZ++;
    +      s->bsBuff <<= 8;
    +      s->bsLive -= 8;
    +   }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +#define bsNEEDW(nz)                           \
    +{                                             \
    +   while (s->bsLive >= 8) {                   \
    +      s->zbits[s->numZ]                       \
    +         = (UChar)(s->bsBuff >> 24);          \
    +      s->numZ++;                              \
    +      s->bsBuff <<= 8;                        \
    +      s->bsLive -= 8;                         \
    +   }                                          \
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +__inline__
    +void bsW ( EState* s, Int32 n, UInt32 v )
    +{
    +   bsNEEDW ( n );
    +   s->bsBuff |= (v << (32 - s->bsLive - n));
    +   s->bsLive += n;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void bsPutUInt32 ( EState* s, UInt32 u )
    +{
    +   bsW ( s, 8, (u >> 24) & 0xffL );
    +   bsW ( s, 8, (u >> 16) & 0xffL );
    +   bsW ( s, 8, (u >>  8) & 0xffL );
    +   bsW ( s, 8,  u        & 0xffL );
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void bsPutUChar ( EState* s, UChar c )
    +{
    +   bsW( s, 8, (UInt32)c );
    +}
    +
    +
    +/*---------------------------------------------------*/
    +/*--- The back end proper                         ---*/
    +/*---------------------------------------------------*/
    +
    +/*---------------------------------------------------*/
    +static
    +void makeMaps_e ( EState* s )
    +{
    +   Int32 i;
    +   s->nInUse = 0;
    +   for (i = 0; i < 256; i++)
    +      if (s->inUse[i]) {
    +         s->unseqToSeq[i] = s->nInUse;
    +         s->nInUse++;
    +      }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void generateMTFValues ( EState* s )
    +{
    +   UChar   yy[256];
    +   Int32   i, j;
    +   Int32   zPend;
    +   Int32   wr;
    +   Int32   EOB;
    +
    +   /* 
    +      After sorting (eg, here),
    +         s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
    +         and
    +         ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] 
    +         holds the original block data.
    +
    +      The first thing to do is generate the MTF values,
    +      and put them in
    +         ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
    +      Because there are strictly fewer or equal MTF values
    +      than block values, ptr values in this area are overwritten
    +      with MTF values only when they are no longer needed.
    +
    +      The final compressed bitstream is generated into the
    +      area starting at
    +         (UChar*) (&((UChar*)s->arr2)[s->nblock])
    +
    +      These storage aliases are set up in bzCompressInit(),
    +      except for the last one, which is arranged in 
    +      compressBlock().
    +   */
    +   UInt32* ptr   = s->ptr;
    +   UChar* block  = s->block;
    +   UInt16* mtfv  = s->mtfv;
    +
    +   makeMaps_e ( s );
    +   EOB = s->nInUse+1;
    +
    +   for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
    +
    +   wr = 0;
    +   zPend = 0;
    +   for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
    +
    +   for (i = 0; i < s->nblock; i++) {
    +      UChar ll_i;
    +      AssertD ( wr <= i, "generateMTFValues(1)" );
    +      j = ptr[i]-1; if (j < 0) j += s->nblock;
    +      ll_i = s->unseqToSeq[block[j]];
    +      AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
    +
    +      if (yy[0] == ll_i) { 
    +         zPend++;
    +      } else {
    +
    +         if (zPend > 0) {
    +            zPend--;
    +            while (True) {
    +               if (zPend & 1) {
    +                  mtfv[wr] = BZ_RUNB; wr++; 
    +                  s->mtfFreq[BZ_RUNB]++; 
    +               } else {
    +                  mtfv[wr] = BZ_RUNA; wr++; 
    +                  s->mtfFreq[BZ_RUNA]++; 
    +               }
    +               if (zPend < 2) break;
    +               zPend = (zPend - 2) / 2;
    +            };
    +            zPend = 0;
    +         }
    +         {
    +            register UChar  rtmp;
    +            register UChar* ryy_j;
    +            register UChar  rll_i;
    +            rtmp  = yy[1];
    +            yy[1] = yy[0];
    +            ryy_j = &(yy[1]);
    +            rll_i = ll_i;
    +            while ( rll_i != rtmp ) {
    +               register UChar rtmp2;
    +               ryy_j++;
    +               rtmp2  = rtmp;
    +               rtmp   = *ryy_j;
    +               *ryy_j = rtmp2;
    +            };
    +            yy[0] = rtmp;
    +            j = ryy_j - &(yy[0]);
    +            mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
    +         }
    +
    +      }
    +   }
    +
    +   if (zPend > 0) {
    +      zPend--;
    +      while (True) {
    +         if (zPend & 1) {
    +            mtfv[wr] = BZ_RUNB; wr++; 
    +            s->mtfFreq[BZ_RUNB]++; 
    +         } else {
    +            mtfv[wr] = BZ_RUNA; wr++; 
    +            s->mtfFreq[BZ_RUNA]++; 
    +         }
    +         if (zPend < 2) break;
    +         zPend = (zPend - 2) / 2;
    +      };
    +      zPend = 0;
    +   }
    +
    +   mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
    +
    +   s->nMTF = wr;
    +}
    +
    +
    +/*---------------------------------------------------*/
    +#define BZ_LESSER_ICOST  0
    +#define BZ_GREATER_ICOST 15
    +
    +static
    +void sendMTFValues ( EState* s )
    +{
    +   Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
    +   Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
    +   Int32 nGroups, nBytes;
    +
    +   /*--
    +   UChar  len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +   is a global since the decoder also needs it.
    +
    +   Int32  code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +   Int32  rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
    +   are also globals only used in this proc.
    +   Made global to keep stack frame size small.
    +   --*/
    +
    +
    +   UInt16 cost[BZ_N_GROUPS];
    +   Int32  fave[BZ_N_GROUPS];
    +
    +   UInt16* mtfv = s->mtfv;
    +
    +   if (s->verbosity >= 3)
    +      VPrintf3( "      %d in block, %d after MTF & 1-2 coding, "
    +                "%d+2 syms in use\n", 
    +                s->nblock, s->nMTF, s->nInUse );
    +
    +   alphaSize = s->nInUse+2;
    +   for (t = 0; t < BZ_N_GROUPS; t++)
    +      for (v = 0; v < alphaSize; v++)
    +         s->len[t][v] = BZ_GREATER_ICOST;
    +
    +   /*--- Decide how many coding tables to use ---*/
    +   AssertH ( s->nMTF > 0, 3001 );
    +   if (s->nMTF < 200)  nGroups = 2; else
    +   if (s->nMTF < 600)  nGroups = 3; else
    +   if (s->nMTF < 1200) nGroups = 4; else
    +   if (s->nMTF < 2400) nGroups = 5; else
    +                       nGroups = 6;
    +
    +   /*--- Generate an initial set of coding tables ---*/
    +   { 
    +      Int32 nPart, remF, tFreq, aFreq;
    +
    +      nPart = nGroups;
    +      remF  = s->nMTF;
    +      gs = 0;
    +      while (nPart > 0) {
    +         tFreq = remF / nPart;
    +         ge = gs-1;
    +         aFreq = 0;
    +         while (aFreq < tFreq && ge < alphaSize-1) {
    +            ge++;
    +            aFreq += s->mtfFreq[ge];
    +         }
    +
    +         if (ge > gs 
    +             && nPart != nGroups && nPart != 1 
    +             && ((nGroups-nPart) % 2 == 1)) {
    +            aFreq -= s->mtfFreq[ge];
    +            ge--;
    +         }
    +
    +         if (s->verbosity >= 3)
    +            VPrintf5( "      initial group %d, [%d .. %d], "
    +                      "has %d syms (%4.1f%%)\n",
    +                      nPart, gs, ge, aFreq, 
    +                      (100.0 * (float)aFreq) / (float)(s->nMTF) );
    + 
    +         for (v = 0; v < alphaSize; v++)
    +            if (v >= gs && v <= ge) 
    +               s->len[nPart-1][v] = BZ_LESSER_ICOST; else
    +               s->len[nPart-1][v] = BZ_GREATER_ICOST;
    + 
    +         nPart--;
    +         gs = ge+1;
    +         remF -= aFreq;
    +      }
    +   }
    +
    +   /*--- 
    +      Iterate up to BZ_N_ITERS times to improve the tables.
    +   ---*/
    +   for (iter = 0; iter < BZ_N_ITERS; iter++) {
    +
    +      for (t = 0; t < nGroups; t++) fave[t] = 0;
    +
    +      for (t = 0; t < nGroups; t++)
    +         for (v = 0; v < alphaSize; v++)
    +            s->rfreq[t][v] = 0;
    +
    +      /*---
    +        Set up an auxiliary length table which is used to fast-track
    +	the common case (nGroups == 6). 
    +      ---*/
    +      if (nGroups == 6) {
    +         for (v = 0; v < alphaSize; v++) {
    +            s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
    +            s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
    +            s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
    +	 }
    +      }
    +
    +      nSelectors = 0;
    +      totc = 0;
    +      gs = 0;
    +      while (True) {
    +
    +         /*--- Set group start & end marks. --*/
    +         if (gs >= s->nMTF) break;
    +         ge = gs + BZ_G_SIZE - 1; 
    +         if (ge >= s->nMTF) ge = s->nMTF-1;
    +
    +         /*-- 
    +            Calculate the cost of this group as coded
    +            by each of the coding tables.
    +         --*/
    +         for (t = 0; t < nGroups; t++) cost[t] = 0;
    +
    +         if (nGroups == 6 && 50 == ge-gs+1) {
    +            /*--- fast track the common case ---*/
    +            register UInt32 cost01, cost23, cost45;
    +            register UInt16 icv;
    +            cost01 = cost23 = cost45 = 0;
    +
    +#           define BZ_ITER(nn)                \
    +               icv = mtfv[gs+(nn)];           \
    +               cost01 += s->len_pack[icv][0]; \
    +               cost23 += s->len_pack[icv][1]; \
    +               cost45 += s->len_pack[icv][2]; \
    +
    +            BZ_ITER(0);  BZ_ITER(1);  BZ_ITER(2);  BZ_ITER(3);  BZ_ITER(4);
    +            BZ_ITER(5);  BZ_ITER(6);  BZ_ITER(7);  BZ_ITER(8);  BZ_ITER(9);
    +            BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
    +            BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
    +            BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
    +            BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
    +            BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
    +            BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
    +            BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
    +            BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
    +
    +#           undef BZ_ITER
    +
    +            cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
    +            cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
    +            cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
    +
    +         } else {
    +	    /*--- slow version which correctly handles all situations ---*/
    +            for (i = gs; i <= ge; i++) { 
    +               UInt16 icv = mtfv[i];
    +               for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
    +            }
    +         }
    + 
    +         /*-- 
    +            Find the coding table which is best for this group,
    +            and record its identity in the selector table.
    +         --*/
    +         bc = 999999999; bt = -1;
    +         for (t = 0; t < nGroups; t++)
    +            if (cost[t] < bc) { bc = cost[t]; bt = t; };
    +         totc += bc;
    +         fave[bt]++;
    +         s->selector[nSelectors] = bt;
    +         nSelectors++;
    +
    +         /*-- 
    +            Increment the symbol frequencies for the selected table.
    +          --*/
    +         if (nGroups == 6 && 50 == ge-gs+1) {
    +            /*--- fast track the common case ---*/
    +
    +#           define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
    +
    +            BZ_ITUR(0);  BZ_ITUR(1);  BZ_ITUR(2);  BZ_ITUR(3);  BZ_ITUR(4);
    +            BZ_ITUR(5);  BZ_ITUR(6);  BZ_ITUR(7);  BZ_ITUR(8);  BZ_ITUR(9);
    +            BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
    +            BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
    +            BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
    +            BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
    +            BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
    +            BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
    +            BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
    +            BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
    +
    +#           undef BZ_ITUR
    +
    +         } else {
    +	    /*--- slow version which correctly handles all situations ---*/
    +            for (i = gs; i <= ge; i++)
    +               s->rfreq[bt][ mtfv[i] ]++;
    +         }
    +
    +         gs = ge+1;
    +      }
    +      if (s->verbosity >= 3) {
    +         VPrintf2 ( "      pass %d: size is %d, grp uses are ", 
    +                   iter+1, totc/8 );
    +         for (t = 0; t < nGroups; t++)
    +            VPrintf1 ( "%d ", fave[t] );
    +         VPrintf0 ( "\n" );
    +      }
    +
    +      /*--
    +        Recompute the tables based on the accumulated frequencies.
    +      --*/
    +      /* maxLen was changed from 20 to 17 in bzip2-1.0.3.  See 
    +         comment in huffman.c for details. */
    +      for (t = 0; t < nGroups; t++)
    +         BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), 
    +                                 alphaSize, 17 /*20*/ );
    +   }
    +
    +
    +   AssertH( nGroups < 8, 3002 );
    +   AssertH( nSelectors < 32768 &&
    +            nSelectors <= BZ_MAX_SELECTORS,
    +            3003 );
    +
    +
    +   /*--- Compute MTF values for the selectors. ---*/
    +   {
    +      UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
    +      for (i = 0; i < nGroups; i++) pos[i] = i;
    +      for (i = 0; i < nSelectors; i++) {
    +         ll_i = s->selector[i];
    +         j = 0;
    +         tmp = pos[j];
    +         while ( ll_i != tmp ) {
    +            j++;
    +            tmp2 = tmp;
    +            tmp = pos[j];
    +            pos[j] = tmp2;
    +         };
    +         pos[0] = tmp;
    +         s->selectorMtf[i] = j;
    +      }
    +   };
    +
    +   /*--- Assign actual codes for the tables. --*/
    +   for (t = 0; t < nGroups; t++) {
    +      minLen = 32;
    +      maxLen = 0;
    +      for (i = 0; i < alphaSize; i++) {
    +         if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
    +         if (s->len[t][i] < minLen) minLen = s->len[t][i];
    +      }
    +      AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
    +      AssertH ( !(minLen < 1),  3005 );
    +      BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), 
    +                          minLen, maxLen, alphaSize );
    +   }
    +
    +   /*--- Transmit the mapping table. ---*/
    +   { 
    +      Bool inUse16[16];
    +      for (i = 0; i < 16; i++) {
    +          inUse16[i] = False;
    +          for (j = 0; j < 16; j++)
    +             if (s->inUse[i * 16 + j]) inUse16[i] = True;
    +      }
    +     
    +      nBytes = s->numZ;
    +      for (i = 0; i < 16; i++)
    +         if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
    +
    +      for (i = 0; i < 16; i++)
    +         if (inUse16[i])
    +            for (j = 0; j < 16; j++) {
    +               if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
    +            }
    +
    +      if (s->verbosity >= 3) 
    +         VPrintf1( "      bytes: mapping %d, ", s->numZ-nBytes );
    +   }
    +
    +   /*--- Now the selectors. ---*/
    +   nBytes = s->numZ;
    +   bsW ( s, 3, nGroups );
    +   bsW ( s, 15, nSelectors );
    +   for (i = 0; i < nSelectors; i++) { 
    +      for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
    +      bsW(s,1,0);
    +   }
    +   if (s->verbosity >= 3)
    +      VPrintf1( "selectors %d, ", s->numZ-nBytes );
    +
    +   /*--- Now the coding tables. ---*/
    +   nBytes = s->numZ;
    +
    +   for (t = 0; t < nGroups; t++) {
    +      Int32 curr = s->len[t][0];
    +      bsW ( s, 5, curr );
    +      for (i = 0; i < alphaSize; i++) {
    +         while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
    +         while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
    +         bsW ( s, 1, 0 );
    +      }
    +   }
    +
    +   if (s->verbosity >= 3)
    +      VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
    +
    +   /*--- And finally, the block data proper ---*/
    +   nBytes = s->numZ;
    +   selCtr = 0;
    +   gs = 0;
    +   while (True) {
    +      if (gs >= s->nMTF) break;
    +      ge = gs + BZ_G_SIZE - 1; 
    +      if (ge >= s->nMTF) ge = s->nMTF-1;
    +      AssertH ( s->selector[selCtr] < nGroups, 3006 );
    +
    +      if (nGroups == 6 && 50 == ge-gs+1) {
    +            /*--- fast track the common case ---*/
    +            UInt16 mtfv_i;
    +            UChar* s_len_sel_selCtr 
    +               = &(s->len[s->selector[selCtr]][0]);
    +            Int32* s_code_sel_selCtr
    +               = &(s->code[s->selector[selCtr]][0]);
    +
    +#           define BZ_ITAH(nn)                      \
    +               mtfv_i = mtfv[gs+(nn)];              \
    +               bsW ( s,                             \
    +                     s_len_sel_selCtr[mtfv_i],      \
    +                     s_code_sel_selCtr[mtfv_i] )
    +
    +            BZ_ITAH(0);  BZ_ITAH(1);  BZ_ITAH(2);  BZ_ITAH(3);  BZ_ITAH(4);
    +            BZ_ITAH(5);  BZ_ITAH(6);  BZ_ITAH(7);  BZ_ITAH(8);  BZ_ITAH(9);
    +            BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
    +            BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
    +            BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
    +            BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
    +            BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
    +            BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
    +            BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
    +            BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
    +
    +#           undef BZ_ITAH
    +
    +      } else {
    +	 /*--- slow version which correctly handles all situations ---*/
    +         for (i = gs; i <= ge; i++) {
    +            bsW ( s, 
    +                  s->len  [s->selector[selCtr]] [mtfv[i]],
    +                  s->code [s->selector[selCtr]] [mtfv[i]] );
    +         }
    +      }
    +
    +
    +      gs = ge+1;
    +      selCtr++;
    +   }
    +   AssertH( selCtr == nSelectors, 3007 );
    +
    +   if (s->verbosity >= 3)
    +      VPrintf1( "codes %d\n", s->numZ-nBytes );
    +}
    +
    +
    +/*---------------------------------------------------*/
    +void BZ2_compressBlock ( EState* s, Bool is_last_block )
    +{
    +   if (s->nblock > 0) {
    +
    +      BZ_FINALISE_CRC ( s->blockCRC );
    +      s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
    +      s->combinedCRC ^= s->blockCRC;
    +      if (s->blockNo > 1) s->numZ = 0;
    +
    +      if (s->verbosity >= 2)
    +         VPrintf4( "    block %d: crc = 0x%08x, "
    +                   "combined CRC = 0x%08x, size = %d\n",
    +                   s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
    +
    +      BZ2_blockSort ( s );
    +   }
    +
    +   s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
    +
    +   /*-- If this is the first block, create the stream header. --*/
    +   if (s->blockNo == 1) {
    +      BZ2_bsInitWrite ( s );
    +      bsPutUChar ( s, BZ_HDR_B );
    +      bsPutUChar ( s, BZ_HDR_Z );
    +      bsPutUChar ( s, BZ_HDR_h );
    +      bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
    +   }
    +
    +   if (s->nblock > 0) {
    +
    +      bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
    +      bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
    +      bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
    +
    +      /*-- Now the block's CRC, so it is in a known place. --*/
    +      bsPutUInt32 ( s, s->blockCRC );
    +
    +      /*-- 
    +         Now a single bit indicating (non-)randomisation. 
    +         As of version 0.9.5, we use a better sorting algorithm
    +         which makes randomisation unnecessary.  So always set
    +         the randomised bit to 'no'.  Of course, the decoder
    +         still needs to be able to handle randomised blocks
    +         so as to maintain backwards compatibility with
    +         older versions of bzip2.
    +      --*/
    +      bsW(s,1,0);
    +
    +      bsW ( s, 24, s->origPtr );
    +      generateMTFValues ( s );
    +      sendMTFValues ( s );
    +   }
    +
    +
    +   /*-- If this is the last block, add the stream trailer. --*/
    +   if (is_last_block) {
    +
    +      bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
    +      bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
    +      bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
    +      bsPutUInt32 ( s, s->combinedCRC );
    +      if (s->verbosity >= 2)
    +         VPrintf1( "    final combined CRC = 0x%08x\n   ", s->combinedCRC );
    +      bsFinishWrite ( s );
    +   }
    +}
    +
    +
    +/*-------------------------------------------------------------*/
    +/*--- end                                        compress.c ---*/
    +/*-------------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/crctable.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/crctable.c
    new file mode 100644
    index 00000000000..2b33c253533
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/crctable.c
    @@ -0,0 +1,104 @@
    +
    +/*-------------------------------------------------------------*/
    +/*--- Table for doing CRCs                                  ---*/
    +/*---                                            crctable.c ---*/
    +/*-------------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +
    +#include "bzlib_private.h"
    +
    +/*--
    +  I think this is an implementation of the AUTODIN-II,
    +  Ethernet & FDDI 32-bit CRC standard.  Vaguely derived
    +  from code by Rob Warnock, in Section 51 of the
    +  comp.compression FAQ.
    +--*/
    +
    +UInt32 BZ2_crc32Table[256] = {
    +
    +   /*-- Ugly, innit? --*/
    +
    +   0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
    +   0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
    +   0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
    +   0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
    +   0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
    +   0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
    +   0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
    +   0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
    +   0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
    +   0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
    +   0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
    +   0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
    +   0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
    +   0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
    +   0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
    +   0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
    +   0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
    +   0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
    +   0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
    +   0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
    +   0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
    +   0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
    +   0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
    +   0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
    +   0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
    +   0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
    +   0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
    +   0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
    +   0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
    +   0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
    +   0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
    +   0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
    +   0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
    +   0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
    +   0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
    +   0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
    +   0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
    +   0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
    +   0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
    +   0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
    +   0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
    +   0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
    +   0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
    +   0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
    +   0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
    +   0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
    +   0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
    +   0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
    +   0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
    +   0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
    +   0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
    +   0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
    +   0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
    +   0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
    +   0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
    +   0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
    +   0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
    +   0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
    +   0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
    +   0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
    +   0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
    +   0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
    +   0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
    +   0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
    +};
    +
    +
    +/*-------------------------------------------------------------*/
    +/*--- end                                        crctable.c ---*/
    +/*-------------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/decompress.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/decompress.c
    new file mode 100644
    index 00000000000..a1a0bac8922
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/decompress.c
    @@ -0,0 +1,652 @@
    +
    +/*-------------------------------------------------------------*/
    +/*--- Decompression machinery                               ---*/
    +/*---                                          decompress.c ---*/
    +/*-------------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +
    +#include "bzlib_private.h"
    +
    +
    +/*---------------------------------------------------*/
    +static
    +void makeMaps_d ( DState* s )
    +{
    +   Int32 i;
    +   s->nInUse = 0;
    +   for (i = 0; i < 256; i++)
    +      if (s->inUse[i]) {
    +         s->seqToUnseq[s->nInUse] = i;
    +         s->nInUse++;
    +      }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +#define RETURN(rrr)                               \
    +   { retVal = rrr; goto save_state_and_return; };
    +
    +#define GET_BITS(lll,vvv,nnn)                     \
    +   case lll: s->state = lll;                      \
    +   while (True) {                                 \
    +      if (s->bsLive >= nnn) {                     \
    +         UInt32 v;                                \
    +         v = (s->bsBuff >>                        \
    +             (s->bsLive-nnn)) & ((1 << nnn)-1);   \
    +         s->bsLive -= nnn;                        \
    +         vvv = v;                                 \
    +         break;                                   \
    +      }                                           \
    +      if (s->strm->avail_in == 0) RETURN(BZ_OK);  \
    +      s->bsBuff                                   \
    +         = (s->bsBuff << 8) |                     \
    +           ((UInt32)                              \
    +              (*((UChar*)(s->strm->next_in))));   \
    +      s->bsLive += 8;                             \
    +      s->strm->next_in++;                         \
    +      s->strm->avail_in--;                        \
    +      s->strm->total_in_lo32++;                   \
    +      if (s->strm->total_in_lo32 == 0)            \
    +         s->strm->total_in_hi32++;                \
    +   }
    +
    +#define GET_UCHAR(lll,uuu)                        \
    +   GET_BITS(lll,uuu,8)
    +
    +#define GET_BIT(lll,uuu)                          \
    +   GET_BITS(lll,uuu,1)
    +
    +/*---------------------------------------------------*/
    +#define GET_MTF_VAL(label1,label2,lval)           \
    +{                                                 \
    +   if (groupPos == 0) {                           \
    +      groupNo++;                                  \
    +      if (groupNo >= nSelectors)                  \
    +         RETURN(BZ_DATA_ERROR);                   \
    +      groupPos = BZ_G_SIZE;                       \
    +      gSel = s->selector[groupNo];                \
    +      gMinlen = s->minLens[gSel];                 \
    +      gLimit = &(s->limit[gSel][0]);              \
    +      gPerm = &(s->perm[gSel][0]);                \
    +      gBase = &(s->base[gSel][0]);                \
    +   }                                              \
    +   groupPos--;                                    \
    +   zn = gMinlen;                                  \
    +   GET_BITS(label1, zvec, zn);                    \
    +   while (1) {                                    \
    +      if (zn > 20 /* the longest code */)         \
    +         RETURN(BZ_DATA_ERROR);                   \
    +      if (zvec <= gLimit[zn]) break;              \
    +      zn++;                                       \
    +      GET_BIT(label2, zj);                        \
    +      zvec = (zvec << 1) | zj;                    \
    +   };                                             \
    +   if (zvec - gBase[zn] < 0                       \
    +       || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE)  \
    +      RETURN(BZ_DATA_ERROR);                      \
    +   lval = gPerm[zvec - gBase[zn]];                \
    +}
    +
    +
    +/*---------------------------------------------------*/
    +Int32 BZ2_decompress ( DState* s )
    +{
    +   UChar      uc;
    +   Int32      retVal;
    +   Int32      minLen, maxLen;
    +   bz_stream* strm = s->strm;
    +
    +   /* stuff that needs to be saved/restored */
    +   Int32  i;
    +   Int32  j;
    +   Int32  t;
    +   Int32  alphaSize;
    +   Int32  nGroups;
    +   Int32  nSelectors;
    +   Int32  EOB;
    +   Int32  groupNo;
    +   Int32  groupPos;
    +   Int32  nextSym;
    +   Int32  nblockMAX;
    +   Int32  nblock;
    +   Int32  es;
    +   Int32  N;
    +   Int32  curr;
    +   Int32  zt;
    +   Int32  zn; 
    +   Int32  zvec;
    +   Int32  zj;
    +   Int32  gSel;
    +   Int32  gMinlen;
    +   Int32* gLimit;
    +   Int32* gBase;
    +   Int32* gPerm;
    +
    +   if (s->state == BZ_X_MAGIC_1) {
    +      /*initialise the save area*/
    +      s->save_i           = 0;
    +      s->save_j           = 0;
    +      s->save_t           = 0;
    +      s->save_alphaSize   = 0;
    +      s->save_nGroups     = 0;
    +      s->save_nSelectors  = 0;
    +      s->save_EOB         = 0;
    +      s->save_groupNo     = 0;
    +      s->save_groupPos    = 0;
    +      s->save_nextSym     = 0;
    +      s->save_nblockMAX   = 0;
    +      s->save_nblock      = 0;
    +      s->save_es          = 0;
    +      s->save_N           = 0;
    +      s->save_curr        = 0;
    +      s->save_zt          = 0;
    +      s->save_zn          = 0;
    +      s->save_zvec        = 0;
    +      s->save_zj          = 0;
    +      s->save_gSel        = 0;
    +      s->save_gMinlen     = 0;
    +      s->save_gLimit      = NULL;
    +      s->save_gBase       = NULL;
    +      s->save_gPerm       = NULL;
    +   }
    +
    +   /*restore from the save area*/
    +   i           = s->save_i;
    +   j           = s->save_j;
    +   t           = s->save_t;
    +   alphaSize   = s->save_alphaSize;
    +   nGroups     = s->save_nGroups;
    +   nSelectors  = s->save_nSelectors;
    +   EOB         = s->save_EOB;
    +   groupNo     = s->save_groupNo;
    +   groupPos    = s->save_groupPos;
    +   nextSym     = s->save_nextSym;
    +   nblockMAX   = s->save_nblockMAX;
    +   nblock      = s->save_nblock;
    +   es          = s->save_es;
    +   N           = s->save_N;
    +   curr        = s->save_curr;
    +   zt          = s->save_zt;
    +   zn          = s->save_zn; 
    +   zvec        = s->save_zvec;
    +   zj          = s->save_zj;
    +   gSel        = s->save_gSel;
    +   gMinlen     = s->save_gMinlen;
    +   gLimit      = s->save_gLimit;
    +   gBase       = s->save_gBase;
    +   gPerm       = s->save_gPerm;
    +
    +   retVal = BZ_OK;
    +
    +   switch (s->state) {
    +
    +      GET_UCHAR(BZ_X_MAGIC_1, uc);
    +      if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
    +
    +      GET_UCHAR(BZ_X_MAGIC_2, uc);
    +      if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
    +
    +      GET_UCHAR(BZ_X_MAGIC_3, uc)
    +      if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
    +
    +      GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
    +      if (s->blockSize100k < (BZ_HDR_0 + 1) || 
    +          s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
    +      s->blockSize100k -= BZ_HDR_0;
    +
    +      if (s->smallDecompress) {
    +         s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
    +         s->ll4  = BZALLOC( 
    +                      ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) 
    +                   );
    +         if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
    +      } else {
    +         s->tt  = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
    +         if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
    +      }
    +
    +      GET_UCHAR(BZ_X_BLKHDR_1, uc);
    +
    +      if (uc == 0x17) goto endhdr_2;
    +      if (uc != 0x31) RETURN(BZ_DATA_ERROR);
    +      GET_UCHAR(BZ_X_BLKHDR_2, uc);
    +      if (uc != 0x41) RETURN(BZ_DATA_ERROR);
    +      GET_UCHAR(BZ_X_BLKHDR_3, uc);
    +      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
    +      GET_UCHAR(BZ_X_BLKHDR_4, uc);
    +      if (uc != 0x26) RETURN(BZ_DATA_ERROR);
    +      GET_UCHAR(BZ_X_BLKHDR_5, uc);
    +      if (uc != 0x53) RETURN(BZ_DATA_ERROR);
    +      GET_UCHAR(BZ_X_BLKHDR_6, uc);
    +      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
    +
    +      s->currBlockNo++;
    +      if (s->verbosity >= 2)
    +         VPrintf1 ( "\n    [%d: huff+mtf ", s->currBlockNo );
    + 
    +      s->storedBlockCRC = 0;
    +      GET_UCHAR(BZ_X_BCRC_1, uc);
    +      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
    +      GET_UCHAR(BZ_X_BCRC_2, uc);
    +      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
    +      GET_UCHAR(BZ_X_BCRC_3, uc);
    +      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
    +      GET_UCHAR(BZ_X_BCRC_4, uc);
    +      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
    +
    +      GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
    +
    +      s->origPtr = 0;
    +      GET_UCHAR(BZ_X_ORIGPTR_1, uc);
    +      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
    +      GET_UCHAR(BZ_X_ORIGPTR_2, uc);
    +      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
    +      GET_UCHAR(BZ_X_ORIGPTR_3, uc);
    +      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
    +
    +      if (s->origPtr < 0)
    +         RETURN(BZ_DATA_ERROR);
    +      if (s->origPtr > 10 + 100000*s->blockSize100k) 
    +         RETURN(BZ_DATA_ERROR);
    +
    +      /*--- Receive the mapping table ---*/
    +      for (i = 0; i < 16; i++) {
    +         GET_BIT(BZ_X_MAPPING_1, uc);
    +         if (uc == 1) 
    +            s->inUse16[i] = True; else 
    +            s->inUse16[i] = False;
    +      }
    +
    +      for (i = 0; i < 256; i++) s->inUse[i] = False;
    +
    +      for (i = 0; i < 16; i++)
    +         if (s->inUse16[i])
    +            for (j = 0; j < 16; j++) {
    +               GET_BIT(BZ_X_MAPPING_2, uc);
    +               if (uc == 1) s->inUse[i * 16 + j] = True;
    +            }
    +      makeMaps_d ( s );
    +      if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
    +      alphaSize = s->nInUse+2;
    +
    +      /*--- Now the selectors ---*/
    +      GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
    +      if (nGroups < 2 || nGroups > BZ_N_GROUPS) RETURN(BZ_DATA_ERROR);
    +      GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
    +      if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
    +      for (i = 0; i < nSelectors; i++) {
    +         j = 0;
    +         while (True) {
    +            GET_BIT(BZ_X_SELECTOR_3, uc);
    +            if (uc == 0) break;
    +            j++;
    +            if (j >= nGroups) RETURN(BZ_DATA_ERROR);
    +         }
    +         /* Having more than BZ_MAX_SELECTORS doesn't make much sense
    +            since they will never be used, but some implementations might
    +            "round up" the number of selectors, so just ignore those. */
    +         if (i < BZ_MAX_SELECTORS)
    +           s->selectorMtf[i] = j;
    +      }
    +      if (nSelectors > BZ_MAX_SELECTORS)
    +        nSelectors = BZ_MAX_SELECTORS;
    +
    +      /*--- Undo the MTF values for the selectors. ---*/
    +      {
    +         UChar pos[BZ_N_GROUPS], tmp, v;
    +         for (v = 0; v < nGroups; v++) pos[v] = v;
    +   
    +         for (i = 0; i < nSelectors; i++) {
    +            v = s->selectorMtf[i];
    +            tmp = pos[v];
    +            while (v > 0) { pos[v] = pos[v-1]; v--; }
    +            pos[0] = tmp;
    +            s->selector[i] = tmp;
    +         }
    +      }
    +
    +      /*--- Now the coding tables ---*/
    +      for (t = 0; t < nGroups; t++) {
    +         GET_BITS(BZ_X_CODING_1, curr, 5);
    +         for (i = 0; i < alphaSize; i++) {
    +            while (True) {
    +               if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
    +               GET_BIT(BZ_X_CODING_2, uc);
    +               if (uc == 0) break;
    +               GET_BIT(BZ_X_CODING_3, uc);
    +               if (uc == 0) curr++; else curr--;
    +            }
    +            s->len[t][i] = curr;
    +         }
    +      }
    +
    +      /*--- Create the Huffman decoding tables ---*/
    +      for (t = 0; t < nGroups; t++) {
    +         minLen = 32;
    +         maxLen = 0;
    +         for (i = 0; i < alphaSize; i++) {
    +            if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
    +            if (s->len[t][i] < minLen) minLen = s->len[t][i];
    +         }
    +         BZ2_hbCreateDecodeTables ( 
    +            &(s->limit[t][0]), 
    +            &(s->base[t][0]), 
    +            &(s->perm[t][0]), 
    +            &(s->len[t][0]),
    +            minLen, maxLen, alphaSize
    +         );
    +         s->minLens[t] = minLen;
    +      }
    +
    +      /*--- Now the MTF values ---*/
    +
    +      EOB      = s->nInUse+1;
    +      nblockMAX = 100000 * s->blockSize100k;
    +      groupNo  = -1;
    +      groupPos = 0;
    +
    +      for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
    +
    +      /*-- MTF init --*/
    +      {
    +         Int32 ii, jj, kk;
    +         kk = MTFA_SIZE-1;
    +         for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
    +            for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
    +               s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
    +               kk--;
    +            }
    +            s->mtfbase[ii] = kk + 1;
    +         }
    +      }
    +      /*-- end MTF init --*/
    +
    +      nblock = 0;
    +      GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
    +
    +      while (True) {
    +
    +         if (nextSym == EOB) break;
    +
    +         if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
    +
    +            es = -1;
    +            N = 1;
    +            do {
    +               /* Check that N doesn't get too big, so that es doesn't
    +                  go negative.  The maximum value that can be
    +                  RUNA/RUNB encoded is equal to the block size (post
    +                  the initial RLE), viz, 900k, so bounding N at 2
    +                  million should guard against overflow without
    +                  rejecting any legitimate inputs. */
    +               if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
    +               if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
    +               if (nextSym == BZ_RUNB) es = es + (1+1) * N;
    +               N = N * 2;
    +               GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
    +            }
    +               while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
    +
    +            es++;
    +            uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
    +            s->unzftab[uc] += es;
    +
    +            if (s->smallDecompress)
    +               while (es > 0) {
    +                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
    +                  s->ll16[nblock] = (UInt16)uc;
    +                  nblock++;
    +                  es--;
    +               }
    +            else
    +               while (es > 0) {
    +                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
    +                  s->tt[nblock] = (UInt32)uc;
    +                  nblock++;
    +                  es--;
    +               };
    +
    +            continue;
    +
    +         } else {
    +
    +            if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
    +
    +            /*-- uc = MTF ( nextSym-1 ) --*/
    +            {
    +               Int32 ii, jj, kk, pp, lno, off;
    +               UInt32 nn;
    +               nn = (UInt32)(nextSym - 1);
    +
    +               if (nn < MTFL_SIZE) {
    +                  /* avoid general-case expense */
    +                  pp = s->mtfbase[0];
    +                  uc = s->mtfa[pp+nn];
    +                  while (nn > 3) {
    +                     Int32 z = pp+nn;
    +                     s->mtfa[(z)  ] = s->mtfa[(z)-1];
    +                     s->mtfa[(z)-1] = s->mtfa[(z)-2];
    +                     s->mtfa[(z)-2] = s->mtfa[(z)-3];
    +                     s->mtfa[(z)-3] = s->mtfa[(z)-4];
    +                     nn -= 4;
    +                  }
    +                  while (nn > 0) { 
    +                     s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; 
    +                  };
    +                  s->mtfa[pp] = uc;
    +               } else { 
    +                  /* general case */
    +                  lno = nn / MTFL_SIZE;
    +                  off = nn % MTFL_SIZE;
    +                  pp = s->mtfbase[lno] + off;
    +                  uc = s->mtfa[pp];
    +                  while (pp > s->mtfbase[lno]) { 
    +                     s->mtfa[pp] = s->mtfa[pp-1]; pp--; 
    +                  };
    +                  s->mtfbase[lno]++;
    +                  while (lno > 0) {
    +                     s->mtfbase[lno]--;
    +                     s->mtfa[s->mtfbase[lno]] 
    +                        = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
    +                     lno--;
    +                  }
    +                  s->mtfbase[0]--;
    +                  s->mtfa[s->mtfbase[0]] = uc;
    +                  if (s->mtfbase[0] == 0) {
    +                     kk = MTFA_SIZE-1;
    +                     for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
    +                        for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
    +                           s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
    +                           kk--;
    +                        }
    +                        s->mtfbase[ii] = kk + 1;
    +                     }
    +                  }
    +               }
    +            }
    +            /*-- end uc = MTF ( nextSym-1 ) --*/
    +
    +            s->unzftab[s->seqToUnseq[uc]]++;
    +            if (s->smallDecompress)
    +               s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
    +               s->tt[nblock]   = (UInt32)(s->seqToUnseq[uc]);
    +            nblock++;
    +
    +            GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
    +            continue;
    +         }
    +      }
    +
    +      /* Now we know what nblock is, we can do a better sanity
    +         check on s->origPtr.
    +      */
    +      if (s->origPtr < 0 || s->origPtr >= nblock)
    +         RETURN(BZ_DATA_ERROR);
    +
    +      /*-- Set up cftab to facilitate generation of T^(-1) --*/
    +      /* Check: unzftab entries in range. */
    +      for (i = 0; i <= 255; i++) {
    +         if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
    +            RETURN(BZ_DATA_ERROR);
    +      }
    +      /* Actually generate cftab. */
    +      s->cftab[0] = 0;
    +      for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
    +      for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
    +      /* Check: cftab entries in range. */
    +      for (i = 0; i <= 256; i++) {
    +         if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
    +            /* s->cftab[i] can legitimately be == nblock */
    +            RETURN(BZ_DATA_ERROR);
    +         }
    +      }
    +      /* Check: cftab entries non-descending. */
    +      for (i = 1; i <= 256; i++) {
    +         if (s->cftab[i-1] > s->cftab[i]) {
    +            RETURN(BZ_DATA_ERROR);
    +         }
    +      }
    +
    +      s->state_out_len = 0;
    +      s->state_out_ch  = 0;
    +      BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
    +      s->state = BZ_X_OUTPUT;
    +      if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
    +
    +      if (s->smallDecompress) {
    +
    +         /*-- Make a copy of cftab, used in generation of T --*/
    +         for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
    +
    +         /*-- compute the T vector --*/
    +         for (i = 0; i < nblock; i++) {
    +            uc = (UChar)(s->ll16[i]);
    +            SET_LL(i, s->cftabCopy[uc]);
    +            s->cftabCopy[uc]++;
    +         }
    +
    +         /*-- Compute T^(-1) by pointer reversal on T --*/
    +         i = s->origPtr;
    +         j = GET_LL(i);
    +         do {
    +            Int32 tmp = GET_LL(j);
    +            SET_LL(j, i);
    +            i = j;
    +            j = tmp;
    +         }
    +            while (i != s->origPtr);
    +
    +         s->tPos = s->origPtr;
    +         s->nblock_used = 0;
    +         if (s->blockRandomised) {
    +            BZ_RAND_INIT_MASK;
    +            BZ_GET_SMALL(s->k0); s->nblock_used++;
    +            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
    +         } else {
    +            BZ_GET_SMALL(s->k0); s->nblock_used++;
    +         }
    +
    +      } else {
    +
    +         /*-- compute the T^(-1) vector --*/
    +         for (i = 0; i < nblock; i++) {
    +            uc = (UChar)(s->tt[i] & 0xff);
    +            s->tt[s->cftab[uc]] |= (i << 8);
    +            s->cftab[uc]++;
    +         }
    +
    +         s->tPos = s->tt[s->origPtr] >> 8;
    +         s->nblock_used = 0;
    +         if (s->blockRandomised) {
    +            BZ_RAND_INIT_MASK;
    +            BZ_GET_FAST(s->k0); s->nblock_used++;
    +            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
    +         } else {
    +            BZ_GET_FAST(s->k0); s->nblock_used++;
    +         }
    +
    +      }
    +
    +      RETURN(BZ_OK);
    +
    +
    +
    +    endhdr_2:
    +
    +      GET_UCHAR(BZ_X_ENDHDR_2, uc);
    +      if (uc != 0x72) RETURN(BZ_DATA_ERROR);
    +      GET_UCHAR(BZ_X_ENDHDR_3, uc);
    +      if (uc != 0x45) RETURN(BZ_DATA_ERROR);
    +      GET_UCHAR(BZ_X_ENDHDR_4, uc);
    +      if (uc != 0x38) RETURN(BZ_DATA_ERROR);
    +      GET_UCHAR(BZ_X_ENDHDR_5, uc);
    +      if (uc != 0x50) RETURN(BZ_DATA_ERROR);
    +      GET_UCHAR(BZ_X_ENDHDR_6, uc);
    +      if (uc != 0x90) RETURN(BZ_DATA_ERROR);
    +
    +      s->storedCombinedCRC = 0;
    +      GET_UCHAR(BZ_X_CCRC_1, uc);
    +      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
    +      GET_UCHAR(BZ_X_CCRC_2, uc);
    +      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
    +      GET_UCHAR(BZ_X_CCRC_3, uc);
    +      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
    +      GET_UCHAR(BZ_X_CCRC_4, uc);
    +      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
    +
    +      s->state = BZ_X_IDLE;
    +      RETURN(BZ_STREAM_END);
    +
    +      default: AssertH ( False, 4001 );
    +   }
    +
    +   AssertH ( False, 4002 );
    +
    +   save_state_and_return:
    +
    +   s->save_i           = i;
    +   s->save_j           = j;
    +   s->save_t           = t;
    +   s->save_alphaSize   = alphaSize;
    +   s->save_nGroups     = nGroups;
    +   s->save_nSelectors  = nSelectors;
    +   s->save_EOB         = EOB;
    +   s->save_groupNo     = groupNo;
    +   s->save_groupPos    = groupPos;
    +   s->save_nextSym     = nextSym;
    +   s->save_nblockMAX   = nblockMAX;
    +   s->save_nblock      = nblock;
    +   s->save_es          = es;
    +   s->save_N           = N;
    +   s->save_curr        = curr;
    +   s->save_zt          = zt;
    +   s->save_zn          = zn;
    +   s->save_zvec        = zvec;
    +   s->save_zj          = zj;
    +   s->save_gSel        = gSel;
    +   s->save_gMinlen     = gMinlen;
    +   s->save_gLimit      = gLimit;
    +   s->save_gBase       = gBase;
    +   s->save_gPerm       = gPerm;
    +
    +   return retVal;   
    +}
    +
    +
    +/*-------------------------------------------------------------*/
    +/*--- end                                      decompress.c ---*/
    +/*-------------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/huffman.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/huffman.c
    new file mode 100644
    index 00000000000..43a1899e468
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/huffman.c
    @@ -0,0 +1,205 @@
    +
    +/*-------------------------------------------------------------*/
    +/*--- Huffman coding low-level stuff                        ---*/
    +/*---                                             huffman.c ---*/
    +/*-------------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +
    +#include "bzlib_private.h"
    +
    +/*---------------------------------------------------*/
    +#define WEIGHTOF(zz0)  ((zz0) & 0xffffff00)
    +#define DEPTHOF(zz1)   ((zz1) & 0x000000ff)
    +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
    +
    +#define ADDWEIGHTS(zw1,zw2)                           \
    +   (WEIGHTOF(zw1)+WEIGHTOF(zw2)) |                    \
    +   (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
    +
    +#define UPHEAP(z)                                     \
    +{                                                     \
    +   Int32 zz, tmp;                                     \
    +   zz = z; tmp = heap[zz];                            \
    +   while (weight[tmp] < weight[heap[zz >> 1]]) {      \
    +      heap[zz] = heap[zz >> 1];                       \
    +      zz >>= 1;                                       \
    +   }                                                  \
    +   heap[zz] = tmp;                                    \
    +}
    +
    +#define DOWNHEAP(z)                                   \
    +{                                                     \
    +   Int32 zz, yy, tmp;                                 \
    +   zz = z; tmp = heap[zz];                            \
    +   while (True) {                                     \
    +      yy = zz << 1;                                   \
    +      if (yy > nHeap) break;                          \
    +      if (yy < nHeap &&                               \
    +          weight[heap[yy+1]] < weight[heap[yy]])      \
    +         yy++;                                        \
    +      if (weight[tmp] < weight[heap[yy]]) break;      \
    +      heap[zz] = heap[yy];                            \
    +      zz = yy;                                        \
    +   }                                                  \
    +   heap[zz] = tmp;                                    \
    +}
    +
    +
    +/*---------------------------------------------------*/
    +void BZ2_hbMakeCodeLengths ( UChar *len, 
    +                             Int32 *freq,
    +                             Int32 alphaSize,
    +                             Int32 maxLen )
    +{
    +   /*--
    +      Nodes and heap entries run from 1.  Entry 0
    +      for both the heap and nodes is a sentinel.
    +   --*/
    +   Int32 nNodes, nHeap, n1, n2, i, j, k;
    +   Bool  tooLong;
    +
    +   Int32 heap   [ BZ_MAX_ALPHA_SIZE + 2 ];
    +   Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
    +   Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; 
    +
    +   for (i = 0; i < alphaSize; i++)
    +      weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
    +
    +   while (True) {
    +
    +      nNodes = alphaSize;
    +      nHeap = 0;
    +
    +      heap[0] = 0;
    +      weight[0] = 0;
    +      parent[0] = -2;
    +
    +      for (i = 1; i <= alphaSize; i++) {
    +         parent[i] = -1;
    +         nHeap++;
    +         heap[nHeap] = i;
    +         UPHEAP(nHeap);
    +      }
    +
    +      AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
    +   
    +      while (nHeap > 1) {
    +         n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
    +         n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
    +         nNodes++;
    +         parent[n1] = parent[n2] = nNodes;
    +         weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
    +         parent[nNodes] = -1;
    +         nHeap++;
    +         heap[nHeap] = nNodes;
    +         UPHEAP(nHeap);
    +      }
    +
    +      AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
    +
    +      tooLong = False;
    +      for (i = 1; i <= alphaSize; i++) {
    +         j = 0;
    +         k = i;
    +         while (parent[k] >= 0) { k = parent[k]; j++; }
    +         len[i-1] = j;
    +         if (j > maxLen) tooLong = True;
    +      }
    +      
    +      if (! tooLong) break;
    +
    +      /* 17 Oct 04: keep-going condition for the following loop used
    +         to be 'i < alphaSize', which missed the last element,
    +         theoretically leading to the possibility of the compressor
    +         looping.  However, this count-scaling step is only needed if
    +         one of the generated Huffman code words is longer than
    +         maxLen, which up to and including version 1.0.2 was 20 bits,
    +         which is extremely unlikely.  In version 1.0.3 maxLen was
    +         changed to 17 bits, which has minimal effect on compression
    +         ratio, but does mean this scaling step is used from time to
    +         time, enough to verify that it works.
    +
    +         This means that bzip2-1.0.3 and later will only produce
    +         Huffman codes with a maximum length of 17 bits.  However, in
    +         order to preserve backwards compatibility with bitstreams
    +         produced by versions pre-1.0.3, the decompressor must still
    +         handle lengths of up to 20. */
    +
    +      for (i = 1; i <= alphaSize; i++) {
    +         j = weight[i] >> 8;
    +         j = 1 + (j / 2);
    +         weight[i] = j << 8;
    +      }
    +   }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +void BZ2_hbAssignCodes ( Int32 *code,
    +                         UChar *length,
    +                         Int32 minLen,
    +                         Int32 maxLen,
    +                         Int32 alphaSize )
    +{
    +   Int32 n, vec, i;
    +
    +   vec = 0;
    +   for (n = minLen; n <= maxLen; n++) {
    +      for (i = 0; i < alphaSize; i++)
    +         if (length[i] == n) { code[i] = vec; vec++; };
    +      vec <<= 1;
    +   }
    +}
    +
    +
    +/*---------------------------------------------------*/
    +void BZ2_hbCreateDecodeTables ( Int32 *limit,
    +                                Int32 *base,
    +                                Int32 *perm,
    +                                UChar *length,
    +                                Int32 minLen,
    +                                Int32 maxLen,
    +                                Int32 alphaSize )
    +{
    +   Int32 pp, i, j, vec;
    +
    +   pp = 0;
    +   for (i = minLen; i <= maxLen; i++)
    +      for (j = 0; j < alphaSize; j++)
    +         if (length[j] == i) { perm[pp] = j; pp++; };
    +
    +   for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
    +   for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
    +
    +   for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
    +
    +   for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
    +   vec = 0;
    +
    +   for (i = minLen; i <= maxLen; i++) {
    +      vec += (base[i+1] - base[i]);
    +      limit[i] = vec-1;
    +      vec <<= 1;
    +   }
    +   for (i = minLen + 1; i <= maxLen; i++)
    +      base[i] = ((limit[i-1] + 1) << 1) - base[i];
    +}
    +
    +
    +/*-------------------------------------------------------------*/
    +/*--- end                                         huffman.c ---*/
    +/*-------------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/mk251.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/mk251.c
    new file mode 100644
    index 00000000000..6c5bbf9350e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/mk251.c
    @@ -0,0 +1,31 @@
    +
    +/* Spew out a long sequence of the byte 251.  When fed to bzip2
    +   versions 1.0.0 or 1.0.1, causes it to die with internal error
    +   1007 in blocksort.c.  This assertion misses an extremely rare
    +   case, which is fixed in this version (1.0.2) and above.
    +*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +
    +#include 
    +
    +int main ()
    +{
    +   int i;
    +   for (i = 0; i < 48500000 ; i++)
    +     putchar(251);
    +   return 0;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/randtable.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/randtable.c
    new file mode 100644
    index 00000000000..bdc6d4a4cc9
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/randtable.c
    @@ -0,0 +1,84 @@
    +
    +/*-------------------------------------------------------------*/
    +/*--- Table for randomising repetitive blocks               ---*/
    +/*---                                           randtable.c ---*/
    +/*-------------------------------------------------------------*/
    +
    +/* ------------------------------------------------------------------
    +   This file is part of bzip2/libbzip2, a program and library for
    +   lossless, block-sorting data compression.
    +
    +   bzip2/libbzip2 version 1.0.8 of 13 July 2019
    +   Copyright (C) 1996-2019 Julian Seward 
    +
    +   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
    +   README file.
    +
    +   This program is released under the terms of the license contained
    +   in the file LICENSE.
    +   ------------------------------------------------------------------ */
    +
    +
    +#include "bzlib_private.h"
    +
    +
    +/*---------------------------------------------*/
    +Int32 BZ2_rNums[512] = { 
    +   619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 
    +   985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 
    +   733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 
    +   419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 
    +   878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 
    +   862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 
    +   150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 
    +   170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 
    +   73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 
    +   909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 
    +   641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 
    +   161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 
    +   382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 
    +   98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 
    +   227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 
    +   469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 
    +   184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 
    +   715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 
    +   951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 
    +   652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 
    +   645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 
    +   609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 
    +   653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 
    +   411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 
    +   170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 
    +   857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 
    +   669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 
    +   944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 
    +   344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 
    +   897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 
    +   433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 
    +   686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 
    +   946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 
    +   978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 
    +   680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 
    +   707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 
    +   297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 
    +   134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 
    +   343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 
    +   140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 
    +   170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 
    +   369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 
    +   804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 
    +   896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 
    +   661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 
    +   768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 
    +   61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 
    +   372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 
    +   780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 
    +   920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 
    +   645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 
    +   936, 638
    +};
    +
    +
    +/*-------------------------------------------------------------*/
    +/*--- end                                       randtable.c ---*/
    +/*-------------------------------------------------------------*/
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/AUTHORS b/src/libs/3rdparty/karchive/3rdparty/xz/AUTHORS
    new file mode 100644
    index 00000000000..5eff238ae41
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/AUTHORS
    @@ -0,0 +1,58 @@
    +
    +Authors of XZ Utils
    +===================
    +
    +    XZ Utils is developed and maintained by
    +    Lasse Collin .
    +
    +    Major parts of liblzma are based on code written by Igor Pavlov,
    +    specifically the LZMA SDK . Without
    +    this code, XZ Utils wouldn't exist.
    +
    +    The SHA-256 implementation in liblzma is based on code written by
    +    Wei Dai in Crypto++ Library .
    +
    +    A few scripts have been adapted from GNU gzip. The original
    +    versions were written by Jean-loup Gailly, Charles Levert, and
    +    Paul Eggert. Andrew Dudman helped adapting the scripts and their
    +    man pages for XZ Utils.
    +
    +    The initial version of the threaded .xz decompressor was written
    +    by Sebastian Andrzej Siewior.
    +
    +    The initial version of the .lz (lzip) decoder was written
    +    by Michał Górny.
    +
    +    Architecture-specific CRC optimizations were contributed by
    +    Ilya Kurdyukov, Hans Jansen, and Chenxi Mao.
    +
    +    Other authors:
    +      - Jonathan Nieder
    +      - Joachim Henke
    +
    +    Special author: Jia Tan was a co-maintainer in 2022-2024. He and
    +    the team behind him inserted a backdoor (CVE-2024-3094) into
    +    XZ Utils 5.6.0 and 5.6.1 releases. He suddenly disappeared when
    +    this was discovered.
    +
    +    Many people have contributed improvements or reported bugs.
    +    Most of these people are mentioned in the file THANKS.
    +
    +    The translations of the command line tools and man pages have been
    +    contributed by many people via the Translation Project:
    +
    +      - https://translationproject.org/domain/xz.html
    +      - https://translationproject.org/domain/xz-man.html
    +
    +    The authors of the translated man pages are in the header comments
    +    of the man page files. In the source package, the authors of the
    +    translations are in po/*.po and po4a/*.po files.
    +
    +    Third-party code whose authors aren't listed here:
    +
    +      - GNU getopt_long() in the 'lib' directory is included for
    +        platforms that don't have a usable getopt_long().
    +
    +      - The build system files from GNU Autoconf, GNU Automake,
    +        GNU Libtool, GNU Gettext, Autoconf Archive, and related files.
    +
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING
    new file mode 100644
    index 00000000000..aed21531497
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING
    @@ -0,0 +1,83 @@
    +
    +XZ Utils Licensing
    +==================
    +
    +    Different licenses apply to different files in this package. Here
    +    is a summary of which licenses apply to which parts of this package:
    +
    +      - liblzma is under the BSD Zero Clause License (0BSD).
    +
    +      - The command line tools xz, xzdec, lzmadec, and lzmainfo are
    +        under 0BSD except that, on systems that don't have a usable
    +        getopt_long, GNU getopt_long is compiled and linked in from the
    +        'lib' directory. The getopt_long code is under GNU LGPLv2.1+.
    +
    +      - The scripts to grep, diff, and view compressed files have been
    +        adapted from GNU gzip. These scripts (xzgrep, xzdiff, xzless,
    +        and xzmore) are under GNU GPLv2+. The man pages of the scripts
    +        are under 0BSD; they aren't based on the man pages of GNU gzip.
    +
    +      - Most of the XZ Utils specific documentation that is in
    +        plain text files (like README, INSTALL, PACKAGERS, NEWS,
    +        and ChangeLog) are under 0BSD unless stated otherwise in
    +        the file itself. The files xz-file-format.txt and
    +        lzma-file-format.xt are in the public domain but may
    +        be distributed under the terms of 0BSD too.
    +
    +      - Translated messages and man pages are under 0BSD except that
    +        some old translations are in the public domain.
    +
    +      - Test files and test code in the 'tests' directory, and
    +        debugging utilities in the 'debug' directory are under
    +        the BSD Zero Clause License (0BSD).
    +
    +      - The GNU Autotools based build system contains files that are
    +        under GNU GPLv2+, GNU GPLv3+, and a few permissive licenses.
    +        These files don't affect the licensing of the binaries being
    +        built.
    +
    +      - The 'extra' directory contains files that are under various
    +        free software licenses. These aren't built or installed as
    +        part of XZ Utils.
    +
    +    For the files under the BSD Zero Clause License (0BSD), if
    +    a copyright notice is needed, the following is sufficient:
    +
    +        Copyright (C) The XZ Utils authors and contributors
    +
    +    If you copy significant amounts of 0BSD-licensed code from XZ Utils
    +    into your project, acknowledging this somewhere in your software is
    +    polite (especially if it is proprietary, non-free software), but
    +    it is not legally required by the license terms. Here is an example
    +    of a good notice to put into "about box" or into documentation:
    +
    +        This software includes code from XZ Utils .
    +
    +    The following license texts are included in the following files:
    +      - COPYING.0BSD: BSD Zero Clause License
    +      - COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1
    +      - COPYING.GPLv2: GNU General Public License version 2
    +      - COPYING.GPLv3: GNU General Public License version 3
    +
    +    A note about old XZ Utils releases:
    +
    +        XZ Utils releases 5.4.6 and older and 5.5.1alpha have a
    +        significant amount of code put into the public domain and
    +        that obviously remains so. The switch from public domain to
    +        0BSD for newer releases was made in Febrary 2024 because
    +        public domain has (real or perceived) legal ambiguities in
    +        some jurisdictions.
    +
    +        There is very little *practical* difference between public
    +        domain and 0BSD. The main difference likely is that one
    +        shouldn't claim that 0BSD-licensed code is in the public
    +        domain; 0BSD-licensed code is copyrighted but available under
    +        an extremely permissive license. Neither 0BSD nor public domain
    +        require retaining or reproducing author, copyright holder, or
    +        license notices when distributing the software. (Compare to,
    +        for example, BSD 2-Clause "Simplified" License which does have
    +        such requirements.)
    +
    +    If you have questions, don't hesitate to ask for more information.
    +    The contact information is in the README file.
    +
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.0BSD b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.0BSD
    new file mode 100644
    index 00000000000..4322122aecf
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.0BSD
    @@ -0,0 +1,11 @@
    +Permission to use, copy, modify, and/or distribute this
    +software for any purpose with or without fee is hereby granted.
    +
    +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
    +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
    +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
    +THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
    +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
    +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
    +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv2 b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv2
    new file mode 100644
    index 00000000000..d159169d105
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv2
    @@ -0,0 +1,339 @@
    +                    GNU GENERAL PUBLIC LICENSE
    +                       Version 2, June 1991
    +
    + Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
    + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    + Everyone is permitted to copy and distribute verbatim copies
    + of this license document, but changing it is not allowed.
    +
    +                            Preamble
    +
    +  The licenses for most software are designed to take away your
    +freedom to share and change it.  By contrast, the GNU General Public
    +License is intended to guarantee your freedom to share and change free
    +software--to make sure the software is free for all its users.  This
    +General Public License applies to most of the Free Software
    +Foundation's software and to any other program whose authors commit to
    +using it.  (Some other Free Software Foundation software is covered by
    +the GNU Lesser General Public License instead.)  You can apply it to
    +your programs, too.
    +
    +  When we speak of free software, we are referring to freedom, not
    +price.  Our General Public Licenses are designed to make sure that you
    +have the freedom to distribute copies of free software (and charge for
    +this service if you wish), that you receive source code or can get it
    +if you want it, that you can change the software or use pieces of it
    +in new free programs; and that you know you can do these things.
    +
    +  To protect your rights, we need to make restrictions that forbid
    +anyone to deny you these rights or to ask you to surrender the rights.
    +These restrictions translate to certain responsibilities for you if you
    +distribute copies of the software, or if you modify it.
    +
    +  For example, if you distribute copies of such a program, whether
    +gratis or for a fee, you must give the recipients all the rights that
    +you have.  You must make sure that they, too, receive or can get the
    +source code.  And you must show them these terms so they know their
    +rights.
    +
    +  We protect your rights with two steps: (1) copyright the software, and
    +(2) offer you this license which gives you legal permission to copy,
    +distribute and/or modify the software.
    +
    +  Also, for each author's protection and ours, we want to make certain
    +that everyone understands that there is no warranty for this free
    +software.  If the software is modified by someone else and passed on, we
    +want its recipients to know that what they have is not the original, so
    +that any problems introduced by others will not reflect on the original
    +authors' reputations.
    +
    +  Finally, any free program is threatened constantly by software
    +patents.  We wish to avoid the danger that redistributors of a free
    +program will individually obtain patent licenses, in effect making the
    +program proprietary.  To prevent this, we have made it clear that any
    +patent must be licensed for everyone's free use or not licensed at all.
    +
    +  The precise terms and conditions for copying, distribution and
    +modification follow.
    +
    +                    GNU GENERAL PUBLIC LICENSE
    +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    +
    +  0. This License applies to any program or other work which contains
    +a notice placed by the copyright holder saying it may be distributed
    +under the terms of this General Public License.  The "Program", below,
    +refers to any such program or work, and a "work based on the Program"
    +means either the Program or any derivative work under copyright law:
    +that is to say, a work containing the Program or a portion of it,
    +either verbatim or with modifications and/or translated into another
    +language.  (Hereinafter, translation is included without limitation in
    +the term "modification".)  Each licensee is addressed as "you".
    +
    +Activities other than copying, distribution and modification are not
    +covered by this License; they are outside its scope.  The act of
    +running the Program is not restricted, and the output from the Program
    +is covered only if its contents constitute a work based on the
    +Program (independent of having been made by running the Program).
    +Whether that is true depends on what the Program does.
    +
    +  1. You may copy and distribute verbatim copies of the Program's
    +source code as you receive it, in any medium, provided that you
    +conspicuously and appropriately publish on each copy an appropriate
    +copyright notice and disclaimer of warranty; keep intact all the
    +notices that refer to this License and to the absence of any warranty;
    +and give any other recipients of the Program a copy of this License
    +along with the Program.
    +
    +You may charge a fee for the physical act of transferring a copy, and
    +you may at your option offer warranty protection in exchange for a fee.
    +
    +  2. You may modify your copy or copies of the Program or any portion
    +of it, thus forming a work based on the Program, and copy and
    +distribute such modifications or work under the terms of Section 1
    +above, provided that you also meet all of these conditions:
    +
    +    a) You must cause the modified files to carry prominent notices
    +    stating that you changed the files and the date of any change.
    +
    +    b) You must cause any work that you distribute or publish, that in
    +    whole or in part contains or is derived from the Program or any
    +    part thereof, to be licensed as a whole at no charge to all third
    +    parties under the terms of this License.
    +
    +    c) If the modified program normally reads commands interactively
    +    when run, you must cause it, when started running for such
    +    interactive use in the most ordinary way, to print or display an
    +    announcement including an appropriate copyright notice and a
    +    notice that there is no warranty (or else, saying that you provide
    +    a warranty) and that users may redistribute the program under
    +    these conditions, and telling the user how to view a copy of this
    +    License.  (Exception: if the Program itself is interactive but
    +    does not normally print such an announcement, your work based on
    +    the Program is not required to print an announcement.)
    +
    +These requirements apply to the modified work as a whole.  If
    +identifiable sections of that work are not derived from the Program,
    +and can be reasonably considered independent and separate works in
    +themselves, then this License, and its terms, do not apply to those
    +sections when you distribute them as separate works.  But when you
    +distribute the same sections as part of a whole which is a work based
    +on the Program, the distribution of the whole must be on the terms of
    +this License, whose permissions for other licensees extend to the
    +entire whole, and thus to each and every part regardless of who wrote it.
    +
    +Thus, it is not the intent of this section to claim rights or contest
    +your rights to work written entirely by you; rather, the intent is to
    +exercise the right to control the distribution of derivative or
    +collective works based on the Program.
    +
    +In addition, mere aggregation of another work not based on the Program
    +with the Program (or with a work based on the Program) on a volume of
    +a storage or distribution medium does not bring the other work under
    +the scope of this License.
    +
    +  3. You may copy and distribute the Program (or a work based on it,
    +under Section 2) in object code or executable form under the terms of
    +Sections 1 and 2 above provided that you also do one of the following:
    +
    +    a) Accompany it with the complete corresponding machine-readable
    +    source code, which must be distributed under the terms of Sections
    +    1 and 2 above on a medium customarily used for software interchange; or,
    +
    +    b) Accompany it with a written offer, valid for at least three
    +    years, to give any third party, for a charge no more than your
    +    cost of physically performing source distribution, a complete
    +    machine-readable copy of the corresponding source code, to be
    +    distributed under the terms of Sections 1 and 2 above on a medium
    +    customarily used for software interchange; or,
    +
    +    c) Accompany it with the information you received as to the offer
    +    to distribute corresponding source code.  (This alternative is
    +    allowed only for noncommercial distribution and only if you
    +    received the program in object code or executable form with such
    +    an offer, in accord with Subsection b above.)
    +
    +The source code for a work means the preferred form of the work for
    +making modifications to it.  For an executable work, complete source
    +code means all the source code for all modules it contains, plus any
    +associated interface definition files, plus the scripts used to
    +control compilation and installation of the executable.  However, as a
    +special exception, the source code distributed need not include
    +anything that is normally distributed (in either source or binary
    +form) with the major components (compiler, kernel, and so on) of the
    +operating system on which the executable runs, unless that component
    +itself accompanies the executable.
    +
    +If distribution of executable or object code is made by offering
    +access to copy from a designated place, then offering equivalent
    +access to copy the source code from the same place counts as
    +distribution of the source code, even though third parties are not
    +compelled to copy the source along with the object code.
    +
    +  4. You may not copy, modify, sublicense, or distribute the Program
    +except as expressly provided under this License.  Any attempt
    +otherwise to copy, modify, sublicense or distribute the Program is
    +void, and will automatically terminate your rights under this License.
    +However, parties who have received copies, or rights, from you under
    +this License will not have their licenses terminated so long as such
    +parties remain in full compliance.
    +
    +  5. You are not required to accept this License, since you have not
    +signed it.  However, nothing else grants you permission to modify or
    +distribute the Program or its derivative works.  These actions are
    +prohibited by law if you do not accept this License.  Therefore, by
    +modifying or distributing the Program (or any work based on the
    +Program), you indicate your acceptance of this License to do so, and
    +all its terms and conditions for copying, distributing or modifying
    +the Program or works based on it.
    +
    +  6. Each time you redistribute the Program (or any work based on the
    +Program), the recipient automatically receives a license from the
    +original licensor to copy, distribute or modify the Program subject to
    +these terms and conditions.  You may not impose any further
    +restrictions on the recipients' exercise of the rights granted herein.
    +You are not responsible for enforcing compliance by third parties to
    +this License.
    +
    +  7. If, as a consequence of a court judgment or allegation of patent
    +infringement or for any other reason (not limited to patent issues),
    +conditions are imposed on you (whether by court order, agreement or
    +otherwise) that contradict the conditions of this License, they do not
    +excuse you from the conditions of this License.  If you cannot
    +distribute so as to satisfy simultaneously your obligations under this
    +License and any other pertinent obligations, then as a consequence you
    +may not distribute the Program at all.  For example, if a patent
    +license would not permit royalty-free redistribution of the Program by
    +all those who receive copies directly or indirectly through you, then
    +the only way you could satisfy both it and this License would be to
    +refrain entirely from distribution of the Program.
    +
    +If any portion of this section is held invalid or unenforceable under
    +any particular circumstance, the balance of the section is intended to
    +apply and the section as a whole is intended to apply in other
    +circumstances.
    +
    +It is not the purpose of this section to induce you to infringe any
    +patents or other property right claims or to contest validity of any
    +such claims; this section has the sole purpose of protecting the
    +integrity of the free software distribution system, which is
    +implemented by public license practices.  Many people have made
    +generous contributions to the wide range of software distributed
    +through that system in reliance on consistent application of that
    +system; it is up to the author/donor to decide if he or she is willing
    +to distribute software through any other system and a licensee cannot
    +impose that choice.
    +
    +This section is intended to make thoroughly clear what is believed to
    +be a consequence of the rest of this License.
    +
    +  8. If the distribution and/or use of the Program is restricted in
    +certain countries either by patents or by copyrighted interfaces, the
    +original copyright holder who places the Program under this License
    +may add an explicit geographical distribution limitation excluding
    +those countries, so that distribution is permitted only in or among
    +countries not thus excluded.  In such case, this License incorporates
    +the limitation as if written in the body of this License.
    +
    +  9. The Free Software Foundation may publish revised and/or new versions
    +of the General Public License from time to time.  Such new versions will
    +be similar in spirit to the present version, but may differ in detail to
    +address new problems or concerns.
    +
    +Each version is given a distinguishing version number.  If the Program
    +specifies a version number of this License which applies to it and "any
    +later version", you have the option of following the terms and conditions
    +either of that version or of any later version published by the Free
    +Software Foundation.  If the Program does not specify a version number of
    +this License, you may choose any version ever published by the Free Software
    +Foundation.
    +
    +  10. If you wish to incorporate parts of the Program into other free
    +programs whose distribution conditions are different, write to the author
    +to ask for permission.  For software which is copyrighted by the Free
    +Software Foundation, write to the Free Software Foundation; we sometimes
    +make exceptions for this.  Our decision will be guided by the two goals
    +of preserving the free status of all derivatives of our free software and
    +of promoting the sharing and reuse of software generally.
    +
    +                            NO WARRANTY
    +
    +  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
    +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
    +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
    +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
    +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
    +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
    +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
    +REPAIR OR CORRECTION.
    +
    +  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
    +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
    +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
    +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
    +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
    +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
    +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
    +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
    +POSSIBILITY OF SUCH DAMAGES.
    +
    +                     END OF TERMS AND CONDITIONS
    +
    +            How to Apply These Terms to Your New Programs
    +
    +  If you develop a new program, and you want it to be of the greatest
    +possible use to the public, the best way to achieve this is to make it
    +free software which everyone can redistribute and change under these terms.
    +
    +  To do so, attach the following notices to the program.  It is safest
    +to attach them to the start of each source file to most effectively
    +convey the exclusion of warranty; and each file should have at least
    +the "copyright" line and a pointer to where the full notice is found.
    +
    +    
    +    Copyright (C)   
    +
    +    This program is free software; you can redistribute it and/or modify
    +    it under the terms of the GNU General Public License as published by
    +    the Free Software Foundation; either version 2 of the License, or
    +    (at your option) any later version.
    +
    +    This program is distributed in the hope that it will be useful,
    +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +    GNU General Public License for more details.
    +
    +    You should have received a copy of the GNU General Public License along
    +    with this program; if not, write to the Free Software Foundation, Inc.,
    +    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    +
    +Also add information on how to contact you by electronic and paper mail.
    +
    +If the program is interactive, make it output a short notice like this
    +when it starts in an interactive mode:
    +
    +    Gnomovision version 69, Copyright (C) year name of author
    +    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    +    This is free software, and you are welcome to redistribute it
    +    under certain conditions; type `show c' for details.
    +
    +The hypothetical commands `show w' and `show c' should show the appropriate
    +parts of the General Public License.  Of course, the commands you use may
    +be called something other than `show w' and `show c'; they could even be
    +mouse-clicks or menu items--whatever suits your program.
    +
    +You should also get your employer (if you work as a programmer) or your
    +school, if any, to sign a "copyright disclaimer" for the program, if
    +necessary.  Here is a sample; alter the names:
    +
    +  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
    +  `Gnomovision' (which makes passes at compilers) written by James Hacker.
    +
    +  , 1 April 1989
    +  Ty Coon, President of Vice
    +
    +This General Public License does not permit incorporating your program into
    +proprietary programs.  If your program is a subroutine library, you may
    +consider it more useful to permit linking proprietary applications with the
    +library.  If this is what you want to do, use the GNU Lesser General
    +Public License instead of this License.
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv3 b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv3
    new file mode 100644
    index 00000000000..f288702d2fa
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv3
    @@ -0,0 +1,674 @@
    +                    GNU GENERAL PUBLIC LICENSE
    +                       Version 3, 29 June 2007
    +
    + Copyright (C) 2007 Free Software Foundation, Inc. 
    + Everyone is permitted to copy and distribute verbatim copies
    + of this license document, but changing it is not allowed.
    +
    +                            Preamble
    +
    +  The GNU General Public License is a free, copyleft license for
    +software and other kinds of works.
    +
    +  The licenses for most software and other practical works are designed
    +to take away your freedom to share and change the works.  By contrast,
    +the GNU General Public License is intended to guarantee your freedom to
    +share and change all versions of a program--to make sure it remains free
    +software for all its users.  We, the Free Software Foundation, use the
    +GNU General Public License for most of our software; it applies also to
    +any other work released this way by its authors.  You can apply it to
    +your programs, too.
    +
    +  When we speak of free software, we are referring to freedom, not
    +price.  Our General Public Licenses are designed to make sure that you
    +have the freedom to distribute copies of free software (and charge for
    +them if you wish), that you receive source code or can get it if you
    +want it, that you can change the software or use pieces of it in new
    +free programs, and that you know you can do these things.
    +
    +  To protect your rights, we need to prevent others from denying you
    +these rights or asking you to surrender the rights.  Therefore, you have
    +certain responsibilities if you distribute copies of the software, or if
    +you modify it: responsibilities to respect the freedom of others.
    +
    +  For example, if you distribute copies of such a program, whether
    +gratis or for a fee, you must pass on to the recipients the same
    +freedoms that you received.  You must make sure that they, too, receive
    +or can get the source code.  And you must show them these terms so they
    +know their rights.
    +
    +  Developers that use the GNU GPL protect your rights with two steps:
    +(1) assert copyright on the software, and (2) offer you this License
    +giving you legal permission to copy, distribute and/or modify it.
    +
    +  For the developers' and authors' protection, the GPL clearly explains
    +that there is no warranty for this free software.  For both users' and
    +authors' sake, the GPL requires that modified versions be marked as
    +changed, so that their problems will not be attributed erroneously to
    +authors of previous versions.
    +
    +  Some devices are designed to deny users access to install or run
    +modified versions of the software inside them, although the manufacturer
    +can do so.  This is fundamentally incompatible with the aim of
    +protecting users' freedom to change the software.  The systematic
    +pattern of such abuse occurs in the area of products for individuals to
    +use, which is precisely where it is most unacceptable.  Therefore, we
    +have designed this version of the GPL to prohibit the practice for those
    +products.  If such problems arise substantially in other domains, we
    +stand ready to extend this provision to those domains in future versions
    +of the GPL, as needed to protect the freedom of users.
    +
    +  Finally, every program is threatened constantly by software patents.
    +States should not allow patents to restrict development and use of
    +software on general-purpose computers, but in those that do, we wish to
    +avoid the special danger that patents applied to a free program could
    +make it effectively proprietary.  To prevent this, the GPL assures that
    +patents cannot be used to render the program non-free.
    +
    +  The precise terms and conditions for copying, distribution and
    +modification follow.
    +
    +                       TERMS AND CONDITIONS
    +
    +  0. Definitions.
    +
    +  "This License" refers to version 3 of the GNU General Public License.
    +
    +  "Copyright" also means copyright-like laws that apply to other kinds of
    +works, such as semiconductor masks.
    +
    +  "The Program" refers to any copyrightable work licensed under this
    +License.  Each licensee is addressed as "you".  "Licensees" and
    +"recipients" may be individuals or organizations.
    +
    +  To "modify" a work means to copy from or adapt all or part of the work
    +in a fashion requiring copyright permission, other than the making of an
    +exact copy.  The resulting work is called a "modified version" of the
    +earlier work or a work "based on" the earlier work.
    +
    +  A "covered work" means either the unmodified Program or a work based
    +on the Program.
    +
    +  To "propagate" a work means to do anything with it that, without
    +permission, would make you directly or secondarily liable for
    +infringement under applicable copyright law, except executing it on a
    +computer or modifying a private copy.  Propagation includes copying,
    +distribution (with or without modification), making available to the
    +public, and in some countries other activities as well.
    +
    +  To "convey" a work means any kind of propagation that enables other
    +parties to make or receive copies.  Mere interaction with a user through
    +a computer network, with no transfer of a copy, is not conveying.
    +
    +  An interactive user interface displays "Appropriate Legal Notices"
    +to the extent that it includes a convenient and prominently visible
    +feature that (1) displays an appropriate copyright notice, and (2)
    +tells the user that there is no warranty for the work (except to the
    +extent that warranties are provided), that licensees may convey the
    +work under this License, and how to view a copy of this License.  If
    +the interface presents a list of user commands or options, such as a
    +menu, a prominent item in the list meets this criterion.
    +
    +  1. Source Code.
    +
    +  The "source code" for a work means the preferred form of the work
    +for making modifications to it.  "Object code" means any non-source
    +form of a work.
    +
    +  A "Standard Interface" means an interface that either is an official
    +standard defined by a recognized standards body, or, in the case of
    +interfaces specified for a particular programming language, one that
    +is widely used among developers working in that language.
    +
    +  The "System Libraries" of an executable work include anything, other
    +than the work as a whole, that (a) is included in the normal form of
    +packaging a Major Component, but which is not part of that Major
    +Component, and (b) serves only to enable use of the work with that
    +Major Component, or to implement a Standard Interface for which an
    +implementation is available to the public in source code form.  A
    +"Major Component", in this context, means a major essential component
    +(kernel, window system, and so on) of the specific operating system
    +(if any) on which the executable work runs, or a compiler used to
    +produce the work, or an object code interpreter used to run it.
    +
    +  The "Corresponding Source" for a work in object code form means all
    +the source code needed to generate, install, and (for an executable
    +work) run the object code and to modify the work, including scripts to
    +control those activities.  However, it does not include the work's
    +System Libraries, or general-purpose tools or generally available free
    +programs which are used unmodified in performing those activities but
    +which are not part of the work.  For example, Corresponding Source
    +includes interface definition files associated with source files for
    +the work, and the source code for shared libraries and dynamically
    +linked subprograms that the work is specifically designed to require,
    +such as by intimate data communication or control flow between those
    +subprograms and other parts of the work.
    +
    +  The Corresponding Source need not include anything that users
    +can regenerate automatically from other parts of the Corresponding
    +Source.
    +
    +  The Corresponding Source for a work in source code form is that
    +same work.
    +
    +  2. Basic Permissions.
    +
    +  All rights granted under this License are granted for the term of
    +copyright on the Program, and are irrevocable provided the stated
    +conditions are met.  This License explicitly affirms your unlimited
    +permission to run the unmodified Program.  The output from running a
    +covered work is covered by this License only if the output, given its
    +content, constitutes a covered work.  This License acknowledges your
    +rights of fair use or other equivalent, as provided by copyright law.
    +
    +  You may make, run and propagate covered works that you do not
    +convey, without conditions so long as your license otherwise remains
    +in force.  You may convey covered works to others for the sole purpose
    +of having them make modifications exclusively for you, or provide you
    +with facilities for running those works, provided that you comply with
    +the terms of this License in conveying all material for which you do
    +not control copyright.  Those thus making or running the covered works
    +for you must do so exclusively on your behalf, under your direction
    +and control, on terms that prohibit them from making any copies of
    +your copyrighted material outside their relationship with you.
    +
    +  Conveying under any other circumstances is permitted solely under
    +the conditions stated below.  Sublicensing is not allowed; section 10
    +makes it unnecessary.
    +
    +  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
    +
    +  No covered work shall be deemed part of an effective technological
    +measure under any applicable law fulfilling obligations under article
    +11 of the WIPO copyright treaty adopted on 20 December 1996, or
    +similar laws prohibiting or restricting circumvention of such
    +measures.
    +
    +  When you convey a covered work, you waive any legal power to forbid
    +circumvention of technological measures to the extent such circumvention
    +is effected by exercising rights under this License with respect to
    +the covered work, and you disclaim any intention to limit operation or
    +modification of the work as a means of enforcing, against the work's
    +users, your or third parties' legal rights to forbid circumvention of
    +technological measures.
    +
    +  4. Conveying Verbatim Copies.
    +
    +  You may convey verbatim copies of the Program's source code as you
    +receive it, in any medium, provided that you conspicuously and
    +appropriately publish on each copy an appropriate copyright notice;
    +keep intact all notices stating that this License and any
    +non-permissive terms added in accord with section 7 apply to the code;
    +keep intact all notices of the absence of any warranty; and give all
    +recipients a copy of this License along with the Program.
    +
    +  You may charge any price or no price for each copy that you convey,
    +and you may offer support or warranty protection for a fee.
    +
    +  5. Conveying Modified Source Versions.
    +
    +  You may convey a work based on the Program, or the modifications to
    +produce it from the Program, in the form of source code under the
    +terms of section 4, provided that you also meet all of these conditions:
    +
    +    a) The work must carry prominent notices stating that you modified
    +    it, and giving a relevant date.
    +
    +    b) The work must carry prominent notices stating that it is
    +    released under this License and any conditions added under section
    +    7.  This requirement modifies the requirement in section 4 to
    +    "keep intact all notices".
    +
    +    c) You must license the entire work, as a whole, under this
    +    License to anyone who comes into possession of a copy.  This
    +    License will therefore apply, along with any applicable section 7
    +    additional terms, to the whole of the work, and all its parts,
    +    regardless of how they are packaged.  This License gives no
    +    permission to license the work in any other way, but it does not
    +    invalidate such permission if you have separately received it.
    +
    +    d) If the work has interactive user interfaces, each must display
    +    Appropriate Legal Notices; however, if the Program has interactive
    +    interfaces that do not display Appropriate Legal Notices, your
    +    work need not make them do so.
    +
    +  A compilation of a covered work with other separate and independent
    +works, which are not by their nature extensions of the covered work,
    +and which are not combined with it such as to form a larger program,
    +in or on a volume of a storage or distribution medium, is called an
    +"aggregate" if the compilation and its resulting copyright are not
    +used to limit the access or legal rights of the compilation's users
    +beyond what the individual works permit.  Inclusion of a covered work
    +in an aggregate does not cause this License to apply to the other
    +parts of the aggregate.
    +
    +  6. Conveying Non-Source Forms.
    +
    +  You may convey a covered work in object code form under the terms
    +of sections 4 and 5, provided that you also convey the
    +machine-readable Corresponding Source under the terms of this License,
    +in one of these ways:
    +
    +    a) Convey the object code in, or embodied in, a physical product
    +    (including a physical distribution medium), accompanied by the
    +    Corresponding Source fixed on a durable physical medium
    +    customarily used for software interchange.
    +
    +    b) Convey the object code in, or embodied in, a physical product
    +    (including a physical distribution medium), accompanied by a
    +    written offer, valid for at least three years and valid for as
    +    long as you offer spare parts or customer support for that product
    +    model, to give anyone who possesses the object code either (1) a
    +    copy of the Corresponding Source for all the software in the
    +    product that is covered by this License, on a durable physical
    +    medium customarily used for software interchange, for a price no
    +    more than your reasonable cost of physically performing this
    +    conveying of source, or (2) access to copy the
    +    Corresponding Source from a network server at no charge.
    +
    +    c) Convey individual copies of the object code with a copy of the
    +    written offer to provide the Corresponding Source.  This
    +    alternative is allowed only occasionally and noncommercially, and
    +    only if you received the object code with such an offer, in accord
    +    with subsection 6b.
    +
    +    d) Convey the object code by offering access from a designated
    +    place (gratis or for a charge), and offer equivalent access to the
    +    Corresponding Source in the same way through the same place at no
    +    further charge.  You need not require recipients to copy the
    +    Corresponding Source along with the object code.  If the place to
    +    copy the object code is a network server, the Corresponding Source
    +    may be on a different server (operated by you or a third party)
    +    that supports equivalent copying facilities, provided you maintain
    +    clear directions next to the object code saying where to find the
    +    Corresponding Source.  Regardless of what server hosts the
    +    Corresponding Source, you remain obligated to ensure that it is
    +    available for as long as needed to satisfy these requirements.
    +
    +    e) Convey the object code using peer-to-peer transmission, provided
    +    you inform other peers where the object code and Corresponding
    +    Source of the work are being offered to the general public at no
    +    charge under subsection 6d.
    +
    +  A separable portion of the object code, whose source code is excluded
    +from the Corresponding Source as a System Library, need not be
    +included in conveying the object code work.
    +
    +  A "User Product" is either (1) a "consumer product", which means any
    +tangible personal property which is normally used for personal, family,
    +or household purposes, or (2) anything designed or sold for incorporation
    +into a dwelling.  In determining whether a product is a consumer product,
    +doubtful cases shall be resolved in favor of coverage.  For a particular
    +product received by a particular user, "normally used" refers to a
    +typical or common use of that class of product, regardless of the status
    +of the particular user or of the way in which the particular user
    +actually uses, or expects or is expected to use, the product.  A product
    +is a consumer product regardless of whether the product has substantial
    +commercial, industrial or non-consumer uses, unless such uses represent
    +the only significant mode of use of the product.
    +
    +  "Installation Information" for a User Product means any methods,
    +procedures, authorization keys, or other information required to install
    +and execute modified versions of a covered work in that User Product from
    +a modified version of its Corresponding Source.  The information must
    +suffice to ensure that the continued functioning of the modified object
    +code is in no case prevented or interfered with solely because
    +modification has been made.
    +
    +  If you convey an object code work under this section in, or with, or
    +specifically for use in, a User Product, and the conveying occurs as
    +part of a transaction in which the right of possession and use of the
    +User Product is transferred to the recipient in perpetuity or for a
    +fixed term (regardless of how the transaction is characterized), the
    +Corresponding Source conveyed under this section must be accompanied
    +by the Installation Information.  But this requirement does not apply
    +if neither you nor any third party retains the ability to install
    +modified object code on the User Product (for example, the work has
    +been installed in ROM).
    +
    +  The requirement to provide Installation Information does not include a
    +requirement to continue to provide support service, warranty, or updates
    +for a work that has been modified or installed by the recipient, or for
    +the User Product in which it has been modified or installed.  Access to a
    +network may be denied when the modification itself materially and
    +adversely affects the operation of the network or violates the rules and
    +protocols for communication across the network.
    +
    +  Corresponding Source conveyed, and Installation Information provided,
    +in accord with this section must be in a format that is publicly
    +documented (and with an implementation available to the public in
    +source code form), and must require no special password or key for
    +unpacking, reading or copying.
    +
    +  7. Additional Terms.
    +
    +  "Additional permissions" are terms that supplement the terms of this
    +License by making exceptions from one or more of its conditions.
    +Additional permissions that are applicable to the entire Program shall
    +be treated as though they were included in this License, to the extent
    +that they are valid under applicable law.  If additional permissions
    +apply only to part of the Program, that part may be used separately
    +under those permissions, but the entire Program remains governed by
    +this License without regard to the additional permissions.
    +
    +  When you convey a copy of a covered work, you may at your option
    +remove any additional permissions from that copy, or from any part of
    +it.  (Additional permissions may be written to require their own
    +removal in certain cases when you modify the work.)  You may place
    +additional permissions on material, added by you to a covered work,
    +for which you have or can give appropriate copyright permission.
    +
    +  Notwithstanding any other provision of this License, for material you
    +add to a covered work, you may (if authorized by the copyright holders of
    +that material) supplement the terms of this License with terms:
    +
    +    a) Disclaiming warranty or limiting liability differently from the
    +    terms of sections 15 and 16 of this License; or
    +
    +    b) Requiring preservation of specified reasonable legal notices or
    +    author attributions in that material or in the Appropriate Legal
    +    Notices displayed by works containing it; or
    +
    +    c) Prohibiting misrepresentation of the origin of that material, or
    +    requiring that modified versions of such material be marked in
    +    reasonable ways as different from the original version; or
    +
    +    d) Limiting the use for publicity purposes of names of licensors or
    +    authors of the material; or
    +
    +    e) Declining to grant rights under trademark law for use of some
    +    trade names, trademarks, or service marks; or
    +
    +    f) Requiring indemnification of licensors and authors of that
    +    material by anyone who conveys the material (or modified versions of
    +    it) with contractual assumptions of liability to the recipient, for
    +    any liability that these contractual assumptions directly impose on
    +    those licensors and authors.
    +
    +  All other non-permissive additional terms are considered "further
    +restrictions" within the meaning of section 10.  If the Program as you
    +received it, or any part of it, contains a notice stating that it is
    +governed by this License along with a term that is a further
    +restriction, you may remove that term.  If a license document contains
    +a further restriction but permits relicensing or conveying under this
    +License, you may add to a covered work material governed by the terms
    +of that license document, provided that the further restriction does
    +not survive such relicensing or conveying.
    +
    +  If you add terms to a covered work in accord with this section, you
    +must place, in the relevant source files, a statement of the
    +additional terms that apply to those files, or a notice indicating
    +where to find the applicable terms.
    +
    +  Additional terms, permissive or non-permissive, may be stated in the
    +form of a separately written license, or stated as exceptions;
    +the above requirements apply either way.
    +
    +  8. Termination.
    +
    +  You may not propagate or modify a covered work except as expressly
    +provided under this License.  Any attempt otherwise to propagate or
    +modify it is void, and will automatically terminate your rights under
    +this License (including any patent licenses granted under the third
    +paragraph of section 11).
    +
    +  However, if you cease all violation of this License, then your
    +license from a particular copyright holder is reinstated (a)
    +provisionally, unless and until the copyright holder explicitly and
    +finally terminates your license, and (b) permanently, if the copyright
    +holder fails to notify you of the violation by some reasonable means
    +prior to 60 days after the cessation.
    +
    +  Moreover, your license from a particular copyright holder is
    +reinstated permanently if the copyright holder notifies you of the
    +violation by some reasonable means, this is the first time you have
    +received notice of violation of this License (for any work) from that
    +copyright holder, and you cure the violation prior to 30 days after
    +your receipt of the notice.
    +
    +  Termination of your rights under this section does not terminate the
    +licenses of parties who have received copies or rights from you under
    +this License.  If your rights have been terminated and not permanently
    +reinstated, you do not qualify to receive new licenses for the same
    +material under section 10.
    +
    +  9. Acceptance Not Required for Having Copies.
    +
    +  You are not required to accept this License in order to receive or
    +run a copy of the Program.  Ancillary propagation of a covered work
    +occurring solely as a consequence of using peer-to-peer transmission
    +to receive a copy likewise does not require acceptance.  However,
    +nothing other than this License grants you permission to propagate or
    +modify any covered work.  These actions infringe copyright if you do
    +not accept this License.  Therefore, by modifying or propagating a
    +covered work, you indicate your acceptance of this License to do so.
    +
    +  10. Automatic Licensing of Downstream Recipients.
    +
    +  Each time you convey a covered work, the recipient automatically
    +receives a license from the original licensors, to run, modify and
    +propagate that work, subject to this License.  You are not responsible
    +for enforcing compliance by third parties with this License.
    +
    +  An "entity transaction" is a transaction transferring control of an
    +organization, or substantially all assets of one, or subdividing an
    +organization, or merging organizations.  If propagation of a covered
    +work results from an entity transaction, each party to that
    +transaction who receives a copy of the work also receives whatever
    +licenses to the work the party's predecessor in interest had or could
    +give under the previous paragraph, plus a right to possession of the
    +Corresponding Source of the work from the predecessor in interest, if
    +the predecessor has it or can get it with reasonable efforts.
    +
    +  You may not impose any further restrictions on the exercise of the
    +rights granted or affirmed under this License.  For example, you may
    +not impose a license fee, royalty, or other charge for exercise of
    +rights granted under this License, and you may not initiate litigation
    +(including a cross-claim or counterclaim in a lawsuit) alleging that
    +any patent claim is infringed by making, using, selling, offering for
    +sale, or importing the Program or any portion of it.
    +
    +  11. Patents.
    +
    +  A "contributor" is a copyright holder who authorizes use under this
    +License of the Program or a work on which the Program is based.  The
    +work thus licensed is called the contributor's "contributor version".
    +
    +  A contributor's "essential patent claims" are all patent claims
    +owned or controlled by the contributor, whether already acquired or
    +hereafter acquired, that would be infringed by some manner, permitted
    +by this License, of making, using, or selling its contributor version,
    +but do not include claims that would be infringed only as a
    +consequence of further modification of the contributor version.  For
    +purposes of this definition, "control" includes the right to grant
    +patent sublicenses in a manner consistent with the requirements of
    +this License.
    +
    +  Each contributor grants you a non-exclusive, worldwide, royalty-free
    +patent license under the contributor's essential patent claims, to
    +make, use, sell, offer for sale, import and otherwise run, modify and
    +propagate the contents of its contributor version.
    +
    +  In the following three paragraphs, a "patent license" is any express
    +agreement or commitment, however denominated, not to enforce a patent
    +(such as an express permission to practice a patent or covenant not to
    +sue for patent infringement).  To "grant" such a patent license to a
    +party means to make such an agreement or commitment not to enforce a
    +patent against the party.
    +
    +  If you convey a covered work, knowingly relying on a patent license,
    +and the Corresponding Source of the work is not available for anyone
    +to copy, free of charge and under the terms of this License, through a
    +publicly available network server or other readily accessible means,
    +then you must either (1) cause the Corresponding Source to be so
    +available, or (2) arrange to deprive yourself of the benefit of the
    +patent license for this particular work, or (3) arrange, in a manner
    +consistent with the requirements of this License, to extend the patent
    +license to downstream recipients.  "Knowingly relying" means you have
    +actual knowledge that, but for the patent license, your conveying the
    +covered work in a country, or your recipient's use of the covered work
    +in a country, would infringe one or more identifiable patents in that
    +country that you have reason to believe are valid.
    +
    +  If, pursuant to or in connection with a single transaction or
    +arrangement, you convey, or propagate by procuring conveyance of, a
    +covered work, and grant a patent license to some of the parties
    +receiving the covered work authorizing them to use, propagate, modify
    +or convey a specific copy of the covered work, then the patent license
    +you grant is automatically extended to all recipients of the covered
    +work and works based on it.
    +
    +  A patent license is "discriminatory" if it does not include within
    +the scope of its coverage, prohibits the exercise of, or is
    +conditioned on the non-exercise of one or more of the rights that are
    +specifically granted under this License.  You may not convey a covered
    +work if you are a party to an arrangement with a third party that is
    +in the business of distributing software, under which you make payment
    +to the third party based on the extent of your activity of conveying
    +the work, and under which the third party grants, to any of the
    +parties who would receive the covered work from you, a discriminatory
    +patent license (a) in connection with copies of the covered work
    +conveyed by you (or copies made from those copies), or (b) primarily
    +for and in connection with specific products or compilations that
    +contain the covered work, unless you entered into that arrangement,
    +or that patent license was granted, prior to 28 March 2007.
    +
    +  Nothing in this License shall be construed as excluding or limiting
    +any implied license or other defenses to infringement that may
    +otherwise be available to you under applicable patent law.
    +
    +  12. No Surrender of Others' Freedom.
    +
    +  If conditions are imposed on you (whether by court order, agreement or
    +otherwise) that contradict the conditions of this License, they do not
    +excuse you from the conditions of this License.  If you cannot convey a
    +covered work so as to satisfy simultaneously your obligations under this
    +License and any other pertinent obligations, then as a consequence you may
    +not convey it at all.  For example, if you agree to terms that obligate you
    +to collect a royalty for further conveying from those to whom you convey
    +the Program, the only way you could satisfy both those terms and this
    +License would be to refrain entirely from conveying the Program.
    +
    +  13. Use with the GNU Affero General Public License.
    +
    +  Notwithstanding any other provision of this License, you have
    +permission to link or combine any covered work with a work licensed
    +under version 3 of the GNU Affero General Public License into a single
    +combined work, and to convey the resulting work.  The terms of this
    +License will continue to apply to the part which is the covered work,
    +but the special requirements of the GNU Affero General Public License,
    +section 13, concerning interaction through a network will apply to the
    +combination as such.
    +
    +  14. Revised Versions of this License.
    +
    +  The Free Software Foundation may publish revised and/or new versions of
    +the GNU General Public License from time to time.  Such new versions will
    +be similar in spirit to the present version, but may differ in detail to
    +address new problems or concerns.
    +
    +  Each version is given a distinguishing version number.  If the
    +Program specifies that a certain numbered version of the GNU General
    +Public License "or any later version" applies to it, you have the
    +option of following the terms and conditions either of that numbered
    +version or of any later version published by the Free Software
    +Foundation.  If the Program does not specify a version number of the
    +GNU General Public License, you may choose any version ever published
    +by the Free Software Foundation.
    +
    +  If the Program specifies that a proxy can decide which future
    +versions of the GNU General Public License can be used, that proxy's
    +public statement of acceptance of a version permanently authorizes you
    +to choose that version for the Program.
    +
    +  Later license versions may give you additional or different
    +permissions.  However, no additional obligations are imposed on any
    +author or copyright holder as a result of your choosing to follow a
    +later version.
    +
    +  15. Disclaimer of Warranty.
    +
    +  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
    +APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
    +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
    +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
    +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
    +IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
    +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
    +
    +  16. Limitation of Liability.
    +
    +  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
    +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
    +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
    +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
    +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
    +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
    +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
    +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
    +SUCH DAMAGES.
    +
    +  17. Interpretation of Sections 15 and 16.
    +
    +  If the disclaimer of warranty and limitation of liability provided
    +above cannot be given local legal effect according to their terms,
    +reviewing courts shall apply local law that most closely approximates
    +an absolute waiver of all civil liability in connection with the
    +Program, unless a warranty or assumption of liability accompanies a
    +copy of the Program in return for a fee.
    +
    +                     END OF TERMS AND CONDITIONS
    +
    +            How to Apply These Terms to Your New Programs
    +
    +  If you develop a new program, and you want it to be of the greatest
    +possible use to the public, the best way to achieve this is to make it
    +free software which everyone can redistribute and change under these terms.
    +
    +  To do so, attach the following notices to the program.  It is safest
    +to attach them to the start of each source file to most effectively
    +state the exclusion of warranty; and each file should have at least
    +the "copyright" line and a pointer to where the full notice is found.
    +
    +    
    +    Copyright (C)   
    +
    +    This program is free software: you can redistribute it and/or modify
    +    it under the terms of the GNU General Public License as published by
    +    the Free Software Foundation, either version 3 of the License, or
    +    (at your option) any later version.
    +
    +    This program is distributed in the hope that it will be useful,
    +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +    GNU General Public License for more details.
    +
    +    You should have received a copy of the GNU General Public License
    +    along with this program.  If not, see .
    +
    +Also add information on how to contact you by electronic and paper mail.
    +
    +  If the program does terminal interaction, make it output a short
    +notice like this when it starts in an interactive mode:
    +
    +      Copyright (C)   
    +    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    +    This is free software, and you are welcome to redistribute it
    +    under certain conditions; type `show c' for details.
    +
    +The hypothetical commands `show w' and `show c' should show the appropriate
    +parts of the General Public License.  Of course, your program's commands
    +might be different; for a GUI interface, you would use an "about box".
    +
    +  You should also get your employer (if you work as a programmer) or school,
    +if any, to sign a "copyright disclaimer" for the program, if necessary.
    +For more information on this, and how to apply and follow the GNU GPL, see
    +.
    +
    +  The GNU General Public License does not permit incorporating your program
    +into proprietary programs.  If your program is a subroutine library, you
    +may consider it more useful to permit linking proprietary applications with
    +the library.  If this is what you want to do, use the GNU Lesser General
    +Public License instead of this License.  But first, please read
    +.
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.LGPLv2.1 b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.LGPLv2.1
    new file mode 100644
    index 00000000000..4362b49151d
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.LGPLv2.1
    @@ -0,0 +1,502 @@
    +                  GNU LESSER GENERAL PUBLIC LICENSE
    +                       Version 2.1, February 1999
    +
    + Copyright (C) 1991, 1999 Free Software Foundation, Inc.
    + 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    + Everyone is permitted to copy and distribute verbatim copies
    + of this license document, but changing it is not allowed.
    +
    +[This is the first released version of the Lesser GPL.  It also counts
    + as the successor of the GNU Library Public License, version 2, hence
    + the version number 2.1.]
    +
    +                            Preamble
    +
    +  The licenses for most software are designed to take away your
    +freedom to share and change it.  By contrast, the GNU General Public
    +Licenses are intended to guarantee your freedom to share and change
    +free software--to make sure the software is free for all its users.
    +
    +  This license, the Lesser General Public License, applies to some
    +specially designated software packages--typically libraries--of the
    +Free Software Foundation and other authors who decide to use it.  You
    +can use it too, but we suggest you first think carefully about whether
    +this license or the ordinary General Public License is the better
    +strategy to use in any particular case, based on the explanations below.
    +
    +  When we speak of free software, we are referring to freedom of use,
    +not price.  Our General Public Licenses are designed to make sure that
    +you have the freedom to distribute copies of free software (and charge
    +for this service if you wish); that you receive source code or can get
    +it if you want it; that you can change the software and use pieces of
    +it in new free programs; and that you are informed that you can do
    +these things.
    +
    +  To protect your rights, we need to make restrictions that forbid
    +distributors to deny you these rights or to ask you to surrender these
    +rights.  These restrictions translate to certain responsibilities for
    +you if you distribute copies of the library or if you modify it.
    +
    +  For example, if you distribute copies of the library, whether gratis
    +or for a fee, you must give the recipients all the rights that we gave
    +you.  You must make sure that they, too, receive or can get the source
    +code.  If you link other code with the library, you must provide
    +complete object files to the recipients, so that they can relink them
    +with the library after making changes to the library and recompiling
    +it.  And you must show them these terms so they know their rights.
    +
    +  We protect your rights with a two-step method: (1) we copyright the
    +library, and (2) we offer you this license, which gives you legal
    +permission to copy, distribute and/or modify the library.
    +
    +  To protect each distributor, we want to make it very clear that
    +there is no warranty for the free library.  Also, if the library is
    +modified by someone else and passed on, the recipients should know
    +that what they have is not the original version, so that the original
    +author's reputation will not be affected by problems that might be
    +introduced by others.
    +
    +  Finally, software patents pose a constant threat to the existence of
    +any free program.  We wish to make sure that a company cannot
    +effectively restrict the users of a free program by obtaining a
    +restrictive license from a patent holder.  Therefore, we insist that
    +any patent license obtained for a version of the library must be
    +consistent with the full freedom of use specified in this license.
    +
    +  Most GNU software, including some libraries, is covered by the
    +ordinary GNU General Public License.  This license, the GNU Lesser
    +General Public License, applies to certain designated libraries, and
    +is quite different from the ordinary General Public License.  We use
    +this license for certain libraries in order to permit linking those
    +libraries into non-free programs.
    +
    +  When a program is linked with a library, whether statically or using
    +a shared library, the combination of the two is legally speaking a
    +combined work, a derivative of the original library.  The ordinary
    +General Public License therefore permits such linking only if the
    +entire combination fits its criteria of freedom.  The Lesser General
    +Public License permits more lax criteria for linking other code with
    +the library.
    +
    +  We call this license the "Lesser" General Public License because it
    +does Less to protect the user's freedom than the ordinary General
    +Public License.  It also provides other free software developers Less
    +of an advantage over competing non-free programs.  These disadvantages
    +are the reason we use the ordinary General Public License for many
    +libraries.  However, the Lesser license provides advantages in certain
    +special circumstances.
    +
    +  For example, on rare occasions, there may be a special need to
    +encourage the widest possible use of a certain library, so that it becomes
    +a de-facto standard.  To achieve this, non-free programs must be
    +allowed to use the library.  A more frequent case is that a free
    +library does the same job as widely used non-free libraries.  In this
    +case, there is little to gain by limiting the free library to free
    +software only, so we use the Lesser General Public License.
    +
    +  In other cases, permission to use a particular library in non-free
    +programs enables a greater number of people to use a large body of
    +free software.  For example, permission to use the GNU C Library in
    +non-free programs enables many more people to use the whole GNU
    +operating system, as well as its variant, the GNU/Linux operating
    +system.
    +
    +  Although the Lesser General Public License is Less protective of the
    +users' freedom, it does ensure that the user of a program that is
    +linked with the Library has the freedom and the wherewithal to run
    +that program using a modified version of the Library.
    +
    +  The precise terms and conditions for copying, distribution and
    +modification follow.  Pay close attention to the difference between a
    +"work based on the library" and a "work that uses the library".  The
    +former contains code derived from the library, whereas the latter must
    +be combined with the library in order to run.
    +
    +                  GNU LESSER GENERAL PUBLIC LICENSE
    +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    +
    +  0. This License Agreement applies to any software library or other
    +program which contains a notice placed by the copyright holder or
    +other authorized party saying it may be distributed under the terms of
    +this Lesser General Public License (also called "this License").
    +Each licensee is addressed as "you".
    +
    +  A "library" means a collection of software functions and/or data
    +prepared so as to be conveniently linked with application programs
    +(which use some of those functions and data) to form executables.
    +
    +  The "Library", below, refers to any such software library or work
    +which has been distributed under these terms.  A "work based on the
    +Library" means either the Library or any derivative work under
    +copyright law: that is to say, a work containing the Library or a
    +portion of it, either verbatim or with modifications and/or translated
    +straightforwardly into another language.  (Hereinafter, translation is
    +included without limitation in the term "modification".)
    +
    +  "Source code" for a work means the preferred form of the work for
    +making modifications to it.  For a library, complete source code means
    +all the source code for all modules it contains, plus any associated
    +interface definition files, plus the scripts used to control compilation
    +and installation of the library.
    +
    +  Activities other than copying, distribution and modification are not
    +covered by this License; they are outside its scope.  The act of
    +running a program using the Library is not restricted, and output from
    +such a program is covered only if its contents constitute a work based
    +on the Library (independent of the use of the Library in a tool for
    +writing it).  Whether that is true depends on what the Library does
    +and what the program that uses the Library does.
    +
    +  1. You may copy and distribute verbatim copies of the Library's
    +complete source code as you receive it, in any medium, provided that
    +you conspicuously and appropriately publish on each copy an
    +appropriate copyright notice and disclaimer of warranty; keep intact
    +all the notices that refer to this License and to the absence of any
    +warranty; and distribute a copy of this License along with the
    +Library.
    +
    +  You may charge a fee for the physical act of transferring a copy,
    +and you may at your option offer warranty protection in exchange for a
    +fee.
    +
    +  2. You may modify your copy or copies of the Library or any portion
    +of it, thus forming a work based on the Library, and copy and
    +distribute such modifications or work under the terms of Section 1
    +above, provided that you also meet all of these conditions:
    +
    +    a) The modified work must itself be a software library.
    +
    +    b) You must cause the files modified to carry prominent notices
    +    stating that you changed the files and the date of any change.
    +
    +    c) You must cause the whole of the work to be licensed at no
    +    charge to all third parties under the terms of this License.
    +
    +    d) If a facility in the modified Library refers to a function or a
    +    table of data to be supplied by an application program that uses
    +    the facility, other than as an argument passed when the facility
    +    is invoked, then you must make a good faith effort to ensure that,
    +    in the event an application does not supply such function or
    +    table, the facility still operates, and performs whatever part of
    +    its purpose remains meaningful.
    +
    +    (For example, a function in a library to compute square roots has
    +    a purpose that is entirely well-defined independent of the
    +    application.  Therefore, Subsection 2d requires that any
    +    application-supplied function or table used by this function must
    +    be optional: if the application does not supply it, the square
    +    root function must still compute square roots.)
    +
    +These requirements apply to the modified work as a whole.  If
    +identifiable sections of that work are not derived from the Library,
    +and can be reasonably considered independent and separate works in
    +themselves, then this License, and its terms, do not apply to those
    +sections when you distribute them as separate works.  But when you
    +distribute the same sections as part of a whole which is a work based
    +on the Library, the distribution of the whole must be on the terms of
    +this License, whose permissions for other licensees extend to the
    +entire whole, and thus to each and every part regardless of who wrote
    +it.
    +
    +Thus, it is not the intent of this section to claim rights or contest
    +your rights to work written entirely by you; rather, the intent is to
    +exercise the right to control the distribution of derivative or
    +collective works based on the Library.
    +
    +In addition, mere aggregation of another work not based on the Library
    +with the Library (or with a work based on the Library) on a volume of
    +a storage or distribution medium does not bring the other work under
    +the scope of this License.
    +
    +  3. You may opt to apply the terms of the ordinary GNU General Public
    +License instead of this License to a given copy of the Library.  To do
    +this, you must alter all the notices that refer to this License, so
    +that they refer to the ordinary GNU General Public License, version 2,
    +instead of to this License.  (If a newer version than version 2 of the
    +ordinary GNU General Public License has appeared, then you can specify
    +that version instead if you wish.)  Do not make any other change in
    +these notices.
    +
    +  Once this change is made in a given copy, it is irreversible for
    +that copy, so the ordinary GNU General Public License applies to all
    +subsequent copies and derivative works made from that copy.
    +
    +  This option is useful when you wish to copy part of the code of
    +the Library into a program that is not a library.
    +
    +  4. You may copy and distribute the Library (or a portion or
    +derivative of it, under Section 2) in object code or executable form
    +under the terms of Sections 1 and 2 above provided that you accompany
    +it with the complete corresponding machine-readable source code, which
    +must be distributed under the terms of Sections 1 and 2 above on a
    +medium customarily used for software interchange.
    +
    +  If distribution of object code is made by offering access to copy
    +from a designated place, then offering equivalent access to copy the
    +source code from the same place satisfies the requirement to
    +distribute the source code, even though third parties are not
    +compelled to copy the source along with the object code.
    +
    +  5. A program that contains no derivative of any portion of the
    +Library, but is designed to work with the Library by being compiled or
    +linked with it, is called a "work that uses the Library".  Such a
    +work, in isolation, is not a derivative work of the Library, and
    +therefore falls outside the scope of this License.
    +
    +  However, linking a "work that uses the Library" with the Library
    +creates an executable that is a derivative of the Library (because it
    +contains portions of the Library), rather than a "work that uses the
    +library".  The executable is therefore covered by this License.
    +Section 6 states terms for distribution of such executables.
    +
    +  When a "work that uses the Library" uses material from a header file
    +that is part of the Library, the object code for the work may be a
    +derivative work of the Library even though the source code is not.
    +Whether this is true is especially significant if the work can be
    +linked without the Library, or if the work is itself a library.  The
    +threshold for this to be true is not precisely defined by law.
    +
    +  If such an object file uses only numerical parameters, data
    +structure layouts and accessors, and small macros and small inline
    +functions (ten lines or less in length), then the use of the object
    +file is unrestricted, regardless of whether it is legally a derivative
    +work.  (Executables containing this object code plus portions of the
    +Library will still fall under Section 6.)
    +
    +  Otherwise, if the work is a derivative of the Library, you may
    +distribute the object code for the work under the terms of Section 6.
    +Any executables containing that work also fall under Section 6,
    +whether or not they are linked directly with the Library itself.
    +
    +  6. As an exception to the Sections above, you may also combine or
    +link a "work that uses the Library" with the Library to produce a
    +work containing portions of the Library, and distribute that work
    +under terms of your choice, provided that the terms permit
    +modification of the work for the customer's own use and reverse
    +engineering for debugging such modifications.
    +
    +  You must give prominent notice with each copy of the work that the
    +Library is used in it and that the Library and its use are covered by
    +this License.  You must supply a copy of this License.  If the work
    +during execution displays copyright notices, you must include the
    +copyright notice for the Library among them, as well as a reference
    +directing the user to the copy of this License.  Also, you must do one
    +of these things:
    +
    +    a) Accompany the work with the complete corresponding
    +    machine-readable source code for the Library including whatever
    +    changes were used in the work (which must be distributed under
    +    Sections 1 and 2 above); and, if the work is an executable linked
    +    with the Library, with the complete machine-readable "work that
    +    uses the Library", as object code and/or source code, so that the
    +    user can modify the Library and then relink to produce a modified
    +    executable containing the modified Library.  (It is understood
    +    that the user who changes the contents of definitions files in the
    +    Library will not necessarily be able to recompile the application
    +    to use the modified definitions.)
    +
    +    b) Use a suitable shared library mechanism for linking with the
    +    Library.  A suitable mechanism is one that (1) uses at run time a
    +    copy of the library already present on the user's computer system,
    +    rather than copying library functions into the executable, and (2)
    +    will operate properly with a modified version of the library, if
    +    the user installs one, as long as the modified version is
    +    interface-compatible with the version that the work was made with.
    +
    +    c) Accompany the work with a written offer, valid for at
    +    least three years, to give the same user the materials
    +    specified in Subsection 6a, above, for a charge no more
    +    than the cost of performing this distribution.
    +
    +    d) If distribution of the work is made by offering access to copy
    +    from a designated place, offer equivalent access to copy the above
    +    specified materials from the same place.
    +
    +    e) Verify that the user has already received a copy of these
    +    materials or that you have already sent this user a copy.
    +
    +  For an executable, the required form of the "work that uses the
    +Library" must include any data and utility programs needed for
    +reproducing the executable from it.  However, as a special exception,
    +the materials to be distributed need not include anything that is
    +normally distributed (in either source or binary form) with the major
    +components (compiler, kernel, and so on) of the operating system on
    +which the executable runs, unless that component itself accompanies
    +the executable.
    +
    +  It may happen that this requirement contradicts the license
    +restrictions of other proprietary libraries that do not normally
    +accompany the operating system.  Such a contradiction means you cannot
    +use both them and the Library together in an executable that you
    +distribute.
    +
    +  7. You may place library facilities that are a work based on the
    +Library side-by-side in a single library together with other library
    +facilities not covered by this License, and distribute such a combined
    +library, provided that the separate distribution of the work based on
    +the Library and of the other library facilities is otherwise
    +permitted, and provided that you do these two things:
    +
    +    a) Accompany the combined library with a copy of the same work
    +    based on the Library, uncombined with any other library
    +    facilities.  This must be distributed under the terms of the
    +    Sections above.
    +
    +    b) Give prominent notice with the combined library of the fact
    +    that part of it is a work based on the Library, and explaining
    +    where to find the accompanying uncombined form of the same work.
    +
    +  8. You may not copy, modify, sublicense, link with, or distribute
    +the Library except as expressly provided under this License.  Any
    +attempt otherwise to copy, modify, sublicense, link with, or
    +distribute the Library is void, and will automatically terminate your
    +rights under this License.  However, parties who have received copies,
    +or rights, from you under this License will not have their licenses
    +terminated so long as such parties remain in full compliance.
    +
    +  9. You are not required to accept this License, since you have not
    +signed it.  However, nothing else grants you permission to modify or
    +distribute the Library or its derivative works.  These actions are
    +prohibited by law if you do not accept this License.  Therefore, by
    +modifying or distributing the Library (or any work based on the
    +Library), you indicate your acceptance of this License to do so, and
    +all its terms and conditions for copying, distributing or modifying
    +the Library or works based on it.
    +
    +  10. Each time you redistribute the Library (or any work based on the
    +Library), the recipient automatically receives a license from the
    +original licensor to copy, distribute, link with or modify the Library
    +subject to these terms and conditions.  You may not impose any further
    +restrictions on the recipients' exercise of the rights granted herein.
    +You are not responsible for enforcing compliance by third parties with
    +this License.
    +
    +  11. If, as a consequence of a court judgment or allegation of patent
    +infringement or for any other reason (not limited to patent issues),
    +conditions are imposed on you (whether by court order, agreement or
    +otherwise) that contradict the conditions of this License, they do not
    +excuse you from the conditions of this License.  If you cannot
    +distribute so as to satisfy simultaneously your obligations under this
    +License and any other pertinent obligations, then as a consequence you
    +may not distribute the Library at all.  For example, if a patent
    +license would not permit royalty-free redistribution of the Library by
    +all those who receive copies directly or indirectly through you, then
    +the only way you could satisfy both it and this License would be to
    +refrain entirely from distribution of the Library.
    +
    +If any portion of this section is held invalid or unenforceable under any
    +particular circumstance, the balance of the section is intended to apply,
    +and the section as a whole is intended to apply in other circumstances.
    +
    +It is not the purpose of this section to induce you to infringe any
    +patents or other property right claims or to contest validity of any
    +such claims; this section has the sole purpose of protecting the
    +integrity of the free software distribution system which is
    +implemented by public license practices.  Many people have made
    +generous contributions to the wide range of software distributed
    +through that system in reliance on consistent application of that
    +system; it is up to the author/donor to decide if he or she is willing
    +to distribute software through any other system and a licensee cannot
    +impose that choice.
    +
    +This section is intended to make thoroughly clear what is believed to
    +be a consequence of the rest of this License.
    +
    +  12. If the distribution and/or use of the Library is restricted in
    +certain countries either by patents or by copyrighted interfaces, the
    +original copyright holder who places the Library under this License may add
    +an explicit geographical distribution limitation excluding those countries,
    +so that distribution is permitted only in or among countries not thus
    +excluded.  In such case, this License incorporates the limitation as if
    +written in the body of this License.
    +
    +  13. The Free Software Foundation may publish revised and/or new
    +versions of the Lesser General Public License from time to time.
    +Such new versions will be similar in spirit to the present version,
    +but may differ in detail to address new problems or concerns.
    +
    +Each version is given a distinguishing version number.  If the Library
    +specifies a version number of this License which applies to it and
    +"any later version", you have the option of following the terms and
    +conditions either of that version or of any later version published by
    +the Free Software Foundation.  If the Library does not specify a
    +license version number, you may choose any version ever published by
    +the Free Software Foundation.
    +
    +  14. If you wish to incorporate parts of the Library into other free
    +programs whose distribution conditions are incompatible with these,
    +write to the author to ask for permission.  For software which is
    +copyrighted by the Free Software Foundation, write to the Free
    +Software Foundation; we sometimes make exceptions for this.  Our
    +decision will be guided by the two goals of preserving the free status
    +of all derivatives of our free software and of promoting the sharing
    +and reuse of software generally.
    +
    +                            NO WARRANTY
    +
    +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
    +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
    +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
    +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
    +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
    +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
    +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
    +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
    +
    +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
    +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
    +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
    +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
    +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
    +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
    +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
    +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
    +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    +DAMAGES.
    +
    +                     END OF TERMS AND CONDITIONS
    +
    +           How to Apply These Terms to Your New Libraries
    +
    +  If you develop a new library, and you want it to be of the greatest
    +possible use to the public, we recommend making it free software that
    +everyone can redistribute and change.  You can do so by permitting
    +redistribution under these terms (or, alternatively, under the terms of the
    +ordinary General Public License).
    +
    +  To apply these terms, attach the following notices to the library.  It is
    +safest to attach them to the start of each source file to most effectively
    +convey the exclusion of warranty; and each file should have at least the
    +"copyright" line and a pointer to where the full notice is found.
    +
    +    
    +    Copyright (C)   
    +
    +    This library is free software; you can redistribute it and/or
    +    modify it under the terms of the GNU Lesser General Public
    +    License as published by the Free Software Foundation; either
    +    version 2.1 of the License, or (at your option) any later version.
    +
    +    This library is distributed in the hope that it will be useful,
    +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    +    Lesser General Public License for more details.
    +
    +    You should have received a copy of the GNU Lesser General Public
    +    License along with this library; if not, write to the Free Software
    +    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    +
    +Also add information on how to contact you by electronic and paper mail.
    +
    +You should also get your employer (if you work as a programmer) or your
    +school, if any, to sign a "copyright disclaimer" for the library, if
    +necessary.  Here is a sample; alter the names:
    +
    +  Yoyodyne, Inc., hereby disclaims all copyright interest in the
    +  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
    +
    +  , 1 April 1990
    +  Ty Coon, President of Vice
    +
    +That's all there is to it!
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/README b/src/libs/3rdparty/karchive/3rdparty/xz/README
    new file mode 100644
    index 00000000000..9d097deff37
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/README
    @@ -0,0 +1,310 @@
    +
    +XZ Utils
    +========
    +
    +    0. Overview
    +    1. Documentation
    +       1.1. Overall documentation
    +       1.2. Documentation for command-line tools
    +       1.3. Documentation for liblzma
    +    2. Version numbering
    +    3. Reporting bugs
    +    4. Translations
    +    5. Other implementations of the .xz format
    +    6. Contact information
    +
    +
    +0. Overview
    +-----------
    +
    +    XZ Utils provide a general-purpose data-compression library plus
    +    command-line tools. The native file format is the .xz format, but
    +    also the legacy .lzma format is supported. The .xz format supports
    +    multiple compression algorithms, which are called "filters" in the
    +    context of XZ Utils. The primary filter is currently LZMA2. With
    +    typical files, XZ Utils create about 30 % smaller files than gzip.
    +
    +    To ease adapting support for the .xz format into existing applications
    +    and scripts, the API of liblzma is somewhat similar to the API of the
    +    popular zlib library. For the same reason, the command-line tool xz
    +    has a command-line syntax similar to that of gzip.
    +
    +    When aiming for the highest compression ratio, the LZMA2 encoder uses
    +    a lot of CPU time and may use, depending on the settings, even
    +    hundreds of megabytes of RAM. However, in fast modes, the LZMA2 encoder
    +    competes with bzip2 in compression speed, RAM usage, and compression
    +    ratio.
    +
    +    LZMA2 is reasonably fast to decompress. It is a little slower than
    +    gzip, but a lot faster than bzip2. Being fast to decompress means
    +    that the .xz format is especially nice when the same file will be
    +    decompressed very many times (usually on different computers), which
    +    is the case e.g. when distributing software packages. In such
    +    situations, it's not too bad if the compression takes some time,
    +    since that needs to be done only once to benefit many people.
    +
    +    With some file types, combining (or "chaining") LZMA2 with an
    +    additional filter can improve the compression ratio. A filter chain may
    +    contain up to four filters, although usually only one or two are used.
    +    For example, putting a BCJ (Branch/Call/Jump) filter before LZMA2
    +    in the filter chain can improve compression ratio of executable files.
    +
    +    Since the .xz format allows adding new filter IDs, it is possible that
    +    some day there will be a filter that is, for example, much faster to
    +    compress than LZMA2 (but probably with worse compression ratio).
    +    Similarly, it is possible that some day there is a filter that will
    +    compress better than LZMA2.
    +
    +    XZ Utils supports multithreaded compression. XZ Utils doesn't support
    +    multithreaded decompression yet. It has been planned though and taken
    +    into account when designing the .xz file format. In the future, files
    +    that were created in threaded mode can be decompressed in threaded
    +    mode too.
    +
    +
    +1. Documentation
    +----------------
    +
    +1.1. Overall documentation
    +
    +    README                This file
    +
    +    INSTALL.generic       Generic install instructions for those not
    +                          familiar with packages using GNU Autotools
    +    INSTALL               Installation instructions specific to XZ Utils
    +    PACKAGERS             Information to packagers of XZ Utils
    +
    +    COPYING               XZ Utils copyright and license information
    +    COPYING.0BSD          BSD Zero Clause License
    +    COPYING.GPLv2         GNU General Public License version 2
    +    COPYING.GPLv3         GNU General Public License version 3
    +    COPYING.LGPLv2.1      GNU Lesser General Public License version 2.1
    +
    +    AUTHORS               The main authors of XZ Utils
    +    THANKS                Incomplete list of people who have helped making
    +                          this software
    +    NEWS                  User-visible changes between XZ Utils releases
    +    ChangeLog             Detailed list of changes (commit log)
    +    TODO                  Known bugs and some sort of to-do list
    +
    +    Note that only some of the above files are included in binary
    +    packages.
    +
    +
    +1.2. Documentation for command-line tools
    +
    +    The command-line tools are documented as man pages. In source code
    +    releases (and possibly also in some binary packages), the man pages
    +    are also provided in plain text (ASCII only) format in the directory
    +    "doc/man" to make the man pages more accessible to those whose
    +    operating system doesn't provide an easy way to view man pages.
    +
    +
    +1.3. Documentation for liblzma
    +
    +    The liblzma API headers include short docs about each function
    +    and data type as Doxygen tags. These docs should be quite OK as
    +    a quick reference.
    +
    +    There are a few example/tutorial programs that should help in
    +    getting started with liblzma. In the source package the examples
    +    are in "doc/examples" and in binary packages they may be under
    +    "examples" in the same directory as this README.
    +
    +    Since the liblzma API has similarities to the zlib API, some people
    +    may find it useful to read the zlib docs and tutorial too:
    +
    +        https://zlib.net/manual.html
    +        https://zlib.net/zlib_how.html
    +
    +
    +2. Version numbering
    +--------------------
    +
    +    The version number format of XZ Utils is X.Y.ZS:
    +
    +      - X is the major version. When this is incremented, the library
    +        API and ABI break.
    +
    +      - Y is the minor version. It is incremented when new features
    +        are added without breaking the existing API or ABI. An even Y
    +        indicates a stable release and an odd Y indicates unstable
    +        (alpha or beta version).
    +
    +      - Z is the revision. This has a different meaning for stable and
    +        unstable releases:
    +
    +          * Stable: Z is incremented when bugs get fixed without adding
    +            any new features. This is intended to be convenient for
    +            downstream distributors that want bug fixes but don't want
    +            any new features to minimize the risk of introducing new bugs.
    +
    +          * Unstable: Z is just a counter. API or ABI of features added
    +            in earlier unstable releases having the same X.Y may break.
    +
    +      - S indicates stability of the release. It is missing from the
    +        stable releases, where Y is an even number. When Y is odd, S
    +        is either "alpha" or "beta" to make it very clear that such
    +        versions are not stable releases. The same X.Y.Z combination is
    +        not used for more than one stability level, i.e. after X.Y.Zalpha,
    +        the next version can be X.Y.(Z+1)beta but not X.Y.Zbeta.
    +
    +
    +3. Reporting bugs
    +-----------------
    +
    +    Naturally it is easiest for me if you already know what causes the
    +    unexpected behavior. Even better if you have a patch to propose.
    +    However, quite often the reason for unexpected behavior is unknown,
    +    so here are a few things to do before sending a bug report:
    +
    +      1. Try to create a small example how to reproduce the issue.
    +
    +      2. Compile XZ Utils with debugging code using configure switches
    +         --enable-debug and, if possible, --disable-shared. If you are
    +         using GCC, use CFLAGS='-O0 -ggdb3'. Don't strip the resulting
    +         binaries.
    +
    +      3. Turn on core dumps. The exact command depends on your shell;
    +         for example in GNU bash it is done with "ulimit -c unlimited",
    +         and in tcsh with "limit coredumpsize unlimited".
    +
    +      4. Try to reproduce the suspected bug. If you get "assertion failed"
    +         message, be sure to include the complete message in your bug
    +         report. If the application leaves a coredump, get a backtrace
    +         using gdb:
    +           $ gdb /path/to/app-binary   # Load the app to the debugger.
    +           (gdb) core core   # Open the coredump.
    +           (gdb) bt   # Print the backtrace. Copy & paste to bug report.
    +           (gdb) quit   # Quit gdb.
    +
    +    Report your bug via email or IRC (see Contact information below).
    +    Don't send core dump files or any executables. If you have a small
    +    example file(s) (total size less than 256 KiB), please include
    +    it/them as an attachment. If you have bigger test files, put them
    +    online somewhere and include a URL to the file(s) in the bug report.
    +
    +    Always include the exact version number of XZ Utils in the bug report.
    +    If you are using a snapshot from the git repository, use "git describe"
    +    to get the exact snapshot version. If you are using XZ Utils shipped
    +    in an operating system distribution, mention the distribution name,
    +    distribution version, and exact xz package version; if you cannot
    +    repeat the bug with the code compiled from unpatched source code,
    +    you probably need to report a bug to your distribution's bug tracking
    +    system.
    +
    +
    +4. Translations
    +---------------
    +
    +    The xz command line tool and all man pages can be translated.
    +    The translations are handled via the Translation Project. If you
    +    wish to help translating xz, please join the Translation Project:
    +
    +        https://translationproject.org/html/translators.html
    +
    +    Below are notes and testing instructions specific to xz
    +    translations.
    +
    +    Testing can be done by installing xz into a temporary directory:
    +
    +        ./configure --disable-shared --prefix=/tmp/xz-test
    +        # 
    +        make -C po update-po
    +        make install
    +        bash debug/translation.bash | less
    +        bash debug/translation.bash | less -S  # For --list outputs
    +
    +    Repeat the above as needed (no need to re-run configure though).
    +
    +    Note especially the following:
    +
    +      - The output of --help and --long-help must look nice on
    +        an 80-column terminal. It's OK to add extra lines if needed.
    +
    +      - In contrast, don't add extra lines to error messages and such.
    +        They are often preceded with e.g. a filename on the same line,
    +        so you have no way to predict where to put a \n. Let the terminal
    +        do the wrapping even if it looks ugly. Adding new lines will be
    +        even uglier in the generic case even if it looks nice in a few
    +        limited examples.
    +
    +      - Be careful with column alignment in tables and table-like output
    +        (--list, --list --verbose --verbose, --info-memory, --help, and
    +        --long-help):
    +
    +          * All descriptions of options in --help should start in the
    +            same column (but it doesn't need to be the same column as
    +            in the English messages; just be consistent if you change it).
    +            Check that both --help and --long-help look OK, since they
    +            share several strings.
    +
    +          * --list --verbose and --info-memory print lines that have
    +            the format "Description:   %s". If you need a longer
    +            description, you can put extra space between the colon
    +            and %s. Then you may need to add extra space to other
    +            strings too so that the result as a whole looks good (all
    +            values start at the same column).
    +
    +          * The columns of the actual tables in --list --verbose --verbose
    +            should be aligned properly. Abbreviate if necessary. It might
    +            be good to keep at least 2 or 3 spaces between column headings
    +            and avoid spaces in the headings so that the columns stand out
    +            better, but this is a matter of opinion. Do what you think
    +            looks best.
    +
    +      - Be careful to put a period at the end of a sentence when the
    +        original version has it, and don't put it when the original
    +        doesn't have it. Similarly, be careful with \n characters
    +        at the beginning and end of the strings.
    +
    +      - Read the TRANSLATORS comments that have been extracted from the
    +        source code and included in xz.pot. Some comments suggest
    +        testing with a specific command which needs an .xz file. You
    +        may use e.g. any tests/files/good-*.xz. However, these test
    +        commands are included in translations.bash output, so reading
    +        translations.bash output carefully can be enough.
    +
    +      - If you find language problems in the original English strings,
    +        feel free to suggest improvements. Ask if something is unclear.
    +
    +      - The translated messages should be understandable (sometimes this
    +        may be a problem with the original English messages too). Don't
    +        make a direct word-by-word translation from English especially if
    +        the result doesn't sound good in your language.
    +
    +    Thanks for your help!
    +
    +
    +5. Other implementations of the .xz format
    +------------------------------------------
    +
    +    7-Zip and the p7zip port of 7-Zip support the .xz format starting
    +    from the version 9.00alpha.
    +
    +        https://7-zip.org/
    +        https://p7zip.sourceforge.net/
    +
    +    XZ Embedded is a limited implementation written for use in the Linux
    +    kernel, but it is also suitable for other embedded use.
    +
    +        https://tukaani.org/xz/embedded.html
    +
    +    XZ for Java is a complete implementation written in pure Java.
    +
    +        https://tukaani.org/xz/java.html
    +
    +
    +6. Contact information
    +----------------------
    +
    +    XZ Utils in general:
    +      - Home page: https://tukaani.org/xz/
    +      - Email to maintainer(s): xz@tukaani.org
    +      - IRC: #tukaani on Libera Chat
    +      - GitHub: https://github.com/tukaani-project/xz
    +
    +    Lead maintainer:
    +      - Email: Lasse Collin 
    +      - IRC: Larhzu on Libera Chat
    +
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/README.qtcreator b/src/libs/3rdparty/karchive/3rdparty/xz/README.qtcreator
    new file mode 100644
    index 00000000000..4c1e7fef3df
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/README.qtcreator
    @@ -0,0 +1,4 @@
    +This directory contains a stripped down version of `https://github.com/tukaani-project/xz` with the following modifications:
    +
    +* Branch v5.6 was checked out (6084b25c29ce50a5ec86daa1bb0bcb5e9afb5c32)
    +* All unnecessary files have been removed.
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/THANKS b/src/libs/3rdparty/karchive/3rdparty/xz/THANKS
    new file mode 100644
    index 00000000000..5ed0743b50f
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/THANKS
    @@ -0,0 +1,202 @@
    +
    +Thanks
    +======
    +
    +Some people have helped more, some less, but nevertheless everyone's help
    +has been important. :-) In alphabetical order:
    +  - Mark Adler
    +  - Kian-Meng Ang
    +  - H. Peter Anvin
    +  - Jeff Bastian
    +  - Nelson H. F. Beebe
    +  - Karl Beldan
    +  - Karl Berry
    +  - Anders F. Björklund
    +  - Emmanuel Blot
    +  - Melanie Blower
    +  - Alexander Bluhm
    +  - Martin Blumenstingl
    +  - Ben Boeckel
    +  - Jakub Bogusz
    +  - Adam Borowski
    +  - Maarten Bosmans
    +  - Lukas Braune
    +  - Benjamin Buch
    +  - Trent W. Buck
    +  - Kevin R. Bulgrien
    +  - James Buren
    +  - David Burklund
    +  - Frank Busse
    +  - Daniel Mealha Cabrita
    +  - Milo Casagrande
    +  - Marek Černocký
    +  - Tomer Chachamu
    +  - Vitaly Chikunov
    +  - Antoine Cœur
    +  - Felix Collin
    +  - Gabi Davar
    +  - İhsan Doğan
    +  - Chris Donawa
    +  - Andrew Dudman
    +  - Markus Duft
    +  - İsmail Dönmez
    +  - Paul Eggert
    +  - Robert Elz
    +  - Gilles Espinasse
    +  - Denis Excoffier
    +  - Vincent Fazio
    +  - Michael Felt
    +  - Michael Fox
    +  - Andres Freund
    +  - Mike Frysinger
    +  - Daniel Richard G.
    +  - Tomasz Gajc
    +  - Bjarni Ingi Gislason
    +  - John Paul Adrian Glaubitz
    +  - Bill Glessner
    +  - Matthew Good
    +  - Michał Górny
    +  - Jason Gorski
    +  - Juan Manuel Guerrero
    +  - Gabriela Gutierrez
    +  - Diederik de Haas
    +  - Joachim Henke
    +  - Christian Hesse
    +  - Vincenzo Innocente
    +  - Peter Ivanov
    +  - Nicholas Jackson
    +  - Sam James
    +  - Hajin Jang
    +  - Hans Jansen
    +  - Jouk Jansen
    +  - Jun I Jin
    +  - Christoph Junghans
    +  - Kiyoshi Kanazawa
    +  - Joona Kannisto
    +  - Per Øyvind Karlsen
    +  - Firas Khalil Khana
    +  - Iouri Kharon
    +  - Thomas Klausner
    +  - Richard Koch
    +  - Anton Kochkov
    +  - Ville Koskinen
    +  - Sergey Kosukhin
    +  - Marcin Kowalczyk
    +  - Jan Kratochvil
    +  - Christian Kujau
    +  - Stephan Kulow
    +  - Ilya Kurdyukov
    +  - Peter Lawler
    +  - James M Leddy
    +  - Kelvin Lee
    +  - Vincent Lefevre
    +  - Hin-Tak Leung
    +  - Andraž 'ruskie' Levstik
    +  - Cary Lewis
    +  - Wim Lewis
    +  - Xin Li
    +  - Yifeng Li
    +  - Eric Lindblad
    +  - Lorenzo De Liso
    +  - H.J. Lu
    +  - Bela Lubkin
    +  - Chenxi Mao
    +  - Gregory Margo
    +  - Julien Marrec
    +  - Ed Maste
    +  - Martin Matuška
    +  - Ivan A. Melnikov
    +  - Jim Meyering
    +  - Arkadiusz Miskiewicz
    +  - Nathan Moinvaziri
    +  - Étienne Mollier
    +  - Conley Moorhous
    +  - Andrew Murray
    +  - Rafał Mużyło
    +  - Adrien Nader
    +  - Evan Nemerson
    +  - Alexander Neumann
    +  - Hongbo Ni
    +  - Jonathan Nieder
    +  - Andre Noll
    +  - Peter O'Gorman
    +  - Dimitri Papadopoulos Orfanos
    +  - Daniel Packard
    +  - Filip Palian
    +  - Peter Pallinger
    +  - Kai Pastor
    +  - Rui Paulo
    +  - Igor Pavlov
    +  - Diego Elio Pettenò
    +  - Elbert Pol
    +  - Mikko Pouru
    +  - Frank Prochnow
    +  - Rich Prohaska
    +  - Trần Ngọc Quân
    +  - Pavel Raiskup
    +  - Ole André Vadla Ravnås
    +  - Eric S. Raymond
    +  - Robert Readman
    +  - Bernhard Reutner-Fischer
    +  - Markus Rickert
    +  - Cristian Rodríguez
    +  - Christian von Roques
    +  - Boud Roukema
    +  - Torsten Rupp
    +  - Stephen Sachs
    +  - Jukka Salmi
    +  - Agostino Sarubbo
    +  - Vijay Sarvepalli
    +  - Alexandre Sauvé
    +  - Benno Schulenberg
    +  - Andreas Schwab
    +  - Eli Schwartz
    +  - Peter Seiderer
    +  - Bhargava Shastry
    +  - Dan Shechter
    +  - Stuart Shelton
    +  - Sebastian Andrzej Siewior
    +  - Ville Skyttä
    +  - Brad Smith
    +  - Bruce Stark
    +  - Pippijn van Steenhoven
    +  - Tobias Stoeckmann
    +  - Martin Storsjö
    +  - Jonathan Stott
    +  - Dan Stromberg
    +  - Douglas Thor
    +  - Vincent Torri
    +  - Alexey Tourbin
    +  - Paul Townsend
    +  - Mohammed Adnène Trojette
    +  - Orange Tsai
    +  - Taiki Tsunekawa
    +  - Mathieu Vachon
    +  - Maksym Vatsyk
    +  - Loganaden Velvindron
    +  - Patrick J. Volkerding
    +  - Martin Väth
    +  - Adam Walling
    +  - Jeffrey Walton
    +  - Christian Weisgerber
    +  - Dan Weiss
    +  - Bert Wesarg
    +  - Fredrik Wikstrom
    +  - Jim Wilcoxson
    +  - Ralf Wildenhues
    +  - Charles Wilson
    +  - Lars Wirzenius
    +  - Pilorz Wojciech
    +  - Chien Wong
    +  - Ryan Young
    +  - Andreas Zieringer
    +
    +Companies:
    +  - Google
    +  - Sandfly Security
    +
    +Also thanks to all the people who have participated in the Tukaani project.
    +
    +I have probably forgot to add some names to the above list. Sorry about
    +that and thanks for your help.
    +
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/TODO b/src/libs/3rdparty/karchive/3rdparty/xz/TODO
    new file mode 100644
    index 00000000000..ad37f3f559a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/TODO
    @@ -0,0 +1,105 @@
    +
    +XZ Utils To-Do List
    +===================
    +
    +Known bugs
    +----------
    +
    +    The test suite is too incomplete.
    +
    +    If the memory usage limit is less than about 13 MiB, xz is unable to
    +    automatically scale down the compression settings enough even though
    +    it would be  possible by switching from BT2/BT3/BT4 match finder to
    +    HC3/HC4.
    +
    +    XZ Utils compress some files significantly worse than LZMA Utils.
    +    This is due to faster compression presets used by XZ Utils, and
    +    can often be worked around by using "xz --extreme". With some files
    +    --extreme isn't enough though: it's most likely with files that
    +    compress extremely well, so going from compression ratio of 0.003
    +    to 0.004 means big relative increase in the compressed file size.
    +
    +    xz doesn't quote unprintable characters when it displays file names
    +    given on the command line.
    +
    +    tuklib_exit() doesn't block signals => EINTR is possible.
    +
    +    If liblzma has created threads and fork() gets called, liblzma
    +    code will break in the child process unless it calls exec() and
    +    doesn't touch liblzma.
    +
    +
    +Missing features
    +----------------
    +
    +    Add support for storing metadata in .xz files. A preliminary
    +    idea is to create a new Stream type for metadata. When both
    +    metadata and data are wanted in the same .xz file, two or more
    +    Streams would be concatenated.
    +
    +    The state stored in lzma_stream should be cloneable, which would
    +    be mostly useful when using a preset dictionary in LZMA2, but
    +    it may have other uses too. Compare to deflateCopy() in zlib.
    +
    +    Support LZMA_FINISH in raw decoder to indicate end of LZMA1 and
    +    other streams that don't have an end of payload marker.
    +
    +    Adjust dictionary size when the input file size is known.
    +    Maybe do this only if an option is given.
    +
    +    xz doesn't support copying extended attributes, access control
    +    lists etc. from source to target file.
    +
    +    Multithreaded compression:
    +      - Reduce memory usage of the current method.
    +      - Implement threaded match finders.
    +      - Implement pigz-style threading in LZMA2.
    +
    +    Buffer-to-buffer coding could use less RAM (especially when
    +    decompressing LZMA1 or LZMA2).
    +
    +    I/O library is not implemented (similar to gzopen() in zlib).
    +    It will be a separate library that supports uncompressed, .gz,
    +    .bz2, .lzma, and .xz files.
    +
    +    Support changing lzma_options_lzma.mode with lzma_filters_update().
    +
    +    Support LZMA_FULL_FLUSH for lzma_stream_decoder() to stop at
    +    Block and Stream boundaries.
    +
    +    lzma_strerror() to convert lzma_ret to human readable form?
    +    This is tricky, because the same error codes are used with
    +    slightly different meanings, and this cannot be fixed anymore.
    +
    +    Make it possible to adjust LZMA2 options in the middle of a Block
    +    so that the encoding speed vs. compression ratio can be optimized
    +    when the compressed data is streamed over network.
    +
    +    Improved BCJ filters. The current filters are small but they aren't
    +    so great when compressing binary packages that contain various file
    +    types. Specifically, they make things worse if there are static
    +    libraries or Linux kernel modules. The filtering could also be
    +    more effective (without getting overly complex), for example,
    +    streamable variant BCJ2 from 7-Zip could be implemented.
    +
    +    Filter that autodetects specific data types in the input stream
    +    and applies appropriate filters for the corrects parts of the input.
    +    Perhaps combine this with the BCJ filter improvement point above.
    +
    +    Long-range LZ77 method as a separate filter or as a new LZMA2
    +    match finder.
    +
    +
    +Documentation
    +-------------
    +
    +    More tutorial programs are needed for liblzma.
    +
    +    Document the LZMA1 and LZMA2 algorithms.
    +
    +
    +Miscellaneous
    +------------
    +
    +    Try to get the media type for .xz registered at IANA.
    +
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/mythread.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/mythread.h
    new file mode 100644
    index 00000000000..10ea2d42c24
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/mythread.h
    @@ -0,0 +1,548 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       mythread.h
    +/// \brief      Some threading related helper macros and functions
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef MYTHREAD_H
    +#define MYTHREAD_H
    +
    +#include "sysdefs.h"
    +
    +// If any type of threading is enabled, #define MYTHREAD_ENABLED.
    +#if defined(MYTHREAD_POSIX) || defined(MYTHREAD_WIN95) \
    +		|| defined(MYTHREAD_VISTA)
    +#	define MYTHREAD_ENABLED 1
    +#endif
    +
    +
    +#ifdef MYTHREAD_ENABLED
    +
    +////////////////////////////////////////
    +// Shared between all threading types //
    +////////////////////////////////////////
    +
    +// Locks a mutex for a duration of a block.
    +//
    +// Perform mythread_mutex_lock(&mutex) in the beginning of a block
    +// and mythread_mutex_unlock(&mutex) at the end of the block. "break"
    +// may be used to unlock the mutex and jump out of the block.
    +// mythread_sync blocks may be nested.
    +//
    +// Example:
    +//
    +//     mythread_sync(mutex) {
    +//         foo();
    +//         if (some_error)
    +//             break; // Skips bar()
    +//         bar();
    +//     }
    +//
    +// At least GCC optimizes the loops completely away so it doesn't slow
    +// things down at all compared to plain mythread_mutex_lock(&mutex)
    +// and mythread_mutex_unlock(&mutex) calls.
    +//
    +#define mythread_sync(mutex) mythread_sync_helper1(mutex, __LINE__)
    +#define mythread_sync_helper1(mutex, line) mythread_sync_helper2(mutex, line)
    +#define mythread_sync_helper2(mutex, line) \
    +	for (unsigned int mythread_i_ ## line = 0; \
    +			mythread_i_ ## line \
    +				? (mythread_mutex_unlock(&(mutex)), 0) \
    +				: (mythread_mutex_lock(&(mutex)), 1); \
    +			mythread_i_ ## line = 1) \
    +		for (unsigned int mythread_j_ ## line = 0; \
    +				!mythread_j_ ## line; \
    +				mythread_j_ ## line = 1)
    +#endif
    +
    +
    +#if !defined(MYTHREAD_ENABLED)
    +
    +//////////////////
    +// No threading //
    +//////////////////
    +
    +// Calls the given function once. This isn't thread safe.
    +#define mythread_once(func) \
    +do { \
    +	static bool once_ = false; \
    +	if (!once_) { \
    +		func(); \
    +		once_ = true; \
    +	} \
    +} while (0)
    +
    +
    +#if !(defined(_WIN32) && !defined(__CYGWIN__)) && !defined(__wasm__)
    +// Use sigprocmask() to set the signal mask in single-threaded programs.
    +#include 
    +
    +static inline void
    +mythread_sigmask(int how, const sigset_t *restrict set,
    +		sigset_t *restrict oset)
    +{
    +	int ret = sigprocmask(how, set, oset);
    +	assert(ret == 0);
    +	(void)ret;
    +}
    +#endif
    +
    +
    +#elif defined(MYTHREAD_POSIX)
    +
    +////////////////////
    +// Using pthreads //
    +////////////////////
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +// If clock_gettime() isn't available, use gettimeofday() from 
    +// as a fallback. gettimeofday() is in SUSv2 and thus is supported on all
    +// relevant POSIX systems.
    +#ifndef HAVE_CLOCK_GETTIME
    +#	include 
    +#endif
    +
    +// MinGW-w64 with winpthreads:
    +//
    +// NOTE: Typical builds with MinGW-w64 don't use this code (MYTHREAD_POSIX).
    +// Instead, native Windows threading APIs are used (MYTHREAD_VISTA or
    +// MYTHREAD_WIN95).
    +//
    +// MinGW-w64 has _sigset_t (an integer type) in .
    +// If _POSIX was #defined, the header would add the alias sigset_t too.
    +// Let's keep this working even without _POSIX.
    +//
    +// There are no functions that actually do something with sigset_t
    +// because signals barely exist on Windows. The sigfillset macro below
    +// is just to silence warnings. There is no sigfillset() in MinGW-w64.
    +#ifdef __MINGW32__
    +#	include 
    +#	define sigset_t _sigset_t
    +#	define sigfillset(set_ptr) do { *(set_ptr) = 0; } while (0)
    +#endif
    +
    +#define MYTHREAD_RET_TYPE void *
    +#define MYTHREAD_RET_VALUE NULL
    +
    +typedef pthread_t mythread;
    +typedef pthread_mutex_t mythread_mutex;
    +
    +typedef struct {
    +	pthread_cond_t cond;
    +#ifdef HAVE_CLOCK_GETTIME
    +	// Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with
    +	// the condition variable.
    +	clockid_t clk_id;
    +#endif
    +} mythread_cond;
    +
    +typedef struct timespec mythread_condtime;
    +
    +
    +// Calls the given function once in a thread-safe way.
    +#define mythread_once(func) \
    +	do { \
    +		static pthread_once_t once_ = PTHREAD_ONCE_INIT; \
    +		pthread_once(&once_, &func); \
    +	} while (0)
    +
    +
    +// Use pthread_sigmask() to set the signal mask in multi-threaded programs.
    +// Do nothing on OpenVMS since it lacks pthread_sigmask().
    +// Do nothing on MinGW-w64 too to silence warnings (its pthread_sigmask()
    +// is #defined to 0 so it's a no-op).
    +static inline void
    +mythread_sigmask(int how, const sigset_t *restrict set,
    +		sigset_t *restrict oset)
    +{
    +#if defined(__VMS) || defined(__MINGW32__)
    +	(void)how;
    +	(void)set;
    +	(void)oset;
    +#else
    +	int ret = pthread_sigmask(how, set, oset);
    +	assert(ret == 0);
    +	(void)ret;
    +#endif
    +}
    +
    +
    +// Creates a new thread with all signals blocked. Returns zero on success
    +// and non-zero on error.
    +static inline int
    +mythread_create(mythread *thread, void *(*func)(void *arg), void *arg)
    +{
    +	sigset_t old;
    +	sigset_t all;
    +	sigfillset(&all);
    +
    +	mythread_sigmask(SIG_SETMASK, &all, &old);
    +	const int ret = pthread_create(thread, NULL, func, arg);
    +	mythread_sigmask(SIG_SETMASK, &old, NULL);
    +
    +	return ret;
    +}
    +
    +// Joins a thread. Returns zero on success and non-zero on error.
    +static inline int
    +mythread_join(mythread thread)
    +{
    +	return pthread_join(thread, NULL);
    +}
    +
    +
    +// Initializes a mutex. Returns zero on success and non-zero on error.
    +static inline int
    +mythread_mutex_init(mythread_mutex *mutex)
    +{
    +	return pthread_mutex_init(mutex, NULL);
    +}
    +
    +static inline void
    +mythread_mutex_destroy(mythread_mutex *mutex)
    +{
    +	int ret = pthread_mutex_destroy(mutex);
    +	assert(ret == 0);
    +	(void)ret;
    +}
    +
    +static inline void
    +mythread_mutex_lock(mythread_mutex *mutex)
    +{
    +	int ret = pthread_mutex_lock(mutex);
    +	assert(ret == 0);
    +	(void)ret;
    +}
    +
    +static inline void
    +mythread_mutex_unlock(mythread_mutex *mutex)
    +{
    +	int ret = pthread_mutex_unlock(mutex);
    +	assert(ret == 0);
    +	(void)ret;
    +}
    +
    +
    +// Initializes a condition variable.
    +//
    +// Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the
    +// timeout in pthread_cond_timedwait() work correctly also if system time
    +// is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available
    +// everywhere while the default CLOCK_REALTIME is, so the default is
    +// used if CLOCK_MONOTONIC isn't available.
    +//
    +// If clock_gettime() isn't available at all, gettimeofday() will be used.
    +static inline int
    +mythread_cond_init(mythread_cond *mycond)
    +{
    +#ifdef HAVE_CLOCK_GETTIME
    +#	if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \
    +		defined(HAVE_CLOCK_MONOTONIC)
    +	struct timespec ts;
    +	pthread_condattr_t condattr;
    +
    +	// POSIX doesn't seem to *require* that pthread_condattr_setclock()
    +	// will fail if given an unsupported clock ID. Test that
    +	// CLOCK_MONOTONIC really is supported using clock_gettime().
    +	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0
    +			&& pthread_condattr_init(&condattr) == 0) {
    +		int ret = pthread_condattr_setclock(
    +				&condattr, CLOCK_MONOTONIC);
    +		if (ret == 0)
    +			ret = pthread_cond_init(&mycond->cond, &condattr);
    +
    +		pthread_condattr_destroy(&condattr);
    +
    +		if (ret == 0) {
    +			mycond->clk_id = CLOCK_MONOTONIC;
    +			return 0;
    +		}
    +	}
    +
    +	// If anything above fails, fall back to the default CLOCK_REALTIME.
    +	// POSIX requires that all implementations of clock_gettime() must
    +	// support at least CLOCK_REALTIME.
    +#	endif
    +
    +	mycond->clk_id = CLOCK_REALTIME;
    +#endif
    +
    +	return pthread_cond_init(&mycond->cond, NULL);
    +}
    +
    +static inline void
    +mythread_cond_destroy(mythread_cond *cond)
    +{
    +	int ret = pthread_cond_destroy(&cond->cond);
    +	assert(ret == 0);
    +	(void)ret;
    +}
    +
    +static inline void
    +mythread_cond_signal(mythread_cond *cond)
    +{
    +	int ret = pthread_cond_signal(&cond->cond);
    +	assert(ret == 0);
    +	(void)ret;
    +}
    +
    +static inline void
    +mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
    +{
    +	int ret = pthread_cond_wait(&cond->cond, mutex);
    +	assert(ret == 0);
    +	(void)ret;
    +}
    +
    +// Waits on a condition or until a timeout expires. If the timeout expires,
    +// non-zero is returned, otherwise zero is returned.
    +static inline int
    +mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
    +		const mythread_condtime *condtime)
    +{
    +	int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime);
    +	assert(ret == 0 || ret == ETIMEDOUT);
    +	return ret;
    +}
    +
    +// Sets condtime to the absolute time that is timeout_ms milliseconds
    +// in the future. The type of the clock to use is taken from cond.
    +static inline void
    +mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
    +		uint32_t timeout_ms)
    +{
    +	condtime->tv_sec = (time_t)(timeout_ms / 1000);
    +	condtime->tv_nsec = (long)((timeout_ms % 1000) * 1000000);
    +
    +#ifdef HAVE_CLOCK_GETTIME
    +	struct timespec now;
    +	int ret = clock_gettime(cond->clk_id, &now);
    +	assert(ret == 0);
    +	(void)ret;
    +
    +	condtime->tv_sec += now.tv_sec;
    +	condtime->tv_nsec += now.tv_nsec;
    +#else
    +	(void)cond;
    +
    +	struct timeval now;
    +	gettimeofday(&now, NULL);
    +
    +	condtime->tv_sec += now.tv_sec;
    +	condtime->tv_nsec += now.tv_usec * 1000L;
    +#endif
    +
    +	// tv_nsec must stay in the range [0, 999_999_999].
    +	if (condtime->tv_nsec >= 1000000000L) {
    +		condtime->tv_nsec -= 1000000000L;
    +		++condtime->tv_sec;
    +	}
    +}
    +
    +
    +#elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA)
    +
    +/////////////////////
    +// Windows threads //
    +/////////////////////
    +
    +#define WIN32_LEAN_AND_MEAN
    +#ifdef MYTHREAD_VISTA
    +#	undef _WIN32_WINNT
    +#	define _WIN32_WINNT 0x0600
    +#endif
    +#include 
    +#include 
    +
    +#define MYTHREAD_RET_TYPE unsigned int __stdcall
    +#define MYTHREAD_RET_VALUE 0
    +
    +typedef HANDLE mythread;
    +typedef CRITICAL_SECTION mythread_mutex;
    +
    +#ifdef MYTHREAD_WIN95
    +typedef HANDLE mythread_cond;
    +#else
    +typedef CONDITION_VARIABLE mythread_cond;
    +#endif
    +
    +typedef struct {
    +	// Tick count (milliseconds) in the beginning of the timeout.
    +	// NOTE: This is 32 bits so it wraps around after 49.7 days.
    +	// Multi-day timeouts may not work as expected.
    +	DWORD start;
    +
    +	// Length of the timeout in milliseconds. The timeout expires
    +	// when the current tick count minus "start" is equal or greater
    +	// than "timeout".
    +	DWORD timeout;
    +} mythread_condtime;
    +
    +
    +// mythread_once() is only available with Vista threads.
    +#ifdef MYTHREAD_VISTA
    +#define mythread_once(func) \
    +	do { \
    +		static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \
    +		BOOL pending_; \
    +		if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \
    +			abort(); \
    +		if (pending_) { \
    +			func(); \
    +			if (!InitOnceComplete(&once_, 0, NULL)) \
    +				abort(); \
    +		} \
    +	} while (0)
    +#endif
    +
    +
    +// mythread_sigmask() isn't available on Windows. Even a dummy version would
    +// make no sense because the other POSIX signal functions are missing anyway.
    +
    +
    +static inline int
    +mythread_create(mythread *thread,
    +		unsigned int (__stdcall *func)(void *arg), void *arg)
    +{
    +	uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL);
    +	if (ret == 0)
    +		return -1;
    +
    +	*thread = (HANDLE)ret;
    +	return 0;
    +}
    +
    +static inline int
    +mythread_join(mythread thread)
    +{
    +	int ret = 0;
    +
    +	if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
    +		ret = -1;
    +
    +	if (!CloseHandle(thread))
    +		ret = -1;
    +
    +	return ret;
    +}
    +
    +
    +static inline int
    +mythread_mutex_init(mythread_mutex *mutex)
    +{
    +	InitializeCriticalSection(mutex);
    +	return 0;
    +}
    +
    +static inline void
    +mythread_mutex_destroy(mythread_mutex *mutex)
    +{
    +	DeleteCriticalSection(mutex);
    +}
    +
    +static inline void
    +mythread_mutex_lock(mythread_mutex *mutex)
    +{
    +	EnterCriticalSection(mutex);
    +}
    +
    +static inline void
    +mythread_mutex_unlock(mythread_mutex *mutex)
    +{
    +	LeaveCriticalSection(mutex);
    +}
    +
    +
    +static inline int
    +mythread_cond_init(mythread_cond *cond)
    +{
    +#ifdef MYTHREAD_WIN95
    +	*cond = CreateEvent(NULL, FALSE, FALSE, NULL);
    +	return *cond == NULL ? -1 : 0;
    +#else
    +	InitializeConditionVariable(cond);
    +	return 0;
    +#endif
    +}
    +
    +static inline void
    +mythread_cond_destroy(mythread_cond *cond)
    +{
    +#ifdef MYTHREAD_WIN95
    +	CloseHandle(*cond);
    +#else
    +	(void)cond;
    +#endif
    +}
    +
    +static inline void
    +mythread_cond_signal(mythread_cond *cond)
    +{
    +#ifdef MYTHREAD_WIN95
    +	SetEvent(*cond);
    +#else
    +	WakeConditionVariable(cond);
    +#endif
    +}
    +
    +static inline void
    +mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
    +{
    +#ifdef MYTHREAD_WIN95
    +	LeaveCriticalSection(mutex);
    +	WaitForSingleObject(*cond, INFINITE);
    +	EnterCriticalSection(mutex);
    +#else
    +	BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE);
    +	assert(ret);
    +	(void)ret;
    +#endif
    +}
    +
    +static inline int
    +mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
    +		const mythread_condtime *condtime)
    +{
    +#ifdef MYTHREAD_WIN95
    +	LeaveCriticalSection(mutex);
    +#endif
    +
    +	DWORD elapsed = GetTickCount() - condtime->start;
    +	DWORD timeout = elapsed >= condtime->timeout
    +			? 0 : condtime->timeout - elapsed;
    +
    +#ifdef MYTHREAD_WIN95
    +	DWORD ret = WaitForSingleObject(*cond, timeout);
    +	assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT);
    +
    +	EnterCriticalSection(mutex);
    +
    +	return ret == WAIT_TIMEOUT;
    +#else
    +	BOOL ret = SleepConditionVariableCS(cond, mutex, timeout);
    +	assert(ret || GetLastError() == ERROR_TIMEOUT);
    +	return !ret;
    +#endif
    +}
    +
    +static inline void
    +mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
    +		uint32_t timeout)
    +{
    +	(void)cond;
    +	condtime->start = GetTickCount();
    +	condtime->timeout = timeout;
    +}
    +
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/sysdefs.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/sysdefs.h
    new file mode 100644
    index 00000000000..5f3785b5137
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/sysdefs.h
    @@ -0,0 +1,199 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       sysdefs.h
    +/// \brief      Common includes, definitions, system-specific things etc.
    +///
    +/// This file is used also by the lzma command line tool, that's why this
    +/// file is separate from common.h.
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_SYSDEFS_H
    +#define LZMA_SYSDEFS_H
    +
    +//////////////
    +// Includes //
    +//////////////
    +
    +#ifdef HAVE_CONFIG_H
    +#	include 
    +#endif
    +
    +// This #define ensures that C99 and POSIX compliant stdio functions are
    +// available with MinGW-w64 (both 32-bit and 64-bit). Modern MinGW-w64 adds
    +// this automatically, for example, when the compiler is in C99 (or later)
    +// mode when building against msvcrt.dll. It still doesn't hurt to be explicit
    +// that we always want this and #define this unconditionally.
    +//
    +// With Universal CRT (UCRT) this is less important because UCRT contains
    +// C99-compatible stdio functions. It's still nice to #define this as UCRT
    +// doesn't support the POSIX thousand separator flag in printf (like "%'u").
    +#ifdef __MINGW32__
    +#	define __USE_MINGW_ANSI_STDIO 1
    +#endif
    +
    +// size_t and NULL
    +#include 
    +
    +#ifdef HAVE_INTTYPES_H
    +#	include 
    +#endif
    +
    +// C99 says that inttypes.h always includes stdint.h, but some systems
    +// don't do that, and require including stdint.h separately.
    +#ifdef HAVE_STDINT_H
    +#	include 
    +#endif
    +
    +// Some pre-C99 systems have SIZE_MAX in limits.h instead of stdint.h. The
    +// limits are also used to figure out some macros missing from pre-C99 systems.
    +#include 
    +
    +// Be more compatible with systems that have non-conforming inttypes.h.
    +// We assume that int is 32-bit and that long is either 32-bit or 64-bit.
    +// Full Autoconf test could be more correct, but this should work well enough.
    +// Note that this duplicates some code from lzma.h, but this is better since
    +// we can work without inttypes.h thanks to Autoconf tests.
    +#ifndef UINT32_C
    +#	if UINT_MAX != 4294967295U
    +#		error UINT32_C is not defined and unsigned int is not 32-bit.
    +#	endif
    +#	define UINT32_C(n) n ## U
    +#endif
    +#ifndef UINT32_MAX
    +#	define UINT32_MAX UINT32_C(4294967295)
    +#endif
    +#ifndef PRIu32
    +#	define PRIu32 "u"
    +#endif
    +#ifndef PRIx32
    +#	define PRIx32 "x"
    +#endif
    +#ifndef PRIX32
    +#	define PRIX32 "X"
    +#endif
    +
    +#if ULONG_MAX == 4294967295UL
    +#	ifndef UINT64_C
    +#		define UINT64_C(n) n ## ULL
    +#	endif
    +#	ifndef PRIu64
    +#		define PRIu64 "llu"
    +#	endif
    +#	ifndef PRIx64
    +#		define PRIx64 "llx"
    +#	endif
    +#	ifndef PRIX64
    +#		define PRIX64 "llX"
    +#	endif
    +#else
    +#	ifndef UINT64_C
    +#		define UINT64_C(n) n ## UL
    +#	endif
    +#	ifndef PRIu64
    +#		define PRIu64 "lu"
    +#	endif
    +#	ifndef PRIx64
    +#		define PRIx64 "lx"
    +#	endif
    +#	ifndef PRIX64
    +#		define PRIX64 "lX"
    +#	endif
    +#endif
    +#ifndef UINT64_MAX
    +#	define UINT64_MAX UINT64_C(18446744073709551615)
    +#endif
    +
    +// Incorrect(?) SIZE_MAX:
    +//   - Interix headers typedef size_t to unsigned long,
    +//     but a few lines later define SIZE_MAX to INT32_MAX.
    +//   - SCO OpenServer (x86) headers typedef size_t to unsigned int
    +//     but define SIZE_MAX to INT32_MAX.
    +#if defined(__INTERIX) || defined(_SCO_DS)
    +#	undef SIZE_MAX
    +#endif
    +
    +// The code currently assumes that size_t is either 32-bit or 64-bit.
    +#ifndef SIZE_MAX
    +#	if SIZEOF_SIZE_T == 4
    +#		define SIZE_MAX UINT32_MAX
    +#	elif SIZEOF_SIZE_T == 8
    +#		define SIZE_MAX UINT64_MAX
    +#	else
    +#		error size_t is not 32-bit or 64-bit
    +#	endif
    +#endif
    +#if SIZE_MAX != UINT32_MAX && SIZE_MAX != UINT64_MAX
    +#	error size_t is not 32-bit or 64-bit
    +#endif
    +
    +#include 
    +#include 
    +
    +// Pre-C99 systems lack stdbool.h. All the code in XZ Utils must be written
    +// so that it works with fake bool type, for example:
    +//
    +//    bool foo = (flags & 0x100) != 0;
    +//    bool bar = !!(flags & 0x100);
    +//
    +// This works with the real C99 bool but breaks with fake bool:
    +//
    +//    bool baz = (flags & 0x100);
    +//
    +#ifdef HAVE_STDBOOL_H
    +#	include 
    +#else
    +#	if ! HAVE__BOOL
    +typedef unsigned char _Bool;
    +#	endif
    +#	define bool _Bool
    +#	define false 0
    +#	define true 1
    +#	define __bool_true_false_are_defined 1
    +#endif
    +
    +#include 
    +
    +// Visual Studio 2013 update 2 supports only __inline, not inline.
    +// MSVC v19.0 / VS 2015 and newer support both.
    +//
    +// MSVC v19.27 (VS 2019 version 16.7) added support for restrict.
    +// Older ones support only __restrict.
    +#ifdef _MSC_VER
    +#	if _MSC_VER < 1900 && !defined(inline)
    +#		define inline __inline
    +#	endif
    +#	if _MSC_VER < 1927 && !defined(restrict)
    +#		define restrict __restrict
    +#	endif
    +#endif
    +
    +////////////
    +// Macros //
    +////////////
    +
    +#undef memzero
    +#define memzero(s, n) memset(s, 0, n)
    +
    +// NOTE: Avoid using MIN() and MAX(), because even conditionally defining
    +// those macros can cause some portability trouble, since on some systems
    +// the system headers insist defining their own versions.
    +#define my_min(x, y) ((x) < (y) ? (x) : (y))
    +#define my_max(x, y) ((x) > (y) ? (x) : (y))
    +
    +#ifndef ARRAY_SIZE
    +#	define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
    +#endif
    +
    +#if defined(__GNUC__) \
    +		&& ((__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4)
    +#	define lzma_attr_alloc_size(x) __attribute__((__alloc_size__(x)))
    +#else
    +#	define lzma_attr_alloc_size(x)
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_common.h
    new file mode 100644
    index 00000000000..7554dfc86fb
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_common.h
    @@ -0,0 +1,90 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_common.h
    +/// \brief      Common definitions for tuklib modules
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef TUKLIB_COMMON_H
    +#define TUKLIB_COMMON_H
    +
    +// The config file may be replaced by a package-specific file.
    +// It should include at least stddef.h, stdbool.h, inttypes.h, and limits.h.
    +#include "tuklib_config.h"
    +
    +// TUKLIB_SYMBOL_PREFIX is prefixed to all symbols exported by
    +// the tuklib modules. If you use a tuklib module in a library,
    +// you should use TUKLIB_SYMBOL_PREFIX to make sure that there
    +// are no symbol conflicts in case someone links your library
    +// into application that also uses the same tuklib module.
    +#ifndef TUKLIB_SYMBOL_PREFIX
    +#	define TUKLIB_SYMBOL_PREFIX
    +#endif
    +
    +#define TUKLIB_CAT_X(a, b) a ## b
    +#define TUKLIB_CAT(a, b) TUKLIB_CAT_X(a, b)
    +
    +#ifndef TUKLIB_SYMBOL
    +#	define TUKLIB_SYMBOL(sym) TUKLIB_CAT(TUKLIB_SYMBOL_PREFIX, sym)
    +#endif
    +
    +#ifndef TUKLIB_DECLS_BEGIN
    +#	ifdef __cplusplus
    +#		define TUKLIB_DECLS_BEGIN extern "C" {
    +#	else
    +#		define TUKLIB_DECLS_BEGIN
    +#	endif
    +#endif
    +
    +#ifndef TUKLIB_DECLS_END
    +#	ifdef __cplusplus
    +#		define TUKLIB_DECLS_END }
    +#	else
    +#		define TUKLIB_DECLS_END
    +#	endif
    +#endif
    +
    +#if defined(__GNUC__) && defined(__GNUC_MINOR__)
    +#	define TUKLIB_GNUC_REQ(major, minor) \
    +		((__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)) \
    +			|| __GNUC__ > (major))
    +#else
    +#	define TUKLIB_GNUC_REQ(major, minor) 0
    +#endif
    +
    +// tuklib_attr_noreturn attribute is used to mark functions as non-returning.
    +// We cannot use "noreturn" as the macro name because then C23 code that
    +// uses [[noreturn]] would break as it would expand to [[ [[noreturn]] ]].
    +//
    +// tuklib_attr_noreturn must be used at the beginning of function declaration
    +// to work in all cases. The [[noreturn]] syntax is the most limiting, it
    +// must be even before any GNU C's __attribute__ keywords:
    +//
    +//     tuklib_attr_noreturn
    +//     __attribute__((nonnull(1)))
    +//     extern void foo(const char *s);
    +//
    +// FIXME: Update __STDC_VERSION__ for the final C23 version. 202000 is used
    +// by GCC 13 and Clang 15 with -std=c2x.
    +#if   defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000
    +#	define tuklib_attr_noreturn [[noreturn]]
    +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112
    +#	define tuklib_attr_noreturn _Noreturn
    +#elif TUKLIB_GNUC_REQ(2, 5)
    +#	define tuklib_attr_noreturn __attribute__((__noreturn__))
    +#elif defined(_MSC_VER)
    +#	define tuklib_attr_noreturn __declspec(noreturn)
    +#else
    +#	define tuklib_attr_noreturn
    +#endif
    +
    +#if (defined(_WIN32) && !defined(__CYGWIN__)) \
    +		|| defined(__OS2__) || defined(__MSDOS__)
    +#	define TUKLIB_DOSLIKE 1
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_config.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_config.h
    new file mode 100644
    index 00000000000..b27251dc276
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_config.h
    @@ -0,0 +1,12 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +// If config.h isn't available, assume that the headers required by
    +// tuklib_common.h are available. This is required by crc32_tablegen.c.
    +#ifdef HAVE_CONFIG_H
    +#	include "sysdefs.h"
    +#else
    +#	include 
    +#	include 
    +#	include 
    +#	include 
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.c
    new file mode 100644
    index 00000000000..c4a781ac387
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.c
    @@ -0,0 +1,108 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_cpucores.c
    +/// \brief      Get the number of CPU cores online
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "tuklib_cpucores.h"
    +
    +#if defined(_WIN32) || defined(__CYGWIN__)
    +#	ifndef _WIN32_WINNT
    +#		define _WIN32_WINNT 0x0500
    +#	endif
    +#	include 
    +
    +// glibc >= 2.9
    +#elif defined(TUKLIB_CPUCORES_SCHED_GETAFFINITY)
    +#	include 
    +
    +// FreeBSD
    +#elif defined(TUKLIB_CPUCORES_CPUSET)
    +#	include 
    +#	include 
    +
    +#elif defined(TUKLIB_CPUCORES_SYSCTL)
    +#	ifdef HAVE_SYS_PARAM_H
    +#		include 
    +#	endif
    +#	include 
    +
    +#elif defined(TUKLIB_CPUCORES_SYSCONF)
    +#	include 
    +
    +// HP-UX
    +#elif defined(TUKLIB_CPUCORES_PSTAT_GETDYNAMIC)
    +#	include 
    +#	include 
    +#endif
    +
    +
    +extern uint32_t
    +tuklib_cpucores(void)
    +{
    +	uint32_t ret = 0;
    +
    +#if defined(_WIN32) || defined(__CYGWIN__)
    +	SYSTEM_INFO sysinfo;
    +	GetSystemInfo(&sysinfo);
    +	ret = sysinfo.dwNumberOfProcessors;
    +
    +#elif defined(TUKLIB_CPUCORES_SCHED_GETAFFINITY)
    +	cpu_set_t cpu_mask;
    +	if (sched_getaffinity(0, sizeof(cpu_mask), &cpu_mask) == 0)
    +		ret = (uint32_t)CPU_COUNT(&cpu_mask);
    +
    +#elif defined(TUKLIB_CPUCORES_CPUSET)
    +	cpuset_t set;
    +	if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
    +			sizeof(set), &set) == 0) {
    +#	ifdef CPU_COUNT
    +		ret = (uint32_t)CPU_COUNT(&set);
    +#	else
    +		for (unsigned i = 0; i < CPU_SETSIZE; ++i)
    +			if (CPU_ISSET(i, &set))
    +				++ret;
    +#	endif
    +	}
    +
    +#elif defined(TUKLIB_CPUCORES_SYSCTL)
    +	// On OpenBSD HW_NCPUONLINE tells the number of processor cores that
    +	// are online so it is preferred over HW_NCPU which also counts cores
    +	// that aren't currently available. The number of cores online is
    +	// often less than HW_NCPU because OpenBSD disables simultaneous
    +	// multi-threading (SMT) by default.
    +#	ifdef HW_NCPUONLINE
    +	int name[2] = { CTL_HW, HW_NCPUONLINE };
    +#	else
    +	int name[2] = { CTL_HW, HW_NCPU };
    +#	endif
    +	int cpus;
    +	size_t cpus_size = sizeof(cpus);
    +	if (sysctl(name, 2, &cpus, &cpus_size, NULL, 0) != -1
    +			&& cpus_size == sizeof(cpus) && cpus > 0)
    +		ret = (uint32_t)cpus;
    +
    +#elif defined(TUKLIB_CPUCORES_SYSCONF)
    +#	ifdef _SC_NPROCESSORS_ONLN
    +	// Most systems
    +	const long cpus = sysconf(_SC_NPROCESSORS_ONLN);
    +#	else
    +	// IRIX
    +	const long cpus = sysconf(_SC_NPROC_ONLN);
    +#	endif
    +	if (cpus > 0)
    +		ret = (uint32_t)cpus;
    +
    +#elif defined(TUKLIB_CPUCORES_PSTAT_GETDYNAMIC)
    +	struct pst_dynamic pst;
    +	if (pstat_getdynamic(&pst, sizeof(pst), 1, 0) != -1)
    +		ret = (uint32_t)pst.psd_proc_cnt;
    +#endif
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.h
    new file mode 100644
    index 00000000000..edff9395e41
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.h
    @@ -0,0 +1,22 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_cpucores.h
    +/// \brief      Get the number of CPU cores online
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef TUKLIB_CPUCORES_H
    +#define TUKLIB_CPUCORES_H
    +
    +#include "tuklib_common.h"
    +TUKLIB_DECLS_BEGIN
    +
    +#define tuklib_cpucores TUKLIB_SYMBOL(tuklib_cpucores)
    +extern uint32_t tuklib_cpucores(void);
    +
    +TUKLIB_DECLS_END
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.c
    new file mode 100644
    index 00000000000..c84e0f679a6
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.c
    @@ -0,0 +1,57 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_exit.c
    +/// \brief      Close stdout and stderr, and exit
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "tuklib_common.h"
    +
    +#include 
    +#include 
    +#include 
    +
    +#include "tuklib_gettext.h"
    +#include "tuklib_progname.h"
    +#include "tuklib_exit.h"
    +
    +
    +extern void
    +tuklib_exit(int status, int err_status, int show_error)
    +{
    +	if (status != err_status) {
    +		// Close stdout. If something goes wrong,
    +		// print an error message to stderr.
    +		const int ferror_err = ferror(stdout);
    +		const int fclose_err = fclose(stdout);
    +		if (ferror_err || fclose_err) {
    +			status = err_status;
    +
    +			// If it was fclose() that failed, we have the reason
    +			// in errno. If only ferror() indicated an error,
    +			// we have no idea what the reason was.
    +			if (show_error)
    +				fprintf(stderr, "%s: %s: %s\n", progname,
    +						_("Writing to standard "
    +							"output failed"),
    +						fclose_err ? strerror(errno)
    +							: _("Unknown error"));
    +		}
    +	}
    +
    +	if (status != err_status) {
    +		// Close stderr. If something goes wrong, there's
    +		// nothing where we could print an error message.
    +		// Just set the exit status.
    +		const int ferror_err = ferror(stderr);
    +		const int fclose_err = fclose(stderr);
    +		if (fclose_err || ferror_err)
    +			status = err_status;
    +	}
    +
    +	exit(status);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.h
    new file mode 100644
    index 00000000000..d4e6b4a7e83
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.h
    @@ -0,0 +1,24 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_exit.h
    +/// \brief      Close stdout and stderr, and exit
    +/// \note       Requires tuklib_progname and tuklib_gettext modules
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef TUKLIB_EXIT_H
    +#define TUKLIB_EXIT_H
    +
    +#include "tuklib_common.h"
    +TUKLIB_DECLS_BEGIN
    +
    +#define tuklib_exit TUKLIB_SYMBOL(tuklib_exit)
    +tuklib_attr_noreturn
    +extern void tuklib_exit(int status, int err_status, int show_error);
    +
    +TUKLIB_DECLS_END
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_gettext.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_gettext.h
    new file mode 100644
    index 00000000000..3ef5cb7292b
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_gettext.h
    @@ -0,0 +1,43 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_gettext.h
    +/// \brief      Wrapper for gettext and friends
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef TUKLIB_GETTEXT_H
    +#define TUKLIB_GETTEXT_H
    +
    +#include "tuklib_common.h"
    +#include 
    +
    +#ifndef TUKLIB_GETTEXT
    +#	ifdef ENABLE_NLS
    +#		define TUKLIB_GETTEXT 1
    +#	else
    +#		define TUKLIB_GETTEXT 0
    +#	endif
    +#endif
    +
    +#if TUKLIB_GETTEXT
    +#	include 
    +#	define tuklib_gettext_init(package, localedir) \
    +		do { \
    +			setlocale(LC_ALL, ""); \
    +			bindtextdomain(package, localedir); \
    +			textdomain(package); \
    +		} while (0)
    +#	define _(msgid) gettext(msgid)
    +#else
    +#	define tuklib_gettext_init(package, localedir) \
    +		setlocale(LC_ALL, "")
    +#	define _(msgid) (msgid)
    +#	define ngettext(msgid1, msgid2, n) ((n) == 1 ? (msgid1) : (msgid2))
    +#endif
    +#define N_(msgid) msgid
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_integer.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_integer.h
    new file mode 100644
    index 00000000000..4026249e546
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_integer.h
    @@ -0,0 +1,954 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_integer.h
    +/// \brief      Various integer and bit operations
    +///
    +/// This file provides macros or functions to do some basic integer and bit
    +/// operations.
    +///
    +/// Native endian inline functions (XX = 16, 32, or 64):
    +///   - Unaligned native endian reads: readXXne(ptr)
    +///   - Unaligned native endian writes: writeXXne(ptr, num)
    +///   - Aligned native endian reads: aligned_readXXne(ptr)
    +///   - Aligned native endian writes: aligned_writeXXne(ptr, num)
    +///
    +/// Endianness-converting integer operations (these can be macros!)
    +/// (XX = 16, 32, or 64; Y = b or l):
    +///   - Byte swapping: byteswapXX(num)
    +///   - Byte order conversions to/from native (byteswaps if Y isn't
    +///     the native endianness): convXXYe(num)
    +///   - Unaligned reads: readXXYe(ptr)
    +///   - Unaligned writes: writeXXYe(ptr, num)
    +///   - Aligned reads: aligned_readXXYe(ptr)
    +///   - Aligned writes: aligned_writeXXYe(ptr, num)
    +///
    +/// Since the above can macros, the arguments should have no side effects
    +/// because they may be evaluated more than once.
    +///
    +/// Bit scan operations for non-zero 32-bit integers (inline functions):
    +///   - Bit scan reverse (find highest non-zero bit): bsr32(num)
    +///   - Count leading zeros: clz32(num)
    +///   - Count trailing zeros: ctz32(num)
    +///   - Bit scan forward (simply an alias for ctz32()): bsf32(num)
    +///
    +/// The above bit scan operations return 0-31. If num is zero,
    +/// the result is undefined.
    +//
    +//  Authors:    Lasse Collin
    +//              Joachim Henke
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef TUKLIB_INTEGER_H
    +#define TUKLIB_INTEGER_H
    +
    +#include "tuklib_common.h"
    +#include 
    +
    +// Newer Intel C compilers require immintrin.h for _bit_scan_reverse()
    +// and such functions.
    +#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500)
    +#	include 
    +// Only include  when it is needed. GCC and Clang can both
    +// use __builtin's, so we only need Windows instrincs when using MSVC.
    +// GCC and Clang can set _MSC_VER on Windows, so we need to exclude these
    +// cases explicitly.
    +#elif defined(_MSC_VER) && !TUKLIB_GNUC_REQ(3, 4) && !defined(__clang__)
    +#	include 
    +#endif
    +
    +
    +///////////////////
    +// Byte swapping //
    +///////////////////
    +
    +#if defined(HAVE___BUILTIN_BSWAPXX)
    +	// GCC >= 4.8 and Clang
    +#	define byteswap16(num) __builtin_bswap16(num)
    +#	define byteswap32(num) __builtin_bswap32(num)
    +#	define byteswap64(num) __builtin_bswap64(num)
    +
    +#elif defined(HAVE_BYTESWAP_H)
    +	// glibc, uClibc, dietlibc
    +#	include 
    +#	ifdef HAVE_BSWAP_16
    +#		define byteswap16(num) bswap_16(num)
    +#	endif
    +#	ifdef HAVE_BSWAP_32
    +#		define byteswap32(num) bswap_32(num)
    +#	endif
    +#	ifdef HAVE_BSWAP_64
    +#		define byteswap64(num) bswap_64(num)
    +#	endif
    +
    +#elif defined(HAVE_SYS_ENDIAN_H)
    +	// *BSDs and Darwin
    +#	include 
    +#	ifdef __OpenBSD__
    +#		define byteswap16(num) swap16(num)
    +#		define byteswap32(num) swap32(num)
    +#		define byteswap64(num) swap64(num)
    +#	else
    +#		define byteswap16(num) bswap16(num)
    +#		define byteswap32(num) bswap32(num)
    +#		define byteswap64(num) bswap64(num)
    +#	endif
    +
    +#elif defined(HAVE_SYS_BYTEORDER_H)
    +	// Solaris
    +#	include 
    +#	ifdef BSWAP_16
    +#		define byteswap16(num) BSWAP_16(num)
    +#	endif
    +#	ifdef BSWAP_32
    +#		define byteswap32(num) BSWAP_32(num)
    +#	endif
    +#	ifdef BSWAP_64
    +#		define byteswap64(num) BSWAP_64(num)
    +#	endif
    +#	ifdef BE_16
    +#		define conv16be(num) BE_16(num)
    +#	endif
    +#	ifdef BE_32
    +#		define conv32be(num) BE_32(num)
    +#	endif
    +#	ifdef BE_64
    +#		define conv64be(num) BE_64(num)
    +#	endif
    +#	ifdef LE_16
    +#		define conv16le(num) LE_16(num)
    +#	endif
    +#	ifdef LE_32
    +#		define conv32le(num) LE_32(num)
    +#	endif
    +#	ifdef LE_64
    +#		define conv64le(num) LE_64(num)
    +#	endif
    +#endif
    +
    +#ifndef byteswap16
    +#	define byteswap16(n) (uint16_t)( \
    +		  (((n) & 0x00FFU) << 8) \
    +		| (((n) & 0xFF00U) >> 8) \
    +	)
    +#endif
    +
    +#ifndef byteswap32
    +#	define byteswap32(n) (uint32_t)( \
    +		  (((n) & UINT32_C(0x000000FF)) << 24) \
    +		| (((n) & UINT32_C(0x0000FF00)) << 8) \
    +		| (((n) & UINT32_C(0x00FF0000)) >> 8) \
    +		| (((n) & UINT32_C(0xFF000000)) >> 24) \
    +	)
    +#endif
    +
    +#ifndef byteswap64
    +#	define byteswap64(n) (uint64_t)( \
    +		  (((n) & UINT64_C(0x00000000000000FF)) << 56) \
    +		| (((n) & UINT64_C(0x000000000000FF00)) << 40) \
    +		| (((n) & UINT64_C(0x0000000000FF0000)) << 24) \
    +		| (((n) & UINT64_C(0x00000000FF000000)) << 8) \
    +		| (((n) & UINT64_C(0x000000FF00000000)) >> 8) \
    +		| (((n) & UINT64_C(0x0000FF0000000000)) >> 24) \
    +		| (((n) & UINT64_C(0x00FF000000000000)) >> 40) \
    +		| (((n) & UINT64_C(0xFF00000000000000)) >> 56) \
    +	)
    +#endif
    +
    +// Define conversion macros using the basic byte swapping macros.
    +#ifdef WORDS_BIGENDIAN
    +#	ifndef conv16be
    +#		define conv16be(num) ((uint16_t)(num))
    +#	endif
    +#	ifndef conv32be
    +#		define conv32be(num) ((uint32_t)(num))
    +#	endif
    +#	ifndef conv64be
    +#		define conv64be(num) ((uint64_t)(num))
    +#	endif
    +#	ifndef conv16le
    +#		define conv16le(num) byteswap16(num)
    +#	endif
    +#	ifndef conv32le
    +#		define conv32le(num) byteswap32(num)
    +#	endif
    +#	ifndef conv64le
    +#		define conv64le(num) byteswap64(num)
    +#	endif
    +#else
    +#	ifndef conv16be
    +#		define conv16be(num) byteswap16(num)
    +#	endif
    +#	ifndef conv32be
    +#		define conv32be(num) byteswap32(num)
    +#	endif
    +#	ifndef conv64be
    +#		define conv64be(num) byteswap64(num)
    +#	endif
    +#	ifndef conv16le
    +#		define conv16le(num) ((uint16_t)(num))
    +#	endif
    +#	ifndef conv32le
    +#		define conv32le(num) ((uint32_t)(num))
    +#	endif
    +#	ifndef conv64le
    +#		define conv64le(num) ((uint64_t)(num))
    +#	endif
    +#endif
    +
    +
    +////////////////////////////////
    +// Unaligned reads and writes //
    +////////////////////////////////
    +
    +// No-strict-align archs like x86-64
    +// ---------------------------------
    +//
    +// The traditional way of casting e.g. *(const uint16_t *)uint8_pointer
    +// is bad even if the uint8_pointer is properly aligned because this kind
    +// of casts break strict aliasing rules and result in undefined behavior.
    +// With unaligned pointers it's even worse: compilers may emit vector
    +// instructions that require aligned pointers even if non-vector
    +// instructions work with unaligned pointers.
    +//
    +// Using memcpy() is the standard compliant way to do unaligned access.
    +// Many modern compilers inline it so there is no function call overhead.
    +// For those compilers that don't handle the memcpy() method well, the
    +// old casting method (that violates strict aliasing) can be requested at
    +// build time. A third method, casting to a packed struct, would also be
    +// an option but isn't provided to keep things simpler (it's already a mess).
    +// Hopefully this is flexible enough in practice.
    +//
    +// Some compilers on x86-64 like Clang >= 10 and GCC >= 5.1 detect that
    +//
    +//     buf[0] | (buf[1] << 8)
    +//
    +// reads a 16-bit value and can emit a single 16-bit load and produce
    +// identical code than with the memcpy() method. In other cases Clang and GCC
    +// produce either the same or better code with memcpy(). For example, Clang 9
    +// on x86-64 can detect 32-bit load but not 16-bit load.
    +//
    +// MSVC uses unaligned access with the memcpy() method but emits byte-by-byte
    +// code for "buf[0] | (buf[1] << 8)".
    +//
    +// Conclusion: The memcpy() method is the best choice when unaligned access
    +// is supported.
    +//
    +// Strict-align archs like SPARC
    +// -----------------------------
    +//
    +// GCC versions from around 4.x to to at least 13.2.0 produce worse code
    +// from the memcpy() method than from simple byte-by-byte shift-or code
    +// when reading a 32-bit integer:
    +//
    +//     (1) It may be constructed on stack using four 8-bit loads,
    +//         four 8-bit stores to stack, and finally one 32-bit load from stack.
    +//
    +//     (2) Especially with -Os, an actual memcpy() call may be emitted.
    +//
    +// This is true on at least on ARM, ARM64, SPARC, SPARC64, MIPS64EL, and
    +// RISC-V. Of these, ARM, ARM64, and RISC-V support unaligned access in
    +// some processors but not all so this is relevant only in the case when
    +// GCC assumes that unaligned is not supported or -mstrict-align or
    +// -mno-unaligned-access is used.
    +//
    +// For Clang it makes little difference. ARM64 with -O2 -mstrict-align
    +// was one the very few with a minor difference: the memcpy() version
    +// was one instruction longer.
    +//
    +// Conclusion: At least in case of GCC and Clang, byte-by-byte code is
    +// the best choice for strict-align archs to do unaligned access.
    +//
    +// See also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111502
    +//
    +// Thanks to  it was easy to test different compilers.
    +// The following is for little endian targets:
    +/*
    +#include 
    +#include 
    +
    +uint32_t bytes16(const uint8_t *b)
    +{
    +    return (uint32_t)b[0]
    +        | ((uint32_t)b[1] << 8);
    +}
    +
    +uint32_t copy16(const uint8_t *b)
    +{
    +    uint16_t v;
    +    memcpy(&v, b, sizeof(v));
    +    return v;
    +}
    +
    +uint32_t bytes32(const uint8_t *b)
    +{
    +    return (uint32_t)b[0]
    +        | ((uint32_t)b[1] << 8)
    +        | ((uint32_t)b[2] << 16)
    +        | ((uint32_t)b[3] << 24);
    +}
    +
    +uint32_t copy32(const uint8_t *b)
    +{
    +    uint32_t v;
    +    memcpy(&v, b, sizeof(v));
    +    return v;
    +}
    +
    +void wbytes16(uint8_t *b, uint16_t v)
    +{
    +    b[0] = (uint8_t)v;
    +    b[1] = (uint8_t)(v >> 8);
    +}
    +
    +void wcopy16(uint8_t *b, uint16_t v)
    +{
    +    memcpy(b, &v, sizeof(v));
    +}
    +
    +void wbytes32(uint8_t *b, uint32_t v)
    +{
    +    b[0] = (uint8_t)v;
    +    b[1] = (uint8_t)(v >> 8);
    +    b[2] = (uint8_t)(v >> 16);
    +    b[3] = (uint8_t)(v >> 24);
    +}
    +
    +void wcopy32(uint8_t *b, uint32_t v)
    +{
    +    memcpy(b, &v, sizeof(v));
    +}
    +*/
    +
    +
    +#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
    +
    +static inline uint16_t
    +read16ne(const uint8_t *buf)
    +{
    +#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
    +	return *(const uint16_t *)buf;
    +#else
    +	uint16_t num;
    +	memcpy(&num, buf, sizeof(num));
    +	return num;
    +#endif
    +}
    +
    +
    +static inline uint32_t
    +read32ne(const uint8_t *buf)
    +{
    +#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
    +	return *(const uint32_t *)buf;
    +#else
    +	uint32_t num;
    +	memcpy(&num, buf, sizeof(num));
    +	return num;
    +#endif
    +}
    +
    +
    +static inline uint64_t
    +read64ne(const uint8_t *buf)
    +{
    +#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
    +	return *(const uint64_t *)buf;
    +#else
    +	uint64_t num;
    +	memcpy(&num, buf, sizeof(num));
    +	return num;
    +#endif
    +}
    +
    +
    +static inline void
    +write16ne(uint8_t *buf, uint16_t num)
    +{
    +#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
    +	*(uint16_t *)buf = num;
    +#else
    +	memcpy(buf, &num, sizeof(num));
    +#endif
    +	return;
    +}
    +
    +
    +static inline void
    +write32ne(uint8_t *buf, uint32_t num)
    +{
    +#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
    +	*(uint32_t *)buf = num;
    +#else
    +	memcpy(buf, &num, sizeof(num));
    +#endif
    +	return;
    +}
    +
    +
    +static inline void
    +write64ne(uint8_t *buf, uint64_t num)
    +{
    +#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
    +	*(uint64_t *)buf = num;
    +#else
    +	memcpy(buf, &num, sizeof(num));
    +#endif
    +	return;
    +}
    +
    +
    +static inline uint16_t
    +read16be(const uint8_t *buf)
    +{
    +	uint16_t num = read16ne(buf);
    +	return conv16be(num);
    +}
    +
    +
    +static inline uint16_t
    +read16le(const uint8_t *buf)
    +{
    +	uint16_t num = read16ne(buf);
    +	return conv16le(num);
    +}
    +
    +
    +static inline uint32_t
    +read32be(const uint8_t *buf)
    +{
    +	uint32_t num = read32ne(buf);
    +	return conv32be(num);
    +}
    +
    +
    +static inline uint32_t
    +read32le(const uint8_t *buf)
    +{
    +	uint32_t num = read32ne(buf);
    +	return conv32le(num);
    +}
    +
    +
    +static inline uint64_t
    +read64be(const uint8_t *buf)
    +{
    +	uint64_t num = read64ne(buf);
    +	return conv64be(num);
    +}
    +
    +
    +static inline uint64_t
    +read64le(const uint8_t *buf)
    +{
    +	uint64_t num = read64ne(buf);
    +	return conv64le(num);
    +}
    +
    +
    +// NOTE: Possible byte swapping must be done in a macro to allow the compiler
    +// to optimize byte swapping of constants when using glibc's or *BSD's
    +// byte swapping macros. The actual write is done in an inline function
    +// to make type checking of the buf pointer possible.
    +#define write16be(buf, num) write16ne(buf, conv16be(num))
    +#define write32be(buf, num) write32ne(buf, conv32be(num))
    +#define write64be(buf, num) write64ne(buf, conv64be(num))
    +#define write16le(buf, num) write16ne(buf, conv16le(num))
    +#define write32le(buf, num) write32ne(buf, conv32le(num))
    +#define write64le(buf, num) write64ne(buf, conv64le(num))
    +
    +#else
    +
    +#ifdef WORDS_BIGENDIAN
    +#	define read16ne read16be
    +#	define read32ne read32be
    +#	define read64ne read64be
    +#	define write16ne write16be
    +#	define write32ne write32be
    +#	define write64ne write64be
    +#else
    +#	define read16ne read16le
    +#	define read32ne read32le
    +#	define read64ne read64le
    +#	define write16ne write16le
    +#	define write32ne write32le
    +#	define write64ne write64le
    +#endif
    +
    +
    +static inline uint16_t
    +read16be(const uint8_t *buf)
    +{
    +	uint16_t num = ((uint16_t)buf[0] << 8) | (uint16_t)buf[1];
    +	return num;
    +}
    +
    +
    +static inline uint16_t
    +read16le(const uint8_t *buf)
    +{
    +	uint16_t num = ((uint16_t)buf[0]) | ((uint16_t)buf[1] << 8);
    +	return num;
    +}
    +
    +
    +static inline uint32_t
    +read32be(const uint8_t *buf)
    +{
    +	uint32_t num = (uint32_t)buf[0] << 24;
    +	num |= (uint32_t)buf[1] << 16;
    +	num |= (uint32_t)buf[2] << 8;
    +	num |= (uint32_t)buf[3];
    +	return num;
    +}
    +
    +
    +static inline uint32_t
    +read32le(const uint8_t *buf)
    +{
    +	uint32_t num = (uint32_t)buf[0];
    +	num |= (uint32_t)buf[1] << 8;
    +	num |= (uint32_t)buf[2] << 16;
    +	num |= (uint32_t)buf[3] << 24;
    +	return num;
    +}
    +
    +
    +static inline uint64_t
    +read64be(const uint8_t *buf)
    +{
    +	uint64_t num = (uint64_t)buf[0] << 56;
    +	num |= (uint64_t)buf[1] << 48;
    +	num |= (uint64_t)buf[2] << 40;
    +	num |= (uint64_t)buf[3] << 32;
    +	num |= (uint64_t)buf[4] << 24;
    +	num |= (uint64_t)buf[5] << 16;
    +	num |= (uint64_t)buf[6] << 8;
    +	num |= (uint64_t)buf[7];
    +	return num;
    +}
    +
    +
    +static inline uint64_t
    +read64le(const uint8_t *buf)
    +{
    +	uint64_t num = (uint64_t)buf[0];
    +	num |= (uint64_t)buf[1] << 8;
    +	num |= (uint64_t)buf[2] << 16;
    +	num |= (uint64_t)buf[3] << 24;
    +	num |= (uint64_t)buf[4] << 32;
    +	num |= (uint64_t)buf[5] << 40;
    +	num |= (uint64_t)buf[6] << 48;
    +	num |= (uint64_t)buf[7] << 56;
    +	return num;
    +}
    +
    +
    +static inline void
    +write16be(uint8_t *buf, uint16_t num)
    +{
    +	buf[0] = (uint8_t)(num >> 8);
    +	buf[1] = (uint8_t)num;
    +	return;
    +}
    +
    +
    +static inline void
    +write16le(uint8_t *buf, uint16_t num)
    +{
    +	buf[0] = (uint8_t)num;
    +	buf[1] = (uint8_t)(num >> 8);
    +	return;
    +}
    +
    +
    +static inline void
    +write32be(uint8_t *buf, uint32_t num)
    +{
    +	buf[0] = (uint8_t)(num >> 24);
    +	buf[1] = (uint8_t)(num >> 16);
    +	buf[2] = (uint8_t)(num >> 8);
    +	buf[3] = (uint8_t)num;
    +	return;
    +}
    +
    +
    +static inline void
    +write32le(uint8_t *buf, uint32_t num)
    +{
    +	buf[0] = (uint8_t)num;
    +	buf[1] = (uint8_t)(num >> 8);
    +	buf[2] = (uint8_t)(num >> 16);
    +	buf[3] = (uint8_t)(num >> 24);
    +	return;
    +}
    +
    +
    +static inline void
    +write64be(uint8_t *buf, uint64_t num)
    +{
    +	buf[0] = (uint8_t)(num >> 56);
    +	buf[1] = (uint8_t)(num >> 48);
    +	buf[2] = (uint8_t)(num >> 40);
    +	buf[3] = (uint8_t)(num >> 32);
    +	buf[4] = (uint8_t)(num >> 24);
    +	buf[5] = (uint8_t)(num >> 16);
    +	buf[6] = (uint8_t)(num >> 8);
    +	buf[7] = (uint8_t)num;
    +	return;
    +}
    +
    +
    +static inline void
    +write64le(uint8_t *buf, uint64_t num)
    +{
    +	buf[0] = (uint8_t)num;
    +	buf[1] = (uint8_t)(num >> 8);
    +	buf[2] = (uint8_t)(num >> 16);
    +	buf[3] = (uint8_t)(num >> 24);
    +	buf[4] = (uint8_t)(num >> 32);
    +	buf[5] = (uint8_t)(num >> 40);
    +	buf[6] = (uint8_t)(num >> 48);
    +	buf[7] = (uint8_t)(num >> 56);
    +	return;
    +}
    +
    +#endif
    +
    +
    +//////////////////////////////
    +// Aligned reads and writes //
    +//////////////////////////////
    +
    +// Separate functions for aligned reads and writes are provided since on
    +// strict-align archs aligned access is much faster than unaligned access.
    +//
    +// Just like in the unaligned case, memcpy() is needed to avoid
    +// strict aliasing violations. However, on archs that don't support
    +// unaligned access the compiler cannot know that the pointers given
    +// to memcpy() are aligned which results in slow code. As of C11 there is
    +// no standard way to tell the compiler that we know that the address is
    +// aligned but some compilers have language extensions to do that. With
    +// such language extensions the memcpy() method gives excellent results.
    +//
    +// What to do on a strict-align system when no known language extensions
    +// are available? Falling back to byte-by-byte access would be safe but ruin
    +// optimizations that have been made specifically with aligned access in mind.
    +// As a compromise, aligned reads will fall back to non-compliant type punning
    +// but aligned writes will be byte-by-byte, that is, fast reads are preferred
    +// over fast writes. This obviously isn't great but hopefully it's a working
    +// compromise for now.
    +//
    +// __builtin_assume_aligned is support by GCC >= 4.7 and clang >= 3.6.
    +#ifdef HAVE___BUILTIN_ASSUME_ALIGNED
    +#	define tuklib_memcpy_aligned(dest, src, size) \
    +		memcpy(dest, __builtin_assume_aligned(src, size), size)
    +#else
    +#	define tuklib_memcpy_aligned(dest, src, size) \
    +		memcpy(dest, src, size)
    +#	ifndef TUKLIB_FAST_UNALIGNED_ACCESS
    +#		define TUKLIB_USE_UNSAFE_ALIGNED_READS 1
    +#	endif
    +#endif
    +
    +
    +static inline uint16_t
    +aligned_read16ne(const uint8_t *buf)
    +{
    +#if defined(TUKLIB_USE_UNSAFE_TYPE_PUNNING) \
    +		|| defined(TUKLIB_USE_UNSAFE_ALIGNED_READS)
    +	return *(const uint16_t *)buf;
    +#else
    +	uint16_t num;
    +	tuklib_memcpy_aligned(&num, buf, sizeof(num));
    +	return num;
    +#endif
    +}
    +
    +
    +static inline uint32_t
    +aligned_read32ne(const uint8_t *buf)
    +{
    +#if defined(TUKLIB_USE_UNSAFE_TYPE_PUNNING) \
    +		|| defined(TUKLIB_USE_UNSAFE_ALIGNED_READS)
    +	return *(const uint32_t *)buf;
    +#else
    +	uint32_t num;
    +	tuklib_memcpy_aligned(&num, buf, sizeof(num));
    +	return num;
    +#endif
    +}
    +
    +
    +static inline uint64_t
    +aligned_read64ne(const uint8_t *buf)
    +{
    +#if defined(TUKLIB_USE_UNSAFE_TYPE_PUNNING) \
    +		|| defined(TUKLIB_USE_UNSAFE_ALIGNED_READS)
    +	return *(const uint64_t *)buf;
    +#else
    +	uint64_t num;
    +	tuklib_memcpy_aligned(&num, buf, sizeof(num));
    +	return num;
    +#endif
    +}
    +
    +
    +static inline void
    +aligned_write16ne(uint8_t *buf, uint16_t num)
    +{
    +#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
    +	*(uint16_t *)buf = num;
    +#else
    +	tuklib_memcpy_aligned(buf, &num, sizeof(num));
    +#endif
    +	return;
    +}
    +
    +
    +static inline void
    +aligned_write32ne(uint8_t *buf, uint32_t num)
    +{
    +#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
    +	*(uint32_t *)buf = num;
    +#else
    +	tuklib_memcpy_aligned(buf, &num, sizeof(num));
    +#endif
    +	return;
    +}
    +
    +
    +static inline void
    +aligned_write64ne(uint8_t *buf, uint64_t num)
    +{
    +#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
    +	*(uint64_t *)buf = num;
    +#else
    +	tuklib_memcpy_aligned(buf, &num, sizeof(num));
    +#endif
    +	return;
    +}
    +
    +
    +static inline uint16_t
    +aligned_read16be(const uint8_t *buf)
    +{
    +	uint16_t num = aligned_read16ne(buf);
    +	return conv16be(num);
    +}
    +
    +
    +static inline uint16_t
    +aligned_read16le(const uint8_t *buf)
    +{
    +	uint16_t num = aligned_read16ne(buf);
    +	return conv16le(num);
    +}
    +
    +
    +static inline uint32_t
    +aligned_read32be(const uint8_t *buf)
    +{
    +	uint32_t num = aligned_read32ne(buf);
    +	return conv32be(num);
    +}
    +
    +
    +static inline uint32_t
    +aligned_read32le(const uint8_t *buf)
    +{
    +	uint32_t num = aligned_read32ne(buf);
    +	return conv32le(num);
    +}
    +
    +
    +static inline uint64_t
    +aligned_read64be(const uint8_t *buf)
    +{
    +	uint64_t num = aligned_read64ne(buf);
    +	return conv64be(num);
    +}
    +
    +
    +static inline uint64_t
    +aligned_read64le(const uint8_t *buf)
    +{
    +	uint64_t num = aligned_read64ne(buf);
    +	return conv64le(num);
    +}
    +
    +
    +// These need to be macros like in the unaligned case.
    +#define aligned_write16be(buf, num) aligned_write16ne((buf), conv16be(num))
    +#define aligned_write16le(buf, num) aligned_write16ne((buf), conv16le(num))
    +#define aligned_write32be(buf, num) aligned_write32ne((buf), conv32be(num))
    +#define aligned_write32le(buf, num) aligned_write32ne((buf), conv32le(num))
    +#define aligned_write64be(buf, num) aligned_write64ne((buf), conv64be(num))
    +#define aligned_write64le(buf, num) aligned_write64ne((buf), conv64le(num))
    +
    +
    +////////////////////
    +// Bit operations //
    +////////////////////
    +
    +static inline uint32_t
    +bsr32(uint32_t n)
    +{
    +	// Check for ICC first, since it tends to define __GNUC__ too.
    +#if defined(__INTEL_COMPILER)
    +	return _bit_scan_reverse(n);
    +
    +#elif (TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) && UINT_MAX == UINT32_MAX
    +	// GCC >= 3.4 has __builtin_clz(), which gives good results on
    +	// multiple architectures. On x86, __builtin_clz() ^ 31U becomes
    +	// either plain BSR (so the XOR gets optimized away) or LZCNT and
    +	// XOR (if -march indicates that SSE4a instructions are supported).
    +	return (uint32_t)__builtin_clz(n) ^ 31U;
    +
    +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
    +	uint32_t i;
    +	__asm__("bsrl %1, %0" : "=r" (i) : "rm" (n));
    +	return i;
    +
    +#elif defined(_MSC_VER)
    +	unsigned long i;
    +	_BitScanReverse(&i, n);
    +	return i;
    +
    +#else
    +	uint32_t i = 31;
    +
    +	if ((n & 0xFFFF0000) == 0) {
    +		n <<= 16;
    +		i = 15;
    +	}
    +
    +	if ((n & 0xFF000000) == 0) {
    +		n <<= 8;
    +		i -= 8;
    +	}
    +
    +	if ((n & 0xF0000000) == 0) {
    +		n <<= 4;
    +		i -= 4;
    +	}
    +
    +	if ((n & 0xC0000000) == 0) {
    +		n <<= 2;
    +		i -= 2;
    +	}
    +
    +	if ((n & 0x80000000) == 0)
    +		--i;
    +
    +	return i;
    +#endif
    +}
    +
    +
    +static inline uint32_t
    +clz32(uint32_t n)
    +{
    +#if defined(__INTEL_COMPILER)
    +	return _bit_scan_reverse(n) ^ 31U;
    +
    +#elif (TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) && UINT_MAX == UINT32_MAX
    +	return (uint32_t)__builtin_clz(n);
    +
    +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
    +	uint32_t i;
    +	__asm__("bsrl %1, %0\n\t"
    +		"xorl $31, %0"
    +		: "=r" (i) : "rm" (n));
    +	return i;
    +
    +#elif defined(_MSC_VER)
    +	unsigned long i;
    +	_BitScanReverse(&i, n);
    +	return i ^ 31U;
    +
    +#else
    +	uint32_t i = 0;
    +
    +	if ((n & 0xFFFF0000) == 0) {
    +		n <<= 16;
    +		i = 16;
    +	}
    +
    +	if ((n & 0xFF000000) == 0) {
    +		n <<= 8;
    +		i += 8;
    +	}
    +
    +	if ((n & 0xF0000000) == 0) {
    +		n <<= 4;
    +		i += 4;
    +	}
    +
    +	if ((n & 0xC0000000) == 0) {
    +		n <<= 2;
    +		i += 2;
    +	}
    +
    +	if ((n & 0x80000000) == 0)
    +		++i;
    +
    +	return i;
    +#endif
    +}
    +
    +
    +static inline uint32_t
    +ctz32(uint32_t n)
    +{
    +#if defined(__INTEL_COMPILER)
    +	return _bit_scan_forward(n);
    +
    +#elif (TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) && UINT_MAX >= UINT32_MAX
    +	return (uint32_t)__builtin_ctz(n);
    +
    +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
    +	uint32_t i;
    +	__asm__("bsfl %1, %0" : "=r" (i) : "rm" (n));
    +	return i;
    +
    +#elif defined(_MSC_VER)
    +	unsigned long i;
    +	_BitScanForward(&i, n);
    +	return i;
    +
    +#else
    +	uint32_t i = 0;
    +
    +	if ((n & 0x0000FFFF) == 0) {
    +		n >>= 16;
    +		i = 16;
    +	}
    +
    +	if ((n & 0x000000FF) == 0) {
    +		n >>= 8;
    +		i += 8;
    +	}
    +
    +	if ((n & 0x0000000F) == 0) {
    +		n >>= 4;
    +		i += 4;
    +	}
    +
    +	if ((n & 0x00000003) == 0) {
    +		n >>= 2;
    +		i += 2;
    +	}
    +
    +	if ((n & 0x00000001) == 0)
    +		++i;
    +
    +	return i;
    +#endif
    +}
    +
    +#define bsf32 ctz32
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr.h
    new file mode 100644
    index 00000000000..4c8eeb7e370
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr.h
    @@ -0,0 +1,65 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_mbstr.h
    +/// \brief      Utility functions for handling multibyte strings
    +///
    +/// If not enough multibyte string support is available in the C library,
    +/// these functions keep working with the assumption that all strings
    +/// are in a single-byte character set without combining characters, e.g.
    +/// US-ASCII or ISO-8859-*.
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef TUKLIB_MBSTR_H
    +#define TUKLIB_MBSTR_H
    +
    +#include "tuklib_common.h"
    +TUKLIB_DECLS_BEGIN
    +
    +#define tuklib_mbstr_width TUKLIB_SYMBOL(tuklib_mbstr_width)
    +extern size_t tuklib_mbstr_width(const char *str, size_t *bytes);
    +///<
    +/// \brief      Get the number of columns needed for the multibyte string
    +///
    +/// This is somewhat similar to wcswidth() but works on multibyte strings.
    +///
    +/// \param      str         String whose width is to be calculated. If the
    +///                         current locale uses a multibyte character set
    +///                         that has shift states, the string must begin
    +///                         and end in the initial shift state.
    +/// \param      bytes       If this is not NULL, *bytes is set to the
    +///                         value returned by strlen(str) (even if an
    +///                         error occurs when calculating the width).
    +///
    +/// \return     On success, the number of columns needed to display the
    +///             string e.g. in a terminal emulator is returned. On error,
    +///             (size_t)-1 is returned. Possible errors include invalid,
    +///             partial, or non-printable multibyte character in str, or
    +///             that str doesn't end in the initial shift state.
    +
    +#define tuklib_mbstr_fw TUKLIB_SYMBOL(tuklib_mbstr_fw)
    +extern int tuklib_mbstr_fw(const char *str, int columns_min);
    +///<
    +/// \brief      Get the field width for printf() e.g. to align table columns
    +///
    +/// Printing simple tables to a terminal can be done using the field field
    +/// feature in the printf() format string, but it works only with single-byte
    +/// character sets. To do the same with multibyte strings, tuklib_mbstr_fw()
    +/// can be used to calculate appropriate field width.
    +///
    +/// The behavior of this function is undefined, if
    +///   - str is NULL or not terminated with '\0';
    +///   - columns_min <= 0; or
    +///   - the calculated field width exceeds INT_MAX.
    +///
    +/// \return     If tuklib_mbstr_width(str, NULL) fails, -1 is returned.
    +///             If str needs more columns than columns_min, zero is returned.
    +///             Otherwise a positive integer is returned, which can be
    +///             used as the field width, e.g. printf("%*s", fw, str).
    +
    +TUKLIB_DECLS_END
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_fw.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_fw.c
    new file mode 100644
    index 00000000000..22d883b569f
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_fw.c
    @@ -0,0 +1,30 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_mbstr_fw.c
    +/// \brief      Get the field width for printf() e.g. to align table columns
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "tuklib_mbstr.h"
    +
    +
    +extern int
    +tuklib_mbstr_fw(const char *str, int columns_min)
    +{
    +	size_t len;
    +	const size_t width = tuklib_mbstr_width(str, &len);
    +	if (width == (size_t)-1)
    +		return -1;
    +
    +	if (width > (size_t)columns_min)
    +		return 0;
    +
    +	if (width < (size_t)columns_min)
    +		len += (size_t)columns_min - width;
    +
    +	return (int)len;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_width.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_width.c
    new file mode 100644
    index 00000000000..7a8bf070751
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_width.c
    @@ -0,0 +1,64 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_mbstr_width.c
    +/// \brief      Calculate width of a multibyte string
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "tuklib_mbstr.h"
    +#include 
    +
    +#if defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
    +#	include 
    +#endif
    +
    +
    +extern size_t
    +tuklib_mbstr_width(const char *str, size_t *bytes)
    +{
    +	const size_t len = strlen(str);
    +	if (bytes != NULL)
    +		*bytes = len;
    +
    +#if !(defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH))
    +	// In single-byte mode, the width of the string is the same
    +	// as its length.
    +	return len;
    +
    +#else
    +	mbstate_t state;
    +	memset(&state, 0, sizeof(state));
    +
    +	size_t width = 0;
    +	size_t i = 0;
    +
    +	// Convert one multibyte character at a time to wchar_t
    +	// and get its width using wcwidth().
    +	while (i < len) {
    +		wchar_t wc;
    +		const size_t ret = mbrtowc(&wc, str + i, len - i, &state);
    +		if (ret < 1 || ret > len)
    +			return (size_t)-1;
    +
    +		i += ret;
    +
    +		const int wc_width = wcwidth(wc);
    +		if (wc_width < 0)
    +			return (size_t)-1;
    +
    +		width += (size_t)wc_width;
    +	}
    +
    +	// Require that the string ends in the initial shift state.
    +	// This way the caller can be combine the string with other
    +	// strings without needing to worry about the shift states.
    +	if (!mbsinit(&state))
    +		return (size_t)-1;
    +
    +	return width;
    +#endif
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.c
    new file mode 100644
    index 00000000000..b93e61d3b68
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.c
    @@ -0,0 +1,56 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_open_stdxxx.c
    +/// \brief      Make sure that file descriptors 0, 1, and 2 are open
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "tuklib_open_stdxxx.h"
    +
    +#ifndef TUKLIB_DOSLIKE
    +#	include 
    +#	include 
    +#	include 
    +#	include 
    +#endif
    +
    +
    +extern void
    +tuklib_open_stdxxx(int err_status)
    +{
    +#ifdef TUKLIB_DOSLIKE
    +	// Do nothing, just silence warnings.
    +	(void)err_status;
    +
    +#else
    +	for (int i = 0; i <= 2; ++i) {
    +		// We use fcntl() to check if the file descriptor is open.
    +		if (fcntl(i, F_GETFD) == -1 && errno == EBADF) {
    +			// With stdin, we could use /dev/full so that
    +			// writing to stdin would fail. However, /dev/full
    +			// is Linux specific, and if the program tries to
    +			// write to stdin, there's already a problem anyway.
    +			const int fd = open("/dev/null", O_NOCTTY
    +					| (i == 0 ? O_WRONLY : O_RDONLY));
    +
    +			if (fd != i) {
    +				if (fd != -1)
    +					(void)close(fd);
    +
    +				// Something went wrong. Exit with the
    +				// exit status we were given. Don't try
    +				// to print an error message, since stderr
    +				// may very well be non-existent. This
    +				// error should be extremely rare.
    +				exit(err_status);
    +			}
    +		}
    +	}
    +#endif
    +
    +	return;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.h
    new file mode 100644
    index 00000000000..3ee3ade3552
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.h
    @@ -0,0 +1,22 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_open_stdxxx.h
    +/// \brief      Make sure that file descriptors 0, 1, and 2 are open
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef TUKLIB_OPEN_STDXXX_H
    +#define TUKLIB_OPEN_STDXXX_H
    +
    +#include "tuklib_common.h"
    +TUKLIB_DECLS_BEGIN
    +
    +#define tuklib_open_stdxx TUKLIB_SYMBOL(tuklib_open_stdxxx)
    +extern void tuklib_open_stdxxx(int err_status);
    +
    +TUKLIB_DECLS_END
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.c
    new file mode 100644
    index 00000000000..1009df14d9d
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.c
    @@ -0,0 +1,231 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_physmem.c
    +/// \brief      Get the amount of physical memory
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "tuklib_physmem.h"
    +
    +// We want to use Windows-specific code on Cygwin, which also has memory
    +// information available via sysconf(), but on Cygwin 1.5 and older it
    +// gives wrong results (from our point of view).
    +#if defined(_WIN32) || defined(__CYGWIN__)
    +#	ifndef _WIN32_WINNT
    +#		define _WIN32_WINNT 0x0500
    +#	endif
    +#	include 
    +
    +#elif defined(__OS2__)
    +#	define INCL_DOSMISC
    +#	include 
    +
    +#elif defined(__DJGPP__)
    +#	include 
    +
    +#elif defined(__VMS)
    +#	include 
    +#	include 
    +#	include 
    +
    +#elif defined(AMIGA) || defined(__AROS__)
    +#	define __USE_INLINE__
    +#	include 
    +
    +#elif defined(__QNX__)
    +#	include 
    +#	include 
    +
    +#elif defined(TUKLIB_PHYSMEM_AIX)
    +#	include 
    +
    +#elif defined(TUKLIB_PHYSMEM_SYSCONF)
    +#	include 
    +
    +#elif defined(TUKLIB_PHYSMEM_SYSCTL)
    +#	ifdef HAVE_SYS_PARAM_H
    +#		include 
    +#	endif
    +#	include 
    +
    +// Tru64
    +#elif defined(TUKLIB_PHYSMEM_GETSYSINFO)
    +#	include 
    +#	include 
    +
    +// HP-UX
    +#elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC)
    +#	include 
    +#	include 
    +
    +// IRIX
    +#elif defined(TUKLIB_PHYSMEM_GETINVENT_R)
    +#	include 
    +
    +// This sysinfo() is Linux-specific.
    +#elif defined(TUKLIB_PHYSMEM_SYSINFO)
    +#	include 
    +#endif
    +
    +
    +extern uint64_t
    +tuklib_physmem(void)
    +{
    +	uint64_t ret = 0;
    +
    +#if defined(_WIN32) || defined(__CYGWIN__)
    +	// This requires Windows 2000 or later.
    +	MEMORYSTATUSEX meminfo;
    +	meminfo.dwLength = sizeof(meminfo);
    +	if (GlobalMemoryStatusEx(&meminfo))
    +		ret = meminfo.ullTotalPhys;
    +
    +/*
    +	// Old version that is compatible with even Win95:
    +	if ((GetVersion() & 0xFF) >= 5) {
    +		// Windows 2000 and later have GlobalMemoryStatusEx() which
    +		// supports reporting values greater than 4 GiB. To keep the
    +		// code working also on older Windows versions, use
    +		// GlobalMemoryStatusEx() conditionally.
    +		HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
    +		if (kernel32 != NULL) {
    +			typedef BOOL (WINAPI *gmse_type)(LPMEMORYSTATUSEX);
    +#ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE
    +#	pragma GCC diagnostic push
    +#	pragma GCC diagnostic ignored "-Wcast-function-type"
    +#endif
    +			gmse_type gmse = (gmse_type)GetProcAddress(
    +					kernel32, "GlobalMemoryStatusEx");
    +#ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE
    +#	pragma GCC diagnostic pop
    +#endif
    +			if (gmse != NULL) {
    +				MEMORYSTATUSEX meminfo;
    +				meminfo.dwLength = sizeof(meminfo);
    +				if (gmse(&meminfo))
    +					ret = meminfo.ullTotalPhys;
    +			}
    +		}
    +	}
    +
    +	if (ret == 0) {
    +		// GlobalMemoryStatus() is supported by Windows 95 and later,
    +		// so it is fine to link against it unconditionally. Note that
    +		// GlobalMemoryStatus() has no return value.
    +		MEMORYSTATUS meminfo;
    +		meminfo.dwLength = sizeof(meminfo);
    +		GlobalMemoryStatus(&meminfo);
    +		ret = meminfo.dwTotalPhys;
    +	}
    +*/
    +
    +#elif defined(__OS2__)
    +	unsigned long mem;
    +	if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM,
    +			&mem, sizeof(mem)) == 0)
    +		ret = mem;
    +
    +#elif defined(__DJGPP__)
    +	__dpmi_free_mem_info meminfo;
    +	if (__dpmi_get_free_memory_information(&meminfo) == 0
    +			&& meminfo.total_number_of_physical_pages
    +				!= (unsigned long)-1)
    +		ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096;
    +
    +#elif defined(__VMS)
    +	int vms_mem;
    +	int val = SYI$_MEMSIZE;
    +	if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL)
    +		ret = (uint64_t)vms_mem * 8192;
    +
    +#elif defined(AMIGA) || defined(__AROS__)
    +	ret = AvailMem(MEMF_TOTAL);
    +
    +#elif defined(__QNX__)
    +	const struct asinfo_entry *entries = SYSPAGE_ENTRY(asinfo);
    +	size_t count = SYSPAGE_ENTRY_SIZE(asinfo) / sizeof(struct asinfo_entry);
    +	const char *strings = SYSPAGE_ENTRY(strings)->data;
    +
    +	for (size_t i = 0; i < count; ++i)
    +		if (strcmp(strings + entries[i].name, "ram") == 0)
    +			ret += entries[i].end - entries[i].start + 1;
    +
    +#elif defined(TUKLIB_PHYSMEM_AIX)
    +	ret = _system_configuration.physmem;
    +
    +#elif defined(TUKLIB_PHYSMEM_SYSCONF)
    +	const long pagesize = sysconf(_SC_PAGESIZE);
    +	const long pages = sysconf(_SC_PHYS_PAGES);
    +	if (pagesize != -1 && pages != -1)
    +		// According to docs, pagesize * pages can overflow.
    +		// Simple case is 32-bit box with 4 GiB or more RAM,
    +		// which may report exactly 4 GiB of RAM, and "long"
    +		// being 32-bit will overflow. Casting to uint64_t
    +		// hopefully avoids overflows in the near future.
    +		ret = (uint64_t)pagesize * (uint64_t)pages;
    +
    +#elif defined(TUKLIB_PHYSMEM_SYSCTL)
    +	int name[2] = {
    +		CTL_HW,
    +#ifdef HW_PHYSMEM64
    +		HW_PHYSMEM64
    +#else
    +		HW_PHYSMEM
    +#endif
    +	};
    +	union {
    +		uint32_t u32;
    +		uint64_t u64;
    +	} mem;
    +	size_t mem_ptr_size = sizeof(mem.u64);
    +	if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) {
    +		// IIRC, 64-bit "return value" is possible on some 64-bit
    +		// BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64),
    +		// so support both.
    +		if (mem_ptr_size == sizeof(mem.u64))
    +			ret = mem.u64;
    +		else if (mem_ptr_size == sizeof(mem.u32))
    +			ret = mem.u32;
    +	}
    +
    +#elif defined(TUKLIB_PHYSMEM_GETSYSINFO)
    +	// Docs are unclear if "start" is needed, but it doesn't hurt
    +	// much to have it.
    +	int memkb;
    +	int start = 0;
    +	if (getsysinfo(GSI_PHYSMEM, (caddr_t)&memkb, sizeof(memkb), &start)
    +			!= -1)
    +		ret = (uint64_t)memkb * 1024;
    +
    +#elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC)
    +	struct pst_static pst;
    +	if (pstat_getstatic(&pst, sizeof(pst), 1, 0) != -1)
    +		ret = (uint64_t)pst.physical_memory * (uint64_t)pst.page_size;
    +
    +#elif defined(TUKLIB_PHYSMEM_GETINVENT_R)
    +	inv_state_t *st = NULL;
    +	if (setinvent_r(&st) != -1) {
    +		inventory_t *i;
    +		while ((i = getinvent_r(st)) != NULL) {
    +			if (i->inv_class == INV_MEMORY
    +					&& i->inv_type == INV_MAIN_MB) {
    +				ret = (uint64_t)i->inv_state << 20;
    +				break;
    +			}
    +		}
    +
    +		endinvent_r(st);
    +	}
    +
    +#elif defined(TUKLIB_PHYSMEM_SYSINFO)
    +	struct sysinfo si;
    +	if (sysinfo(&si) == 0)
    +		ret = (uint64_t)si.totalram * si.mem_unit;
    +#endif
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.h
    new file mode 100644
    index 00000000000..f35bfbab9c1
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.h
    @@ -0,0 +1,27 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_physmem.h
    +/// \brief      Get the amount of physical memory
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef TUKLIB_PHYSMEM_H
    +#define TUKLIB_PHYSMEM_H
    +
    +#include "tuklib_common.h"
    +TUKLIB_DECLS_BEGIN
    +
    +#define tuklib_physmem TUKLIB_SYMBOL(tuklib_physmem)
    +extern uint64_t tuklib_physmem(void);
    +///<
    +/// \brief      Get the amount of physical memory in bytes
    +///
    +/// \return     Amount of physical memory in bytes. On error, zero is
    +///             returned.
    +
    +TUKLIB_DECLS_END
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.c
    new file mode 100644
    index 00000000000..959c1270ce3
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.c
    @@ -0,0 +1,49 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_progname.c
    +/// \brief      Program name to be displayed in messages
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "tuklib_progname.h"
    +#include 
    +
    +
    +#ifndef HAVE_PROGRAM_INVOCATION_NAME
    +char *progname = NULL;
    +#endif
    +
    +
    +extern void
    +tuklib_progname_init(char **argv)
    +{
    +#ifdef TUKLIB_DOSLIKE
    +	// On these systems, argv[0] always has the full path and .exe
    +	// suffix even if the user just types the plain program name.
    +	// We modify argv[0] to make it nicer to read.
    +
    +	// Strip the leading path.
    +	char *p = argv[0] + strlen(argv[0]);
    +	while (argv[0] < p && p[-1] != '/' && p[-1] != '\\')
    +		--p;
    +
    +	argv[0] = p;
    +
    +	// Strip the .exe suffix.
    +	p = strrchr(p, '.');
    +	if (p != NULL)
    +		*p = '\0';
    +
    +	// Make it lowercase.
    +	for (p = argv[0]; *p != '\0'; ++p)
    +		if (*p >= 'A' && *p <= 'Z')
    +			*p = *p - 'A' + 'a';
    +#endif
    +
    +	progname = argv[0];
    +	return;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.h
    new file mode 100644
    index 00000000000..a3d90cb1f21
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.h
    @@ -0,0 +1,31 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       tuklib_progname.h
    +/// \brief      Program name to be displayed in messages
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef TUKLIB_PROGNAME_H
    +#define TUKLIB_PROGNAME_H
    +
    +#include "tuklib_common.h"
    +#include 
    +
    +TUKLIB_DECLS_BEGIN
    +
    +#ifdef HAVE_PROGRAM_INVOCATION_NAME
    +#	define progname program_invocation_name
    +#else
    +#	define progname TUKLIB_SYMBOL(tuklib_progname)
    +	extern char *progname;
    +#endif
    +
    +#define tuklib_progname_init TUKLIB_SYMBOL(tuklib_progname_init)
    +extern void tuklib_progname_init(char **argv);
    +
    +TUKLIB_DECLS_END
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest
    new file mode 100644
    index 00000000000..2f8750879b1
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest
    @@ -0,0 +1,28 @@
    +
    +
    +
    +    
    +        
    +             
    +             
    +             
    +             
    +             
    +        
    +    
    +
    +    
    +        
    +            
    +                
    +            
    +        
    +    
    +
    +    
    +        
    +            true
    +            UTF-8
    +        
    +    
    +
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest.comments.txt b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest.comments.txt
    new file mode 100644
    index 00000000000..ad0835ccb0b
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest.comments.txt
    @@ -0,0 +1,178 @@
    +
    +Windows application manifest for UTF-8 and long paths
    +=====================================================
    +
    +The .manifest file is embedded as is in the executables, thus
    +the comments are here in a separate file. These comments were
    +written in context of XZ Utils but might be useful when porting
    +other command line tools from POSIX environments to Windows.
    +
    +    NOTE: On Cygwin and MSYS2, command line arguments and file
    +    system access aren't tied to a Windows code page. Cygwin
    +    and MSYS2 include a default application manifest. Replacing
    +    it doesn't seem useful and might even be harmful if Cygwin
    +    and MSYS2 some day change their default manifest.
    +
    +
    +UTF-8 code page
    +---------------
    +
    +On Windows, command line applications can use main() or wmain().
    +With the Windows-specific wmain(), argv contains UTF-16 code units
    +which is the native encoding on Windows. With main(), argv uses the
    +system active code page by default. It typically is a legacy code
    +page like Windows-1252.
    +
    +    NOTE: On POSIX, argv for main() is constructed by the calling
    +    process. On Windows, argv is constructed by a new process
    +    itself: a program receives the command line as a single string,
    +    and the startup code splits it into individual arguments,
    +    including quote removal and wildcard expansion. Then main() or
    +    wmain() is called.
    +
    +This application manifest forces the process code page to UTF-8
    +when the application runs on Windows 10 version 1903 or later.
    +This is useful for programs that use main():
    +
    +  * UTF-8 allows such programs to access files whose names contain
    +    characters that don't exist in the current legacy code page.
    +    However, filenames on Windows may contain unpaired surrogates
    +    (invalid UTF-16). Such files cannot be accesses even with the
    +    UTF-8 code page.
    +
    +  * UTF-8 avoids a security issue in command line argument handling:
    +    If a command line contains Unicode characters (for example,
    +    filenames) that don't exist in the current legacy code page,
    +    the characters are converted to similar-looking characters
    +    with best-fit mapping. Some best-fit mappings result in ASCII
    +    characters that change the meaning of the command line, which
    +    can be exploited with malicious filenames. For example:
    +
    +      - Double quote (") breaks quoting and makes argument
    +        injection possible.
    +
    +      - Question mark (?) is a wildcard character which may
    +        expand to one or more filenames.
    +
    +      - Forward slash (/) makes a directory traversal attack
    +        possible. This character can appear in a dangerous way
    +        even from a wildcard expansion; a look-alike character
    +        doesn't need to be passed directly on the command line.
    +
    +    UTF-8 avoids best-fit mappings. However, it's still not
    +    perfect. Unpaired surrogates (invalid UTF-16) on the command
    +    line (including those from wildcard expansion) are converted
    +    to the replacement character U+FFFD. Thus, filenames with
    +    different unpaired surrogates appear identical when converted
    +    to the UTF-8 code page and aren't distinguishable from
    +    filenames that contain the actual replacement character U+FFFD.
    +
    +If different programs use different code pages, compatibility issues
    +are possible. For example, if one program produces a list of
    +filenames and another program reads it, both programs should use
    +the same code page because the code page affects filenames in the
    +char-based file system APIs.
    +
    +If building with a MinGW-w64 toolchain, it is strongly recommended
    +to use UCRT instead of the old MSVCRT. For example, with the UTF-8
    +code page, MSVCRT doesn't convert non-ASCII characters correctly
    +when writing to console with printf(). With UCRT it works.
    +
    +
    +Long path names
    +---------------
    +
    +The manifest enables support for path names longer than 259
    +characters if the feature has been enabled in the Windows registry.
    +Omit the longPathAware element from the manifest if the application
    +isn't compatible with it. For example, uses of MAX_PATH might be
    +a sign of incompatibility.
    +
    +Documentation of the registry setting:
    +https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry#enable-long-paths-in-windows-10-version-1607-and-later
    +
    +
    +Summary of the manifest contents
    +--------------------------------
    +
    +See also Microsoft's documentation:
    +https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests
    +
    +assemblyIdentity (omitted)
    +
    +    This is documented as mandatory but not all apps in the real world
    +    have it, and of those that do, not all put an up-to-date version
    +    number there. Things seem to work correctly without
    +     so let's keep this simpler and omit it.
    +
    +compatibility
    +
    +    Declare the application compatible with different Windows versions.
    +    Without this, Windows versions newer than Vista will run the
    +    application using Vista as the Operating System Context.
    +
    +trustInfo
    +
    +    Declare the application as UAC-compliant. This avoids file system
    +    and registry virtualization that Windows otherwise does with 32-bit
    +    executables to make some ancient applications work. UAC-compliancy
    +    also stops Windows from using heuristics based on the filename
    +    (like setup.exe) to guess when elevated privileges might be
    +    needed which would then bring up the UAC prompt.
    +
    +longPathAware
    +
    +    Declare the application as long path aware. This way many file
    +    system operations aren't limited by MAX_PATH (260 characters
    +    including the terminating null character) if the feature has
    +    also been enabled in the Windows registry.
    +
    +activeCodePage
    +
    +    Force the process code page to UTF-8 on Windows 10 version 1903
    +    and later. For example:
    +
    +      - main() gets the command line arguments in UTF-8 instead of
    +        in a legacy code page.
    +
    +      - File system APIs that take char-based strings use UTF-8
    +        instead of a legacy code page.
    +
    +      - Text written to the console via stdio.h's stdout or stderr
    +        (like calling printf()) are expected to be in UTF-8.
    +
    +
    +CMake notes
    +-----------
    +
    +As of CMake 3.30, one can add a .manifest file as a source file but
    +it only works with MSVC; it's ignored with MinGW-w64 toolchains.
    +Embedding the manifest with a resource file works with all
    +toolchains. However, then the default manifest needs to be
    +disabled with MSVC in CMakeLists.txt to avoid duplicate
    +manifests which would break the build.
    +
    +w32_application.manifest.rc:
    +
    +    #include 
    +    CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "w32_application.manifest"
    +
    +Or the same thing without the #include:
    +
    +    1 24 "w32_application.manifest"
    +
    +CMakeLists.txt:
    +
    +    if(MSVC)
    +        set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
    +    endif()
    +
    +    add_executable(foo foo.c)
    +
    +    # WIN32 isn't set on Cygwin or MSYS2, thus if(WIN32) is correct here.
    +    if(WIN32)
    +        target_sources(foo PRIVATE w32_application.manifest.rc)
    +        set_source_files_properties(w32_application.manifest.rc PROPERTIES
    +            OBJECT_DEPENDS w32_application.manifest
    +        )
    +    endif()
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma.h
    new file mode 100644
    index 00000000000..6ca6e503d8a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma.h
    @@ -0,0 +1,327 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        api/lzma.h
    + * \brief       The public API of liblzma data compression library
    + * \mainpage
    + *
    + * liblzma is a general-purpose data compression library with a zlib-like API.
    + * The native file format is .xz, but also the old .lzma format and raw (no
    + * headers) streams are supported. Multiple compression algorithms (filters)
    + * are supported. Currently LZMA2 is the primary filter.
    + *
    + * liblzma is part of XZ Utils . XZ Utils
    + * includes a gzip-like command line tool named xz and some other tools.
    + * XZ Utils is developed and maintained by Lasse Collin.
    + *
    + * Major parts of liblzma are based on code written by Igor Pavlov,
    + * specifically the LZMA SDK .
    + *
    + * The SHA-256 implementation in liblzma is based on code written by
    + * Wei Dai in Crypto++ Library .
    + *
    + * liblzma is distributed under the BSD Zero Clause License (0BSD).
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H
    +#define LZMA_H
    +
    +/*****************************
    + * Required standard headers *
    + *****************************/
    +
    +/*
    + * liblzma API headers need some standard types and macros. To allow
    + * including lzma.h without requiring the application to include other
    + * headers first, lzma.h includes the required standard headers unless
    + * they already seem to be included already or if LZMA_MANUAL_HEADERS
    + * has been defined.
    + *
    + * Here's what types and macros are needed and from which headers:
    + *  - stddef.h: size_t, NULL
    + *  - stdint.h: uint8_t, uint32_t, uint64_t, UINT32_C(n), uint64_C(n),
    + *    UINT32_MAX, UINT64_MAX
    + *
    + * However, inttypes.h is a little more portable than stdint.h, although
    + * inttypes.h declares some unneeded things compared to plain stdint.h.
    + *
    + * The hacks below aren't perfect, specifically they assume that inttypes.h
    + * exists and that it typedefs at least uint8_t, uint32_t, and uint64_t,
    + * and that, in case of incomplete inttypes.h, unsigned int is 32-bit.
    + * If the application already takes care of setting up all the types and
    + * macros properly (for example by using gnulib's stdint.h or inttypes.h),
    + * we try to detect that the macros are already defined and don't include
    + * inttypes.h here again. However, you may define LZMA_MANUAL_HEADERS to
    + * force this file to never include any system headers.
    + *
    + * Some could argue that liblzma API should provide all the required types,
    + * for example lzma_uint64, LZMA_UINT64_C(n), and LZMA_UINT64_MAX. This was
    + * seen as an unnecessary mess, since most systems already provide all the
    + * necessary types and macros in the standard headers.
    + *
    + * Note that liblzma API still has lzma_bool, because using stdbool.h would
    + * break C89 and C++ programs on many systems. sizeof(bool) in C99 isn't
    + * necessarily the same as sizeof(bool) in C++.
    + */
    +
    +#ifndef LZMA_MANUAL_HEADERS
    +	/*
    +	 * I suppose this works portably also in C++. Note that in C++,
    +	 * we need to get size_t into the global namespace.
    +	 */
    +#	include 
    +
    +	/*
    +	 * Skip inttypes.h if we already have all the required macros. If we
    +	 * have the macros, we assume that we have the matching typedefs too.
    +	 */
    +#	if !defined(UINT32_C) || !defined(UINT64_C) \
    +			|| !defined(UINT32_MAX) || !defined(UINT64_MAX)
    +		/*
    +		 * MSVC versions older than 2013 have no C99 support, and
    +		 * thus they cannot be used to compile liblzma. Using an
    +		 * existing liblzma.dll with old MSVC can work though(*),
    +		 * but we need to define the required standard integer
    +		 * types here in a MSVC-specific way.
    +		 *
    +		 * (*) If you do this, the existing liblzma.dll probably uses
    +		 *     a different runtime library than your MSVC-built
    +		 *     application. Mixing runtimes is generally bad, but
    +		 *     in this case it should work as long as you avoid
    +		 *     the few rarely-needed liblzma functions that allocate
    +		 *     memory and expect the caller to free it using free().
    +		 */
    +#		if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1800
    +			typedef unsigned __int8 uint8_t;
    +			typedef unsigned __int32 uint32_t;
    +			typedef unsigned __int64 uint64_t;
    +#		else
    +			/* Use the standard inttypes.h. */
    +#			ifdef __cplusplus
    +				/*
    +				 * C99 sections 7.18.2 and 7.18.4 specify
    +				 * that C++ implementations define the limit
    +				 * and constant macros only if specifically
    +				 * requested. Note that if you want the
    +				 * format macros (PRIu64 etc.) too, you need
    +				 * to define __STDC_FORMAT_MACROS before
    +				 * including lzma.h, since re-including
    +				 * inttypes.h with __STDC_FORMAT_MACROS
    +				 * defined doesn't necessarily work.
    +				 */
    +#				ifndef __STDC_LIMIT_MACROS
    +#					define __STDC_LIMIT_MACROS 1
    +#				endif
    +#				ifndef __STDC_CONSTANT_MACROS
    +#					define __STDC_CONSTANT_MACROS 1
    +#				endif
    +#			endif
    +
    +#			include 
    +#		endif
    +
    +		/*
    +		 * Some old systems have only the typedefs in inttypes.h, and
    +		 * lack all the macros. For those systems, we need a few more
    +		 * hacks. We assume that unsigned int is 32-bit and unsigned
    +		 * long is either 32-bit or 64-bit. If these hacks aren't
    +		 * enough, the application has to setup the types manually
    +		 * before including lzma.h.
    +		 */
    +#		ifndef UINT32_C
    +#			if defined(_WIN32) && defined(_MSC_VER)
    +#				define UINT32_C(n) n ## UI32
    +#			else
    +#				define UINT32_C(n) n ## U
    +#			endif
    +#		endif
    +
    +#		ifndef UINT64_C
    +#			if defined(_WIN32) && defined(_MSC_VER)
    +#				define UINT64_C(n) n ## UI64
    +#			else
    +				/* Get ULONG_MAX. */
    +#				include 
    +#				if ULONG_MAX == 4294967295UL
    +#					define UINT64_C(n) n ## ULL
    +#				else
    +#					define UINT64_C(n) n ## UL
    +#				endif
    +#			endif
    +#		endif
    +
    +#		ifndef UINT32_MAX
    +#			define UINT32_MAX (UINT32_C(4294967295))
    +#		endif
    +
    +#		ifndef UINT64_MAX
    +#			define UINT64_MAX (UINT64_C(18446744073709551615))
    +#		endif
    +#	endif
    +#endif /* ifdef LZMA_MANUAL_HEADERS */
    +
    +
    +/******************
    + * LZMA_API macro *
    + ******************/
    +
    +/*
    + * Some systems require that the functions and function pointers are
    + * declared specially in the headers. LZMA_API_IMPORT is for importing
    + * symbols and LZMA_API_CALL is to specify the calling convention.
    + *
    + * By default it is assumed that the application will link dynamically
    + * against liblzma. #define LZMA_API_STATIC in your application if you
    + * want to link against static liblzma. If you don't care about portability
    + * to operating systems like Windows, or at least don't care about linking
    + * against static liblzma on them, don't worry about LZMA_API_STATIC. That
    + * is, most developers will never need to use LZMA_API_STATIC.
    + *
    + * The GCC variants are a special case on Windows (Cygwin and MinGW-w64).
    + * We rely on GCC doing the right thing with its auto-import feature,
    + * and thus don't use __declspec(dllimport). This way developers don't
    + * need to worry about LZMA_API_STATIC. Also the calling convention is
    + * omitted on Cygwin but not on MinGW-w64.
    + */
    +#ifndef LZMA_API_IMPORT
    +#	if !defined(LZMA_API_STATIC) && defined(_WIN32) && !defined(__GNUC__)
    +#		define LZMA_API_IMPORT __declspec(dllimport)
    +#	else
    +#		define LZMA_API_IMPORT
    +#	endif
    +#endif
    +
    +#ifndef LZMA_API_CALL
    +#	if defined(_WIN32) && !defined(__CYGWIN__)
    +#		define LZMA_API_CALL __cdecl
    +#	else
    +#		define LZMA_API_CALL
    +#	endif
    +#endif
    +
    +#ifndef LZMA_API
    +#	define LZMA_API(type) LZMA_API_IMPORT type LZMA_API_CALL
    +#endif
    +
    +
    +/***********
    + * nothrow *
    + ***********/
    +
    +/*
    + * None of the functions in liblzma may throw an exception. Even
    + * the functions that use callback functions won't throw exceptions,
    + * because liblzma would break if a callback function threw an exception.
    + */
    +#ifndef lzma_nothrow
    +#	if defined(__cplusplus)
    +#		if __cplusplus >= 201103L || (defined(_MSVC_LANG) \
    +				&& _MSVC_LANG >= 201103L)
    +#			define lzma_nothrow noexcept
    +#		else
    +#			define lzma_nothrow throw()
    +#		endif
    +#	elif defined(__GNUC__) && (__GNUC__ > 3 \
    +			|| (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
    +#		define lzma_nothrow __attribute__((__nothrow__))
    +#	else
    +#		define lzma_nothrow
    +#	endif
    +#endif
    +
    +
    +/********************
    + * GNU C extensions *
    + ********************/
    +
    +/*
    + * GNU C extensions are used conditionally in the public API. It doesn't
    + * break anything if these are sometimes enabled and sometimes not, only
    + * affects warnings and optimizations.
    + */
    +#if defined(__GNUC__) && __GNUC__ >= 3
    +#	ifndef lzma_attribute
    +#		define lzma_attribute(attr) __attribute__(attr)
    +#	endif
    +
    +	/* warn_unused_result was added in GCC 3.4. */
    +#	ifndef lzma_attr_warn_unused_result
    +#		if __GNUC__ == 3 && __GNUC_MINOR__ < 4
    +#			define lzma_attr_warn_unused_result
    +#		endif
    +#	endif
    +
    +#else
    +#	ifndef lzma_attribute
    +#		define lzma_attribute(attr)
    +#	endif
    +#endif
    +
    +
    +#ifndef lzma_attr_pure
    +#	define lzma_attr_pure lzma_attribute((__pure__))
    +#endif
    +
    +#ifndef lzma_attr_const
    +#	define lzma_attr_const lzma_attribute((__const__))
    +#endif
    +
    +#ifndef lzma_attr_warn_unused_result
    +#	define lzma_attr_warn_unused_result \
    +		lzma_attribute((__warn_unused_result__))
    +#endif
    +
    +
    +/**************
    + * Subheaders *
    + **************/
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +/*
    + * Subheaders check that this is defined. It is to prevent including
    + * them directly from applications.
    + */
    +#define LZMA_H_INTERNAL 1
    +
    +/* Basic features */
    +#include "lzma/version.h"
    +#include "lzma/base.h"
    +#include "lzma/vli.h"
    +#include "lzma/check.h"
    +
    +/* Filters */
    +#include "lzma/filter.h"
    +#include "lzma/bcj.h"
    +#include "lzma/delta.h"
    +#include "lzma/lzma12.h"
    +
    +/* Container formats */
    +#include "lzma/container.h"
    +
    +/* Advanced features */
    +#include "lzma/stream_flags.h"
    +#include "lzma/block.h"
    +#include "lzma/index.h"
    +#include "lzma/index_hash.h"
    +
    +/* Hardware information */
    +#include "lzma/hardware.h"
    +
    +/*
    + * All subheaders included. Undefine LZMA_H_INTERNAL to prevent applications
    + * re-including the subheaders.
    + */
    +#undef LZMA_H_INTERNAL
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif /* ifndef LZMA_H */
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/base.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/base.h
    new file mode 100644
    index 00000000000..590e1d22bb0
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/base.h
    @@ -0,0 +1,747 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/base.h
    + * \brief       Data types and functions used in many places in liblzma API
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       Boolean
    + *
    + * This is here because C89 doesn't have stdbool.h. To set a value for
    + * variables having type lzma_bool, you can use
    + *   - C99's 'true' and 'false' from stdbool.h;
    + *   - C++'s internal 'true' and 'false'; or
    + *   - integers one (true) and zero (false).
    + */
    +typedef unsigned char lzma_bool;
    +
    +
    +/**
    + * \brief       Type of reserved enumeration variable in structures
    + *
    + * To avoid breaking library ABI when new features are added, several
    + * structures contain extra variables that may be used in future. Since
    + * sizeof(enum) can be different than sizeof(int), and sizeof(enum) may
    + * even vary depending on the range of enumeration constants, we specify
    + * a separate type to be used for reserved enumeration variables. All
    + * enumeration constants in liblzma API will be non-negative and less
    + * than 128, which should guarantee that the ABI won't break even when
    + * new constants are added to existing enumerations.
    + */
    +typedef enum {
    +	LZMA_RESERVED_ENUM      = 0
    +} lzma_reserved_enum;
    +
    +
    +/**
    + * \brief       Return values used by several functions in liblzma
    + *
    + * Check the descriptions of specific functions to find out which return
    + * values they can return. With some functions the return values may have
    + * more specific meanings than described here; those differences are
    + * described per-function basis.
    + */
    +typedef enum {
    +	LZMA_OK                 = 0,
    +		/**<
    +		 * \brief       Operation completed successfully
    +		 */
    +
    +	LZMA_STREAM_END         = 1,
    +		/**<
    +		 * \brief       End of stream was reached
    +		 *
    +		 * In encoder, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, or
    +		 * LZMA_FINISH was finished. In decoder, this indicates
    +		 * that all the data was successfully decoded.
    +		 *
    +		 * In all cases, when LZMA_STREAM_END is returned, the last
    +		 * output bytes should be picked from strm->next_out.
    +		 */
    +
    +	LZMA_NO_CHECK           = 2,
    +		/**<
    +		 * \brief       Input stream has no integrity check
    +		 *
    +		 * This return value can be returned only if the
    +		 * LZMA_TELL_NO_CHECK flag was used when initializing
    +		 * the decoder. LZMA_NO_CHECK is just a warning, and
    +		 * the decoding can be continued normally.
    +		 *
    +		 * It is possible to call lzma_get_check() immediately after
    +		 * lzma_code has returned LZMA_NO_CHECK. The result will
    +		 * naturally be LZMA_CHECK_NONE, but the possibility to call
    +		 * lzma_get_check() may be convenient in some applications.
    +		 */
    +
    +	LZMA_UNSUPPORTED_CHECK  = 3,
    +		/**<
    +		 * \brief       Cannot calculate the integrity check
    +		 *
    +		 * The usage of this return value is different in encoders
    +		 * and decoders.
    +		 *
    +		 * Encoders can return this value only from the initialization
    +		 * function. If initialization fails with this value, the
    +		 * encoding cannot be done, because there's no way to produce
    +		 * output with the correct integrity check.
    +		 *
    +		 * Decoders can return this value only from lzma_code() and
    +		 * only if the LZMA_TELL_UNSUPPORTED_CHECK flag was used when
    +		 * initializing the decoder. The decoding can still be
    +		 * continued normally even if the check type is unsupported,
    +		 * but naturally the check will not be validated, and possible
    +		 * errors may go undetected.
    +		 *
    +		 * With decoder, it is possible to call lzma_get_check()
    +		 * immediately after lzma_code() has returned
    +		 * LZMA_UNSUPPORTED_CHECK. This way it is possible to find
    +		 * out what the unsupported Check ID was.
    +		 */
    +
    +	LZMA_GET_CHECK          = 4,
    +		/**<
    +		 * \brief       Integrity check type is now available
    +		 *
    +		 * This value can be returned only by the lzma_code() function
    +		 * and only if the decoder was initialized with the
    +		 * LZMA_TELL_ANY_CHECK flag. LZMA_GET_CHECK tells the
    +		 * application that it may now call lzma_get_check() to find
    +		 * out the Check ID. This can be used, for example, to
    +		 * implement a decoder that accepts only files that have
    +		 * strong enough integrity check.
    +		 */
    +
    +	LZMA_MEM_ERROR          = 5,
    +		/**<
    +		 * \brief       Cannot allocate memory
    +		 *
    +		 * Memory allocation failed, or the size of the allocation
    +		 * would be greater than SIZE_MAX.
    +		 *
    +		 * Due to internal implementation reasons, the coding cannot
    +		 * be continued even if more memory were made available after
    +		 * LZMA_MEM_ERROR.
    +		 */
    +
    +	LZMA_MEMLIMIT_ERROR     = 6,
    +		/**<
    +		 * \brief       Memory usage limit was reached
    +		 *
    +		 * Decoder would need more memory than allowed by the
    +		 * specified memory usage limit. To continue decoding,
    +		 * the memory usage limit has to be increased with
    +		 * lzma_memlimit_set().
    +		 *
    +		 * liblzma 5.2.6 and earlier had a bug in single-threaded .xz
    +		 * decoder (lzma_stream_decoder()) which made it impossible
    +		 * to continue decoding after LZMA_MEMLIMIT_ERROR even if
    +		 * the limit was increased using lzma_memlimit_set().
    +		 * Other decoders worked correctly.
    +		 */
    +
    +	LZMA_FORMAT_ERROR       = 7,
    +		/**<
    +		 * \brief       File format not recognized
    +		 *
    +		 * The decoder did not recognize the input as supported file
    +		 * format. This error can occur, for example, when trying to
    +		 * decode .lzma format file with lzma_stream_decoder,
    +		 * because lzma_stream_decoder accepts only the .xz format.
    +		 */
    +
    +	LZMA_OPTIONS_ERROR      = 8,
    +		/**<
    +		 * \brief       Invalid or unsupported options
    +		 *
    +		 * Invalid or unsupported options, for example
    +		 *  - unsupported filter(s) or filter options; or
    +		 *  - reserved bits set in headers (decoder only).
    +		 *
    +		 * Rebuilding liblzma with more features enabled, or
    +		 * upgrading to a newer version of liblzma may help.
    +		 */
    +
    +	LZMA_DATA_ERROR         = 9,
    +		/**<
    +		 * \brief       Data is corrupt
    +		 *
    +		 * The usage of this return value is different in encoders
    +		 * and decoders. In both encoder and decoder, the coding
    +		 * cannot continue after this error.
    +		 *
    +		 * Encoders return this if size limits of the target file
    +		 * format would be exceeded. These limits are huge, thus
    +		 * getting this error from an encoder is mostly theoretical.
    +		 * For example, the maximum compressed and uncompressed
    +		 * size of a .xz Stream is roughly 8 EiB (2^63 bytes).
    +		 *
    +		 * Decoders return this error if the input data is corrupt.
    +		 * This can mean, for example, invalid CRC32 in headers
    +		 * or invalid check of uncompressed data.
    +		 */
    +
    +	LZMA_BUF_ERROR          = 10,
    +		/**<
    +		 * \brief       No progress is possible
    +		 *
    +		 * This error code is returned when the coder cannot consume
    +		 * any new input and produce any new output. The most common
    +		 * reason for this error is that the input stream being
    +		 * decoded is truncated or corrupt.
    +		 *
    +		 * This error is not fatal. Coding can be continued normally
    +		 * by providing more input and/or more output space, if
    +		 * possible.
    +		 *
    +		 * Typically the first call to lzma_code() that can do no
    +		 * progress returns LZMA_OK instead of LZMA_BUF_ERROR. Only
    +		 * the second consecutive call doing no progress will return
    +		 * LZMA_BUF_ERROR. This is intentional.
    +		 *
    +		 * With zlib, Z_BUF_ERROR may be returned even if the
    +		 * application is doing nothing wrong, so apps will need
    +		 * to handle Z_BUF_ERROR specially. The above hack
    +		 * guarantees that liblzma never returns LZMA_BUF_ERROR
    +		 * to properly written applications unless the input file
    +		 * is truncated or corrupt. This should simplify the
    +		 * applications a little.
    +		 */
    +
    +	LZMA_PROG_ERROR         = 11,
    +		/**<
    +		 * \brief       Programming error
    +		 *
    +		 * This indicates that the arguments given to the function are
    +		 * invalid or the internal state of the decoder is corrupt.
    +		 *   - Function arguments are invalid or the structures
    +		 *     pointed by the argument pointers are invalid
    +		 *     e.g. if strm->next_out has been set to NULL and
    +		 *     strm->avail_out > 0 when calling lzma_code().
    +		 *   - lzma_* functions have been called in wrong order
    +		 *     e.g. lzma_code() was called right after lzma_end().
    +		 *   - If errors occur randomly, the reason might be flaky
    +		 *     hardware.
    +		 *
    +		 * If you think that your code is correct, this error code
    +		 * can be a sign of a bug in liblzma. See the documentation
    +		 * how to report bugs.
    +		 */
    +
    +	LZMA_SEEK_NEEDED        = 12,
    +		/**<
    +		 * \brief       Request to change the input file position
    +		 *
    +		 * Some coders can do random access in the input file. The
    +		 * initialization functions of these coders take the file size
    +		 * as an argument. No other coders can return LZMA_SEEK_NEEDED.
    +		 *
    +		 * When this value is returned, the application must seek to
    +		 * the file position given in lzma_stream.seek_pos. This value
    +		 * is guaranteed to never exceed the file size that was
    +		 * specified at the coder initialization.
    +		 *
    +		 * After seeking the application should read new input and
    +		 * pass it normally via lzma_stream.next_in and .avail_in.
    +		 */
    +
    +	/*
    +	 * These enumerations may be used internally by liblzma
    +	 * but they will never be returned to applications.
    +	 */
    +	LZMA_RET_INTERNAL1      = 101,
    +	LZMA_RET_INTERNAL2      = 102,
    +	LZMA_RET_INTERNAL3      = 103,
    +	LZMA_RET_INTERNAL4      = 104,
    +	LZMA_RET_INTERNAL5      = 105,
    +	LZMA_RET_INTERNAL6      = 106,
    +	LZMA_RET_INTERNAL7      = 107,
    +	LZMA_RET_INTERNAL8      = 108
    +} lzma_ret;
    +
    +
    +/**
    + * \brief       The 'action' argument for lzma_code()
    + *
    + * After the first use of LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, LZMA_FULL_BARRIER,
    + * or LZMA_FINISH, the same 'action' must be used until lzma_code() returns
    + * LZMA_STREAM_END. Also, the amount of input (that is, strm->avail_in) must
    + * not be modified by the application until lzma_code() returns
    + * LZMA_STREAM_END. Changing the 'action' or modifying the amount of input
    + * will make lzma_code() return LZMA_PROG_ERROR.
    + */
    +typedef enum {
    +	LZMA_RUN = 0,
    +		/**<
    +		 * \brief       Continue coding
    +		 *
    +		 * Encoder: Encode as much input as possible. Some internal
    +		 * buffering will probably be done (depends on the filter
    +		 * chain in use), which causes latency: the input used won't
    +		 * usually be decodeable from the output of the same
    +		 * lzma_code() call.
    +		 *
    +		 * Decoder: Decode as much input as possible and produce as
    +		 * much output as possible.
    +		 */
    +
    +	LZMA_SYNC_FLUSH = 1,
    +		/**<
    +		 * \brief       Make all the input available at output
    +		 *
    +		 * Normally the encoder introduces some latency.
    +		 * LZMA_SYNC_FLUSH forces all the buffered data to be
    +		 * available at output without resetting the internal
    +		 * state of the encoder. This way it is possible to use
    +		 * compressed stream for example for communication over
    +		 * network.
    +		 *
    +		 * Only some filters support LZMA_SYNC_FLUSH. Trying to use
    +		 * LZMA_SYNC_FLUSH with filters that don't support it will
    +		 * make lzma_code() return LZMA_OPTIONS_ERROR. For example,
    +		 * LZMA1 doesn't support LZMA_SYNC_FLUSH but LZMA2 does.
    +		 *
    +		 * Using LZMA_SYNC_FLUSH very often can dramatically reduce
    +		 * the compression ratio. With some filters (for example,
    +		 * LZMA2), fine-tuning the compression options may help
    +		 * mitigate this problem significantly (for example,
    +		 * match finder with LZMA2).
    +		 *
    +		 * Decoders don't support LZMA_SYNC_FLUSH.
    +		 */
    +
    +	LZMA_FULL_FLUSH = 2,
    +		/**<
    +		 * \brief       Finish encoding of the current Block
    +		 *
    +		 * All the input data going to the current Block must have
    +		 * been given to the encoder (the last bytes can still be
    +		 * pending in *next_in). Call lzma_code() with LZMA_FULL_FLUSH
    +		 * until it returns LZMA_STREAM_END. Then continue normally
    +		 * with LZMA_RUN or finish the Stream with LZMA_FINISH.
    +		 *
    +		 * This action is currently supported only by Stream encoder
    +		 * and easy encoder (which uses Stream encoder). If there is
    +		 * no unfinished Block, no empty Block is created.
    +		 */
    +
    +	LZMA_FULL_BARRIER = 4,
    +		/**<
    +		 * \brief       Finish encoding of the current Block
    +		 *
    +		 * This is like LZMA_FULL_FLUSH except that this doesn't
    +		 * necessarily wait until all the input has been made
    +		 * available via the output buffer. That is, lzma_code()
    +		 * might return LZMA_STREAM_END as soon as all the input
    +		 * has been consumed (avail_in == 0).
    +		 *
    +		 * LZMA_FULL_BARRIER is useful with a threaded encoder if
    +		 * one wants to split the .xz Stream into Blocks at specific
    +		 * offsets but doesn't care if the output isn't flushed
    +		 * immediately. Using LZMA_FULL_BARRIER allows keeping
    +		 * the threads busy while LZMA_FULL_FLUSH would make
    +		 * lzma_code() wait until all the threads have finished
    +		 * until more data could be passed to the encoder.
    +		 *
    +		 * With a lzma_stream initialized with the single-threaded
    +		 * lzma_stream_encoder() or lzma_easy_encoder(),
    +		 * LZMA_FULL_BARRIER is an alias for LZMA_FULL_FLUSH.
    +		 */
    +
    +	LZMA_FINISH = 3
    +		/**<
    +		 * \brief       Finish the coding operation
    +		 *
    +		 * All the input data must have been given to the encoder
    +		 * (the last bytes can still be pending in next_in).
    +		 * Call lzma_code() with LZMA_FINISH until it returns
    +		 * LZMA_STREAM_END. Once LZMA_FINISH has been used,
    +		 * the amount of input must no longer be changed by
    +		 * the application.
    +		 *
    +		 * When decoding, using LZMA_FINISH is optional unless the
    +		 * LZMA_CONCATENATED flag was used when the decoder was
    +		 * initialized. When LZMA_CONCATENATED was not used, the only
    +		 * effect of LZMA_FINISH is that the amount of input must not
    +		 * be changed just like in the encoder.
    +		 */
    +} lzma_action;
    +
    +
    +/**
    + * \brief       Custom functions for memory handling
    + *
    + * A pointer to lzma_allocator may be passed via lzma_stream structure
    + * to liblzma, and some advanced functions take a pointer to lzma_allocator
    + * as a separate function argument. The library will use the functions
    + * specified in lzma_allocator for memory handling instead of the default
    + * malloc() and free(). C++ users should note that the custom memory
    + * handling functions must not throw exceptions.
    + *
    + * Single-threaded mode only: liblzma doesn't make an internal copy of
    + * lzma_allocator. Thus, it is OK to change these function pointers in
    + * the middle of the coding process, but obviously it must be done
    + * carefully to make sure that the replacement 'free' can deallocate
    + * memory allocated by the earlier 'alloc' function(s).
    + *
    + * Multithreaded mode: liblzma might internally store pointers to the
    + * lzma_allocator given via the lzma_stream structure. The application
    + * must not change the allocator pointer in lzma_stream or the contents
    + * of the pointed lzma_allocator structure until lzma_end() has been used
    + * to free the memory associated with that lzma_stream. The allocation
    + * functions might be called simultaneously from multiple threads, and
    + * thus they must be thread safe.
    + */
    +typedef struct {
    +	/**
    +	 * \brief       Pointer to a custom memory allocation function
    +	 *
    +	 * If you don't want a custom allocator, but still want
    +	 * custom free(), set this to NULL and liblzma will use
    +	 * the standard malloc().
    +	 *
    +	 * \param       opaque  lzma_allocator.opaque (see below)
    +	 * \param       nmemb   Number of elements like in calloc(). liblzma
    +	 *                      will always set nmemb to 1, so it is safe to
    +	 *                      ignore nmemb in a custom allocator if you like.
    +	 *                      The nmemb argument exists only for
    +	 *                      compatibility with zlib and libbzip2.
    +	 * \param       size    Size of an element in bytes.
    +	 *                      liblzma never sets this to zero.
    +	 *
    +	 * \return      Pointer to the beginning of a memory block of
    +	 *              'size' bytes, or NULL if allocation fails
    +	 *              for some reason. When allocation fails, functions
    +	 *              of liblzma return LZMA_MEM_ERROR.
    +	 *
    +	 * The allocator should not waste time zeroing the allocated buffers.
    +	 * This is not only about speed, but also memory usage, since the
    +	 * operating system kernel doesn't necessarily allocate the requested
    +	 * memory in physical memory until it is actually used. With small
    +	 * input files, liblzma may actually need only a fraction of the
    +	 * memory that it requested for allocation.
    +	 *
    +	 * \note        LZMA_MEM_ERROR is also used when the size of the
    +	 *              allocation would be greater than SIZE_MAX. Thus,
    +	 *              don't assume that the custom allocator must have
    +	 *              returned NULL if some function from liblzma
    +	 *              returns LZMA_MEM_ERROR.
    +	 */
    +	void *(LZMA_API_CALL *alloc)(void *opaque, size_t nmemb, size_t size);
    +
    +	/**
    +	 * \brief       Pointer to a custom memory freeing function
    +	 *
    +	 * If you don't want a custom freeing function, but still
    +	 * want a custom allocator, set this to NULL and liblzma
    +	 * will use the standard free().
    +	 *
    +	 * \param       opaque  lzma_allocator.opaque (see below)
    +	 * \param       ptr     Pointer returned by lzma_allocator.alloc(),
    +	 *                      or when it is set to NULL, a pointer returned
    +	 *                      by the standard malloc().
    +	 */
    +	void (LZMA_API_CALL *free)(void *opaque, void *ptr);
    +
    +	/**
    +	 * \brief       Pointer passed to .alloc() and .free()
    +	 *
    +	 * opaque is passed as the first argument to lzma_allocator.alloc()
    +	 * and lzma_allocator.free(). This intended to ease implementing
    +	 * custom memory allocation functions for use with liblzma.
    +	 *
    +	 * If you don't need this, you should set this to NULL.
    +	 */
    +	void *opaque;
    +
    +} lzma_allocator;
    +
    +
    +/**
    + * \brief       Internal data structure
    + *
    + * The contents of this structure is not visible outside the library.
    + */
    +typedef struct lzma_internal_s lzma_internal;
    +
    +
    +/**
    + * \brief       Passing data to and from liblzma
    + *
    + * The lzma_stream structure is used for
    + *  - passing pointers to input and output buffers to liblzma;
    + *  - defining custom memory handler functions; and
    + *  - holding a pointer to coder-specific internal data structures.
    + *
    + * Typical usage:
    + *
    + *  - After allocating lzma_stream (on stack or with malloc()), it must be
    + *    initialized to LZMA_STREAM_INIT (see LZMA_STREAM_INIT for details).
    + *
    + *  - Initialize a coder to the lzma_stream, for example by using
    + *    lzma_easy_encoder() or lzma_auto_decoder(). Some notes:
    + *      - In contrast to zlib, strm->next_in and strm->next_out are
    + *        ignored by all initialization functions, thus it is safe
    + *        to not initialize them yet.
    + *      - The initialization functions always set strm->total_in and
    + *        strm->total_out to zero.
    + *      - If the initialization function fails, no memory is left allocated
    + *        that would require freeing with lzma_end() even if some memory was
    + *        associated with the lzma_stream structure when the initialization
    + *        function was called.
    + *
    + *  - Use lzma_code() to do the actual work.
    + *
    + *  - Once the coding has been finished, the existing lzma_stream can be
    + *    reused. It is OK to reuse lzma_stream with different initialization
    + *    function without calling lzma_end() first. Old allocations are
    + *    automatically freed.
    + *
    + *  - Finally, use lzma_end() to free the allocated memory. lzma_end() never
    + *    frees the lzma_stream structure itself.
    + *
    + * Application may modify the values of total_in and total_out as it wants.
    + * They are updated by liblzma to match the amount of data read and
    + * written but aren't used for anything else except as a possible return
    + * values from lzma_get_progress().
    + */
    +typedef struct {
    +	const uint8_t *next_in; /**< Pointer to the next input byte. */
    +	size_t avail_in;    /**< Number of available input bytes in next_in. */
    +	uint64_t total_in;  /**< Total number of bytes read by liblzma. */
    +
    +	uint8_t *next_out;  /**< Pointer to the next output position. */
    +	size_t avail_out;   /**< Amount of free space in next_out. */
    +	uint64_t total_out; /**< Total number of bytes written by liblzma. */
    +
    +	/**
    +	 * \brief       Custom memory allocation functions
    +	 *
    +	 * In most cases this is NULL which makes liblzma use
    +	 * the standard malloc() and free().
    +	 *
    +	 * \note        In 5.0.x this is not a const pointer.
    +	 */
    +	const lzma_allocator *allocator;
    +
    +	/** Internal state is not visible to applications. */
    +	lzma_internal *internal;
    +
    +	/*
    +	 * Reserved space to allow possible future extensions without
    +	 * breaking the ABI. Excluding the initialization of this structure,
    +	 * you should not touch these, because the names of these variables
    +	 * may change.
    +	 */
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr1;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr2;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr3;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr4;
    +
    +	/**
    +	 * \brief       New seek input position for LZMA_SEEK_NEEDED
    +	 *
    +	 * When lzma_code() returns LZMA_SEEK_NEEDED, the new input position
    +	 * needed by liblzma will be available seek_pos. The value is
    +	 * guaranteed to not exceed the file size that was specified when
    +	 * this lzma_stream was initialized.
    +	 *
    +	 * In all other situations the value of this variable is undefined.
    +	 */
    +	uint64_t seek_pos;
    +
    +	/** \private     Reserved member. */
    +	uint64_t reserved_int2;
    +
    +	/** \private     Reserved member. */
    +	size_t reserved_int3;
    +
    +	/** \private     Reserved member. */
    +	size_t reserved_int4;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum1;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum2;
    +
    +} lzma_stream;
    +
    +
    +/**
    + * \brief       Initialization for lzma_stream
    + *
    + * When you declare an instance of lzma_stream, you can immediately
    + * initialize it so that initialization functions know that no memory
    + * has been allocated yet:
    + *
    + *     lzma_stream strm = LZMA_STREAM_INIT;
    + *
    + * If you need to initialize a dynamically allocated lzma_stream, you can use
    + * memset(strm_pointer, 0, sizeof(lzma_stream)). Strictly speaking, this
    + * violates the C standard since NULL may have different internal
    + * representation than zero, but it should be portable enough in practice.
    + * Anyway, for maximum portability, you can use something like this:
    + *
    + *     lzma_stream tmp = LZMA_STREAM_INIT;
    + *     *strm = tmp;
    + */
    +#define LZMA_STREAM_INIT \
    +	{ NULL, 0, 0, NULL, 0, 0, NULL, NULL, \
    +	NULL, NULL, NULL, NULL, 0, 0, 0, 0, \
    +	LZMA_RESERVED_ENUM, LZMA_RESERVED_ENUM }
    +
    +
    +/**
    + * \brief       Encode or decode data
    + *
    + * Once the lzma_stream has been successfully initialized (e.g. with
    + * lzma_stream_encoder()), the actual encoding or decoding is done
    + * using this function. The application has to update strm->next_in,
    + * strm->avail_in, strm->next_out, and strm->avail_out to pass input
    + * to and get output from liblzma.
    + *
    + * See the description of the coder-specific initialization function to find
    + * out what 'action' values are supported by the coder.
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + * \param       action  Action for this function to take. Must be a valid
    + *                      lzma_action enum value.
    + *
    + * \return      Any valid lzma_ret. See the lzma_ret enum description for more
    + *              information.
    + */
    +extern LZMA_API(lzma_ret) lzma_code(lzma_stream *strm, lzma_action action)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Free memory allocated for the coder data structures
    + *
    + * After lzma_end(strm), strm->internal is guaranteed to be NULL. No other
    + * members of the lzma_stream structure are touched.
    + *
    + * \note        zlib indicates an error if application end()s unfinished
    + *              stream structure. liblzma doesn't do this, and assumes that
    + *              application knows what it is doing.
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + */
    +extern LZMA_API(void) lzma_end(lzma_stream *strm) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Get progress information
    + *
    + * In single-threaded mode, applications can get progress information from
    + * strm->total_in and strm->total_out. In multi-threaded mode this is less
    + * useful because a significant amount of both input and output data gets
    + * buffered internally by liblzma. This makes total_in and total_out give
    + * misleading information and also makes the progress indicator updates
    + * non-smooth.
    + *
    + * This function gives realistic progress information also in multi-threaded
    + * mode by taking into account the progress made by each thread. In
    + * single-threaded mode *progress_in and *progress_out are set to
    + * strm->total_in and strm->total_out, respectively.
    + *
    + * \param       strm          Pointer to lzma_stream that is at least
    + *                            initialized with LZMA_STREAM_INIT.
    + * \param[out]  progress_in   Pointer to the number of input bytes processed.
    + * \param[out]  progress_out  Pointer to the number of output bytes processed.
    + */
    +extern LZMA_API(void) lzma_get_progress(lzma_stream *strm,
    +		uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Get the memory usage of decoder filter chain
    + *
    + * This function is currently supported only when *strm has been initialized
    + * with a function that takes a memlimit argument. With other functions, you
    + * should use e.g. lzma_raw_encoder_memusage() or lzma_raw_decoder_memusage()
    + * to estimate the memory requirements.
    + *
    + * This function is useful e.g. after LZMA_MEMLIMIT_ERROR to find out how big
    + * the memory usage limit should have been to decode the input. Note that
    + * this may give misleading information if decoding .xz Streams that have
    + * multiple Blocks, because each Block can have different memory requirements.
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + *
    + * \return      How much memory is currently allocated for the filter
    + *              decoders. If no filter chain is currently allocated,
    + *              some non-zero value is still returned, which is less than
    + *              or equal to what any filter chain would indicate as its
    + *              memory requirement.
    + *
    + *              If this function isn't supported by *strm or some other error
    + *              occurs, zero is returned.
    + */
    +extern LZMA_API(uint64_t) lzma_memusage(const lzma_stream *strm)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Get the current memory usage limit
    + *
    + * This function is supported only when *strm has been initialized with
    + * a function that takes a memlimit argument.
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + *
    + * \return      On success, the current memory usage limit is returned
    + *              (always non-zero). On error, zero is returned.
    + */
    +extern LZMA_API(uint64_t) lzma_memlimit_get(const lzma_stream *strm)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Set the memory usage limit
    + *
    + * This function is supported only when *strm has been initialized with
    + * a function that takes a memlimit argument.
    + *
    + * liblzma 5.2.3 and earlier has a bug where memlimit value of 0 causes
    + * this function to do nothing (leaving the limit unchanged) and still
    + * return LZMA_OK. Later versions treat 0 as if 1 had been specified (so
    + * lzma_memlimit_get() will return 1 even if you specify 0 here).
    + *
    + * liblzma 5.2.6 and earlier had a bug in single-threaded .xz decoder
    + * (lzma_stream_decoder()) which made it impossible to continue decoding
    + * after LZMA_MEMLIMIT_ERROR even if the limit was increased using
    + * lzma_memlimit_set(). Other decoders worked correctly.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: New memory usage limit successfully set.
    + *              - LZMA_MEMLIMIT_ERROR: The new limit is too small.
    + *                The limit was not changed.
    + *              - LZMA_PROG_ERROR: Invalid arguments, e.g. *strm doesn't
    + *                support memory usage limit.
    + */
    +extern LZMA_API(lzma_ret) lzma_memlimit_set(
    +		lzma_stream *strm, uint64_t memlimit) lzma_nothrow;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/bcj.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/bcj.h
    new file mode 100644
    index 00000000000..7f6611feb32
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/bcj.h
    @@ -0,0 +1,98 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/bcj.h
    + * \brief       Branch/Call/Jump conversion filters
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/* Filter IDs for lzma_filter.id */
    +
    +/**
    + * \brief       Filter for x86 binaries
    + */
    +#define LZMA_FILTER_X86         LZMA_VLI_C(0x04)
    +
    +/**
    + * \brief       Filter for Big endian PowerPC binaries
    + */
    +#define LZMA_FILTER_POWERPC     LZMA_VLI_C(0x05)
    +
    +/**
    + * \brief       Filter for IA-64 (Itanium) binaries
    + */
    +#define LZMA_FILTER_IA64        LZMA_VLI_C(0x06)
    +
    +/**
    + * \brief       Filter for ARM binaries
    + */
    +#define LZMA_FILTER_ARM         LZMA_VLI_C(0x07)
    +
    +/**
    + * \brief       Filter for ARM-Thumb binaries
    + */
    +#define LZMA_FILTER_ARMTHUMB    LZMA_VLI_C(0x08)
    +
    +/**
    + * \brief       Filter for SPARC binaries
    + */
    +#define LZMA_FILTER_SPARC       LZMA_VLI_C(0x09)
    +
    +/**
    + * \brief       Filter for ARM64 binaries
    + */
    +#define LZMA_FILTER_ARM64       LZMA_VLI_C(0x0A)
    +
    +/**
    + * \brief       Filter for RISC-V binaries
    + */
    +#define LZMA_FILTER_RISCV       LZMA_VLI_C(0x0B)
    +
    +
    +/**
    + * \brief       Options for BCJ filters
    + *
    + * The BCJ filters never change the size of the data. Specifying options
    + * for them is optional: if pointer to options is NULL, default value is
    + * used. You probably never need to specify options to BCJ filters, so just
    + * set the options pointer to NULL and be happy.
    + *
    + * If options with non-default values have been specified when encoding,
    + * the same options must also be specified when decoding.
    + *
    + * \note        At the moment, none of the BCJ filters support
    + *              LZMA_SYNC_FLUSH. If LZMA_SYNC_FLUSH is specified,
    + *              LZMA_OPTIONS_ERROR will be returned. If there is need,
    + *              partial support for LZMA_SYNC_FLUSH can be added in future.
    + *              Partial means that flushing would be possible only at
    + *              offsets that are multiple of 2, 4, or 16 depending on
    + *              the filter, except x86 which cannot be made to support
    + *              LZMA_SYNC_FLUSH predictably.
    + */
    +typedef struct {
    +	/**
    +	 * \brief       Start offset for conversions
    +	 *
    +	 * This setting is useful only when the same filter is used
    +	 * _separately_ for multiple sections of the same executable file,
    +	 * and the sections contain cross-section branch/call/jump
    +	 * instructions. In that case it is beneficial to set the start
    +	 * offset of the non-first sections so that the relative addresses
    +	 * of the cross-section branch/call/jump instructions will use the
    +	 * same absolute addresses as in the first section.
    +	 *
    +	 * When the pointer to options is NULL, the default value (zero)
    +	 * is used.
    +	 */
    +	uint32_t start_offset;
    +
    +} lzma_options_bcj;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/block.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/block.h
    new file mode 100644
    index 00000000000..05b77e59aab
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/block.h
    @@ -0,0 +1,694 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/block.h
    + * \brief       .xz Block handling
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       Options for the Block and Block Header encoders and decoders
    + *
    + * Different Block handling functions use different parts of this structure.
    + * Some read some members, other functions write, and some do both. Only the
    + * members listed for reading need to be initialized when the specified
    + * functions are called. The members marked for writing will be assigned
    + * new values at some point either by calling the given function or by
    + * later calls to lzma_code().
    + */
    +typedef struct {
    +	/**
    +	 * \brief       Block format version
    +	 *
    +	 * To prevent API and ABI breakages when new features are needed,
    +	 * a version number is used to indicate which members in this
    +	 * structure are in use:
    +	 *   - liblzma >= 5.0.0: version = 0 is supported.
    +	 *   - liblzma >= 5.1.4beta: Support for version = 1 was added,
    +	 *     which adds the ignore_check member.
    +	 *
    +	 * If version is greater than one, most Block related functions
    +	 * will return LZMA_OPTIONS_ERROR (lzma_block_header_decode() works
    +	 * with any version value).
    +	 *
    +	 * Read by:
    +	 *  - lzma_block_header_size()
    +	 *  - lzma_block_header_encode()
    +	 *  - lzma_block_header_decode()
    +	 *  - lzma_block_compressed_size()
    +	 *  - lzma_block_unpadded_size()
    +	 *  - lzma_block_total_size()
    +	 *  - lzma_block_encoder()
    +	 *  - lzma_block_decoder()
    +	 *  - lzma_block_buffer_encode()
    +	 *  - lzma_block_uncomp_encode()
    +	 *  - lzma_block_buffer_decode()
    +	 *
    +	 * Written by:
    +	 *  - lzma_block_header_decode()
    +	 */
    +	uint32_t version;
    +
    +	/**
    +	 * \brief       Size of the Block Header field in bytes
    +	 *
    +	 * This is always a multiple of four.
    +	 *
    +	 * Read by:
    +	 *  - lzma_block_header_encode()
    +	 *  - lzma_block_header_decode()
    +	 *  - lzma_block_compressed_size()
    +	 *  - lzma_block_unpadded_size()
    +	 *  - lzma_block_total_size()
    +	 *  - lzma_block_decoder()
    +	 *  - lzma_block_buffer_decode()
    +	 *
    +	 * Written by:
    +	 *  - lzma_block_header_size()
    +	 *  - lzma_block_buffer_encode()
    +	 *  - lzma_block_uncomp_encode()
    +	 */
    +	uint32_t header_size;
    +#	define LZMA_BLOCK_HEADER_SIZE_MIN 8
    +#	define LZMA_BLOCK_HEADER_SIZE_MAX 1024
    +
    +	/**
    +	 * \brief       Type of integrity Check
    +	 *
    +	 * The Check ID is not stored into the Block Header, thus its value
    +	 * must be provided also when decoding.
    +	 *
    +	 * Read by:
    +	 *  - lzma_block_header_encode()
    +	 *  - lzma_block_header_decode()
    +	 *  - lzma_block_compressed_size()
    +	 *  - lzma_block_unpadded_size()
    +	 *  - lzma_block_total_size()
    +	 *  - lzma_block_encoder()
    +	 *  - lzma_block_decoder()
    +	 *  - lzma_block_buffer_encode()
    +	 *  - lzma_block_buffer_decode()
    +	 */
    +	lzma_check check;
    +
    +	/**
    +	 * \brief       Size of the Compressed Data in bytes
    +	 *
    +	 * Encoding: If this is not LZMA_VLI_UNKNOWN, Block Header encoder
    +	 * will store this value to the Block Header. Block encoder doesn't
    +	 * care about this value, but will set it once the encoding has been
    +	 * finished.
    +	 *
    +	 * Decoding: If this is not LZMA_VLI_UNKNOWN, Block decoder will
    +	 * verify that the size of the Compressed Data field matches
    +	 * compressed_size.
    +	 *
    +	 * Usually you don't know this value when encoding in streamed mode,
    +	 * and thus cannot write this field into the Block Header.
    +	 *
    +	 * In non-streamed mode you can reserve space for this field before
    +	 * encoding the actual Block. After encoding the data, finish the
    +	 * Block by encoding the Block Header. Steps in detail:
    +	 *
    +	 *  - Set compressed_size to some big enough value. If you don't know
    +	 *    better, use LZMA_VLI_MAX, but remember that bigger values take
    +	 *    more space in Block Header.
    +	 *
    +	 *  - Call lzma_block_header_size() to see how much space you need to
    +	 *    reserve for the Block Header.
    +	 *
    +	 *  - Encode the Block using lzma_block_encoder() and lzma_code().
    +	 *    It sets compressed_size to the correct value.
    +	 *
    +	 *  - Use lzma_block_header_encode() to encode the Block Header.
    +	 *    Because space was reserved in the first step, you don't need
    +	 *    to call lzma_block_header_size() anymore, because due to
    +	 *    reserving, header_size has to be big enough. If it is "too big",
    +	 *    lzma_block_header_encode() will add enough Header Padding to
    +	 *    make Block Header to match the size specified by header_size.
    +	 *
    +	 * Read by:
    +	 *  - lzma_block_header_size()
    +	 *  - lzma_block_header_encode()
    +	 *  - lzma_block_compressed_size()
    +	 *  - lzma_block_unpadded_size()
    +	 *  - lzma_block_total_size()
    +	 *  - lzma_block_decoder()
    +	 *  - lzma_block_buffer_decode()
    +	 *
    +	 * Written by:
    +	 *  - lzma_block_header_decode()
    +	 *  - lzma_block_compressed_size()
    +	 *  - lzma_block_encoder()
    +	 *  - lzma_block_decoder()
    +	 *  - lzma_block_buffer_encode()
    +	 *  - lzma_block_uncomp_encode()
    +	 *  - lzma_block_buffer_decode()
    +	 */
    +	lzma_vli compressed_size;
    +
    +	/**
    +	 * \brief       Uncompressed Size in bytes
    +	 *
    +	 * This is handled very similarly to compressed_size above.
    +	 *
    +	 * uncompressed_size is needed by fewer functions than
    +	 * compressed_size. This is because uncompressed_size isn't
    +	 * needed to validate that Block stays within proper limits.
    +	 *
    +	 * Read by:
    +	 *  - lzma_block_header_size()
    +	 *  - lzma_block_header_encode()
    +	 *  - lzma_block_decoder()
    +	 *  - lzma_block_buffer_decode()
    +	 *
    +	 * Written by:
    +	 *  - lzma_block_header_decode()
    +	 *  - lzma_block_encoder()
    +	 *  - lzma_block_decoder()
    +	 *  - lzma_block_buffer_encode()
    +	 *  - lzma_block_uncomp_encode()
    +	 *  - lzma_block_buffer_decode()
    +	 */
    +	lzma_vli uncompressed_size;
    +
    +	/**
    +	 * \brief       Array of filters
    +	 *
    +	 * There can be 1-4 filters. The end of the array is marked with
    +	 * .id = LZMA_VLI_UNKNOWN.
    +	 *
    +	 * Read by:
    +	 *  - lzma_block_header_size()
    +	 *  - lzma_block_header_encode()
    +	 *  - lzma_block_encoder()
    +	 *  - lzma_block_decoder()
    +	 *  - lzma_block_buffer_encode()
    +	 *  - lzma_block_buffer_decode()
    +	 *
    +	 * Written by:
    +	 *  - lzma_block_header_decode(): Note that this does NOT free()
    +	 *    the old filter options structures. All unused filters[] will
    +	 *    have .id == LZMA_VLI_UNKNOWN and .options == NULL. If
    +	 *    decoding fails, all filters[] are guaranteed to be
    +	 *    LZMA_VLI_UNKNOWN and NULL.
    +	 *
    +	 * \note        Because of the array is terminated with
    +	 *              .id = LZMA_VLI_UNKNOWN, the actual array must
    +	 *              have LZMA_FILTERS_MAX + 1 members or the Block
    +	 *              Header decoder will overflow the buffer.
    +	 */
    +	lzma_filter *filters;
    +
    +	/**
    +	 * \brief       Raw value stored in the Check field
    +	 *
    +	 * After successful coding, the first lzma_check_size(check) bytes
    +	 * of this array contain the raw value stored in the Check field.
    +	 *
    +	 * Note that CRC32 and CRC64 are stored in little endian byte order.
    +	 * Take it into account if you display the Check values to the user.
    +	 *
    +	 * Written by:
    +	 *  - lzma_block_encoder()
    +	 *  - lzma_block_decoder()
    +	 *  - lzma_block_buffer_encode()
    +	 *  - lzma_block_uncomp_encode()
    +	 *  - lzma_block_buffer_decode()
    +	 */
    +	uint8_t raw_check[LZMA_CHECK_SIZE_MAX];
    +
    +	/*
    +	 * Reserved space to allow possible future extensions without
    +	 * breaking the ABI. You should not touch these, because the names
    +	 * of these variables may change. These are and will never be used
    +	 * with the currently supported options, so it is safe to leave these
    +	 * uninitialized.
    +	 */
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr1;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr2;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr3;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int1;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int2;
    +
    +	/** \private     Reserved member. */
    +	lzma_vli reserved_int3;
    +
    +	/** \private     Reserved member. */
    +	lzma_vli reserved_int4;
    +
    +	/** \private     Reserved member. */
    +	lzma_vli reserved_int5;
    +
    +	/** \private     Reserved member. */
    +	lzma_vli reserved_int6;
    +
    +	/** \private     Reserved member. */
    +	lzma_vli reserved_int7;
    +
    +	/** \private     Reserved member. */
    +	lzma_vli reserved_int8;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum1;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum2;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum3;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum4;
    +
    +	/**
    +	 * \brief       A flag to Block decoder to not verify the Check field
    +	 *
    +	 * This member is supported by liblzma >= 5.1.4beta if .version >= 1.
    +	 *
    +	 * If this is set to true, the integrity check won't be calculated
    +	 * and verified. Unless you know what you are doing, you should
    +	 * leave this to false. (A reason to set this to true is when the
    +	 * file integrity is verified externally anyway and you want to
    +	 * speed up the decompression, which matters mostly when using
    +	 * SHA-256 as the integrity check.)
    +	 *
    +	 * If .version >= 1, read by:
    +	 *   - lzma_block_decoder()
    +	 *   - lzma_block_buffer_decode()
    +	 *
    +	 * Written by (.version is ignored):
    +	 *   - lzma_block_header_decode() always sets this to false
    +	 */
    +	lzma_bool ignore_check;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool2;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool3;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool4;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool5;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool6;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool7;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool8;
    +
    +} lzma_block;
    +
    +
    +/**
    + * \brief       Decode the Block Header Size field
    + *
    + * To decode Block Header using lzma_block_header_decode(), the size of the
    + * Block Header has to be known and stored into lzma_block.header_size.
    + * The size can be calculated from the first byte of a Block using this macro.
    + * Note that if the first byte is 0x00, it indicates beginning of Index; use
    + * this macro only when the byte is not 0x00.
    + *
    + * There is no encoding macro because lzma_block_header_size() and
    + * lzma_block_header_encode() should be used.
    + */
    +#define lzma_block_header_size_decode(b) (((uint32_t)(b) + 1) * 4)
    +
    +
    +/**
    + * \brief       Calculate Block Header Size
    + *
    + * Calculate the minimum size needed for the Block Header field using the
    + * settings specified in the lzma_block structure. Note that it is OK to
    + * increase the calculated header_size value as long as it is a multiple of
    + * four and doesn't exceed LZMA_BLOCK_HEADER_SIZE_MAX. Increasing header_size
    + * just means that lzma_block_header_encode() will add Header Padding.
    + *
    + * \note        This doesn't check that all the options are valid i.e. this
    + *              may return LZMA_OK even if lzma_block_header_encode() or
    + *              lzma_block_encoder() would fail. If you want to validate the
    + *              filter chain, consider using lzma_memlimit_encoder() which as
    + *              a side-effect validates the filter chain.
    + *
    + * \param       block   Block options
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Size calculated successfully and stored to
    + *                block->header_size.
    + *              - LZMA_OPTIONS_ERROR: Unsupported version, filters or
    + *                filter options.
    + *              - LZMA_PROG_ERROR: Invalid values like compressed_size == 0.
    + */
    +extern LZMA_API(lzma_ret) lzma_block_header_size(lzma_block *block)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Encode Block Header
    + *
    + * The caller must have calculated the size of the Block Header already with
    + * lzma_block_header_size(). If a value larger than the one calculated by
    + * lzma_block_header_size() is used, the Block Header will be padded to the
    + * specified size.
    + *
    + * \param       block       Block options to be encoded.
    + * \param[out]  out         Beginning of the output buffer. This must be
    + *                          at least block->header_size bytes.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful. block->header_size
    + *                bytes were written to output buffer.
    + *              - LZMA_OPTIONS_ERROR: Invalid or unsupported options.
    + *              - LZMA_PROG_ERROR: Invalid arguments, for example
    + *                block->header_size is invalid or block->filters is NULL.
    + */
    +extern LZMA_API(lzma_ret) lzma_block_header_encode(
    +		const lzma_block *block, uint8_t *out)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Decode Block Header
    + *
    + * block->version should (usually) be set to the highest value supported
    + * by the application. If the application sets block->version to a value
    + * higher than supported by the current liblzma version, this function will
    + * downgrade block->version to the highest value supported by it. Thus one
    + * should check the value of block->version after calling this function if
    + * block->version was set to a non-zero value and the application doesn't
    + * otherwise know that the liblzma version being used is new enough to
    + * support the specified block->version.
    + *
    + * The size of the Block Header must have already been decoded with
    + * lzma_block_header_size_decode() macro and stored to block->header_size.
    + *
    + * The integrity check type from Stream Header must have been stored
    + * to block->check.
    + *
    + * block->filters must have been allocated, but they don't need to be
    + * initialized (possible existing filter options are not freed).
    + *
    + * \param[out]  block       Destination for Block options
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() (and also free()
    + *                          if an error occurs).
    + * \param       in          Beginning of the input buffer. This must be
    + *                          at least block->header_size bytes.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Decoding was successful. block->header_size
    + *                bytes were read from the input buffer.
    + *              - LZMA_OPTIONS_ERROR: The Block Header specifies some
    + *                unsupported options such as unsupported filters. This can
    + *                happen also if block->version was set to a too low value
    + *                compared to what would be required to properly represent
    + *                the information stored in the Block Header.
    + *              - LZMA_DATA_ERROR: Block Header is corrupt, for example,
    + *                the CRC32 doesn't match.
    + *              - LZMA_PROG_ERROR: Invalid arguments, for example
    + *                block->header_size is invalid or block->filters is NULL.
    + */
    +extern LZMA_API(lzma_ret) lzma_block_header_decode(lzma_block *block,
    +		const lzma_allocator *allocator, const uint8_t *in)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Validate and set Compressed Size according to Unpadded Size
    + *
    + * Block Header stores Compressed Size, but Index has Unpadded Size. If the
    + * application has already parsed the Index and is now decoding Blocks,
    + * it can calculate Compressed Size from Unpadded Size. This function does
    + * exactly that with error checking:
    + *
    + *  - Compressed Size calculated from Unpadded Size must be positive integer,
    + *    that is, Unpadded Size must be big enough that after Block Header and
    + *    Check fields there's still at least one byte for Compressed Size.
    + *
    + *  - If Compressed Size was present in Block Header, the new value
    + *    calculated from Unpadded Size is compared against the value
    + *    from Block Header.
    + *
    + * \note        This function must be called _after_ decoding the Block Header
    + *              field so that it can properly validate Compressed Size if it
    + *              was present in Block Header.
    + *
    + * \param       block           Block options: block->header_size must
    + *                              already be set with lzma_block_header_size().
    + * \param       unpadded_size   Unpadded Size from the Index field in bytes
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: block->compressed_size was set successfully.
    + *              - LZMA_DATA_ERROR: unpadded_size is too small compared to
    + *                block->header_size and lzma_check_size(block->check).
    + *              - LZMA_PROG_ERROR: Some values are invalid. For example,
    + *                block->header_size must be a multiple of four and
    + *                between 8 and 1024 inclusive.
    + */
    +extern LZMA_API(lzma_ret) lzma_block_compressed_size(
    +		lzma_block *block, lzma_vli unpadded_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Calculate Unpadded Size
    + *
    + * The Index field stores Unpadded Size and Uncompressed Size. The latter
    + * can be taken directly from the lzma_block structure after coding a Block,
    + * but Unpadded Size needs to be calculated from Block Header Size,
    + * Compressed Size, and size of the Check field. This is where this function
    + * is needed.
    + *
    + * \param       block   Block options: block->header_size must already be
    + *                      set with lzma_block_header_size().
    + *
    + * \return      Unpadded Size on success, or zero on error.
    + */
    +extern LZMA_API(lzma_vli) lzma_block_unpadded_size(const lzma_block *block)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Calculate the total encoded size of a Block
    + *
    + * This is equivalent to lzma_block_unpadded_size() except that the returned
    + * value includes the size of the Block Padding field.
    + *
    + * \param       block   Block options: block->header_size must already be
    + *                      set with lzma_block_header_size().
    + *
    + * \return      On success, total encoded size of the Block. On error,
    + *              zero is returned.
    + */
    +extern LZMA_API(lzma_vli) lzma_block_total_size(const lzma_block *block)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Initialize .xz Block encoder
    + *
    + * Valid actions for lzma_code() are LZMA_RUN, LZMA_SYNC_FLUSH (only if the
    + * filter chain supports it), and LZMA_FINISH.
    + *
    + * The Block encoder encodes the Block Data, Block Padding, and Check value.
    + * It does NOT encode the Block Header which can be encoded with
    + * lzma_block_header_encode().
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + * \param       block   Block options: block->version, block->check,
    + *                      and block->filters must have been initialized.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: All good, continue with lzma_code().
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_UNSUPPORTED_CHECK: block->check specifies a Check ID
    + *                that is not supported by this build of liblzma. Initializing
    + *                the encoder failed.
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_block_encoder(
    +		lzma_stream *strm, lzma_block *block)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Initialize .xz Block decoder
    + *
    + * Valid actions for lzma_code() are LZMA_RUN and LZMA_FINISH. Using
    + * LZMA_FINISH is not required. It is supported only for convenience.
    + *
    + * The Block decoder decodes the Block Data, Block Padding, and Check value.
    + * It does NOT decode the Block Header which can be decoded with
    + * lzma_block_header_decode().
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + * \param       block   Block options
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: All good, continue with lzma_code().
    + *              - LZMA_PROG_ERROR
    + *              - LZMA_MEM_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_block_decoder(
    +		lzma_stream *strm, lzma_block *block)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Calculate maximum output size for single-call Block encoding
    + *
    + * This is equivalent to lzma_stream_buffer_bound() but for .xz Blocks.
    + * See the documentation of lzma_stream_buffer_bound().
    + *
    + * \param       uncompressed_size   Size of the data to be encoded with the
    + *                                  single-call Block encoder.
    + *
    + * \return      Maximum output size in bytes for single-call Block encoding.
    + */
    +extern LZMA_API(size_t) lzma_block_buffer_bound(size_t uncompressed_size)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Single-call .xz Block encoder
    + *
    + * In contrast to the multi-call encoder initialized with
    + * lzma_block_encoder(), this function encodes also the Block Header. This
    + * is required to make it possible to write appropriate Block Header also
    + * in case the data isn't compressible, and different filter chain has to be
    + * used to encode the data in uncompressed form using uncompressed chunks
    + * of the LZMA2 filter.
    + *
    + * When the data isn't compressible, header_size, compressed_size, and
    + * uncompressed_size are set just like when the data was compressible, but
    + * it is possible that header_size is too small to hold the filter chain
    + * specified in block->filters, because that isn't necessarily the filter
    + * chain that was actually used to encode the data. lzma_block_unpadded_size()
    + * still works normally, because it doesn't read the filters array.
    + *
    + * \param       block       Block options: block->version, block->check,
    + *                          and block->filters must have been initialized.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + * \param       in          Beginning of the input buffer
    + * \param       in_size     Size of the input buffer
    + * \param[out]  out         Beginning of the output buffer
    + * \param[out]  out_pos     The next byte will be written to out[*out_pos].
    + *                          *out_pos is updated only if encoding succeeds.
    + * \param       out_size    Size of the out buffer; the first byte into
    + *                          which no data is written to is out[out_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful.
    + *              - LZMA_BUF_ERROR: Not enough output buffer space.
    + *              - LZMA_UNSUPPORTED_CHECK
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_block_buffer_encode(
    +		lzma_block *block, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Single-call uncompressed .xz Block encoder
    + *
    + * This is like lzma_block_buffer_encode() except this doesn't try to
    + * compress the data and instead encodes the data using LZMA2 uncompressed
    + * chunks. The required output buffer size can be determined with
    + * lzma_block_buffer_bound().
    + *
    + * Since the data won't be compressed, this function ignores block->filters.
    + * This function doesn't take lzma_allocator because this function doesn't
    + * allocate any memory from the heap.
    + *
    + * \param       block       Block options: block->version, block->check,
    + *                          and block->filters must have been initialized.
    + * \param       in          Beginning of the input buffer
    + * \param       in_size     Size of the input buffer
    + * \param[out]  out         Beginning of the output buffer
    + * \param[out]  out_pos     The next byte will be written to out[*out_pos].
    + *                          *out_pos is updated only if encoding succeeds.
    + * \param       out_size    Size of the out buffer; the first byte into
    + *                          which no data is written to is out[out_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful.
    + *              - LZMA_BUF_ERROR: Not enough output buffer space.
    + *              - LZMA_UNSUPPORTED_CHECK
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_block_uncomp_encode(lzma_block *block,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Single-call .xz Block decoder
    + *
    + * This is single-call equivalent of lzma_block_decoder(), and requires that
    + * the caller has already decoded Block Header and checked its memory usage.
    + *
    + * \param       block       Block options
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + * \param       in          Beginning of the input buffer
    + * \param       in_pos      The next byte will be read from in[*in_pos].
    + *                          *in_pos is updated only if decoding succeeds.
    + * \param       in_size     Size of the input buffer; the first byte that
    + *                          won't be read is in[in_size].
    + * \param[out]  out         Beginning of the output buffer
    + * \param[out]  out_pos     The next byte will be written to out[*out_pos].
    + *                          *out_pos is updated only if encoding succeeds.
    + * \param       out_size    Size of the out buffer; the first byte into
    + *                          which no data is written to is out[out_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Decoding was successful.
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_BUF_ERROR: Output buffer was too small.
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_block_buffer_decode(
    +		lzma_block *block, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +		lzma_nothrow;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/check.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/check.h
    new file mode 100644
    index 00000000000..e7a50ed3a3c
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/check.h
    @@ -0,0 +1,163 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/check.h
    + * \brief       Integrity checks
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       Type of the integrity check (Check ID)
    + *
    + * The .xz format supports multiple types of checks that are calculated
    + * from the uncompressed data. They vary in both speed and ability to
    + * detect errors.
    + */
    +typedef enum {
    +	LZMA_CHECK_NONE     = 0,
    +		/**<
    +		 * No Check is calculated.
    +		 *
    +		 * Size of the Check field: 0 bytes
    +		 */
    +
    +	LZMA_CHECK_CRC32    = 1,
    +		/**<
    +		 * CRC32 using the polynomial from the IEEE 802.3 standard
    +		 *
    +		 * Size of the Check field: 4 bytes
    +		 */
    +
    +	LZMA_CHECK_CRC64    = 4,
    +		/**<
    +		 * CRC64 using the polynomial from the ECMA-182 standard
    +		 *
    +		 * Size of the Check field: 8 bytes
    +		 */
    +
    +	LZMA_CHECK_SHA256   = 10
    +		/**<
    +		 * SHA-256
    +		 *
    +		 * Size of the Check field: 32 bytes
    +		 */
    +} lzma_check;
    +
    +
    +/**
    + * \brief       Maximum valid Check ID
    + *
    + * The .xz file format specification specifies 16 Check IDs (0-15). Some
    + * of them are only reserved, that is, no actual Check algorithm has been
    + * assigned. When decoding, liblzma still accepts unknown Check IDs for
    + * future compatibility. If a valid but unsupported Check ID is detected,
    + * liblzma can indicate a warning; see the flags LZMA_TELL_NO_CHECK,
    + * LZMA_TELL_UNSUPPORTED_CHECK, and LZMA_TELL_ANY_CHECK in container.h.
    + */
    +#define LZMA_CHECK_ID_MAX 15
    +
    +
    +/**
    + * \brief       Test if the given Check ID is supported
    + *
    + * LZMA_CHECK_NONE and LZMA_CHECK_CRC32 are always supported (even if
    + * liblzma is built with limited features).
    + *
    + * \note        It is safe to call this with a value that is not in the
    + *              range [0, 15]; in that case the return value is always false.
    + *
    + * \param       check   Check ID
    + *
    + * \return      lzma_bool:
    + *              - true if Check ID is supported by this liblzma build.
    + *              - false otherwise.
    + */
    +extern LZMA_API(lzma_bool) lzma_check_is_supported(lzma_check check)
    +		lzma_nothrow lzma_attr_const;
    +
    +
    +/**
    + * \brief       Get the size of the Check field with the given Check ID
    + *
    + * Although not all Check IDs have a check algorithm associated, the size of
    + * every Check is already frozen. This function returns the size (in bytes) of
    + * the Check field with the specified Check ID. The values are:
    + * { 0, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64 }
    + *
    + * \param       check   Check ID
    + *
    + * \return      Size of the Check field in bytes. If the argument is not in
    + *              the range [0, 15], UINT32_MAX is returned.
    + */
    +extern LZMA_API(uint32_t) lzma_check_size(lzma_check check)
    +		lzma_nothrow lzma_attr_const;
    +
    +
    +/**
    + * \brief       Maximum size of a Check field
    + */
    +#define LZMA_CHECK_SIZE_MAX 64
    +
    +
    +/**
    + * \brief       Calculate CRC32
    + *
    + * Calculate CRC32 using the polynomial from the IEEE 802.3 standard.
    + *
    + * \param       buf     Pointer to the input buffer
    + * \param       size    Size of the input buffer
    + * \param       crc     Previously returned CRC value. This is used to
    + *                      calculate the CRC of a big buffer in smaller chunks.
    + *                      Set to zero when starting a new calculation.
    + *
    + * \return      Updated CRC value, which can be passed to this function
    + *              again to continue CRC calculation.
    + */
    +extern LZMA_API(uint32_t) lzma_crc32(
    +		const uint8_t *buf, size_t size, uint32_t crc)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Calculate CRC64
    + *
    + * Calculate CRC64 using the polynomial from the ECMA-182 standard.
    + *
    + * This function is used similarly to lzma_crc32().
    + *
    + * \param       buf     Pointer to the input buffer
    + * \param       size    Size of the input buffer
    + * \param       crc     Previously returned CRC value. This is used to
    + *                      calculate the CRC of a big buffer in smaller chunks.
    + *                      Set to zero when starting a new calculation.
    + *
    + * \return      Updated CRC value, which can be passed to this function
    + *              again to continue CRC calculation.
    + */
    +extern LZMA_API(uint64_t) lzma_crc64(
    +		const uint8_t *buf, size_t size, uint64_t crc)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Get the type of the integrity check
    + *
    + * This function can be called only immediately after lzma_code() has
    + * returned LZMA_NO_CHECK, LZMA_UNSUPPORTED_CHECK, or LZMA_GET_CHECK.
    + * Calling this function in any other situation has undefined behavior.
    + *
    + * \param       strm    Pointer to lzma_stream meeting the above conditions.
    + *
    + * \return      Check ID in the lzma_stream, or undefined if called improperly.
    + */
    +extern LZMA_API(lzma_check) lzma_get_check(const lzma_stream *strm)
    +		lzma_nothrow;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/container.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/container.h
    new file mode 100644
    index 00000000000..ee5d77e4f1a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/container.h
    @@ -0,0 +1,995 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/container.h
    + * \brief       File formats
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/************
    + * Encoding *
    + ************/
    +
    +/**
    + * \brief       Default compression preset
    + *
    + * It's not straightforward to recommend a default preset, because in some
    + * cases keeping the resource usage relatively low is more important that
    + * getting the maximum compression ratio.
    + */
    +#define LZMA_PRESET_DEFAULT     UINT32_C(6)
    +
    +
    +/**
    + * \brief       Mask for preset level
    + *
    + * This is useful only if you need to extract the level from the preset
    + * variable. That should be rare.
    + */
    +#define LZMA_PRESET_LEVEL_MASK  UINT32_C(0x1F)
    +
    +
    +/*
    + * Preset flags
    + *
    + * Currently only one flag is defined.
    + */
    +
    +/**
    + * \brief       Extreme compression preset
    + *
    + * This flag modifies the preset to make the encoding significantly slower
    + * while improving the compression ratio only marginally. This is useful
    + * when you don't mind spending time to get as small result as possible.
    + *
    + * This flag doesn't affect the memory usage requirements of the decoder (at
    + * least not significantly). The memory usage of the encoder may be increased
    + * a little but only at the lowest preset levels (0-3).
    + */
    +#define LZMA_PRESET_EXTREME       (UINT32_C(1) << 31)
    +
    +
    +/**
    + * \brief       Multithreading options
    + */
    +typedef struct {
    +	/**
    +	 * \brief       Flags
    +	 *
    +	 * Set this to zero if no flags are wanted.
    +	 *
    +	 * Encoder: No flags are currently supported.
    +	 *
    +	 * Decoder: Bitwise-or of zero or more of the decoder flags:
    +	 * - LZMA_TELL_NO_CHECK
    +	 * - LZMA_TELL_UNSUPPORTED_CHECK
    +	 * - LZMA_TELL_ANY_CHECK
    +	 * - LZMA_IGNORE_CHECK
    +	 * - LZMA_CONCATENATED
    +	 * - LZMA_FAIL_FAST
    +	 */
    +	uint32_t flags;
    +
    +	/**
    +	 * \brief       Number of worker threads to use
    +	 */
    +	uint32_t threads;
    +
    +	/**
    +	 * \brief       Encoder only: Maximum uncompressed size of a Block
    +	 *
    +	 * The encoder will start a new .xz Block every block_size bytes.
    +	 * Using LZMA_FULL_FLUSH or LZMA_FULL_BARRIER with lzma_code()
    +	 * the caller may tell liblzma to start a new Block earlier.
    +	 *
    +	 * With LZMA2, a recommended block size is 2-4 times the LZMA2
    +	 * dictionary size. With very small dictionaries, it is recommended
    +	 * to use at least 1 MiB block size for good compression ratio, even
    +	 * if this is more than four times the dictionary size. Note that
    +	 * these are only recommendations for typical use cases; feel free
    +	 * to use other values. Just keep in mind that using a block size
    +	 * less than the LZMA2 dictionary size is waste of RAM.
    +	 *
    +	 * Set this to 0 to let liblzma choose the block size depending
    +	 * on the compression options. For LZMA2 it will be 3*dict_size
    +	 * or 1 MiB, whichever is more.
    +	 *
    +	 * For each thread, about 3 * block_size bytes of memory will be
    +	 * allocated. This may change in later liblzma versions. If so,
    +	 * the memory usage will probably be reduced, not increased.
    +	 */
    +	uint64_t block_size;
    +
    +	/**
    +	 * \brief       Timeout to allow lzma_code() to return early
    +	 *
    +	 * Multithreading can make liblzma consume input and produce
    +	 * output in a very bursty way: it may first read a lot of input
    +	 * to fill internal buffers, then no input or output occurs for
    +	 * a while.
    +	 *
    +	 * In single-threaded mode, lzma_code() won't return until it has
    +	 * either consumed all the input or filled the output buffer. If
    +	 * this is done in multithreaded mode, it may cause a call
    +	 * lzma_code() to take even tens of seconds, which isn't acceptable
    +	 * in all applications.
    +	 *
    +	 * To avoid very long blocking times in lzma_code(), a timeout
    +	 * (in milliseconds) may be set here. If lzma_code() would block
    +	 * longer than this number of milliseconds, it will return with
    +	 * LZMA_OK. Reasonable values are 100 ms or more. The xz command
    +	 * line tool uses 300 ms.
    +	 *
    +	 * If long blocking times are acceptable, set timeout to a special
    +	 * value of 0. This will disable the timeout mechanism and will make
    +	 * lzma_code() block until all the input is consumed or the output
    +	 * buffer has been filled.
    +	 *
    +	 * \note        Even with a timeout, lzma_code() might sometimes take
    +	 *              a long time to return. No timing guarantees are made.
    +	 */
    +	uint32_t timeout;
    +
    +	/**
    +	 * \brief       Encoder only: Compression preset
    +	 *
    +	 * The preset is set just like with lzma_easy_encoder().
    +	 * The preset is ignored if filters below is non-NULL.
    +	 */
    +	uint32_t preset;
    +
    +	/**
    +	 * \brief       Encoder only: Filter chain (alternative to a preset)
    +	 *
    +	 * If this is NULL, the preset above is used. Otherwise the preset
    +	 * is ignored and the filter chain specified here is used.
    +	 */
    +	const lzma_filter *filters;
    +
    +	/**
    +	 * \brief       Encoder only: Integrity check type
    +	 *
    +	 * See check.h for available checks. The xz command line tool
    +	 * defaults to LZMA_CHECK_CRC64, which is a good choice if you
    +	 * are unsure.
    +	 */
    +	lzma_check check;
    +
    +	/*
    +	 * Reserved space to allow possible future extensions without
    +	 * breaking the ABI. You should not touch these, because the names
    +	 * of these variables may change. These are and will never be used
    +	 * with the currently supported options, so it is safe to leave these
    +	 * uninitialized.
    +	 */
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum1;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum2;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum3;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int1;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int2;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int3;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int4;
    +
    +	/**
    +	 * \brief       Memory usage limit to reduce the number of threads
    +	 *
    +	 * Encoder: Ignored.
    +	 *
    +	 * Decoder:
    +	 *
    +	 * If the number of threads has been set so high that more than
    +	 * memlimit_threading bytes of memory would be needed, the number
    +	 * of threads will be reduced so that the memory usage will not exceed
    +	 * memlimit_threading bytes. However, if memlimit_threading cannot
    +	 * be met even in single-threaded mode, then decoding will continue
    +	 * in single-threaded mode and memlimit_threading may be exceeded
    +	 * even by a large amount. That is, memlimit_threading will never make
    +	 * lzma_code() return LZMA_MEMLIMIT_ERROR. To truly cap the memory
    +	 * usage, see memlimit_stop below.
    +	 *
    +	 * Setting memlimit_threading to UINT64_MAX or a similar huge value
    +	 * means that liblzma is allowed to keep the whole compressed file
    +	 * and the whole uncompressed file in memory in addition to the memory
    +	 * needed by the decompressor data structures used by each thread!
    +	 * In other words, a reasonable value limit must be set here or it
    +	 * will cause problems sooner or later. If you have no idea what
    +	 * a reasonable value could be, try lzma_physmem() / 4 as a starting
    +	 * point. Setting this limit will never prevent decompression of
    +	 * a file; this will only reduce the number of threads.
    +	 *
    +	 * If memlimit_threading is greater than memlimit_stop, then the value
    +	 * of memlimit_stop will be used for both.
    +	 */
    +	uint64_t memlimit_threading;
    +
    +	/**
    +	 * \brief       Memory usage limit that should never be exceeded
    +	 *
    +	 * Encoder: Ignored.
    +	 *
    +	 * Decoder: If decompressing will need more than this amount of
    +	 * memory even in the single-threaded mode, then lzma_code() will
    +	 * return LZMA_MEMLIMIT_ERROR.
    +	 */
    +	uint64_t memlimit_stop;
    +
    +	/** \private     Reserved member. */
    +	uint64_t reserved_int7;
    +
    +	/** \private     Reserved member. */
    +	uint64_t reserved_int8;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr1;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr2;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr3;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr4;
    +
    +} lzma_mt;
    +
    +
    +/**
    + * \brief       Calculate approximate memory usage of easy encoder
    + *
    + * This function is a wrapper for lzma_raw_encoder_memusage().
    + *
    + * \param       preset  Compression preset (level and possible flags)
    + *
    + * \return      Number of bytes of memory required for the given
    + *              preset when encoding or UINT64_MAX on error.
    + */
    +extern LZMA_API(uint64_t) lzma_easy_encoder_memusage(uint32_t preset)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Calculate approximate decoder memory usage of a preset
    + *
    + * This function is a wrapper for lzma_raw_decoder_memusage().
    + *
    + * \param       preset  Compression preset (level and possible flags)
    + *
    + * \return      Number of bytes of memory required to decompress a file
    + *              that was compressed using the given preset or UINT64_MAX
    + *              on error.
    + */
    +extern LZMA_API(uint64_t) lzma_easy_decoder_memusage(uint32_t preset)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Initialize .xz Stream encoder using a preset number
    + *
    + * This function is intended for those who just want to use the basic features
    + * of liblzma (that is, most developers out there).
    + *
    + * If initialization fails (return value is not LZMA_OK), all the memory
    + * allocated for *strm by liblzma is always freed. Thus, there is no need
    + * to call lzma_end() after failed initialization.
    + *
    + * If initialization succeeds, use lzma_code() to do the actual encoding.
    + * Valid values for 'action' (the second argument of lzma_code()) are
    + * LZMA_RUN, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, and LZMA_FINISH. In future,
    + * there may be compression levels or flags that don't support LZMA_SYNC_FLUSH.
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + * \param       preset  Compression preset to use. A preset consist of level
    + *                      number and zero or more flags. Usually flags aren't
    + *                      used, so preset is simply a number [0, 9] which match
    + *                      the options -0 ... -9 of the xz command line tool.
    + *                      Additional flags can be set using bitwise-or with
    + *                      the preset level number, e.g. 6 | LZMA_PRESET_EXTREME.
    + * \param       check   Integrity check type to use. See check.h for available
    + *                      checks. The xz command line tool defaults to
    + *                      LZMA_CHECK_CRC64, which is a good choice if you are
    + *                      unsure. LZMA_CHECK_CRC32 is good too as long as the
    + *                      uncompressed file is not many gigabytes.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Initialization succeeded. Use lzma_code() to
    + *                encode your data.
    + *              - LZMA_MEM_ERROR: Memory allocation failed.
    + *              - LZMA_OPTIONS_ERROR: The given compression preset is not
    + *                supported by this build of liblzma.
    + *              - LZMA_UNSUPPORTED_CHECK: The given check type is not
    + *                supported by this liblzma build.
    + *              - LZMA_PROG_ERROR: One or more of the parameters have values
    + *                that will never be valid. For example, strm == NULL.
    + */
    +extern LZMA_API(lzma_ret) lzma_easy_encoder(
    +		lzma_stream *strm, uint32_t preset, lzma_check check)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Single-call .xz Stream encoding using a preset number
    + *
    + * The maximum required output buffer size can be calculated with
    + * lzma_stream_buffer_bound().
    + *
    + * \param       preset      Compression preset to use. See the description
    + *                          in lzma_easy_encoder().
    + * \param       check       Type of the integrity check to calculate from
    + *                          uncompressed data.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + * \param       in          Beginning of the input buffer
    + * \param       in_size     Size of the input buffer
    + * \param[out]  out         Beginning of the output buffer
    + * \param[out]  out_pos     The next byte will be written to out[*out_pos].
    + *                          *out_pos is updated only if encoding succeeds.
    + * \param       out_size    Size of the out buffer; the first byte into
    + *                          which no data is written to is out[out_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful.
    + *              - LZMA_BUF_ERROR: Not enough output buffer space.
    + *              - LZMA_UNSUPPORTED_CHECK
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_easy_buffer_encode(
    +		uint32_t preset, lzma_check check,
    +		const lzma_allocator *allocator,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Initialize .xz Stream encoder using a custom filter chain
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + * \param       filters Array of filters terminated with
    + *                      .id == LZMA_VLI_UNKNOWN. See filters.h for more
    + *                      information.
    + * \param       check   Type of the integrity check to calculate from
    + *                      uncompressed data.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Initialization was successful.
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_UNSUPPORTED_CHECK
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_encoder(lzma_stream *strm,
    +		const lzma_filter *filters, lzma_check check)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Calculate approximate memory usage of multithreaded .xz encoder
    + *
    + * Since doing the encoding in threaded mode doesn't affect the memory
    + * requirements of single-threaded decompressor, you can use
    + * lzma_easy_decoder_memusage(options->preset) or
    + * lzma_raw_decoder_memusage(options->filters) to calculate
    + * the decompressor memory requirements.
    + *
    + * \param       options Compression options
    + *
    + * \return      Number of bytes of memory required for encoding with the
    + *              given options. If an error occurs, for example due to
    + *              unsupported preset or filter chain, UINT64_MAX is returned.
    + */
    +extern LZMA_API(uint64_t) lzma_stream_encoder_mt_memusage(
    +		const lzma_mt *options) lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Initialize multithreaded .xz Stream encoder
    + *
    + * This provides the functionality of lzma_easy_encoder() and
    + * lzma_stream_encoder() as a single function for multithreaded use.
    + *
    + * The supported actions for lzma_code() are LZMA_RUN, LZMA_FULL_FLUSH,
    + * LZMA_FULL_BARRIER, and LZMA_FINISH. Support for LZMA_SYNC_FLUSH might be
    + * added in the future.
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + * \param       options Pointer to multithreaded compression options
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_UNSUPPORTED_CHECK
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_encoder_mt(
    +		lzma_stream *strm, const lzma_mt *options)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Calculate recommended Block size for multithreaded .xz encoder
    + *
    + * This calculates a recommended Block size for multithreaded encoding given
    + * a filter chain. This is used internally by lzma_stream_encoder_mt() to
    + * determine the Block size if the block_size member is not set to the
    + * special value of 0 in the lzma_mt options struct.
    + *
    + * If one wishes to change the filters between Blocks, this function is
    + * helpful to set the block_size member of the lzma_mt struct before calling
    + * lzma_stream_encoder_mt(). Since the block_size member represents the
    + * maximum possible Block size for the multithreaded .xz encoder, one can
    + * use this function to find the maximum recommended Block size based on
    + * all planned filter chains. Otherwise, the multithreaded encoder will
    + * base its maximum Block size on the first filter chain used (if the
    + * block_size member is not set), which may unnecessarily limit the Block
    + * size for a later filter chain.
    + *
    + * \param       filters   Array of filters terminated with
    + *                        .id == LZMA_VLI_UNKNOWN.
    + *
    + * \return      Recommended Block size in bytes, or UINT64_MAX if
    + *              an error occurred.
    + */
    +extern LZMA_API(uint64_t) lzma_mt_block_size(const lzma_filter *filters)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Initialize .lzma encoder (legacy file format)
    + *
    + * The .lzma format is sometimes called the LZMA_Alone format, which is the
    + * reason for the name of this function. The .lzma format supports only the
    + * LZMA1 filter. There is no support for integrity checks like CRC32.
    + *
    + * Use this function if and only if you need to create files readable by
    + * legacy LZMA tools such as LZMA Utils 4.32.x. Moving to the .xz format
    + * is strongly recommended.
    + *
    + * The valid action values for lzma_code() are LZMA_RUN and LZMA_FINISH.
    + * No kind of flushing is supported, because the file format doesn't make
    + * it possible.
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + * \param       options Pointer to encoder options
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_alone_encoder(
    +		lzma_stream *strm, const lzma_options_lzma *options)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Calculate output buffer size for single-call Stream encoder
    + *
    + * When trying to compress incompressible data, the encoded size will be
    + * slightly bigger than the input data. This function calculates how much
    + * output buffer space is required to be sure that lzma_stream_buffer_encode()
    + * doesn't return LZMA_BUF_ERROR.
    + *
    + * The calculated value is not exact, but it is guaranteed to be big enough.
    + * The actual maximum output space required may be slightly smaller (up to
    + * about 100 bytes). This should not be a problem in practice.
    + *
    + * If the calculated maximum size doesn't fit into size_t or would make the
    + * Stream grow past LZMA_VLI_MAX (which should never happen in practice),
    + * zero is returned to indicate the error.
    + *
    + * \note        The limit calculated by this function applies only to
    + *              single-call encoding. Multi-call encoding may (and probably
    + *              will) have larger maximum expansion when encoding
    + *              incompressible data. Currently there is no function to
    + *              calculate the maximum expansion of multi-call encoding.
    + *
    + * \param       uncompressed_size   Size in bytes of the uncompressed
    + *                                  input data
    + *
    + * \return      Maximum number of bytes needed to store the compressed data.
    + */
    +extern LZMA_API(size_t) lzma_stream_buffer_bound(size_t uncompressed_size)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Single-call .xz Stream encoder
    + *
    + * \param       filters     Array of filters terminated with
    + *                          .id == LZMA_VLI_UNKNOWN. See filters.h for more
    + *                          information.
    + * \param       check       Type of the integrity check to calculate from
    + *                          uncompressed data.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + * \param       in          Beginning of the input buffer
    + * \param       in_size     Size of the input buffer
    + * \param[out]  out         Beginning of the output buffer
    + * \param[out]  out_pos     The next byte will be written to out[*out_pos].
    + *                          *out_pos is updated only if encoding succeeds.
    + * \param       out_size    Size of the out buffer; the first byte into
    + *                          which no data is written to is out[out_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful.
    + *              - LZMA_BUF_ERROR: Not enough output buffer space.
    + *              - LZMA_UNSUPPORTED_CHECK
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_buffer_encode(
    +		lzma_filter *filters, lzma_check check,
    +		const lzma_allocator *allocator,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       MicroLZMA encoder
    + *
    + * The MicroLZMA format is a raw LZMA stream whose first byte (always 0x00)
    + * has been replaced with bitwise-negation of the LZMA properties (lc/lp/pb).
    + * This encoding ensures that the first byte of MicroLZMA stream is never
    + * 0x00. There is no end of payload marker and thus the uncompressed size
    + * must be stored separately. For the best error detection the dictionary
    + * size should be stored separately as well but alternatively one may use
    + * the uncompressed size as the dictionary size when decoding.
    + *
    + * With the MicroLZMA encoder, lzma_code() behaves slightly unusually.
    + * The action argument must be LZMA_FINISH and the return value will never be
    + * LZMA_OK. Thus the encoding is always done with a single lzma_code() after
    + * the initialization. The benefit of the combination of initialization
    + * function and lzma_code() is that memory allocations can be re-used for
    + * better performance.
    + *
    + * lzma_code() will try to encode as much input as is possible to fit into
    + * the given output buffer. If not all input can be encoded, the stream will
    + * be finished without encoding all the input. The caller must check both
    + * input and output buffer usage after lzma_code() (total_in and total_out
    + * in lzma_stream can be convenient). Often lzma_code() can fill the output
    + * buffer completely if there is a lot of input, but sometimes a few bytes
    + * may remain unused because the next LZMA symbol would require more space.
    + *
    + * lzma_stream.avail_out must be at least 6. Otherwise LZMA_PROG_ERROR
    + * will be returned.
    + *
    + * The LZMA dictionary should be reasonably low to speed up the encoder
    + * re-initialization. A good value is bigger than the resulting
    + * uncompressed size of most of the output chunks. For example, if output
    + * size is 4 KiB, dictionary size of 32 KiB or 64 KiB is good. If the
    + * data compresses extremely well, even 128 KiB may be useful.
    + *
    + * The MicroLZMA format and this encoder variant were made with the EROFS
    + * file system in mind. This format may be convenient in other embedded
    + * uses too where many small streams are needed. XZ Embedded includes a
    + * decoder for this format.
    + *
    + * \param       strm    Pointer to lzma_stream that is at least initialized
    + *                      with LZMA_STREAM_INIT.
    + * \param       options Pointer to encoder options
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_STREAM_END: All good. Check the amounts of input used
    + *                and output produced. Store the amount of input used
    + *                (uncompressed size) as it needs to be known to decompress
    + *                the data.
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_PROG_ERROR: In addition to the generic reasons for this
    + *                error code, this may also be returned if there isn't enough
    + *                output space (6 bytes) to create a valid MicroLZMA stream.
    + */
    +extern LZMA_API(lzma_ret) lzma_microlzma_encoder(
    +		lzma_stream *strm, const lzma_options_lzma *options)
    +		lzma_nothrow;
    +
    +
    +/************
    + * Decoding *
    + ************/
    +
    +/**
    + * This flag makes lzma_code() return LZMA_NO_CHECK if the input stream
    + * being decoded has no integrity check. Note that when used with
    + * lzma_auto_decoder(), all .lzma files will trigger LZMA_NO_CHECK
    + * if LZMA_TELL_NO_CHECK is used.
    + */
    +#define LZMA_TELL_NO_CHECK              UINT32_C(0x01)
    +
    +
    +/**
    + * This flag makes lzma_code() return LZMA_UNSUPPORTED_CHECK if the input
    + * stream has an integrity check, but the type of the integrity check is not
    + * supported by this liblzma version or build. Such files can still be
    + * decoded, but the integrity check cannot be verified.
    + */
    +#define LZMA_TELL_UNSUPPORTED_CHECK     UINT32_C(0x02)
    +
    +
    +/**
    + * This flag makes lzma_code() return LZMA_GET_CHECK as soon as the type
    + * of the integrity check is known. The type can then be got with
    + * lzma_get_check().
    + */
    +#define LZMA_TELL_ANY_CHECK             UINT32_C(0x04)
    +
    +
    +/**
    + * This flag makes lzma_code() not calculate and verify the integrity check
    + * of the compressed data in .xz files. This means that invalid integrity
    + * check values won't be detected and LZMA_DATA_ERROR won't be returned in
    + * such cases.
    + *
    + * This flag only affects the checks of the compressed data itself; the CRC32
    + * values in the .xz headers will still be verified normally.
    + *
    + * Don't use this flag unless you know what you are doing. Possible reasons
    + * to use this flag:
    + *
    + *   - Trying to recover data from a corrupt .xz file.
    + *
    + *   - Speeding up decompression, which matters mostly with SHA-256
    + *     or with files that have compressed extremely well. It's recommended
    + *     to not use this flag for this purpose unless the file integrity is
    + *     verified externally in some other way.
    + *
    + * Support for this flag was added in liblzma 5.1.4beta.
    + */
    +#define LZMA_IGNORE_CHECK               UINT32_C(0x10)
    +
    +
    +/**
    + * This flag enables decoding of concatenated files with file formats that
    + * allow concatenating compressed files as is. From the formats currently
    + * supported by liblzma, only the .xz and .lz formats allow concatenated
    + * files. Concatenated files are not allowed with the legacy .lzma format.
    + *
    + * This flag also affects the usage of the 'action' argument for lzma_code().
    + * When LZMA_CONCATENATED is used, lzma_code() won't return LZMA_STREAM_END
    + * unless LZMA_FINISH is used as 'action'. Thus, the application has to set
    + * LZMA_FINISH in the same way as it does when encoding.
    + *
    + * If LZMA_CONCATENATED is not used, the decoders still accept LZMA_FINISH
    + * as 'action' for lzma_code(), but the usage of LZMA_FINISH isn't required.
    + */
    +#define LZMA_CONCATENATED               UINT32_C(0x08)
    +
    +
    +/**
    + * This flag makes the threaded decoder report errors (like LZMA_DATA_ERROR)
    + * as soon as they are detected. This saves time when the application has no
    + * interest in a partially decompressed truncated or corrupt file. Note that
    + * due to timing randomness, if the same truncated or corrupt input is
    + * decompressed multiple times with this flag, a different amount of output
    + * may be produced by different runs, and even the error code might vary.
    + *
    + * When using LZMA_FAIL_FAST, it is recommended to use LZMA_FINISH to tell
    + * the decoder when no more input will be coming because it can help fast
    + * detection and reporting of truncated files. Note that in this situation
    + * truncated files might be diagnosed with LZMA_DATA_ERROR instead of
    + * LZMA_OK or LZMA_BUF_ERROR!
    + *
    + * Without this flag the threaded decoder will provide as much output as
    + * possible at first and then report the pending error. This default behavior
    + * matches the single-threaded decoder and provides repeatable behavior
    + * with truncated or corrupt input. There are a few special cases where the
    + * behavior can still differ like memory allocation failures (LZMA_MEM_ERROR).
    + *
    + * Single-threaded decoders currently ignore this flag.
    + *
    + * Support for this flag was added in liblzma 5.3.3alpha. Note that in older
    + * versions this flag isn't supported (LZMA_OPTIONS_ERROR) even by functions
    + * that ignore this flag in newer liblzma versions.
    + */
    +#define LZMA_FAIL_FAST                  UINT32_C(0x20)
    +
    +
    +/**
    + * \brief       Initialize .xz Stream decoder
    + *
    + * \param       strm        Pointer to lzma_stream that is at least initialized
    + *                          with LZMA_STREAM_INIT.
    + * \param       memlimit    Memory usage limit as bytes. Use UINT64_MAX
    + *                          to effectively disable the limiter. liblzma
    + *                          5.2.3 and earlier don't allow 0 here and return
    + *                          LZMA_PROG_ERROR; later versions treat 0 as if 1
    + *                          had been specified.
    + * \param       flags       Bitwise-or of zero or more of the decoder flags:
    + *                          LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
    + *                          LZMA_TELL_ANY_CHECK, LZMA_IGNORE_CHECK,
    + *                          LZMA_CONCATENATED, LZMA_FAIL_FAST
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Initialization was successful.
    + *              - LZMA_MEM_ERROR: Cannot allocate memory.
    + *              - LZMA_OPTIONS_ERROR: Unsupported flags
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_decoder(
    +		lzma_stream *strm, uint64_t memlimit, uint32_t flags)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Initialize multithreaded .xz Stream decoder
    + *
    + * The decoder can decode multiple Blocks in parallel. This requires that each
    + * Block Header contains the Compressed Size and Uncompressed size fields
    + * which are added by the multi-threaded encoder, see lzma_stream_encoder_mt().
    + *
    + * A Stream with one Block will only utilize one thread. A Stream with multiple
    + * Blocks but without size information in Block Headers will be processed in
    + * single-threaded mode in the same way as done by lzma_stream_decoder().
    + * Concatenated Streams are processed one Stream at a time; no inter-Stream
    + * parallelization is done.
    + *
    + * This function behaves like lzma_stream_decoder() when options->threads == 1
    + * and options->memlimit_threading <= 1.
    + *
    + * \param       strm        Pointer to lzma_stream that is at least initialized
    + *                          with LZMA_STREAM_INIT.
    + * \param       options     Pointer to multithreaded compression options
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Initialization was successful.
    + *              - LZMA_MEM_ERROR: Cannot allocate memory.
    + *              - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
    + *              - LZMA_OPTIONS_ERROR: Unsupported flags.
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_decoder_mt(
    +		lzma_stream *strm, const lzma_mt *options)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Decode .xz, .lzma, and .lz (lzip) files with autodetection
    + *
    + * This decoder autodetects between the .xz, .lzma, and .lz file formats,
    + * and calls lzma_stream_decoder(), lzma_alone_decoder(), or
    + * lzma_lzip_decoder() once the type of the input file has been detected.
    + *
    + * Support for .lz was added in 5.4.0.
    + *
    + * If the flag LZMA_CONCATENATED is used and the input is a .lzma file:
    + * For historical reasons concatenated .lzma files aren't supported.
    + * If there is trailing data after one .lzma stream, lzma_code() will
    + * return LZMA_DATA_ERROR. (lzma_alone_decoder() doesn't have such a check
    + * as it doesn't support any decoder flags. It will return LZMA_STREAM_END
    + * after one .lzma stream.)
    + *
    + * \param       strm        Pointer to lzma_stream that is at least initialized
    + *                          with LZMA_STREAM_INIT.
    + * \param       memlimit    Memory usage limit as bytes. Use UINT64_MAX
    + *                          to effectively disable the limiter. liblzma
    + *                          5.2.3 and earlier don't allow 0 here and return
    + *                          LZMA_PROG_ERROR; later versions treat 0 as if 1
    + *                          had been specified.
    + * \param       flags       Bitwise-or of zero or more of the decoder flags:
    + *                          LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
    + *                          LZMA_TELL_ANY_CHECK, LZMA_IGNORE_CHECK,
    + *                          LZMA_CONCATENATED, LZMA_FAIL_FAST
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Initialization was successful.
    + *              - LZMA_MEM_ERROR: Cannot allocate memory.
    + *              - LZMA_OPTIONS_ERROR: Unsupported flags
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_auto_decoder(
    +		lzma_stream *strm, uint64_t memlimit, uint32_t flags)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Initialize .lzma decoder (legacy file format)
    + *
    + * Valid 'action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
    + * There is no need to use LZMA_FINISH, but it's allowed because it may
    + * simplify certain types of applications.
    + *
    + * \param       strm        Pointer to lzma_stream that is at least initialized
    + *                          with LZMA_STREAM_INIT.
    + * \param       memlimit    Memory usage limit as bytes. Use UINT64_MAX
    + *                          to effectively disable the limiter. liblzma
    + *                          5.2.3 and earlier don't allow 0 here and return
    + *                          LZMA_PROG_ERROR; later versions treat 0 as if 1
    + *                          had been specified.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_alone_decoder(
    +		lzma_stream *strm, uint64_t memlimit)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Initialize .lz (lzip) decoder (a foreign file format)
    + *
    + * This decoder supports the .lz format version 0 and the unextended .lz
    + * format version 1:
    + *
    + *   - Files in the format version 0 were produced by lzip 1.3 and older.
    + *     Such files aren't common but may be found from file archives
    + *     as a few source packages were released in this format. People
    + *     might have old personal files in this format too. Decompression
    + *     support for the format version 0 was removed in lzip 1.18.
    + *
    + *   - lzip 1.3 added decompression support for .lz format version 1 files.
    + *     Compression support was added in lzip 1.4. In lzip 1.6 the .lz format
    + *     version 1 was extended to support the Sync Flush marker. This extension
    + *     is not supported by liblzma. lzma_code() will return LZMA_DATA_ERROR
    + *     at the location of the Sync Flush marker. In practice files with
    + *     the Sync Flush marker are very rare and thus liblzma can decompress
    + *     almost all .lz files.
    + *
    + * Just like with lzma_stream_decoder() for .xz files, LZMA_CONCATENATED
    + * should be used when decompressing normal standalone .lz files.
    + *
    + * The .lz format allows putting non-.lz data at the end of a file after at
    + * least one valid .lz member. That is, one can append custom data at the end
    + * of a .lz file and the decoder is required to ignore it. In liblzma this
    + * is relevant only when LZMA_CONCATENATED is used. In that case lzma_code()
    + * will return LZMA_STREAM_END and leave lzma_stream.next_in pointing to
    + * the first byte of the non-.lz data. An exception to this is if the first
    + * 1-3 bytes of the non-.lz data are identical to the .lz magic bytes
    + * (0x4C, 0x5A, 0x49, 0x50; "LZIP" in US-ASCII). In such a case the 1-3 bytes
    + * will have been ignored by lzma_code(). If one wishes to locate the non-.lz
    + * data reliably, one must ensure that the first byte isn't 0x4C. Actually
    + * one should ensure that none of the first four bytes of trailing data are
    + * equal to the magic bytes because lzip >= 1.20 requires it by default.
    + *
    + * \param       strm        Pointer to lzma_stream that is at least initialized
    + *                          with LZMA_STREAM_INIT.
    + * \param       memlimit    Memory usage limit as bytes. Use UINT64_MAX
    + *                          to effectively disable the limiter.
    + * \param       flags       Bitwise-or of flags, or zero for no flags.
    + *                          All decoder flags listed above are supported
    + *                          although only LZMA_CONCATENATED and (in very rare
    + *                          cases) LZMA_IGNORE_CHECK are actually useful.
    + *                          LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
    + *                          and LZMA_FAIL_FAST do nothing. LZMA_TELL_ANY_CHECK
    + *                          is supported for consistency only as CRC32 is
    + *                          always used in the .lz format.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Initialization was successful.
    + *              - LZMA_MEM_ERROR: Cannot allocate memory.
    + *              - LZMA_OPTIONS_ERROR: Unsupported flags
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_lzip_decoder(
    +		lzma_stream *strm, uint64_t memlimit, uint32_t flags)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Single-call .xz Stream decoder
    + *
    + * \param       memlimit    Pointer to how much memory the decoder is allowed
    + *                          to allocate. The value pointed by this pointer is
    + *                          modified if and only if LZMA_MEMLIMIT_ERROR is
    + *                          returned.
    + * \param       flags       Bitwise-or of zero or more of the decoder flags:
    + *                          LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
    + *                          LZMA_IGNORE_CHECK, LZMA_CONCATENATED,
    + *                          LZMA_FAIL_FAST. Note that LZMA_TELL_ANY_CHECK
    + *                          is not allowed and will return LZMA_PROG_ERROR.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + * \param       in          Beginning of the input buffer
    + * \param       in_pos      The next byte will be read from in[*in_pos].
    + *                          *in_pos is updated only if decoding succeeds.
    + * \param       in_size     Size of the input buffer; the first byte that
    + *                          won't be read is in[in_size].
    + * \param[out]  out         Beginning of the output buffer
    + * \param[out]  out_pos     The next byte will be written to out[*out_pos].
    + *                          *out_pos is updated only if decoding succeeds.
    + * \param       out_size    Size of the out buffer; the first byte into
    + *                          which no data is written to is out[out_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Decoding was successful.
    + *              - LZMA_FORMAT_ERROR
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_NO_CHECK: This can be returned only if using
    + *                the LZMA_TELL_NO_CHECK flag.
    + *              - LZMA_UNSUPPORTED_CHECK: This can be returned only if using
    + *                the LZMA_TELL_UNSUPPORTED_CHECK flag.
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
    + *                The minimum required memlimit value was stored to *memlimit.
    + *              - LZMA_BUF_ERROR: Output buffer was too small.
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_buffer_decode(
    +		uint64_t *memlimit, uint32_t flags,
    +		const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       MicroLZMA decoder
    + *
    + * See lzma_microlzma_encoder() for more information.
    + *
    + * The lzma_code() usage with this decoder is completely normal. The
    + * special behavior of lzma_code() applies to lzma_microlzma_encoder() only.
    + *
    + * \param       strm        Pointer to lzma_stream that is at least initialized
    + *                          with LZMA_STREAM_INIT.
    + * \param       comp_size   Compressed size of the MicroLZMA stream.
    + *                          The caller must somehow know this exactly.
    + * \param       uncomp_size Uncompressed size of the MicroLZMA stream.
    + *                          If the exact uncompressed size isn't known, this
    + *                          can be set to a value that is at most as big as
    + *                          the exact uncompressed size would be, but then the
    + *                          next argument uncomp_size_is_exact must be false.
    + * \param       uncomp_size_is_exact
    + *                          If true, uncomp_size must be exactly correct.
    + *                          This will improve error detection at the end of
    + *                          the stream. If the exact uncompressed size isn't
    + *                          known, this must be false. uncomp_size must still
    + *                          be at most as big as the exact uncompressed size
    + *                          is. Setting this to false when the exact size is
    + *                          known will work but error detection at the end of
    + *                          the stream will be weaker.
    + * \param       dict_size   LZMA dictionary size that was used when
    + *                          compressing the data. It is OK to use a bigger
    + *                          value too but liblzma will then allocate more
    + *                          memory than would actually be required and error
    + *                          detection will be slightly worse. (Note that with
    + *                          the implementation in XZ Embedded it doesn't
    + *                          affect the memory usage if one specifies bigger
    + *                          dictionary than actually required.)
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_microlzma_decoder(
    +		lzma_stream *strm, uint64_t comp_size,
    +		uint64_t uncomp_size, lzma_bool uncomp_size_is_exact,
    +		uint32_t dict_size) lzma_nothrow;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/delta.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/delta.h
    new file mode 100644
    index 00000000000..5ebacef8158
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/delta.h
    @@ -0,0 +1,95 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/delta.h
    + * \brief       Delta filter
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       Filter ID
    + *
    + * Filter ID of the Delta filter. This is used as lzma_filter.id.
    + */
    +#define LZMA_FILTER_DELTA       LZMA_VLI_C(0x03)
    +
    +
    +/**
    + * \brief       Type of the delta calculation
    + *
    + * Currently only byte-wise delta is supported. Other possible types could
    + * be, for example, delta of 16/32/64-bit little/big endian integers, but
    + * these are not currently planned since byte-wise delta is almost as good.
    + */
    +typedef enum {
    +	LZMA_DELTA_TYPE_BYTE
    +} lzma_delta_type;
    +
    +
    +/**
    + * \brief       Options for the Delta filter
    + *
    + * These options are needed by both encoder and decoder.
    + */
    +typedef struct {
    +	/** For now, this must always be LZMA_DELTA_TYPE_BYTE. */
    +	lzma_delta_type type;
    +
    +	/**
    +	 * \brief       Delta distance
    +	 *
    +	 * With the only currently supported type, LZMA_DELTA_TYPE_BYTE,
    +	 * the distance is as bytes.
    +	 *
    +	 * Examples:
    +	 *  - 16-bit stereo audio: distance = 4 bytes
    +	 *  - 24-bit RGB image data: distance = 3 bytes
    +	 */
    +	uint32_t dist;
    +
    +	/**
    +	 * \brief       Minimum value for lzma_options_delta.dist.
    +	 */
    +#	define LZMA_DELTA_DIST_MIN 1
    +
    +	/**
    +	 * \brief       Maximum value for lzma_options_delta.dist.
    +	 */
    +#	define LZMA_DELTA_DIST_MAX 256
    +
    +	/*
    +	 * Reserved space to allow possible future extensions without
    +	 * breaking the ABI. You should not touch these, because the names
    +	 * of these variables may change. These are and will never be used
    +	 * when type is LZMA_DELTA_TYPE_BYTE, so it is safe to leave these
    +	 * uninitialized.
    +	 */
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int1;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int2;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int3;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int4;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr1;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr2;
    +
    +} lzma_options_delta;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/filter.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/filter.h
    new file mode 100644
    index 00000000000..e86809c4e39
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/filter.h
    @@ -0,0 +1,769 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/filter.h
    + * \brief       Common filter related types and functions
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       Maximum number of filters in a chain
    + *
    + * A filter chain can have 1-4 filters, of which three are allowed to change
    + * the size of the data. Usually only one or two filters are needed.
    + */
    +#define LZMA_FILTERS_MAX 4
    +
    +
    +/**
    + * \brief       Filter options
    + *
    + * This structure is used to pass a Filter ID and a pointer to the filter's
    + * options to liblzma. A few functions work with a single lzma_filter
    + * structure, while most functions expect a filter chain.
    + *
    + * A filter chain is indicated with an array of lzma_filter structures.
    + * The array is terminated with .id = LZMA_VLI_UNKNOWN. Thus, the filter
    + * array must have LZMA_FILTERS_MAX + 1 elements (that is, five) to
    + * be able to hold any arbitrary filter chain. This is important when
    + * using lzma_block_header_decode() from block.h, because a filter array
    + * that is too small would make liblzma write past the end of the array.
    + */
    +typedef struct {
    +	/**
    +	 * \brief       Filter ID
    +	 *
    +	 * Use constants whose name begin with 'LZMA_FILTER_' to specify
    +	 * different filters. In an array of lzma_filter structures, use
    +	 * LZMA_VLI_UNKNOWN to indicate end of filters.
    +	 *
    +	 * \note        This is not an enum, because on some systems enums
    +	 *              cannot be 64-bit.
    +	 */
    +	lzma_vli id;
    +
    +	/**
    +	 * \brief       Pointer to filter-specific options structure
    +	 *
    +	 * If the filter doesn't need options, set this to NULL. If id is
    +	 * set to LZMA_VLI_UNKNOWN, options is ignored, and thus
    +	 * doesn't need be initialized.
    +	 */
    +	void *options;
    +
    +} lzma_filter;
    +
    +
    +/**
    + * \brief       Test if the given Filter ID is supported for encoding
    + *
    + * \param       id      Filter ID
    + *
    + * \return      lzma_bool:
    + *              - true if the Filter ID is supported for encoding by this
    + *                liblzma build.
    +  *             - false otherwise.
    + */
    +extern LZMA_API(lzma_bool) lzma_filter_encoder_is_supported(lzma_vli id)
    +		lzma_nothrow lzma_attr_const;
    +
    +
    +/**
    + * \brief       Test if the given Filter ID is supported for decoding
    + *
    + * \param       id      Filter ID
    + *
    + * \return      lzma_bool:
    + *              - true if the Filter ID is supported for decoding by this
    + *                liblzma build.
    + *              - false otherwise.
    + */
    +extern LZMA_API(lzma_bool) lzma_filter_decoder_is_supported(lzma_vli id)
    +		lzma_nothrow lzma_attr_const;
    +
    +
    +/**
    + * \brief       Copy the filters array
    + *
    + * Copy the Filter IDs and filter-specific options from src to dest.
    + * Up to LZMA_FILTERS_MAX filters are copied, plus the terminating
    + * .id == LZMA_VLI_UNKNOWN. Thus, dest should have at least
    + * LZMA_FILTERS_MAX + 1 elements space unless the caller knows that
    + * src is smaller than that.
    + *
    + * Unless the filter-specific options is NULL, the Filter ID has to be
    + * supported by liblzma, because liblzma needs to know the size of every
    + * filter-specific options structure. The filter-specific options are not
    + * validated. If options is NULL, any unsupported Filter IDs are copied
    + * without returning an error.
    + *
    + * Old filter-specific options in dest are not freed, so dest doesn't
    + * need to be initialized by the caller in any way.
    + *
    + * If an error occurs, memory possibly already allocated by this function
    + * is always freed. liblzma versions older than 5.2.7 may modify the dest
    + * array and leave its contents in an undefined state if an error occurs.
    + * liblzma 5.2.7 and newer only modify the dest array when returning LZMA_OK.
    + *
    + * \param       src         Array of filters terminated with
    + *                          .id == LZMA_VLI_UNKNOWN.
    + * \param[out]  dest        Destination filter array
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_OPTIONS_ERROR: Unsupported Filter ID and its options
    + *                is not NULL.
    + *              - LZMA_PROG_ERROR: src or dest is NULL.
    + */
    +extern LZMA_API(lzma_ret) lzma_filters_copy(
    +		const lzma_filter *src, lzma_filter *dest,
    +		const lzma_allocator *allocator)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Free the options in the array of lzma_filter structures
    + *
    + * This frees the filter chain options. The filters array itself is not freed.
    + *
    + * The filters array must have at most LZMA_FILTERS_MAX + 1 elements
    + * including the terminating element which must have .id = LZMA_VLI_UNKNOWN.
    + * For all elements before the terminating element:
    + *   - options will be freed using the given lzma_allocator or,
    + *     if allocator is NULL, using free().
    + *   - options will be set to NULL.
    + *   - id will be set to LZMA_VLI_UNKNOWN.
    + *
    + * If filters is NULL, this does nothing. Again, this never frees the
    + * filters array itself.
    + *
    + * \param       filters     Array of filters terminated with
    + *                          .id == LZMA_VLI_UNKNOWN.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + */
    +extern LZMA_API(void) lzma_filters_free(
    +		lzma_filter *filters, const lzma_allocator *allocator)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Calculate approximate memory requirements for raw encoder
    + *
    + * This function can be used to calculate the memory requirements for
    + * Block and Stream encoders too because Block and Stream encoders don't
    + * need significantly more memory than raw encoder.
    + *
    + * \param       filters     Array of filters terminated with
    + *                          .id == LZMA_VLI_UNKNOWN.
    + *
    + * \return      Number of bytes of memory required for the given
    + *              filter chain when encoding or UINT64_MAX on error.
    + */
    +extern LZMA_API(uint64_t) lzma_raw_encoder_memusage(const lzma_filter *filters)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Calculate approximate memory requirements for raw decoder
    + *
    + * This function can be used to calculate the memory requirements for
    + * Block and Stream decoders too because Block and Stream decoders don't
    + * need significantly more memory than raw decoder.
    + *
    + * \param       filters     Array of filters terminated with
    + *                          .id == LZMA_VLI_UNKNOWN.
    + *
    + * \return      Number of bytes of memory required for the given
    + *              filter chain when decoding or UINT64_MAX on error.
    + */
    +extern LZMA_API(uint64_t) lzma_raw_decoder_memusage(const lzma_filter *filters)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Initialize raw encoder
    + *
    + * This function may be useful when implementing custom file formats.
    + *
    + * The 'action' with lzma_code() can be LZMA_RUN, LZMA_SYNC_FLUSH (if the
    + * filter chain supports it), or LZMA_FINISH.
    + *
    + * \param       strm      Pointer to lzma_stream that is at least
    + *                        initialized with LZMA_STREAM_INIT.
    + * \param       filters   Array of filters terminated with
    + *                        .id == LZMA_VLI_UNKNOWN.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_raw_encoder(
    +		lzma_stream *strm, const lzma_filter *filters)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Initialize raw decoder
    + *
    + * The initialization of raw decoder goes similarly to raw encoder.
    + *
    + * The 'action' with lzma_code() can be LZMA_RUN or LZMA_FINISH. Using
    + * LZMA_FINISH is not required, it is supported just for convenience.
    + *
    + * \param       strm      Pointer to lzma_stream that is at least
    + *                        initialized with LZMA_STREAM_INIT.
    + * \param       filters   Array of filters terminated with
    + *                        .id == LZMA_VLI_UNKNOWN.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_raw_decoder(
    +		lzma_stream *strm, const lzma_filter *filters)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Update the filter chain in the encoder
    + *
    + * This function may be called after lzma_code() has returned LZMA_STREAM_END
    + * when LZMA_FULL_BARRIER, LZMA_FULL_FLUSH, or LZMA_SYNC_FLUSH was used:
    + *
    + *  - After LZMA_FULL_BARRIER or LZMA_FULL_FLUSH: Single-threaded .xz Stream
    + *    encoder (lzma_stream_encoder()) and (since liblzma 5.4.0) multi-threaded
    + *    Stream encoder (lzma_stream_encoder_mt()) allow setting a new filter
    + *    chain to be used for the next Block(s).
    + *
    + *  - After LZMA_SYNC_FLUSH: Raw encoder (lzma_raw_encoder()),
    + *    Block encoder (lzma_block_encoder()), and single-threaded .xz Stream
    + *    encoder (lzma_stream_encoder()) allow changing certain filter-specific
    + *    options in the middle of encoding. The actual filters in the chain
    + *    (Filter IDs) must not be changed! Currently only the lc, lp, and pb
    + *    options of LZMA2 (not LZMA1) can be changed this way.
    + *
    + *  - In the future some filters might allow changing some of their options
    + *    without any barrier or flushing but currently such filters don't exist.
    + *
    + * This function may also be called when no data has been compressed yet
    + * although this is rarely useful. In that case, this function will behave
    + * as if LZMA_FULL_FLUSH (Stream encoders) or LZMA_SYNC_FLUSH (Raw or Block
    + * encoder) had been used right before calling this function.
    + *
    + * \param       strm      Pointer to lzma_stream that is at least
    + *                        initialized with LZMA_STREAM_INIT.
    + * \param       filters   Array of filters terminated with
    + *                        .id == LZMA_VLI_UNKNOWN.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_MEMLIMIT_ERROR
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_filters_update(
    +		lzma_stream *strm, const lzma_filter *filters) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Single-call raw encoder
    + *
    + * \note        There is no function to calculate how big output buffer
    + *              would surely be big enough. (lzma_stream_buffer_bound()
    + *              works only for lzma_stream_buffer_encode(); raw encoder
    + *              won't necessarily meet that bound.)
    + *
    + * \param       filters     Array of filters terminated with
    + *                          .id == LZMA_VLI_UNKNOWN.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + * \param       in          Beginning of the input buffer
    + * \param       in_size     Size of the input buffer
    + * \param[out]  out         Beginning of the output buffer
    + * \param[out]  out_pos     The next byte will be written to out[*out_pos].
    + *                          *out_pos is updated only if encoding succeeds.
    + * \param       out_size    Size of the out buffer; the first byte into
    + *                          which no data is written to is out[out_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful.
    + *              - LZMA_BUF_ERROR: Not enough output buffer space.
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_raw_buffer_encode(
    +		const lzma_filter *filters, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t in_size, uint8_t *out,
    +		size_t *out_pos, size_t out_size) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Single-call raw decoder
    + *
    + * \param       filters     Array of filters terminated with
    + *                          .id == LZMA_VLI_UNKNOWN.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + * \param       in          Beginning of the input buffer
    + * \param       in_pos      The next byte will be read from in[*in_pos].
    + *                          *in_pos is updated only if decoding succeeds.
    + * \param       in_size     Size of the input buffer; the first byte that
    + *                          won't be read is in[in_size].
    + * \param[out]  out         Beginning of the output buffer
    + * \param[out]  out_pos     The next byte will be written to out[*out_pos].
    + *                          *out_pos is updated only if encoding succeeds.
    + * \param       out_size    Size of the out buffer; the first byte into
    + *                          which no data is written to is out[out_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Decoding was successful.
    + *              - LZMA_BUF_ERROR: Not enough output buffer space.
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_raw_buffer_decode(
    +		const lzma_filter *filters, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Get the size of the Filter Properties field
    + *
    + * This function may be useful when implementing custom file formats
    + * using the raw encoder and decoder.
    + *
    + * \note        This function validates the Filter ID, but does not
    + *              necessarily validate the options. Thus, it is possible
    + *              that this returns LZMA_OK while the following call to
    + *              lzma_properties_encode() returns LZMA_OPTIONS_ERROR.
    + *
    + * \param[out]  size    Pointer to uint32_t to hold the size of the properties
    + * \param       filter  Filter ID and options (the size of the properties may
    + *                      vary depending on the options)
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_properties_size(
    +		uint32_t *size, const lzma_filter *filter) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Encode the Filter Properties field
    + *
    + * \note        Even this function won't validate more options than actually
    + *              necessary. Thus, it is possible that encoding the properties
    + *              succeeds but using the same options to initialize the encoder
    + *              will fail.
    + *
    + * \note        If lzma_properties_size() indicated that the size
    + *              of the Filter Properties field is zero, calling
    + *              lzma_properties_encode() is not required, but it
    + *              won't do any harm either.
    + *
    + * \param       filter  Filter ID and options
    + * \param[out]  props   Buffer to hold the encoded options. The size of
    + *                      the buffer must have been already determined with
    + *                      lzma_properties_size().
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_properties_encode(
    +		const lzma_filter *filter, uint8_t *props) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Decode the Filter Properties field
    + *
    + * \param       filter      filter->id must have been set to the correct
    + *                          Filter ID. filter->options doesn't need to be
    + *                          initialized (it's not freed by this function). The
    + *                          decoded options will be stored in filter->options;
    + *                          it's application's responsibility to free it when
    + *                          appropriate. filter->options is set to NULL if
    + *                          there are no properties or if an error occurs.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + *                          and in case of an error, also free().
    + * \param       props       Input buffer containing the properties.
    + * \param       props_size  Size of the properties. This must be the exact
    + *                          size; giving too much or too little input will
    + *                          return LZMA_OPTIONS_ERROR.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_MEM_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_properties_decode(
    +		lzma_filter *filter, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Calculate encoded size of a Filter Flags field
    + *
    + * Knowing the size of Filter Flags is useful to know when allocating
    + * memory to hold the encoded Filter Flags.
    + *
    + * \note        If you need to calculate size of List of Filter Flags,
    + *              you need to loop over every lzma_filter entry.
    + *
    + * \param[out]  size    Pointer to integer to hold the calculated size
    + * \param       filter  Filter ID and associated options whose encoded
    + *                      size is to be calculated
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: *size set successfully. Note that this doesn't
    + *                guarantee that filter->options is valid, thus
    + *                lzma_filter_flags_encode() may still fail.
    + *              - LZMA_OPTIONS_ERROR: Unknown Filter ID or unsupported options.
    + *              - LZMA_PROG_ERROR: Invalid options
    + */
    +extern LZMA_API(lzma_ret) lzma_filter_flags_size(
    +		uint32_t *size, const lzma_filter *filter)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Encode Filter Flags into given buffer
    + *
    + * In contrast to some functions, this doesn't allocate the needed buffer.
    + * This is due to how this function is used internally by liblzma.
    + *
    + * \param       filter      Filter ID and options to be encoded
    + * \param[out]  out         Beginning of the output buffer
    + * \param[out]  out_pos     out[*out_pos] is the next write position. This
    + *                          is updated by the encoder.
    + * \param       out_size    out[out_size] is the first byte to not write.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful.
    + *              - LZMA_OPTIONS_ERROR: Invalid or unsupported options.
    + *              - LZMA_PROG_ERROR: Invalid options or not enough output
    + *                buffer space (you should have checked it with
    + *                lzma_filter_flags_size()).
    + */
    +extern LZMA_API(lzma_ret) lzma_filter_flags_encode(const lzma_filter *filter,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Decode Filter Flags from given buffer
    + *
    + * The decoded result is stored into *filter. The old value of
    + * filter->options is not free()d. If anything other than LZMA_OK
    + * is returned, filter->options is set to NULL.
    + *
    + * \param[out]  filter      Destination filter. The decoded Filter ID will
    + *                          be stored in filter->id. If options are needed
    + *                          they will be allocated and the pointer will be
    + *                          stored in filter->options.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + * \param       in          Beginning of the input buffer
    + * \param[out]  in_pos      The next byte will be read from in[*in_pos].
    + *                          *in_pos is updated only if decoding succeeds.
    + * \param       in_size     Size of the input buffer; the first byte that
    + *                          won't be read is in[in_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_OPTIONS_ERROR
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_filter_flags_decode(
    +		lzma_filter *filter, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/***********
    + * Strings *
    + ***********/
    +
    +/**
    + * \brief       Allow or show all filters
    + *
    + * By default only the filters supported in the .xz format are accept by
    + * lzma_str_to_filters() or shown by lzma_str_list_filters().
    + */
    +#define LZMA_STR_ALL_FILTERS    UINT32_C(0x01)
    +
    +
    +/**
    + * \brief       Do not validate the filter chain in lzma_str_to_filters()
    + *
    + * By default lzma_str_to_filters() can return an error if the filter chain
    + * as a whole isn't usable in the .xz format or in the raw encoder or decoder.
    + * With this flag, this validation is skipped. This flag doesn't affect the
    + * handling of the individual filter options. To allow non-.xz filters also
    + * LZMA_STR_ALL_FILTERS is needed.
    + */
    +#define LZMA_STR_NO_VALIDATION  UINT32_C(0x02)
    +
    +
    +/**
    + * \brief       Stringify encoder options
    + *
    + * Show the filter-specific options that the encoder will use.
    + * This may be useful for verbose diagnostic messages.
    + *
    + * Note that if options were decoded from .xz headers then the encoder options
    + * may be undefined. This flag shouldn't be used in such a situation.
    + */
    +#define LZMA_STR_ENCODER        UINT32_C(0x10)
    +
    +
    +/**
    + * \brief       Stringify decoder options
    + *
    + * Show the filter-specific options that the decoder will use.
    + * This may be useful for showing what filter options were decoded
    + * from file headers.
    + */
    +#define LZMA_STR_DECODER        UINT32_C(0x20)
    +
    +
    +/**
    + * \brief       Produce xz-compatible getopt_long() syntax
    + *
    + * That is, "delta:dist=2 lzma2:dict=4MiB,pb=1,lp=1" becomes
    + * "--delta=dist=2 --lzma2=dict=4MiB,pb=1,lp=1".
    + *
    + * This syntax is compatible with xz 5.0.0 as long as the filters and
    + * their options are supported too.
    + */
    +#define LZMA_STR_GETOPT_LONG    UINT32_C(0x40)
    +
    +
    +/**
    + * \brief       Use two dashes "--" instead of a space to separate filters
    + *
    + * That is, "delta:dist=2 lzma2:pb=1,lp=1" becomes
    + * "delta:dist=2--lzma2:pb=1,lp=1". This looks slightly odd but this
    + * kind of strings should be usable on the command line without quoting.
    + * However, it is possible that future versions with new filter options
    + * might produce strings that require shell quoting anyway as the exact
    + * set of possible characters isn't frozen for now.
    + *
    + * It is guaranteed that the single quote (') will never be used in
    + * filter chain strings (even if LZMA_STR_NO_SPACES isn't used).
    + */
    +#define LZMA_STR_NO_SPACES      UINT32_C(0x80)
    +
    +
    +/**
    + * \brief       Convert a string to a filter chain
    + *
    + * This tries to make it easier to write applications that allow users
    + * to set custom compression options. This only handles the filter
    + * configuration (including presets) but not the number of threads,
    + * block size, check type, or memory limits.
    + *
    + * The input string can be either a preset or a filter chain. Presets
    + * begin with a digit 0-9 and may be followed by zero or more flags
    + * which are lower-case letters. Currently only "e" is supported, matching
    + * LZMA_PRESET_EXTREME. For partial xz command line syntax compatibility,
    + * a preset string may start with a single dash "-".
    + *
    + * A filter chain consists of one or more "filtername:opt1=value1,opt2=value2"
    + * strings separated by one or more spaces. Leading and trailing spaces are
    + * ignored. All names and values must be lower-case. Extra commas in the
    + * option list are ignored. The order of filters is significant: when
    + * encoding, the uncompressed input data goes to the leftmost filter first.
    + * Normally "lzma2" is the last filter in the chain.
    + *
    + * If one wishes to avoid spaces, for example, to avoid shell quoting,
    + * it is possible to use two dashes "--" instead of spaces to separate
    + * the filters.
    + *
    + * For xz command line compatibility, each filter may be prefixed with
    + * two dashes "--" and the colon ":" separating the filter name from
    + * the options may be replaced with an equals sign "=".
    + *
    + * By default, only filters that can be used in the .xz format are accepted.
    + * To allow all filters (LZMA1) use the flag LZMA_STR_ALL_FILTERS.
    + *
    + * By default, very basic validation is done for the filter chain as a whole,
    + * for example, that LZMA2 is only used as the last filter in the chain.
    + * The validation isn't perfect though and it's possible that this function
    + * succeeds but using the filter chain for encoding or decoding will still
    + * result in LZMA_OPTIONS_ERROR. To disable this validation, use the flag
    + * LZMA_STR_NO_VALIDATION.
    + *
    + * The available filter names and their options are available via
    + * lzma_str_list_filters(). See the xz man page for the description
    + * of filter names and options.
    + *
    + * For command line applications, below is an example how an error message
    + * can be displayed. Note the use of an empty string for the field width.
    + * If "^" was used there it would create an off-by-one error except at
    + * the very beginning of the line.
    + *
    + * \code{.c}
    + * const char *str = ...; // From user
    + * lzma_filter filters[LZMA_FILTERS_MAX + 1];
    + * int pos;
    + * const char *msg = lzma_str_to_filters(str, &pos, filters, 0, NULL);
    + * if (msg != NULL) {
    + *     printf("%s: Error in XZ compression options:\n", argv[0]);
    + *     printf("%s: %s\n", argv[0], str);
    + *     printf("%s: %*s^\n", argv[0], errpos, "");
    + *     printf("%s: %s\n", argv[0], msg);
    + * }
    + * \endcode
    + *
    + * \param       str         User-supplied string describing a preset or
    + *                          a filter chain. If a default value is needed and
    + *                          you don't know what would be good, use "6" since
    + *                          that is the default preset in xz too.
    + * \param[out]  error_pos   If this isn't NULL, this value will be set on
    + *                          both success and on all errors. This tells the
    + *                          location of the error in the string. This is
    + *                          an int to make it straightforward to use this
    + *                          as printf() field width. The value is guaranteed
    + *                          to be in the range [0, INT_MAX] even if strlen(str)
    + *                          somehow was greater than INT_MAX.
    + * \param[out]  filters     An array of lzma_filter structures. There must
    + *                          be LZMA_FILTERS_MAX + 1 (that is, five) elements
    + *                          in the array. The old contents are ignored so it
    + *                          doesn't need to be initialized. This array is
    + *                          modified only if this function returns NULL.
    + *                          Once the allocated filter options are no longer
    + *                          needed, lzma_filters_free() can be used to free the
    + *                          options (it doesn't free the filters array itself).
    + * \param       flags       Bitwise-or of zero or more of the flags
    + *                          LZMA_STR_ALL_FILTERS and LZMA_STR_NO_VALIDATION.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + *
    + * \return      On success, NULL is returned. On error, a statically-allocated
    + *              error message is returned which together with the error_pos
    + *              should give some idea what is wrong.
    + */
    +extern LZMA_API(const char *) lzma_str_to_filters(
    +		const char *str, int *error_pos, lzma_filter *filters,
    +		uint32_t flags, const lzma_allocator *allocator)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Convert a filter chain to a string
    + *
    + * Use cases:
    + *
    + *   - Verbose output showing the full encoder options to the user
    + *     (use LZMA_STR_ENCODER in flags)
    + *
    + *   - Showing the filters and options that are required to decode a file
    + *     (use LZMA_STR_DECODER in flags)
    + *
    + *   - Showing the filter names without any options in informational messages
    + *     where the technical details aren't important (no flags). In this case
    + *     the .options in the filters array are ignored and may be NULL even if
    + *     a filter has a mandatory options structure.
    + *
    + * Note that even if the filter chain was specified using a preset,
    + * the resulting filter chain isn't reversed to a preset. So if you
    + * specify "6" to lzma_str_to_filters() then lzma_str_from_filters()
    + * will produce a string containing "lzma2".
    + *
    + * \param[out]  str         On success *str will be set to point to an
    + *                          allocated string describing the given filter
    + *                          chain. Old value is ignored. On error *str is
    + *                          always set to NULL.
    + * \param       filters     Array of filters terminated with
    + *                          .id == LZMA_VLI_UNKNOWN.
    + * \param       flags       Bitwise-or of zero or more of the flags
    + *                          LZMA_STR_ENCODER, LZMA_STR_DECODER,
    + *                          LZMA_STR_GETOPT_LONG, and LZMA_STR_NO_SPACES.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_OPTIONS_ERROR: Empty filter chain
    + *                (filters[0].id == LZMA_VLI_UNKNOWN) or the filter chain
    + *                includes a Filter ID that is not supported by this function.
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_str_from_filters(
    +		char **str, const lzma_filter *filters, uint32_t flags,
    +		const lzma_allocator *allocator)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       List available filters and/or their options (for help message)
    + *
    + * If a filter_id is given then only one line is created which contains the
    + * filter name. If LZMA_STR_ENCODER or LZMA_STR_DECODER is used then the
    + * options read by the encoder or decoder are printed on the same line.
    + *
    + * If filter_id is LZMA_VLI_UNKNOWN then all supported .xz-compatible filters
    + * are listed:
    + *
    + *   - If neither LZMA_STR_ENCODER nor LZMA_STR_DECODER is used then
    + *     the supported filter names are listed on a single line separated
    + *     by spaces.
    + *
    + *   - If LZMA_STR_ENCODER or LZMA_STR_DECODER is used then filters and
    + *     the supported options are listed one filter per line. There won't
    + *     be a newline after the last filter.
    + *
    + *   - If LZMA_STR_ALL_FILTERS is used then the list will include also
    + *     those filters that cannot be used in the .xz format (LZMA1).
    + *
    + * \param       str         On success *str will be set to point to an
    + *                          allocated string listing the filters and options.
    + *                          Old value is ignored. On error *str is always set
    + *                          to NULL.
    + * \param       filter_id   Filter ID or LZMA_VLI_UNKNOWN.
    + * \param       flags       Bitwise-or of zero or more of the flags
    + *                          LZMA_STR_ALL_FILTERS, LZMA_STR_ENCODER,
    + *                          LZMA_STR_DECODER, and LZMA_STR_GETOPT_LONG.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_OPTIONS_ERROR: Unsupported filter_id or flags
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_str_list_filters(
    +		char **str, lzma_vli filter_id, uint32_t flags,
    +		const lzma_allocator *allocator)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/hardware.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/hardware.h
    new file mode 100644
    index 00000000000..7a1a84fcccf
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/hardware.h
    @@ -0,0 +1,62 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/hardware.h
    + * \brief       Hardware information
    + * \note        Never include this file directly. Use  instead.
    + *
    + * Since liblzma can consume a lot of system resources, it also provides
    + * ways to limit the resource usage. Applications linking against liblzma
    + * need to do the actual decisions how much resources to let liblzma to use.
    + * To ease making these decisions, liblzma provides functions to find out
    + * the relevant capabilities of the underlying hardware. Currently there
    + * is only a function to find out the amount of RAM, but in the future there
    + * will be also a function to detect how many concurrent threads the system
    + * can run.
    + *
    + * \note        On some operating systems, these function may temporarily
    + *              load a shared library or open file descriptor(s) to find out
    + *              the requested hardware information. Unless the application
    + *              assumes that specific file descriptors are not touched by
    + *              other threads, this should have no effect on thread safety.
    + *              Possible operations involving file descriptors will restart
    + *              the syscalls if they return EINTR.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       Get the total amount of physical memory (RAM) in bytes
    + *
    + * This function may be useful when determining a reasonable memory
    + * usage limit for decompressing or how much memory it is OK to use
    + * for compressing.
    + *
    + * \return      On success, the total amount of physical memory in bytes
    + *              is returned. If the amount of RAM cannot be determined,
    + *              zero is returned. This can happen if an error occurs
    + *              or if there is no code in liblzma to detect the amount
    + *              of RAM on the specific operating system.
    + */
    +extern LZMA_API(uint64_t) lzma_physmem(void) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Get the number of processor cores or threads
    + *
    + * This function may be useful when determining how many threads to use.
    + * If the hardware supports more than one thread per CPU core, the number
    + * of hardware threads is returned if that information is available.
    + *
    + * \return      On success, the number of available CPU threads or cores is
    + *              returned. If this information isn't available or an error
    + *              occurs, zero is returned.
    + */
    +extern LZMA_API(uint32_t) lzma_cputhreads(void) lzma_nothrow;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index.h
    new file mode 100644
    index 00000000000..b17025e3d90
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index.h
    @@ -0,0 +1,882 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/index.h
    + * \brief       Handling of .xz Index and related information
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       Opaque data type to hold the Index(es) and other information
    + *
    + * lzma_index often holds just one .xz Index and possibly the Stream Flags
    + * of the same Stream and size of the Stream Padding field. However,
    + * multiple lzma_indexes can be concatenated with lzma_index_cat() and then
    + * there may be information about multiple Streams in the same lzma_index.
    + *
    + * Notes about thread safety: Only one thread may modify lzma_index at
    + * a time. All functions that take non-const pointer to lzma_index
    + * modify it. As long as no thread is modifying the lzma_index, getting
    + * information from the same lzma_index can be done from multiple threads
    + * at the same time with functions that take a const pointer to
    + * lzma_index or use lzma_index_iter. The same iterator must be used
    + * only by one thread at a time, of course, but there can be as many
    + * iterators for the same lzma_index as needed.
    + */
    +typedef struct lzma_index_s lzma_index;
    +
    +
    +/**
    + * \brief       Iterator to get information about Blocks and Streams
    + */
    +typedef struct {
    +	struct {
    +		/**
    +		 * \brief       Pointer to Stream Flags
    +		 *
    +		 * This is NULL if Stream Flags have not been set for
    +		 * this Stream with lzma_index_stream_flags().
    +		 */
    +		const lzma_stream_flags *flags;
    +
    +		/** \private     Reserved member. */
    +		const void *reserved_ptr1;
    +
    +		/** \private     Reserved member. */
    +		const void *reserved_ptr2;
    +
    +		/** \private     Reserved member. */
    +		const void *reserved_ptr3;
    +
    +		/**
    +		 * \brief       Stream number in the lzma_index
    +		 *
    +		 * The first Stream is 1.
    +		 */
    +		lzma_vli number;
    +
    +		/**
    +		 * \brief       Number of Blocks in the Stream
    +		 *
    +		 * If this is zero, the block structure below has
    +		 * undefined values.
    +		 */
    +		lzma_vli block_count;
    +
    +		/**
    +		 * \brief       Compressed start offset of this Stream
    +		 *
    +		 * The offset is relative to the beginning of the lzma_index
    +		 * (i.e. usually the beginning of the .xz file).
    +		 */
    +		lzma_vli compressed_offset;
    +
    +		/**
    +		 * \brief       Uncompressed start offset of this Stream
    +		 *
    +		 * The offset is relative to the beginning of the lzma_index
    +		 * (i.e. usually the beginning of the .xz file).
    +		 */
    +		lzma_vli uncompressed_offset;
    +
    +		/**
    +		 * \brief       Compressed size of this Stream
    +		 *
    +		 * This includes all headers except the possible
    +		 * Stream Padding after this Stream.
    +		 */
    +		lzma_vli compressed_size;
    +
    +		/**
    +		 * \brief       Uncompressed size of this Stream
    +		 */
    +		lzma_vli uncompressed_size;
    +
    +		/**
    +		 * \brief       Size of Stream Padding after this Stream
    +		 *
    +		 * If it hasn't been set with lzma_index_stream_padding(),
    +		 * this defaults to zero. Stream Padding is always
    +		 * a multiple of four bytes.
    +		 */
    +		lzma_vli padding;
    +
    +
    +		/** \private     Reserved member. */
    +		lzma_vli reserved_vli1;
    +
    +		/** \private     Reserved member. */
    +		lzma_vli reserved_vli2;
    +
    +		/** \private     Reserved member. */
    +		lzma_vli reserved_vli3;
    +
    +		/** \private     Reserved member. */
    +		lzma_vli reserved_vli4;
    +	} stream;
    +
    +	struct {
    +		/**
    +		 * \brief       Block number in the file
    +		 *
    +		 * The first Block is 1.
    +		 */
    +		lzma_vli number_in_file;
    +
    +		/**
    +		 * \brief       Compressed start offset of this Block
    +		 *
    +		 * This offset is relative to the beginning of the
    +		 * lzma_index (i.e. usually the beginning of the .xz file).
    +		 * Normally this is where you should seek in the .xz file
    +		 * to start decompressing this Block.
    +		 */
    +		lzma_vli compressed_file_offset;
    +
    +		/**
    +		 * \brief       Uncompressed start offset of this Block
    +		 *
    +		 * This offset is relative to the beginning of the lzma_index
    +		 * (i.e. usually the beginning of the .xz file).
    +		 *
    +		 * When doing random-access reading, it is possible that
    +		 * the target offset is not exactly at Block boundary. One
    +		 * will need to compare the target offset against
    +		 * uncompressed_file_offset or uncompressed_stream_offset,
    +		 * and possibly decode and throw away some amount of data
    +		 * before reaching the target offset.
    +		 */
    +		lzma_vli uncompressed_file_offset;
    +
    +		/**
    +		 * \brief       Block number in this Stream
    +		 *
    +		 * The first Block is 1.
    +		 */
    +		lzma_vli number_in_stream;
    +
    +		/**
    +		 * \brief       Compressed start offset of this Block
    +		 *
    +		 * This offset is relative to the beginning of the Stream
    +		 * containing this Block.
    +		 */
    +		lzma_vli compressed_stream_offset;
    +
    +		/**
    +		 * \brief       Uncompressed start offset of this Block
    +		 *
    +		 * This offset is relative to the beginning of the Stream
    +		 * containing this Block.
    +		 */
    +		lzma_vli uncompressed_stream_offset;
    +
    +		/**
    +		 * \brief       Uncompressed size of this Block
    +		 *
    +		 * You should pass this to the Block decoder if you will
    +		 * decode this Block. It will allow the Block decoder to
    +		 * validate the uncompressed size.
    +		 */
    +		lzma_vli uncompressed_size;
    +
    +		/**
    +		 * \brief       Unpadded size of this Block
    +		 *
    +		 * You should pass this to the Block decoder if you will
    +		 * decode this Block. It will allow the Block decoder to
    +		 * validate the unpadded size.
    +		 */
    +		lzma_vli unpadded_size;
    +
    +		/**
    +		 * \brief       Total compressed size
    +		 *
    +		 * This includes all headers and padding in this Block.
    +		 * This is useful if you need to know how many bytes
    +		 * the Block decoder will actually read.
    +		 */
    +		lzma_vli total_size;
    +
    +		/** \private     Reserved member. */
    +		lzma_vli reserved_vli1;
    +
    +		/** \private     Reserved member. */
    +		lzma_vli reserved_vli2;
    +
    +		/** \private     Reserved member. */
    +		lzma_vli reserved_vli3;
    +
    +		/** \private     Reserved member. */
    +		lzma_vli reserved_vli4;
    +
    +		/** \private     Reserved member. */
    +		const void *reserved_ptr1;
    +
    +		/** \private     Reserved member. */
    +		const void *reserved_ptr2;
    +
    +		/** \private     Reserved member. */
    +		const void *reserved_ptr3;
    +
    +		/** \private     Reserved member. */
    +		const void *reserved_ptr4;
    +	} block;
    +
    +	/**
    +	 * \private     Internal data
    +	 *
    +	 * Internal data which is used to store the state of the iterator.
    +	 * The exact format may vary between liblzma versions, so don't
    +	 * touch these in any way.
    +	 */
    +	union {
    +		/** \private     Internal member. */
    +		const void *p;
    +
    +		/** \private     Internal member. */
    +		size_t s;
    +
    +		/** \private     Internal member. */
    +		lzma_vli v;
    +	} internal[6];
    +} lzma_index_iter;
    +
    +
    +/**
    + * \brief       Operation mode for lzma_index_iter_next()
    + */
    +typedef enum {
    +	LZMA_INDEX_ITER_ANY             = 0,
    +		/**<
    +		 * \brief       Get the next Block or Stream
    +		 *
    +		 * Go to the next Block if the current Stream has at least
    +		 * one Block left. Otherwise go to the next Stream even if
    +		 * it has no Blocks. If the Stream has no Blocks
    +		 * (lzma_index_iter.stream.block_count == 0),
    +		 * lzma_index_iter.block will have undefined values.
    +		 */
    +
    +	LZMA_INDEX_ITER_STREAM          = 1,
    +		/**<
    +		 * \brief       Get the next Stream
    +		 *
    +		 * Go to the next Stream even if the current Stream has
    +		 * unread Blocks left. If the next Stream has at least one
    +		 * Block, the iterator will point to the first Block.
    +		 * If there are no Blocks, lzma_index_iter.block will have
    +		 * undefined values.
    +		 */
    +
    +	LZMA_INDEX_ITER_BLOCK           = 2,
    +		/**<
    +		 * \brief       Get the next Block
    +		 *
    +		 * Go to the next Block if the current Stream has at least
    +		 * one Block left. If the current Stream has no Blocks left,
    +		 * the next Stream with at least one Block is located and
    +		 * the iterator will be made to point to the first Block of
    +		 * that Stream.
    +		 */
    +
    +	LZMA_INDEX_ITER_NONEMPTY_BLOCK  = 3
    +		/**<
    +		 * \brief       Get the next non-empty Block
    +		 *
    +		 * This is like LZMA_INDEX_ITER_BLOCK except that it will
    +		 * skip Blocks whose Uncompressed Size is zero.
    +		 */
    +
    +} lzma_index_iter_mode;
    +
    +
    +/**
    + * \brief       Mask for return value from lzma_index_checks() for check none
    + *
    + * \note        This and the other CHECK_MASK macros were added in 5.5.1alpha.
    + */
    +#define LZMA_INDEX_CHECK_MASK_NONE (UINT32_C(1) << LZMA_CHECK_NONE)
    +
    +/**
    + * \brief       Mask for return value from lzma_index_checks() for check CRC32
    + */
    +#define LZMA_INDEX_CHECK_MASK_CRC32 (UINT32_C(1) << LZMA_CHECK_CRC32)
    +
    +/**
    + * \brief       Mask for return value from lzma_index_checks() for check CRC64
    + */
    +#define LZMA_INDEX_CHECK_MASK_CRC64 (UINT32_C(1) << LZMA_CHECK_CRC64)
    +
    +/**
    + * \brief       Mask for return value from lzma_index_checks() for check SHA256
    + */
    +#define LZMA_INDEX_CHECK_MASK_SHA256 (UINT32_C(1) << LZMA_CHECK_SHA256)
    +
    +/**
    + * \brief       Calculate memory usage of lzma_index
    + *
    + * On disk, the size of the Index field depends on both the number of Records
    + * stored and the size of the Records (due to variable-length integer
    + * encoding). When the Index is kept in lzma_index structure, the memory usage
    + * depends only on the number of Records/Blocks stored in the Index(es), and
    + * in case of concatenated lzma_indexes, the number of Streams. The size in
    + * RAM is almost always significantly bigger than in the encoded form on disk.
    + *
    + * This function calculates an approximate amount of memory needed to hold
    + * the given number of Streams and Blocks in lzma_index structure. This
    + * value may vary between CPU architectures and also between liblzma versions
    + * if the internal implementation is modified.
    + *
    + * \param       streams Number of Streams
    + * \param       blocks  Number of Blocks
    + *
    + * \return      Approximate memory in bytes needed in a lzma_index structure.
    + */
    +extern LZMA_API(uint64_t) lzma_index_memusage(
    +		lzma_vli streams, lzma_vli blocks) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Calculate the memory usage of an existing lzma_index
    + *
    + * This is a shorthand for lzma_index_memusage(lzma_index_stream_count(i),
    + * lzma_index_block_count(i)).
    + *
    + * \param       i   Pointer to lzma_index structure
    + *
    + * \return      Approximate memory in bytes used by the lzma_index structure.
    + */
    +extern LZMA_API(uint64_t) lzma_index_memused(const lzma_index *i)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Allocate and initialize a new lzma_index structure
    + *
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + *
    + * \return      On success, a pointer to an empty initialized lzma_index is
    + *              returned. If allocation fails, NULL is returned.
    + */
    +extern LZMA_API(lzma_index *) lzma_index_init(const lzma_allocator *allocator)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Deallocate lzma_index
    + *
    + * If i is NULL, this does nothing.
    + *
    + * \param       i           Pointer to lzma_index structure to deallocate
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + */
    +extern LZMA_API(void) lzma_index_end(
    +		lzma_index *i, const lzma_allocator *allocator) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Add a new Block to lzma_index
    + *
    + * \param       i                 Pointer to a lzma_index structure
    + * \param       allocator         lzma_allocator for custom allocator
    + *                                functions. Set to NULL to use malloc()
    + *                                and free().
    + * \param       unpadded_size     Unpadded Size of a Block. This can be
    + *                                calculated with lzma_block_unpadded_size()
    + *                                after encoding or decoding the Block.
    + * \param       uncompressed_size Uncompressed Size of a Block. This can be
    + *                                taken directly from lzma_block structure
    + *                                after encoding or decoding the Block.
    + *
    + * Appending a new Block does not invalidate iterators. For example,
    + * if an iterator was pointing to the end of the lzma_index, after
    + * lzma_index_append() it is possible to read the next Block with
    + * an existing iterator.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_DATA_ERROR: Compressed or uncompressed size of the
    + *                Stream or size of the Index field would grow too big.
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_index_append(
    +		lzma_index *i, const lzma_allocator *allocator,
    +		lzma_vli unpadded_size, lzma_vli uncompressed_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Set the Stream Flags
    + *
    + * Set the Stream Flags of the last (and typically the only) Stream
    + * in lzma_index. This can be useful when reading information from the
    + * lzma_index, because to decode Blocks, knowing the integrity check type
    + * is needed.
    + *
    + * \param       i              Pointer to lzma_index structure
    + * \param       stream_flags   Pointer to lzma_stream_flags structure. This
    + *                             is copied into the internal preallocated
    + *                             structure, so the caller doesn't need to keep
    + *                             the flags' data available after calling this
    + *                             function.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_OPTIONS_ERROR: Unsupported stream_flags->version.
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_index_stream_flags(
    +		lzma_index *i, const lzma_stream_flags *stream_flags)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Get the types of integrity Checks
    + *
    + * If lzma_index_stream_flags() is used to set the Stream Flags for
    + * every Stream, lzma_index_checks() can be used to get a bitmask to
    + * indicate which Check types have been used. It can be useful e.g. if
    + * showing the Check types to the user.
    + *
    + * The bitmask is 1 << check_id, e.g. CRC32 is 1 << 1 and SHA-256 is 1 << 10.
    + * These masks are defined for convenience as LZMA_INDEX_CHECK_MASK_XXX
    + *
    + * \param       i   Pointer to lzma_index structure
    + *
    + * \return      Bitmask indicating which Check types are used in the lzma_index
    + */
    +extern LZMA_API(uint32_t) lzma_index_checks(const lzma_index *i)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Set the amount of Stream Padding
    + *
    + * Set the amount of Stream Padding of the last (and typically the only)
    + * Stream in the lzma_index. This is needed when planning to do random-access
    + * reading within multiple concatenated Streams.
    + *
    + * By default, the amount of Stream Padding is assumed to be zero bytes.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_DATA_ERROR: The file size would grow too big.
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_index_stream_padding(
    +		lzma_index *i, lzma_vli stream_padding)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Get the number of Streams
    + *
    + * \param       i   Pointer to lzma_index structure
    + *
    + * \return      Number of Streams in the lzma_index
    + */
    +extern LZMA_API(lzma_vli) lzma_index_stream_count(const lzma_index *i)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Get the number of Blocks
    + *
    + * This returns the total number of Blocks in lzma_index. To get number
    + * of Blocks in individual Streams, use lzma_index_iter.
    + *
    + * \param       i   Pointer to lzma_index structure
    + *
    + * \return      Number of blocks in the lzma_index
    + */
    +extern LZMA_API(lzma_vli) lzma_index_block_count(const lzma_index *i)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Get the size of the Index field as bytes
    + *
    + * This is needed to verify the Backward Size field in the Stream Footer.
    + *
    + * \param       i   Pointer to lzma_index structure
    + *
    + * \return      Size in bytes of the Index
    + */
    +extern LZMA_API(lzma_vli) lzma_index_size(const lzma_index *i)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Get the total size of the Stream
    + *
    + * If multiple lzma_indexes have been combined, this works as if the Blocks
    + * were in a single Stream. This is useful if you are going to combine
    + * Blocks from multiple Streams into a single new Stream.
    + *
    + * \param       i   Pointer to lzma_index structure
    + *
    + * \return      Size in bytes of the Stream (if all Blocks are combined
    + *              into one Stream).
    + */
    +extern LZMA_API(lzma_vli) lzma_index_stream_size(const lzma_index *i)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Get the total size of the Blocks
    + *
    + * This doesn't include the Stream Header, Stream Footer, Stream Padding,
    + * or Index fields.
    + *
    + * \param       i   Pointer to lzma_index structure
    + *
    + * \return      Size in bytes of all Blocks in the Stream(s)
    + */
    +extern LZMA_API(lzma_vli) lzma_index_total_size(const lzma_index *i)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Get the total size of the file
    + *
    + * When no lzma_indexes have been combined with lzma_index_cat() and there is
    + * no Stream Padding, this function is identical to lzma_index_stream_size().
    + * If multiple lzma_indexes have been combined, this includes also the headers
    + * of each separate Stream and the possible Stream Padding fields.
    + *
    + * \param       i   Pointer to lzma_index structure
    + *
    + * \return      Total size of the .xz file in bytes
    + */
    +extern LZMA_API(lzma_vli) lzma_index_file_size(const lzma_index *i)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Get the uncompressed size of the file
    + *
    + * \param       i   Pointer to lzma_index structure
    + *
    + * \return      Size in bytes of the uncompressed data in the file
    + */
    +extern LZMA_API(lzma_vli) lzma_index_uncompressed_size(const lzma_index *i)
    +		lzma_nothrow lzma_attr_pure;
    +
    +
    +/**
    + * \brief       Initialize an iterator
    + *
    + * This function associates the iterator with the given lzma_index, and calls
    + * lzma_index_iter_rewind() on the iterator.
    + *
    + * This function doesn't allocate any memory, thus there is no
    + * lzma_index_iter_end(). The iterator is valid as long as the
    + * associated lzma_index is valid, that is, until lzma_index_end() or
    + * using it as source in lzma_index_cat(). Specifically, lzma_index doesn't
    + * become invalid if new Blocks are added to it with lzma_index_append() or
    + * if it is used as the destination in lzma_index_cat().
    + *
    + * It is safe to make copies of an initialized lzma_index_iter, for example,
    + * to easily restart reading at some particular position.
    + *
    + * \param       iter    Pointer to a lzma_index_iter structure
    + * \param       i       lzma_index to which the iterator will be associated
    + */
    +extern LZMA_API(void) lzma_index_iter_init(
    +		lzma_index_iter *iter, const lzma_index *i) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Rewind the iterator
    + *
    + * Rewind the iterator so that next call to lzma_index_iter_next() will
    + * return the first Block or Stream.
    + *
    + * \param       iter    Pointer to a lzma_index_iter structure
    + */
    +extern LZMA_API(void) lzma_index_iter_rewind(lzma_index_iter *iter)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Get the next Block or Stream
    + *
    + * \param       iter    Iterator initialized with lzma_index_iter_init()
    + * \param       mode    Specify what kind of information the caller wants
    + *                      to get. See lzma_index_iter_mode for details.
    + *
    + * \return      lzma_bool:
    + *              - true if no Block or Stream matching the mode is found.
    + *                *iter is not updated (failure).
    + *              - false if the next Block or Stream matching the mode was
    + *                found. *iter is updated (success).
    + */
    +extern LZMA_API(lzma_bool) lzma_index_iter_next(
    +		lzma_index_iter *iter, lzma_index_iter_mode mode)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Locate a Block
    + *
    + * If it is possible to seek in the .xz file, it is possible to parse
    + * the Index field(s) and use lzma_index_iter_locate() to do random-access
    + * reading with granularity of Block size.
    + *
    + * If the target is smaller than the uncompressed size of the Stream (can be
    + * checked with lzma_index_uncompressed_size()):
    + *  - Information about the Stream and Block containing the requested
    + *    uncompressed offset is stored into *iter.
    + *  - Internal state of the iterator is adjusted so that
    + *    lzma_index_iter_next() can be used to read subsequent Blocks or Streams.
    + *
    + * If the target is greater than the uncompressed size of the Stream, *iter
    + * is not modified.
    + *
    + * \param       iter    Iterator that was earlier initialized with
    + *                      lzma_index_iter_init().
    + * \param       target  Uncompressed target offset which the caller would
    + *                      like to locate from the Stream
    + *
    + * \return      lzma_bool:
    + *              - true if the target is greater than or equal to the
    + *                uncompressed size of the Stream (failure)
    + *              - false if the target is smaller than the uncompressed size
    + *                of the Stream (success)
    + */
    +extern LZMA_API(lzma_bool) lzma_index_iter_locate(
    +		lzma_index_iter *iter, lzma_vli target) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Concatenate lzma_indexes
    + *
    + * Concatenating lzma_indexes is useful when doing random-access reading in
    + * multi-Stream .xz file, or when combining multiple Streams into single
    + * Stream.
    + *
    + * \param[out]  dest      lzma_index after which src is appended
    + * \param       src       lzma_index to be appended after dest. If this
    + *                        function succeeds, the memory allocated for src
    + *                        is freed or moved to be part of dest, and all
    + *                        iterators pointing to src will become invalid.
    + * \param       allocator lzma_allocator for custom allocator functions.
    + *                        Set to NULL to use malloc() and free().
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: lzma_indexes were concatenated successfully.
    + *                src is now a dangling pointer.
    + *              - LZMA_DATA_ERROR: *dest would grow too big.
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_index_cat(lzma_index *dest, lzma_index *src,
    +		const lzma_allocator *allocator)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Duplicate lzma_index
    + *
    + * \param       i         Pointer to lzma_index structure to be duplicated
    + * \param       allocator lzma_allocator for custom allocator functions.
    + *                        Set to NULL to use malloc() and free().
    + *
    + * \return      A copy of the lzma_index, or NULL if memory allocation failed.
    + */
    +extern LZMA_API(lzma_index *) lzma_index_dup(
    +		const lzma_index *i, const lzma_allocator *allocator)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Initialize .xz Index encoder
    + *
    + * \param       strm        Pointer to properly prepared lzma_stream
    + * \param       i           Pointer to lzma_index which should be encoded.
    + *
    + * The valid 'action' values for lzma_code() are LZMA_RUN and LZMA_FINISH.
    + * It is enough to use only one of them (you can choose freely).
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Initialization succeeded, continue with lzma_code().
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_index_encoder(
    +		lzma_stream *strm, const lzma_index *i)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Initialize .xz Index decoder
    + *
    + * \param       strm        Pointer to properly prepared lzma_stream
    + * \param[out]  i           The decoded Index will be made available via
    + *                          this pointer. Initially this function will
    + *                          set *i to NULL (the old value is ignored). If
    + *                          decoding succeeds (lzma_code() returns
    + *                          LZMA_STREAM_END), *i will be set to point
    + *                          to a new lzma_index, which the application
    + *                          has to later free with lzma_index_end().
    + * \param       memlimit    How much memory the resulting lzma_index is
    + *                          allowed to require. liblzma 5.2.3 and earlier
    + *                          don't allow 0 here and return LZMA_PROG_ERROR;
    + *                          later versions treat 0 as if 1 had been specified.
    + *
    + * Valid 'action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
    + * There is no need to use LZMA_FINISH, but it's allowed because it may
    + * simplify certain types of applications.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Initialization succeeded, continue with lzma_code().
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_PROG_ERROR
    + *
    + * \note        liblzma 5.2.3 and older list also LZMA_MEMLIMIT_ERROR here
    + *              but that error code has never been possible from this
    + *              initialization function.
    + */
    +extern LZMA_API(lzma_ret) lzma_index_decoder(
    +		lzma_stream *strm, lzma_index **i, uint64_t memlimit)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Single-call .xz Index encoder
    + *
    + * \note        This function doesn't take allocator argument since all
    + *              the internal data is allocated on stack.
    + *
    + * \param       i         lzma_index to be encoded
    + * \param[out]  out       Beginning of the output buffer
    + * \param[out]  out_pos   The next byte will be written to out[*out_pos].
    + *                        *out_pos is updated only if encoding succeeds.
    + * \param       out_size  Size of the out buffer; the first byte into
    + *                        which no data is written to is out[out_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful.
    + *              - LZMA_BUF_ERROR: Output buffer is too small. Use
    + *                lzma_index_size() to find out how much output
    + *                space is needed.
    + *              - LZMA_PROG_ERROR
    + *
    + */
    +extern LZMA_API(lzma_ret) lzma_index_buffer_encode(const lzma_index *i,
    +		uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Single-call .xz Index decoder
    + *
    + * \param[out]  i           If decoding succeeds, *i will point to a new
    + *                          lzma_index, which the application has to
    + *                          later free with lzma_index_end(). If an error
    + *                          occurs, *i will be NULL. The old value of *i
    + *                          is always ignored and thus doesn't need to be
    + *                          initialized by the caller.
    + * \param[out]  memlimit    Pointer to how much memory the resulting
    + *                          lzma_index is allowed to require. The value
    + *                          pointed by this pointer is modified if and only
    + *                          if LZMA_MEMLIMIT_ERROR is returned.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + * \param       in          Beginning of the input buffer
    + * \param       in_pos      The next byte will be read from in[*in_pos].
    + *                          *in_pos is updated only if decoding succeeds.
    + * \param       in_size     Size of the input buffer; the first byte that
    + *                          won't be read is in[in_size].
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Decoding was successful.
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
    + *                The minimum required memlimit value was stored to *memlimit.
    + *              - LZMA_DATA_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_index_buffer_decode(lzma_index **i,
    +		uint64_t *memlimit, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Initialize a .xz file information decoder
    + *
    + * This decoder decodes the Stream Header, Stream Footer, Index, and
    + * Stream Padding field(s) from the input .xz file and stores the resulting
    + * combined index in *dest_index. This information can be used to get the
    + * uncompressed file size with lzma_index_uncompressed_size(*dest_index) or,
    + * for example, to implement random access reading by locating the Blocks
    + * in the Streams.
    + *
    + * To get the required information from the .xz file, lzma_code() may ask
    + * the application to seek in the input file by returning LZMA_SEEK_NEEDED
    + * and having the target file position specified in lzma_stream.seek_pos.
    + * The number of seeks required depends on the input file and how big buffers
    + * the application provides. When possible, the decoder will seek backward
    + * and forward in the given buffer to avoid useless seek requests. Thus, if
    + * the application provides the whole file at once, no external seeking will
    + * be required (that is, lzma_code() won't return LZMA_SEEK_NEEDED).
    + *
    + * The value in lzma_stream.total_in can be used to estimate how much data
    + * liblzma had to read to get the file information. However, due to seeking
    + * and the way total_in is updated, the value of total_in will be somewhat
    + * inaccurate (a little too big). Thus, total_in is a good estimate but don't
    + * expect to see the same exact value for the same file if you change the
    + * input buffer size or switch to a different liblzma version.
    + *
    + * Valid 'action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
    + * You only need to use LZMA_RUN; LZMA_FINISH is only supported because it
    + * might be convenient for some applications. If you use LZMA_FINISH and if
    + * lzma_code() asks the application to seek, remember to reset 'action' back
    + * to LZMA_RUN unless you hit the end of the file again.
    + *
    + * Possible return values from lzma_code():
    + *   - LZMA_OK: All OK so far, more input needed
    + *   - LZMA_SEEK_NEEDED: Provide more input starting from the absolute
    + *     file position strm->seek_pos
    + *   - LZMA_STREAM_END: Decoding was successful, *dest_index has been set
    + *   - LZMA_FORMAT_ERROR: The input file is not in the .xz format (the
    + *     expected magic bytes were not found from the beginning of the file)
    + *   - LZMA_OPTIONS_ERROR: File looks valid but contains headers that aren't
    + *     supported by this version of liblzma
    + *   - LZMA_DATA_ERROR: File is corrupt
    + *   - LZMA_BUF_ERROR
    + *   - LZMA_MEM_ERROR
    + *   - LZMA_MEMLIMIT_ERROR
    + *   - LZMA_PROG_ERROR
    + *
    + * \param       strm        Pointer to a properly prepared lzma_stream
    + * \param[out]  dest_index  Pointer to a pointer where the decoder will put
    + *                          the decoded lzma_index. The old value
    + *                          of *dest_index is ignored (not freed).
    + * \param       memlimit    How much memory the resulting lzma_index is
    + *                          allowed to require. Use UINT64_MAX to
    + *                          effectively disable the limiter.
    + * \param       file_size   Size of the input .xz file
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_MEM_ERROR
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_file_info_decoder(
    +		lzma_stream *strm, lzma_index **dest_index,
    +		uint64_t memlimit, uint64_t file_size)
    +		lzma_nothrow;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index_hash.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index_hash.h
    new file mode 100644
    index 00000000000..68f9024eb3b
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index_hash.h
    @@ -0,0 +1,123 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/index_hash.h
    + * \brief       Validate Index by using a hash function
    + * \note        Never include this file directly. Use  instead.
    + *
    + * Hashing makes it possible to use constant amount of memory to validate
    + * Index of arbitrary size.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +/**
    + * \brief       Opaque data type to hold the Index hash
    + */
    +typedef struct lzma_index_hash_s lzma_index_hash;
    +
    +
    +/**
    + * \brief       Allocate and initialize a new lzma_index_hash structure
    + *
    + * If index_hash is NULL, this function allocates and initializes a new
    + * lzma_index_hash structure and returns a pointer to it. If allocation
    + * fails, NULL is returned.
    + *
    + * If index_hash is non-NULL, this function reinitializes the lzma_index_hash
    + * structure and returns the same pointer. In this case, return value cannot
    + * be NULL or a different pointer than the index_hash that was given as
    + * an argument.
    + *
    + * \param       index_hash  Pointer to a lzma_index_hash structure or NULL.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + *
    + * \return      Initialized lzma_index_hash structure on success or
    + *              NULL on failure.
    + */
    +extern LZMA_API(lzma_index_hash *) lzma_index_hash_init(
    +		lzma_index_hash *index_hash, const lzma_allocator *allocator)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Deallocate lzma_index_hash structure
    + *
    + * \param       index_hash  Pointer to a lzma_index_hash structure to free.
    + * \param       allocator   lzma_allocator for custom allocator functions.
    + *                          Set to NULL to use malloc() and free().
    + */
    +extern LZMA_API(void) lzma_index_hash_end(
    +		lzma_index_hash *index_hash, const lzma_allocator *allocator)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Add a new Record to an Index hash
    + *
    + * \param       index_hash        Pointer to a lzma_index_hash structure
    + * \param       unpadded_size     Unpadded Size of a Block
    + * \param       uncompressed_size Uncompressed Size of a Block
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK
    + *              - LZMA_DATA_ERROR: Compressed or uncompressed size of the
    + *                Stream or size of the Index field would grow too big.
    + *              - LZMA_PROG_ERROR: Invalid arguments or this function is being
    + *                used when lzma_index_hash_decode() has already been used.
    + */
    +extern LZMA_API(lzma_ret) lzma_index_hash_append(lzma_index_hash *index_hash,
    +		lzma_vli unpadded_size, lzma_vli uncompressed_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Decode and validate the Index field
    + *
    + * After telling the sizes of all Blocks with lzma_index_hash_append(),
    + * the actual Index field is decoded with this function. Specifically,
    + * once decoding of the Index field has been started, no more Records
    + * can be added using lzma_index_hash_append().
    + *
    + * This function doesn't use lzma_stream structure to pass the input data.
    + * Instead, the input buffer is specified using three arguments. This is
    + * because it matches better the internal APIs of liblzma.
    + *
    + * \param       index_hash      Pointer to a lzma_index_hash structure
    + * \param       in              Pointer to the beginning of the input buffer
    + * \param[out]  in_pos          in[*in_pos] is the next byte to process
    + * \param       in_size         in[in_size] is the first byte not to process
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: So far good, but more input is needed.
    + *              - LZMA_STREAM_END: Index decoded successfully and it matches
    + *                the Records given with lzma_index_hash_append().
    + *              - LZMA_DATA_ERROR: Index is corrupt or doesn't match the
    + *                information given with lzma_index_hash_append().
    + *              - LZMA_BUF_ERROR: Cannot progress because *in_pos >= in_size.
    + *              - LZMA_PROG_ERROR
    + */
    +extern LZMA_API(lzma_ret) lzma_index_hash_decode(lzma_index_hash *index_hash,
    +		const uint8_t *in, size_t *in_pos, size_t in_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Get the size of the Index field as bytes
    + *
    + * This is needed to verify the Backward Size field in the Stream Footer.
    + *
    + * \param       index_hash      Pointer to a lzma_index_hash structure
    + *
    + * \return      Size of the Index field in bytes.
    + */
    +extern LZMA_API(lzma_vli) lzma_index_hash_size(
    +		const lzma_index_hash *index_hash)
    +		lzma_nothrow lzma_attr_pure;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/lzma12.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/lzma12.h
    new file mode 100644
    index 00000000000..05f5b66eb56
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/lzma12.h
    @@ -0,0 +1,568 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/lzma12.h
    + * \brief       LZMA1 and LZMA2 filters
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       LZMA1 Filter ID (for raw encoder/decoder only, not in .xz)
    + *
    + * LZMA1 is the very same thing as what was called just LZMA in LZMA Utils,
    + * 7-Zip, and LZMA SDK. It's called LZMA1 here to prevent developers from
    + * accidentally using LZMA when they actually want LZMA2.
    + */
    +#define LZMA_FILTER_LZMA1       LZMA_VLI_C(0x4000000000000001)
    +
    +/**
    + * \brief       LZMA1 Filter ID with extended options (for raw encoder/decoder)
    + *
    + * This is like LZMA_FILTER_LZMA1 but with this ID a few extra options
    + * are supported in the lzma_options_lzma structure:
    + *
    + *   - A flag to tell the encoder if the end of payload marker (EOPM) alias
    + *     end of stream (EOS) marker must be written at the end of the stream.
    + *     In contrast, LZMA_FILTER_LZMA1 always writes the end marker.
    + *
    + *   - Decoder needs to be told the uncompressed size of the stream
    + *     or that it is unknown (using the special value UINT64_MAX).
    + *     If the size is known, a flag can be set to allow the presence of
    + *     the end marker anyway. In contrast, LZMA_FILTER_LZMA1 always
    + *     behaves as if the uncompressed size was unknown.
    + *
    + * This allows handling file formats where LZMA1 streams are used but where
    + * the end marker isn't allowed or where it might not (always) be present.
    + * This extended LZMA1 functionality is provided as a Filter ID for raw
    + * encoder and decoder instead of adding new encoder and decoder initialization
    + * functions because this way it is possible to also use extra filters,
    + * for example, LZMA_FILTER_X86 in a filter chain with LZMA_FILTER_LZMA1EXT,
    + * which might be needed to handle some file formats.
    + */
    +#define LZMA_FILTER_LZMA1EXT    LZMA_VLI_C(0x4000000000000002)
    +
    +/**
    + * \brief       LZMA2 Filter ID
    + *
    + * Usually you want this instead of LZMA1. Compared to LZMA1, LZMA2 adds
    + * support for LZMA_SYNC_FLUSH, uncompressed chunks (smaller expansion
    + * when trying to compress incompressible data), possibility to change
    + * lc/lp/pb in the middle of encoding, and some other internal improvements.
    + */
    +#define LZMA_FILTER_LZMA2       LZMA_VLI_C(0x21)
    +
    +
    +/**
    + * \brief       Match finders
    + *
    + * Match finder has major effect on both speed and compression ratio.
    + * Usually hash chains are faster than binary trees.
    + *
    + * If you will use LZMA_SYNC_FLUSH often, the hash chains may be a better
    + * choice, because binary trees get much higher compression ratio penalty
    + * with LZMA_SYNC_FLUSH.
    + *
    + * The memory usage formulas are only rough estimates, which are closest to
    + * reality when dict_size is a power of two. The formulas are  more complex
    + * in reality, and can also change a little between liblzma versions. Use
    + * lzma_raw_encoder_memusage() to get more accurate estimate of memory usage.
    + */
    +typedef enum {
    +	LZMA_MF_HC3     = 0x03,
    +		/**<
    +		 * \brief       Hash Chain with 2- and 3-byte hashing
    +		 *
    +		 * Minimum nice_len: 3
    +		 *
    +		 * Memory usage:
    +		 *  - dict_size <= 16 MiB: dict_size * 7.5
    +		 *  - dict_size > 16 MiB: dict_size * 5.5 + 64 MiB
    +		 */
    +
    +	LZMA_MF_HC4     = 0x04,
    +		/**<
    +		 * \brief       Hash Chain with 2-, 3-, and 4-byte hashing
    +		 *
    +		 * Minimum nice_len: 4
    +		 *
    +		 * Memory usage:
    +		 *  - dict_size <= 32 MiB: dict_size * 7.5
    +		 *  - dict_size > 32 MiB: dict_size * 6.5
    +		 */
    +
    +	LZMA_MF_BT2     = 0x12,
    +		/**<
    +		 * \brief       Binary Tree with 2-byte hashing
    +		 *
    +		 * Minimum nice_len: 2
    +		 *
    +		 * Memory usage: dict_size * 9.5
    +		 */
    +
    +	LZMA_MF_BT3     = 0x13,
    +		/**<
    +		 * \brief       Binary Tree with 2- and 3-byte hashing
    +		 *
    +		 * Minimum nice_len: 3
    +		 *
    +		 * Memory usage:
    +		 *  - dict_size <= 16 MiB: dict_size * 11.5
    +		 *  - dict_size > 16 MiB: dict_size * 9.5 + 64 MiB
    +		 */
    +
    +	LZMA_MF_BT4     = 0x14
    +		/**<
    +		 * \brief       Binary Tree with 2-, 3-, and 4-byte hashing
    +		 *
    +		 * Minimum nice_len: 4
    +		 *
    +		 * Memory usage:
    +		 *  - dict_size <= 32 MiB: dict_size * 11.5
    +		 *  - dict_size > 32 MiB: dict_size * 10.5
    +		 */
    +} lzma_match_finder;
    +
    +
    +/**
    + * \brief       Test if given match finder is supported
    + *
    + * It is safe to call this with a value that isn't listed in
    + * lzma_match_finder enumeration; the return value will be false.
    + *
    + * There is no way to list which match finders are available in this
    + * particular liblzma version and build. It would be useless, because
    + * a new match finder, which the application developer wasn't aware,
    + * could require giving additional options to the encoder that the older
    + * match finders don't need.
    + *
    + * \param       match_finder    Match finder ID
    + *
    + * \return      lzma_bool:
    + *              - true if the match finder is supported by this liblzma build.
    + *              - false otherwise.
    + */
    +extern LZMA_API(lzma_bool) lzma_mf_is_supported(lzma_match_finder match_finder)
    +		lzma_nothrow lzma_attr_const;
    +
    +
    +/**
    + * \brief       Compression modes
    + *
    + * This selects the function used to analyze the data produced by the match
    + * finder.
    + */
    +typedef enum {
    +	LZMA_MODE_FAST = 1,
    +		/**<
    +		 * \brief       Fast compression
    +		 *
    +		 * Fast mode is usually at its best when combined with
    +		 * a hash chain match finder.
    +		 */
    +
    +	LZMA_MODE_NORMAL = 2
    +		/**<
    +		 * \brief       Normal compression
    +		 *
    +		 * This is usually notably slower than fast mode. Use this
    +		 * together with binary tree match finders to expose the
    +		 * full potential of the LZMA1 or LZMA2 encoder.
    +		 */
    +} lzma_mode;
    +
    +
    +/**
    + * \brief       Test if given compression mode is supported
    + *
    + * It is safe to call this with a value that isn't listed in lzma_mode
    + * enumeration; the return value will be false.
    + *
    + * There is no way to list which modes are available in this particular
    + * liblzma version and build. It would be useless, because a new compression
    + * mode, which the application developer wasn't aware, could require giving
    + * additional options to the encoder that the older modes don't need.
    + *
    + * \param       mode    Mode ID.
    + *
    + * \return      lzma_bool:
    + *              - true if the compression mode is supported by this liblzma
    + *                build.
    + *              - false otherwise.
    + */
    +extern LZMA_API(lzma_bool) lzma_mode_is_supported(lzma_mode mode)
    +		lzma_nothrow lzma_attr_const;
    +
    +
    +/**
    + * \brief       Options specific to the LZMA1 and LZMA2 filters
    + *
    + * Since LZMA1 and LZMA2 share most of the code, it's simplest to share
    + * the options structure too. For encoding, all but the reserved variables
    + * need to be initialized unless specifically mentioned otherwise.
    + * lzma_lzma_preset() can be used to get a good starting point.
    + *
    + * For raw decoding, both LZMA1 and LZMA2 need dict_size, preset_dict, and
    + * preset_dict_size (if preset_dict != NULL). LZMA1 needs also lc, lp, and pb.
    + */
    +typedef struct {
    +	/**
    +	 * \brief       Dictionary size in bytes
    +	 *
    +	 * Dictionary size indicates how many bytes of the recently processed
    +	 * uncompressed data is kept in memory. One method to reduce size of
    +	 * the uncompressed data is to store distance-length pairs, which
    +	 * indicate what data to repeat from the dictionary buffer. Thus,
    +	 * the bigger the dictionary, the better the compression ratio
    +	 * usually is.
    +	 *
    +	 * Maximum size of the dictionary depends on multiple things:
    +	 *  - Memory usage limit
    +	 *  - Available address space (not a problem on 64-bit systems)
    +	 *  - Selected match finder (encoder only)
    +	 *
    +	 * Currently the maximum dictionary size for encoding is 1.5 GiB
    +	 * (i.e. (UINT32_C(1) << 30) + (UINT32_C(1) << 29)) even on 64-bit
    +	 * systems for certain match finder implementation reasons. In the
    +	 * future, there may be match finders that support bigger
    +	 * dictionaries.
    +	 *
    +	 * Decoder already supports dictionaries up to 4 GiB - 1 B (i.e.
    +	 * UINT32_MAX), so increasing the maximum dictionary size of the
    +	 * encoder won't cause problems for old decoders.
    +	 *
    +	 * Because extremely small dictionaries sizes would have unneeded
    +	 * overhead in the decoder, the minimum dictionary size is 4096 bytes.
    +	 *
    +	 * \note        When decoding, too big dictionary does no other harm
    +	 *              than wasting memory.
    +	 */
    +	uint32_t dict_size;
    +#	define LZMA_DICT_SIZE_MIN       UINT32_C(4096)
    +#	define LZMA_DICT_SIZE_DEFAULT   (UINT32_C(1) << 23)
    +
    +	/**
    +	 * \brief       Pointer to an initial dictionary
    +	 *
    +	 * It is possible to initialize the LZ77 history window using
    +	 * a preset dictionary. It is useful when compressing many
    +	 * similar, relatively small chunks of data independently from
    +	 * each other. The preset dictionary should contain typical
    +	 * strings that occur in the files being compressed. The most
    +	 * probable strings should be near the end of the preset dictionary.
    +	 *
    +	 * This feature should be used only in special situations. For
    +	 * now, it works correctly only with raw encoding and decoding.
    +	 * Currently none of the container formats supported by
    +	 * liblzma allow preset dictionary when decoding, thus if
    +	 * you create a .xz or .lzma file with preset dictionary, it
    +	 * cannot be decoded with the regular decoder functions. In the
    +	 * future, the .xz format will likely get support for preset
    +	 * dictionary though.
    +	 */
    +	const uint8_t *preset_dict;
    +
    +	/**
    +	 * \brief       Size of the preset dictionary
    +	 *
    +	 * Specifies the size of the preset dictionary. If the size is
    +	 * bigger than dict_size, only the last dict_size bytes are
    +	 * processed.
    +	 *
    +	 * This variable is read only when preset_dict is not NULL.
    +	 * If preset_dict is not NULL but preset_dict_size is zero,
    +	 * no preset dictionary is used (identical to only setting
    +	 * preset_dict to NULL).
    +	 */
    +	uint32_t preset_dict_size;
    +
    +	/**
    +	 * \brief       Number of literal context bits
    +	 *
    +	 * How many of the highest bits of the previous uncompressed
    +	 * eight-bit byte (also known as 'literal') are taken into
    +	 * account when predicting the bits of the next literal.
    +	 *
    +	 * E.g. in typical English text, an upper-case letter is
    +	 * often followed by a lower-case letter, and a lower-case
    +	 * letter is usually followed by another lower-case letter.
    +	 * In the US-ASCII character set, the highest three bits are 010
    +	 * for upper-case letters and 011 for lower-case letters.
    +	 * When lc is at least 3, the literal coding can take advantage of
    +	 * this property in the uncompressed data.
    +	 *
    +	 * There is a limit that applies to literal context bits and literal
    +	 * position bits together: lc + lp <= 4. Without this limit the
    +	 * decoding could become very slow, which could have security related
    +	 * results in some cases like email servers doing virus scanning.
    +	 * This limit also simplifies the internal implementation in liblzma.
    +	 *
    +	 * There may be LZMA1 streams that have lc + lp > 4 (maximum possible
    +	 * lc would be 8). It is not possible to decode such streams with
    +	 * liblzma.
    +	 */
    +	uint32_t lc;
    +#	define LZMA_LCLP_MIN    0
    +#	define LZMA_LCLP_MAX    4
    +#	define LZMA_LC_DEFAULT  3
    +
    +	/**
    +	 * \brief       Number of literal position bits
    +	 *
    +	 * lp affects what kind of alignment in the uncompressed data is
    +	 * assumed when encoding literals. A literal is a single 8-bit byte.
    +	 * See pb below for more information about alignment.
    +	 */
    +	uint32_t lp;
    +#	define LZMA_LP_DEFAULT  0
    +
    +	/**
    +	 * \brief       Number of position bits
    +	 *
    +	 * pb affects what kind of alignment in the uncompressed data is
    +	 * assumed in general. The default means four-byte alignment
    +	 * (2^ pb =2^2=4), which is often a good choice when there's
    +	 * no better guess.
    +	 *
    +	 * When the alignment is known, setting pb accordingly may reduce
    +	 * the file size a little. E.g. with text files having one-byte
    +	 * alignment (US-ASCII, ISO-8859-*, UTF-8), setting pb=0 can
    +	 * improve compression slightly. For UTF-16 text, pb=1 is a good
    +	 * choice. If the alignment is an odd number like 3 bytes, pb=0
    +	 * might be the best choice.
    +	 *
    +	 * Even though the assumed alignment can be adjusted with pb and
    +	 * lp, LZMA1 and LZMA2 still slightly favor 16-byte alignment.
    +	 * It might be worth taking into account when designing file formats
    +	 * that are likely to be often compressed with LZMA1 or LZMA2.
    +	 */
    +	uint32_t pb;
    +#	define LZMA_PB_MIN      0
    +#	define LZMA_PB_MAX      4
    +#	define LZMA_PB_DEFAULT  2
    +
    +	/** Compression mode */
    +	lzma_mode mode;
    +
    +	/**
    +	 * \brief       Nice length of a match
    +	 *
    +	 * This determines how many bytes the encoder compares from the match
    +	 * candidates when looking for the best match. Once a match of at
    +	 * least nice_len bytes long is found, the encoder stops looking for
    +	 * better candidates and encodes the match. (Naturally, if the found
    +	 * match is actually longer than nice_len, the actual length is
    +	 * encoded; it's not truncated to nice_len.)
    +	 *
    +	 * Bigger values usually increase the compression ratio and
    +	 * compression time. For most files, 32 to 128 is a good value,
    +	 * which gives very good compression ratio at good speed.
    +	 *
    +	 * The exact minimum value depends on the match finder. The maximum
    +	 * is 273, which is the maximum length of a match that LZMA1 and
    +	 * LZMA2 can encode.
    +	 */
    +	uint32_t nice_len;
    +
    +	/** Match finder ID */
    +	lzma_match_finder mf;
    +
    +	/**
    +	 * \brief       Maximum search depth in the match finder
    +	 *
    +	 * For every input byte, match finder searches through the hash chain
    +	 * or binary tree in a loop, each iteration going one step deeper in
    +	 * the chain or tree. The searching stops if
    +	 *  - a match of at least nice_len bytes long is found;
    +	 *  - all match candidates from the hash chain or binary tree have
    +	 *    been checked; or
    +	 *  - maximum search depth is reached.
    +	 *
    +	 * Maximum search depth is needed to prevent the match finder from
    +	 * wasting too much time in case there are lots of short match
    +	 * candidates. On the other hand, stopping the search before all
    +	 * candidates have been checked can reduce compression ratio.
    +	 *
    +	 * Setting depth to zero tells liblzma to use an automatic default
    +	 * value, that depends on the selected match finder and nice_len.
    +	 * The default is in the range [4, 200] or so (it may vary between
    +	 * liblzma versions).
    +	 *
    +	 * Using a bigger depth value than the default can increase
    +	 * compression ratio in some cases. There is no strict maximum value,
    +	 * but high values (thousands or millions) should be used with care:
    +	 * the encoder could remain fast enough with typical input, but
    +	 * malicious input could cause the match finder to slow down
    +	 * dramatically, possibly creating a denial of service attack.
    +	 */
    +	uint32_t depth;
    +
    +	/**
    +	 * \brief       For LZMA_FILTER_LZMA1EXT: Extended flags
    +	 *
    +	 * This is used only with LZMA_FILTER_LZMA1EXT.
    +	 *
    +	 * Currently only one flag is supported, LZMA_LZMA1EXT_ALLOW_EOPM:
    +	 *
    +	 *   - Encoder: If the flag is set, then end marker is written just
    +	 *     like it is with LZMA_FILTER_LZMA1. Without this flag the
    +	 *     end marker isn't written and the application has to store
    +	 *     the uncompressed size somewhere outside the compressed stream.
    +	 *     To decompress streams without the end marker, the application
    +	 *     has to set the correct uncompressed size in ext_size_low and
    +	 *     ext_size_high.
    +	 *
    +	 *   - Decoder: If the uncompressed size in ext_size_low and
    +	 *     ext_size_high is set to the special value UINT64_MAX
    +	 *     (indicating unknown uncompressed size) then this flag is
    +	 *     ignored and the end marker must always be present, that is,
    +	 *     the behavior is identical to LZMA_FILTER_LZMA1.
    +	 *
    +	 *     Otherwise, if this flag isn't set, then the input stream
    +	 *     must not have the end marker; if the end marker is detected
    +	 *     then it will result in LZMA_DATA_ERROR. This is useful when
    +	 *     it is known that the stream must not have the end marker and
    +	 *     strict validation is wanted.
    +	 *
    +	 *     If this flag is set, then it is autodetected if the end marker
    +	 *     is present after the specified number of uncompressed bytes
    +	 *     has been decompressed (ext_size_low and ext_size_high). The
    +	 *     end marker isn't allowed in any other position. This behavior
    +	 *     is useful when uncompressed size is known but the end marker
    +	 *     may or may not be present. This is the case, for example,
    +	 *     in .7z files (valid .7z files that have the end marker in
    +	 *     LZMA1 streams are rare but they do exist).
    +	 */
    +	uint32_t ext_flags;
    +#	define LZMA_LZMA1EXT_ALLOW_EOPM   UINT32_C(0x01)
    +
    +	/**
    +	 * \brief       For LZMA_FILTER_LZMA1EXT: Uncompressed size (low bits)
    +	 *
    +	 * The 64-bit uncompressed size is needed for decompression with
    +	 * LZMA_FILTER_LZMA1EXT. The size is ignored by the encoder.
    +	 *
    +	 * The special value UINT64_MAX indicates that the uncompressed size
    +	 * is unknown and that the end of payload marker (also known as
    +	 * end of stream marker) must be present to indicate the end of
    +	 * the LZMA1 stream. Any other value indicates the expected
    +	 * uncompressed size of the LZMA1 stream. (If LZMA1 was used together
    +	 * with filters that change the size of the data then the uncompressed
    +	 * size of the LZMA1 stream could be different than the final
    +	 * uncompressed size of the filtered stream.)
    +	 *
    +	 * ext_size_low holds the least significant 32 bits of the
    +	 * uncompressed size. The most significant 32 bits must be set
    +	 * in ext_size_high. The macro lzma_ext_size_set(opt_lzma, u64size)
    +	 * can be used to set these members.
    +	 *
    +	 * The 64-bit uncompressed size is split into two uint32_t variables
    +	 * because there were no reserved uint64_t members and using the
    +	 * same options structure for LZMA_FILTER_LZMA1, LZMA_FILTER_LZMA1EXT,
    +	 * and LZMA_FILTER_LZMA2 was otherwise more convenient than having
    +	 * a new options structure for LZMA_FILTER_LZMA1EXT. (Replacing two
    +	 * uint32_t members with one uint64_t changes the ABI on some systems
    +	 * as the alignment of this struct can increase from 4 bytes to 8.)
    +	 */
    +	uint32_t ext_size_low;
    +
    +	/**
    +	 * \brief       For LZMA_FILTER_LZMA1EXT: Uncompressed size (high bits)
    +	 *
    +	 * This holds the most significant 32 bits of the uncompressed size.
    +	 */
    +	uint32_t ext_size_high;
    +
    +	/*
    +	 * Reserved space to allow possible future extensions without
    +	 * breaking the ABI. You should not touch these, because the names
    +	 * of these variables may change. These are and will never be used
    +	 * with the currently supported options, so it is safe to leave these
    +	 * uninitialized.
    +	 */
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int4;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int5;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int6;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int7;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int8;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum1;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum2;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum3;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum4;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr1;
    +
    +	/** \private     Reserved member. */
    +	void *reserved_ptr2;
    +
    +} lzma_options_lzma;
    +
    +
    +/**
    + * \brief       Macro to set the 64-bit uncompressed size in ext_size_*
    + *
    + * This might be convenient when decoding using LZMA_FILTER_LZMA1EXT.
    + * This isn't used with LZMA_FILTER_LZMA1 or LZMA_FILTER_LZMA2.
    + */
    +#define lzma_set_ext_size(opt_lzma2, u64size) \
    +do { \
    +	(opt_lzma2).ext_size_low = (uint32_t)(u64size); \
    +	(opt_lzma2).ext_size_high = (uint32_t)((uint64_t)(u64size) >> 32); \
    +} while (0)
    +
    +
    +/**
    + * \brief       Set a compression preset to lzma_options_lzma structure
    + *
    + * 0 is the fastest and 9 is the slowest. These match the switches -0 .. -9
    + * of the xz command line tool. In addition, it is possible to bitwise-or
    + * flags to the preset. Currently only LZMA_PRESET_EXTREME is supported.
    + * The flags are defined in container.h, because the flags are used also
    + * with lzma_easy_encoder().
    + *
    + * The preset levels are subject to changes between liblzma versions.
    + *
    + * This function is available only if LZMA1 or LZMA2 encoder has been enabled
    + * when building liblzma.
    + *
    + * If features (like certain match finders) have been disabled at build time,
    + * then the function may return success (false) even though the resulting
    + * LZMA1/LZMA2 options may not be usable for encoder initialization
    + * (LZMA_OPTIONS_ERROR).
    + *
    + * \param[out]  options Pointer to LZMA1 or LZMA2 options to be filled
    + * \param       preset  Preset level bitwse-ORed with preset flags
    + *
    + * \return      lzma_bool:
    + *              - true if the preset is not supported (failure).
    + *              - false otherwise (success).
    + */
    +extern LZMA_API(lzma_bool) lzma_lzma_preset(
    +		lzma_options_lzma *options, uint32_t preset) lzma_nothrow;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/stream_flags.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/stream_flags.h
    new file mode 100644
    index 00000000000..a33fe468376
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/stream_flags.h
    @@ -0,0 +1,265 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/stream_flags.h
    + * \brief       .xz Stream Header and Stream Footer encoder and decoder
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       Size of Stream Header and Stream Footer
    + *
    + * Stream Header and Stream Footer have the same size and they are not
    + * going to change even if a newer version of the .xz file format is
    + * developed in future.
    + */
    +#define LZMA_STREAM_HEADER_SIZE 12
    +
    +
    +/**
    + * \brief       Options for encoding/decoding Stream Header and Stream Footer
    + */
    +typedef struct {
    +	/**
    +	 * \brief       Stream Flags format version
    +	 *
    +	 * To prevent API and ABI breakages if new features are needed in
    +	 * Stream Header or Stream Footer, a version number is used to
    +	 * indicate which members in this structure are in use. For now,
    +	 * version must always be zero. With non-zero version, the
    +	 * lzma_stream_header_encode() and lzma_stream_footer_encode()
    +	 * will return LZMA_OPTIONS_ERROR.
    +	 *
    +	 * lzma_stream_header_decode() and lzma_stream_footer_decode()
    +	 * will always set this to the lowest value that supports all the
    +	 * features indicated by the Stream Flags field. The application
    +	 * must check that the version number set by the decoding functions
    +	 * is supported by the application. Otherwise it is possible that
    +	 * the application will decode the Stream incorrectly.
    +	 */
    +	uint32_t version;
    +
    +	/**
    +	 * \brief       Backward Size
    +	 *
    +	 * Backward Size must be a multiple of four bytes. In this Stream
    +	 * format version, Backward Size is the size of the Index field.
    +	 *
    +	 * Backward Size isn't actually part of the Stream Flags field, but
    +	 * it is convenient to include in this structure anyway. Backward
    +	 * Size is present only in the Stream Footer. There is no need to
    +	 * initialize backward_size when encoding Stream Header.
    +	 *
    +	 * lzma_stream_header_decode() always sets backward_size to
    +	 * LZMA_VLI_UNKNOWN so that it is convenient to use
    +	 * lzma_stream_flags_compare() when both Stream Header and Stream
    +	 * Footer have been decoded.
    +	 */
    +	lzma_vli backward_size;
    +
    +	/**
    +	 * \brief       Minimum value for lzma_stream_flags.backward_size
    +	 */
    +#	define LZMA_BACKWARD_SIZE_MIN 4
    +
    +	/**
    +	 * \brief       Maximum value for lzma_stream_flags.backward_size
    +	 */
    +#	define LZMA_BACKWARD_SIZE_MAX (LZMA_VLI_C(1) << 34)
    +
    +	/**
    +	 * \brief       Check ID
    +	 *
    +	 * This indicates the type of the integrity check calculated from
    +	 * uncompressed data.
    +	 */
    +	lzma_check check;
    +
    +	/*
    +	 * Reserved space to allow possible future extensions without
    +	 * breaking the ABI. You should not touch these, because the
    +	 * names of these variables may change.
    +	 *
    +	 * (We will never be able to use all of these since Stream Flags
    +	 * is just two bytes plus Backward Size of four bytes. But it's
    +	 * nice to have the proper types when they are needed.)
    +	 */
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum1;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum2;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum3;
    +
    +	/** \private     Reserved member. */
    +	lzma_reserved_enum reserved_enum4;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool1;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool2;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool3;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool4;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool5;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool6;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool7;
    +
    +	/** \private     Reserved member. */
    +	lzma_bool reserved_bool8;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int1;
    +
    +	/** \private     Reserved member. */
    +	uint32_t reserved_int2;
    +
    +} lzma_stream_flags;
    +
    +
    +/**
    + * \brief       Encode Stream Header
    + *
    + * \param       options     Stream Header options to be encoded.
    + *                          options->backward_size is ignored and doesn't
    + *                          need to be initialized.
    + * \param[out]  out         Beginning of the output buffer of
    + *                          LZMA_STREAM_HEADER_SIZE bytes.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful.
    + *              - LZMA_OPTIONS_ERROR: options->version is not supported by
    + *                this liblzma version.
    + *              - LZMA_PROG_ERROR: Invalid options.
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_header_encode(
    +		const lzma_stream_flags *options, uint8_t *out)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Encode Stream Footer
    + *
    + * \param       options     Stream Footer options to be encoded.
    + * \param[out]  out         Beginning of the output buffer of
    + *                          LZMA_STREAM_HEADER_SIZE bytes.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Encoding was successful.
    + *              - LZMA_OPTIONS_ERROR: options->version is not supported by
    + *                this liblzma version.
    + *              - LZMA_PROG_ERROR: Invalid options.
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_footer_encode(
    +		const lzma_stream_flags *options, uint8_t *out)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Decode Stream Header
    + *
    + * options->backward_size is always set to LZMA_VLI_UNKNOWN. This is to
    + * help comparing Stream Flags from Stream Header and Stream Footer with
    + * lzma_stream_flags_compare().
    + *
    + * \note        When decoding .xz files that contain multiple Streams, it may
    + *              make sense to print "file format not recognized" only if
    + *              decoding of the Stream Header of the \a first Stream gives
    + *              LZMA_FORMAT_ERROR. If non-first Stream Header gives
    + *              LZMA_FORMAT_ERROR, the message used for LZMA_DATA_ERROR is
    + *              probably more appropriate.
    + *              For example, the Stream decoder in liblzma uses
    + *              LZMA_DATA_ERROR if LZMA_FORMAT_ERROR is returned by
    + *              lzma_stream_header_decode() when decoding non-first Stream.
    + *
    + * \param[out]  options     Target for the decoded Stream Header options.
    + * \param       in          Beginning of the input buffer of
    + *                          LZMA_STREAM_HEADER_SIZE bytes.
    + *
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Decoding was successful.
    + *              - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
    + *                buffer cannot be Stream Header.
    + *              - LZMA_DATA_ERROR: CRC32 doesn't match, thus the header
    + *                is corrupt.
    + *              - LZMA_OPTIONS_ERROR: Unsupported options are present
    + *                in the header.
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_header_decode(
    +		lzma_stream_flags *options, const uint8_t *in)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Decode Stream Footer
    + *
    + * \note        If Stream Header was already decoded successfully, but
    + *              decoding Stream Footer returns LZMA_FORMAT_ERROR, the
    + *              application should probably report some other error message
    + *              than "file format not recognized". The file likely
    + *              is corrupt (possibly truncated). The Stream decoder in liblzma
    + *              uses LZMA_DATA_ERROR in this situation.
    + *
    + * \param[out]  options     Target for the decoded Stream Footer options.
    + * \param       in          Beginning of the input buffer of
    + *                          LZMA_STREAM_HEADER_SIZE bytes.
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Decoding was successful.
    + *              - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
    + *                buffer cannot be Stream Footer.
    + *              - LZMA_DATA_ERROR: CRC32 doesn't match, thus the Stream Footer
    + *                is corrupt.
    + *              - LZMA_OPTIONS_ERROR: Unsupported options are present
    + *                in Stream Footer.
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_footer_decode(
    +		lzma_stream_flags *options, const uint8_t *in)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +
    +/**
    + * \brief       Compare two lzma_stream_flags structures
    + *
    + * backward_size values are compared only if both are not
    + * LZMA_VLI_UNKNOWN.
    + *
    + * \param       a       Pointer to lzma_stream_flags structure
    + * \param       b       Pointer to lzma_stream_flags structure
    + *
    + * \return      Possible lzma_ret values:
    + *              - LZMA_OK: Both are equal. If either had backward_size set
    + *                to LZMA_VLI_UNKNOWN, backward_size values were not
    + *                compared or validated.
    + *              - LZMA_DATA_ERROR: The structures differ.
    + *              - LZMA_OPTIONS_ERROR: version in either structure is greater
    + *                than the maximum supported version (currently zero).
    + *              - LZMA_PROG_ERROR: Invalid value, e.g. invalid check or
    + *                backward_size.
    + */
    +extern LZMA_API(lzma_ret) lzma_stream_flags_compare(
    +		const lzma_stream_flags *a, const lzma_stream_flags *b)
    +		lzma_nothrow lzma_attr_pure;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/version.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/version.h
    new file mode 100644
    index 00000000000..e86c0ea4c3d
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/version.h
    @@ -0,0 +1,134 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/version.h
    + * \brief       Version number
    + * \note        Never include this file directly. Use  instead.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/** \brief Major version number of the liblzma release. */
    +#define LZMA_VERSION_MAJOR 5
    +
    +/** \brief Minor version number of the liblzma release. */
    +#define LZMA_VERSION_MINOR 6
    +
    +/** \brief Patch version number of the liblzma release. */
    +#define LZMA_VERSION_PATCH 3
    +
    +/**
    + * \brief Version stability marker
    + *
    + * This will always be one of three values:
    + *   - LZMA_VERSION_STABILITY_ALPHA
    + *   - LZMA_VERSION_STABILITY_BETA
    + *   - LZMA_VERSION_STABILITY_STABLE
    + */
    +#define LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_STABLE
    +
    +/** \brief Commit version number of the liblzma release */
    +#ifndef LZMA_VERSION_COMMIT
    +#	define LZMA_VERSION_COMMIT ""
    +#endif
    +
    +
    +/*
    + * Map symbolic stability levels to integers.
    + */
    +#define LZMA_VERSION_STABILITY_ALPHA 0
    +#define LZMA_VERSION_STABILITY_BETA 1
    +#define LZMA_VERSION_STABILITY_STABLE 2
    +
    +
    +/**
    + * \brief       Compile-time version number
    + *
    + * The version number is of format xyyyzzzs where
    + *  - x = major
    + *  - yyy = minor
    + *  - zzz = revision
    + *  - s indicates stability: 0 = alpha, 1 = beta, 2 = stable
    + *
    + * The same xyyyzzz triplet is never reused with different stability levels.
    + * For example, if 5.1.0alpha has been released, there will never be 5.1.0beta
    + * or 5.1.0 stable.
    + *
    + * \note        The version number of liblzma has nothing to with
    + *              the version number of Igor Pavlov's LZMA SDK.
    + */
    +#define LZMA_VERSION (LZMA_VERSION_MAJOR * UINT32_C(10000000) \
    +		+ LZMA_VERSION_MINOR * UINT32_C(10000) \
    +		+ LZMA_VERSION_PATCH * UINT32_C(10) \
    +		+ LZMA_VERSION_STABILITY)
    +
    +
    +/*
    + * Macros to construct the compile-time version string
    + */
    +#if LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_ALPHA
    +#	define LZMA_VERSION_STABILITY_STRING "alpha"
    +#elif LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_BETA
    +#	define LZMA_VERSION_STABILITY_STRING "beta"
    +#elif LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_STABLE
    +#	define LZMA_VERSION_STABILITY_STRING ""
    +#else
    +#	error Incorrect LZMA_VERSION_STABILITY
    +#endif
    +
    +#define LZMA_VERSION_STRING_C_(major, minor, patch, stability, commit) \
    +		#major "." #minor "." #patch stability commit
    +
    +#define LZMA_VERSION_STRING_C(major, minor, patch, stability, commit) \
    +		LZMA_VERSION_STRING_C_(major, minor, patch, stability, commit)
    +
    +
    +/**
    + * \brief       Compile-time version as a string
    + *
    + * This can be for example "4.999.5alpha", "4.999.8beta", or "5.0.0" (stable
    + * versions don't have any "stable" suffix). In future, a snapshot built
    + * from source code repository may include an additional suffix, for example
    + * "4.999.8beta-21-g1d92". The commit ID won't be available in numeric form
    + * in LZMA_VERSION macro.
    + */
    +#define LZMA_VERSION_STRING LZMA_VERSION_STRING_C( \
    +		LZMA_VERSION_MAJOR, LZMA_VERSION_MINOR, \
    +		LZMA_VERSION_PATCH, LZMA_VERSION_STABILITY_STRING, \
    +		LZMA_VERSION_COMMIT)
    +
    +
    +/* #ifndef is needed for use with windres (MinGW-w64 or Cygwin). */
    +#ifndef LZMA_H_INTERNAL_RC
    +
    +/**
    + * \brief       Run-time version number as an integer
    + *
    + * This allows an application to compare if it was built against the same,
    + * older, or newer version of liblzma that is currently running.
    + *
    + * \return The value of LZMA_VERSION macro at the compile time of liblzma
    + */
    +extern LZMA_API(uint32_t) lzma_version_number(void)
    +		lzma_nothrow lzma_attr_const;
    +
    +
    +/**
    + * \brief       Run-time version as a string
    + *
    + * This function may be useful to display which version of liblzma an
    + * application is currently using.
    + *
    + * \return      Run-time version of liblzma
    + */
    +extern LZMA_API(const char *) lzma_version_string(void)
    +		lzma_nothrow lzma_attr_const;
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/vli.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/vli.h
    new file mode 100644
    index 00000000000..6b049021b90
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/vli.h
    @@ -0,0 +1,166 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/**
    + * \file        lzma/vli.h
    + * \brief       Variable-length integer handling
    + * \note        Never include this file directly. Use  instead.
    + *
    + * In the .xz format, most integers are encoded in a variable-length
    + * representation, which is sometimes called little endian base-128 encoding.
    + * This saves space when smaller values are more likely than bigger values.
    + *
    + * The encoding scheme encodes seven bits to every byte, using minimum
    + * number of bytes required to represent the given value. Encodings that use
    + * non-minimum number of bytes are invalid, thus every integer has exactly
    + * one encoded representation. The maximum number of bits in a VLI is 63,
    + * thus the vli argument must be less than or equal to UINT64_MAX / 2. You
    + * should use LZMA_VLI_MAX for clarity.
    + */
    +
    +/*
    + * Author: Lasse Collin
    + */
    +
    +#ifndef LZMA_H_INTERNAL
    +#	error Never include this file directly. Use  instead.
    +#endif
    +
    +
    +/**
    + * \brief       Maximum supported value of a variable-length integer
    + */
    +#define LZMA_VLI_MAX (UINT64_MAX / 2)
    +
    +/**
    + * \brief       VLI value to denote that the value is unknown
    + */
    +#define LZMA_VLI_UNKNOWN UINT64_MAX
    +
    +/**
    + * \brief       Maximum supported encoded length of variable length integers
    + */
    +#define LZMA_VLI_BYTES_MAX 9
    +
    +/**
    + * \brief       VLI constant suffix
    + */
    +#define LZMA_VLI_C(n) UINT64_C(n)
    +
    +
    +/**
    + * \brief       Variable-length integer type
    + *
    + * Valid VLI values are in the range [0, LZMA_VLI_MAX]. Unknown value is
    + * indicated with LZMA_VLI_UNKNOWN, which is the maximum value of the
    + * underlying integer type.
    + *
    + * lzma_vli will be uint64_t for the foreseeable future. If a bigger size
    + * is needed in the future, it is guaranteed that 2 * LZMA_VLI_MAX will
    + * not overflow lzma_vli. This simplifies integer overflow detection.
    + */
    +typedef uint64_t lzma_vli;
    +
    +
    +/**
    + * \brief       Validate a variable-length integer
    + *
    + * This is useful to test that application has given acceptable values
    + * for example in the uncompressed_size and compressed_size variables.
    + *
    + * \return      True if the integer is representable as a VLI or if it
    + *              indicates an unknown value. False otherwise.
    + */
    +#define lzma_vli_is_valid(vli) \
    +	((vli) <= LZMA_VLI_MAX || (vli) == LZMA_VLI_UNKNOWN)
    +
    +
    +/**
    + * \brief       Encode a variable-length integer
    + *
    + * This function has two modes: single-call and multi-call. Single-call mode
    + * encodes the whole integer at once; it is an error if the output buffer is
    + * too small. Multi-call mode saves the position in *vli_pos, and thus it is
    + * possible to continue encoding if the buffer becomes full before the whole
    + * integer has been encoded.
    + *
    + * \param       vli       Integer to be encoded
    + * \param[out]  vli_pos   How many VLI-encoded bytes have already been written
    + *                        out. When starting to encode a new integer in
    + *                        multi-call mode, *vli_pos must be set to zero.
    + *                        To use single-call encoding, set vli_pos to NULL.
    + * \param[out]  out       Beginning of the output buffer
    + * \param[out]  out_pos   The next byte will be written to out[*out_pos].
    + * \param       out_size  Size of the out buffer; the first byte into
    + *                        which no data is written to is out[out_size].
    + *
    + * \return      Slightly different return values are used in multi-call and
    + *              single-call modes.
    + *
    + *              Single-call (vli_pos == NULL):
    + *              - LZMA_OK: Integer successfully encoded.
    + *              - LZMA_PROG_ERROR: Arguments are not sane. This can be due
    + *                to too little output space; single-call mode doesn't use
    + *                LZMA_BUF_ERROR, since the application should have checked
    + *                the encoded size with lzma_vli_size().
    + *
    + *              Multi-call (vli_pos != NULL):
    + *              - LZMA_OK: So far all OK, but the integer is not
    + *                completely written out yet.
    + *              - LZMA_STREAM_END: Integer successfully encoded.
    + *              - LZMA_BUF_ERROR: No output space was provided.
    + *              - LZMA_PROG_ERROR: Arguments are not sane.
    + */
    +extern LZMA_API(lzma_ret) lzma_vli_encode(lzma_vli vli, size_t *vli_pos,
    +		uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
    +
    +
    +/**
    + * \brief       Decode a variable-length integer
    + *
    + * Like lzma_vli_encode(), this function has single-call and multi-call modes.
    + *
    + * \param[out]  vli       Pointer to decoded integer. The decoder will
    + *                        initialize it to zero when *vli_pos == 0, so
    + *                        application isn't required to initialize *vli.
    + * \param[out]  vli_pos   How many bytes have already been decoded. When
    + *                        starting to decode a new integer in multi-call
    + *                        mode, *vli_pos must be initialized to zero. To
    + *                        use single-call decoding, set vli_pos to NULL.
    + * \param       in        Beginning of the input buffer
    + * \param[out]  in_pos    The next byte will be read from in[*in_pos].
    + * \param       in_size   Size of the input buffer; the first byte that
    + *                        won't be read is in[in_size].
    + *
    + * \return      Slightly different return values are used in multi-call and
    + *              single-call modes.
    + *
    + *              Single-call (vli_pos == NULL):
    + *              - LZMA_OK: Integer successfully decoded.
    + *              - LZMA_DATA_ERROR: Integer is corrupt. This includes hitting
    + *                the end of the input buffer before the whole integer was
    + *                decoded; providing no input at all will use LZMA_DATA_ERROR.
    + *              - LZMA_PROG_ERROR: Arguments are not sane.
    + *
    + *              Multi-call (vli_pos != NULL):
    + *              - LZMA_OK: So far all OK, but the integer is not
    + *                completely decoded yet.
    + *              - LZMA_STREAM_END: Integer successfully decoded.
    + *              - LZMA_DATA_ERROR: Integer is corrupt.
    + *              - LZMA_BUF_ERROR: No input was provided.
    + *              - LZMA_PROG_ERROR: Arguments are not sane.
    + */
    +extern LZMA_API(lzma_ret) lzma_vli_decode(lzma_vli *vli, size_t *vli_pos,
    +		const uint8_t *in, size_t *in_pos, size_t in_size)
    +		lzma_nothrow;
    +
    +
    +/**
    + * \brief       Get the number of bytes required to encode a VLI
    + *
    + * \param       vli       Integer whose encoded size is to be determined
    + *
    + * \return      Number of bytes on success (1-9). If vli isn't valid,
    + *              zero is returned.
    + */
    +extern LZMA_API(uint32_t) lzma_vli_size(lzma_vli vli)
    +		lzma_nothrow lzma_attr_pure;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.c
    new file mode 100644
    index 00000000000..7734ace1856
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.c
    @@ -0,0 +1,173 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       check.c
    +/// \brief      Single API to access different integrity checks
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "check.h"
    +
    +
    +extern LZMA_API(lzma_bool)
    +lzma_check_is_supported(lzma_check type)
    +{
    +	if ((unsigned int)(type) > LZMA_CHECK_ID_MAX)
    +		return false;
    +
    +	static const lzma_bool available_checks[LZMA_CHECK_ID_MAX + 1] = {
    +		true,   // LZMA_CHECK_NONE
    +
    +#ifdef HAVE_CHECK_CRC32
    +		true,
    +#else
    +		false,
    +#endif
    +
    +		false,  // Reserved
    +		false,  // Reserved
    +
    +#ifdef HAVE_CHECK_CRC64
    +		true,
    +#else
    +		false,
    +#endif
    +
    +		false,  // Reserved
    +		false,  // Reserved
    +		false,  // Reserved
    +		false,  // Reserved
    +		false,  // Reserved
    +
    +#ifdef HAVE_CHECK_SHA256
    +		true,
    +#else
    +		false,
    +#endif
    +
    +		false,  // Reserved
    +		false,  // Reserved
    +		false,  // Reserved
    +		false,  // Reserved
    +		false,  // Reserved
    +	};
    +
    +	return available_checks[(unsigned int)(type)];
    +}
    +
    +
    +extern LZMA_API(uint32_t)
    +lzma_check_size(lzma_check type)
    +{
    +	if ((unsigned int)(type) > LZMA_CHECK_ID_MAX)
    +		return UINT32_MAX;
    +
    +	// See file-format.txt section 2.1.1.2.
    +	static const uint8_t check_sizes[LZMA_CHECK_ID_MAX + 1] = {
    +		0,
    +		4, 4, 4,
    +		8, 8, 8,
    +		16, 16, 16,
    +		32, 32, 32,
    +		64, 64, 64
    +	};
    +
    +	return check_sizes[(unsigned int)(type)];
    +}
    +
    +
    +extern void
    +lzma_check_init(lzma_check_state *check, lzma_check type)
    +{
    +	switch (type) {
    +	case LZMA_CHECK_NONE:
    +		break;
    +
    +#ifdef HAVE_CHECK_CRC32
    +	case LZMA_CHECK_CRC32:
    +		check->state.crc32 = 0;
    +		break;
    +#endif
    +
    +#ifdef HAVE_CHECK_CRC64
    +	case LZMA_CHECK_CRC64:
    +		check->state.crc64 = 0;
    +		break;
    +#endif
    +
    +#ifdef HAVE_CHECK_SHA256
    +	case LZMA_CHECK_SHA256:
    +		lzma_sha256_init(check);
    +		break;
    +#endif
    +
    +	default:
    +		break;
    +	}
    +
    +	return;
    +}
    +
    +
    +extern void
    +lzma_check_update(lzma_check_state *check, lzma_check type,
    +		const uint8_t *buf, size_t size)
    +{
    +	switch (type) {
    +#ifdef HAVE_CHECK_CRC32
    +	case LZMA_CHECK_CRC32:
    +		check->state.crc32 = lzma_crc32(buf, size, check->state.crc32);
    +		break;
    +#endif
    +
    +#ifdef HAVE_CHECK_CRC64
    +	case LZMA_CHECK_CRC64:
    +		check->state.crc64 = lzma_crc64(buf, size, check->state.crc64);
    +		break;
    +#endif
    +
    +#ifdef HAVE_CHECK_SHA256
    +	case LZMA_CHECK_SHA256:
    +		lzma_sha256_update(buf, size, check);
    +		break;
    +#endif
    +
    +	default:
    +		break;
    +	}
    +
    +	return;
    +}
    +
    +
    +extern void
    +lzma_check_finish(lzma_check_state *check, lzma_check type)
    +{
    +	switch (type) {
    +#ifdef HAVE_CHECK_CRC32
    +	case LZMA_CHECK_CRC32:
    +		check->buffer.u32[0] = conv32le(check->state.crc32);
    +		break;
    +#endif
    +
    +#ifdef HAVE_CHECK_CRC64
    +	case LZMA_CHECK_CRC64:
    +		check->buffer.u64[0] = conv64le(check->state.crc64);
    +		break;
    +#endif
    +
    +#ifdef HAVE_CHECK_SHA256
    +	case LZMA_CHECK_SHA256:
    +		lzma_sha256_finish(check);
    +		break;
    +#endif
    +
    +	default:
    +		break;
    +	}
    +
    +	return;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.h
    new file mode 100644
    index 00000000000..f0eb1172d90
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.h
    @@ -0,0 +1,174 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       check.h
    +/// \brief      Internal API to different integrity check functions
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_CHECK_H
    +#define LZMA_CHECK_H
    +
    +#include "common.h"
    +
    +// If the function for external SHA-256 is missing, use the internal SHA-256
    +// code. Due to how configure works, these defines can only get defined when
    +// both a usable header and a type have already been found.
    +#if !(defined(HAVE_CC_SHA256_INIT) \
    +		|| defined(HAVE_SHA256_INIT) \
    +		|| defined(HAVE_SHA256INIT))
    +#	define HAVE_INTERNAL_SHA256 1
    +#endif
    +
    +#if defined(HAVE_INTERNAL_SHA256)
    +// Nothing
    +#elif defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
    +#	include 
    +#elif defined(HAVE_SHA256_H)
    +#	include 
    +#	include 
    +#elif defined(HAVE_SHA2_H)
    +#	include 
    +#	include 
    +#endif
    +
    +#if defined(HAVE_INTERNAL_SHA256)
    +/// State for the internal SHA-256 implementation
    +typedef struct {
    +	/// Internal state
    +	uint32_t state[8];
    +
    +	/// Size of the message excluding padding
    +	uint64_t size;
    +} lzma_sha256_state;
    +#elif defined(HAVE_CC_SHA256_CTX)
    +typedef CC_SHA256_CTX lzma_sha256_state;
    +#elif defined(HAVE_SHA256_CTX)
    +typedef SHA256_CTX lzma_sha256_state;
    +#elif defined(HAVE_SHA2_CTX)
    +typedef SHA2_CTX lzma_sha256_state;
    +#endif
    +
    +#if defined(HAVE_INTERNAL_SHA256)
    +// Nothing
    +#elif defined(HAVE_CC_SHA256_INIT)
    +#	define LZMA_SHA256FUNC(x) CC_SHA256_ ## x
    +#elif defined(HAVE_SHA256_INIT)
    +#	define LZMA_SHA256FUNC(x) SHA256_ ## x
    +#elif defined(HAVE_SHA256INIT)
    +#	define LZMA_SHA256FUNC(x) SHA256 ## x
    +#endif
    +
    +// Index hashing needs the best possible hash function (preferably
    +// a cryptographic hash) for maximum reliability.
    +#if defined(HAVE_CHECK_SHA256)
    +#	define LZMA_CHECK_BEST LZMA_CHECK_SHA256
    +#elif defined(HAVE_CHECK_CRC64)
    +#	define LZMA_CHECK_BEST LZMA_CHECK_CRC64
    +#else
    +#	define LZMA_CHECK_BEST LZMA_CHECK_CRC32
    +#endif
    +
    +
    +/// \brief      Structure to hold internal state of the check being calculated
    +///
    +/// \note       This is not in the public API because this structure may
    +///             change in future if new integrity check algorithms are added.
    +typedef struct {
    +	/// Buffer to hold the final result and a temporary buffer for SHA256.
    +	union {
    +		uint8_t u8[64];
    +		uint32_t u32[16];
    +		uint64_t u64[8];
    +	} buffer;
    +
    +	/// Check-specific data
    +	union {
    +		uint32_t crc32;
    +		uint64_t crc64;
    +		lzma_sha256_state sha256;
    +	} state;
    +
    +} lzma_check_state;
    +
    +
    +/// lzma_crc32_table[0] is needed by LZ encoder so we need to keep
    +/// the array two-dimensional.
    +#ifdef HAVE_SMALL
    +lzma_attr_visibility_hidden
    +extern uint32_t lzma_crc32_table[1][256];
    +
    +extern void lzma_crc32_init(void);
    +
    +#else
    +
    +lzma_attr_visibility_hidden
    +extern const uint32_t lzma_crc32_table[8][256];
    +
    +lzma_attr_visibility_hidden
    +extern const uint64_t lzma_crc64_table[4][256];
    +#endif
    +
    +
    +/// \brief      Initialize *check depending on type
    +extern void lzma_check_init(lzma_check_state *check, lzma_check type);
    +
    +/// Update the check state
    +extern void lzma_check_update(lzma_check_state *check, lzma_check type,
    +		const uint8_t *buf, size_t size);
    +
    +/// Finish the check calculation and store the result to check->buffer.u8.
    +extern void lzma_check_finish(lzma_check_state *check, lzma_check type);
    +
    +
    +#ifndef LZMA_SHA256FUNC
    +
    +/// Prepare SHA-256 state for new input.
    +extern void lzma_sha256_init(lzma_check_state *check);
    +
    +/// Update the SHA-256 hash state
    +extern void lzma_sha256_update(
    +		const uint8_t *buf, size_t size, lzma_check_state *check);
    +
    +/// Finish the SHA-256 calculation and store the result to check->buffer.u8.
    +extern void lzma_sha256_finish(lzma_check_state *check);
    +
    +
    +#else
    +
    +static inline void
    +lzma_sha256_init(lzma_check_state *check)
    +{
    +	LZMA_SHA256FUNC(Init)(&check->state.sha256);
    +}
    +
    +
    +static inline void
    +lzma_sha256_update(const uint8_t *buf, size_t size, lzma_check_state *check)
    +{
    +#if defined(HAVE_CC_SHA256_INIT) && SIZE_MAX > UINT32_MAX
    +	// Darwin's CC_SHA256_Update takes uint32_t as the buffer size,
    +	// so use a loop to support size_t.
    +	while (size > UINT32_MAX) {
    +		LZMA_SHA256FUNC(Update)(&check->state.sha256, buf, UINT32_MAX);
    +		buf += UINT32_MAX;
    +		size -= UINT32_MAX;
    +	}
    +#endif
    +
    +	LZMA_SHA256FUNC(Update)(&check->state.sha256, buf, size);
    +}
    +
    +
    +static inline void
    +lzma_sha256_finish(lzma_check_state *check)
    +{
    +	LZMA_SHA256FUNC(Final)(check->buffer.u8, &check->state.sha256);
    +}
    +
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_arm64.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_arm64.h
    new file mode 100644
    index 00000000000..39c1c63ec0e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_arm64.h
    @@ -0,0 +1,122 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc32_arm64.h
    +/// \brief      CRC32 calculation with ARM64 optimization
    +//
    +//  Authors:    Chenxi Mao
    +//              Jia Tan
    +//              Hans Jansen
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_CRC32_ARM64_H
    +#define LZMA_CRC32_ARM64_H
    +
    +// MSVC always has the CRC intrinsics available when building for ARM64
    +// there is no need to include any header files.
    +#ifndef _MSC_VER
    +#	include 
    +#endif
    +
    +// If both versions are going to be built, we need runtime detection
    +// to check if the instructions are supported.
    +#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
    +#	if defined(HAVE_GETAUXVAL) || defined(HAVE_ELF_AUX_INFO)
    +#		include 
    +#	elif defined(_WIN32)
    +#		include 
    +#	elif defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME)
    +#		include 
    +#	endif
    +#endif
    +
    +// Some EDG-based compilers support ARM64 and define __GNUC__
    +// (such as Nvidia's nvcc), but do not support function attributes.
    +//
    +// NOTE: Build systems check for this too, keep them in sync with this.
    +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__EDG__)
    +#	define crc_attr_target __attribute__((__target__("+crc")))
    +#else
    +#	define crc_attr_target
    +#endif
    +
    +
    +crc_attr_target
    +static uint32_t
    +crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)
    +{
    +	crc = ~crc;
    +
    +	// Align the input buffer because this was shown to be
    +	// significantly faster than unaligned accesses.
    +	const size_t align_amount = my_min(size, (0U - (uintptr_t)buf) & 7);
    +
    +	for (const uint8_t *limit = buf + align_amount; buf < limit; ++buf)
    +		crc = __crc32b(crc, *buf);
    +
    +	size -= align_amount;
    +
    +	// Process 8 bytes at a time. The end point is determined by
    +	// ignoring the least significant three bits of size to ensure
    +	// we do not process past the bounds of the buffer. This guarantees
    +	// that limit is a multiple of 8 and is strictly less than size.
    +	for (const uint8_t *limit = buf + (size & ~(size_t)7);
    +			buf < limit; buf += 8)
    +		crc = __crc32d(crc, aligned_read64le(buf));
    +
    +	// Process the remaining bytes that are not 8 byte aligned.
    +	for (const uint8_t *limit = buf + (size & 7); buf < limit; ++buf)
    +		crc = __crc32b(crc, *buf);
    +
    +	return ~crc;
    +}
    +
    +
    +#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
    +static inline bool
    +is_arch_extension_supported(void)
    +{
    +#if defined(HAVE_GETAUXVAL)
    +	return (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0;
    +
    +#elif defined(HAVE_ELF_AUX_INFO)
    +	unsigned long feature_flags;
    +
    +	if (elf_aux_info(AT_HWCAP, &feature_flags, sizeof(feature_flags)) != 0)
    +		return false;
    +
    +	return (feature_flags & HWCAP_CRC32) != 0;
    +
    +#elif defined(_WIN32)
    +	return IsProcessorFeaturePresent(
    +			PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
    +
    +#elif defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME)
    +	int has_crc32 = 0;
    +	size_t size = sizeof(has_crc32);
    +
    +	// The sysctlbyname() function requires a string identifier for the
    +	// CPU feature it tests. The Apple documentation lists the string
    +	// "hw.optional.armv8_crc32", which can be found here:
    +	// https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3915619
    +	if (sysctlbyname("hw.optional.armv8_crc32", &has_crc32,
    +			&size, NULL, 0) != 0)
    +		return false;
    +
    +	return has_crc32;
    +
    +#else
    +	// If a runtime detection method cannot be found, then this must
    +	// be a compile time error. The checks in crc_common.h should ensure
    +	// a runtime detection method is always found if this function is
    +	// built. It would be possible to just return false here, but this
    +	// is inefficient for binary size and runtime since only the generic
    +	// method could ever be used.
    +#	error Runtime detection method unavailable.
    +#endif
    +}
    +#endif
    +
    +#endif // LZMA_CRC32_ARM64_H
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_fast.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_fast.c
    new file mode 100644
    index 00000000000..16dbb746751
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_fast.c
    @@ -0,0 +1,204 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc32.c
    +/// \brief      CRC32 calculation
    +//
    +//  Authors:    Lasse Collin
    +//              Ilya Kurdyukov
    +//              Hans Jansen
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "check.h"
    +#include "crc_common.h"
    +
    +#if defined(CRC_X86_CLMUL)
    +#	define BUILDING_CRC32_CLMUL
    +#	include "crc_x86_clmul.h"
    +#elif defined(CRC32_ARM64)
    +#	include "crc32_arm64.h"
    +#endif
    +
    +
    +#ifdef CRC32_GENERIC
    +
    +///////////////////
    +// Generic CRC32 //
    +///////////////////
    +
    +static uint32_t
    +crc32_generic(const uint8_t *buf, size_t size, uint32_t crc)
    +{
    +	crc = ~crc;
    +
    +#ifdef WORDS_BIGENDIAN
    +	crc = byteswap32(crc);
    +#endif
    +
    +	if (size > 8) {
    +		// Fix the alignment, if needed. The if statement above
    +		// ensures that this won't read past the end of buf[].
    +		while ((uintptr_t)(buf) & 7) {
    +			crc = lzma_crc32_table[0][*buf++ ^ A(crc)] ^ S8(crc);
    +			--size;
    +		}
    +
    +		// Calculate the position where to stop.
    +		const uint8_t *const limit = buf + (size & ~(size_t)(7));
    +
    +		// Calculate how many bytes must be calculated separately
    +		// before returning the result.
    +		size &= (size_t)(7);
    +
    +		// Calculate the CRC32 using the slice-by-eight algorithm.
    +		while (buf < limit) {
    +			crc ^= aligned_read32ne(buf);
    +			buf += 4;
    +
    +			crc = lzma_crc32_table[7][A(crc)]
    +			    ^ lzma_crc32_table[6][B(crc)]
    +			    ^ lzma_crc32_table[5][C(crc)]
    +			    ^ lzma_crc32_table[4][D(crc)];
    +
    +			const uint32_t tmp = aligned_read32ne(buf);
    +			buf += 4;
    +
    +			// At least with some compilers, it is critical for
    +			// performance, that the crc variable is XORed
    +			// between the two table-lookup pairs.
    +			crc = lzma_crc32_table[3][A(tmp)]
    +			    ^ lzma_crc32_table[2][B(tmp)]
    +			    ^ crc
    +			    ^ lzma_crc32_table[1][C(tmp)]
    +			    ^ lzma_crc32_table[0][D(tmp)];
    +		}
    +	}
    +
    +	while (size-- != 0)
    +		crc = lzma_crc32_table[0][*buf++ ^ A(crc)] ^ S8(crc);
    +
    +#ifdef WORDS_BIGENDIAN
    +	crc = byteswap32(crc);
    +#endif
    +
    +	return ~crc;
    +}
    +#endif
    +
    +
    +#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
    +
    +//////////////////////////
    +// Function dispatching //
    +//////////////////////////
    +
    +// If both the generic and arch-optimized implementations are built, then
    +// the function to use is selected at runtime because the system running
    +// the binary might not have the arch-specific instruction set extension(s)
    +// available. The dispatch methods in order of priority:
    +//
    +// 1. Constructor. This method uses __attribute__((__constructor__)) to
    +//    set crc32_func at load time. This avoids extra computation (and any
    +//    unlikely threading bugs) on the first call to lzma_crc32() to decide
    +//    which implementation should be used.
    +//
    +// 2. First Call Resolution. On the very first call to lzma_crc32(), the
    +//    call will be directed to crc32_dispatch() instead. This will set the
    +//    appropriate implementation function and will not be called again.
    +//    This method does not use any kind of locking but is safe because if
    +//    multiple threads run the dispatcher simultaneously then they will all
    +//    set crc32_func to the same value.
    +
    +typedef uint32_t (*crc32_func_type)(
    +		const uint8_t *buf, size_t size, uint32_t crc);
    +
    +// This resolver is shared between all dispatch methods.
    +static crc32_func_type
    +crc32_resolve(void)
    +{
    +	return is_arch_extension_supported()
    +			? &crc32_arch_optimized : &crc32_generic;
    +}
    +
    +
    +#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +// Constructor method.
    +#	define CRC32_SET_FUNC_ATTR __attribute__((__constructor__))
    +static crc32_func_type crc32_func;
    +#else
    +// First Call Resolution method.
    +#	define CRC32_SET_FUNC_ATTR
    +static uint32_t crc32_dispatch(const uint8_t *buf, size_t size, uint32_t crc);
    +static crc32_func_type crc32_func = &crc32_dispatch;
    +#endif
    +
    +CRC32_SET_FUNC_ATTR
    +static void
    +crc32_set_func(void)
    +{
    +	crc32_func = crc32_resolve();
    +	return;
    +}
    +
    +#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +static uint32_t
    +crc32_dispatch(const uint8_t *buf, size_t size, uint32_t crc)
    +{
    +	// When __attribute__((__constructor__)) isn't supported, set the
    +	// function pointer without any locking. If multiple threads run
    +	// the detection code in parallel, they will all end up setting
    +	// the pointer to the same value. This avoids the use of
    +	// mythread_once() on every call to lzma_crc32() but this likely
    +	// isn't strictly standards compliant. Let's change it if it breaks.
    +	crc32_set_func();
    +	return crc32_func(buf, size, crc);
    +}
    +
    +#endif
    +#endif
    +
    +
    +extern LZMA_API(uint32_t)
    +lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
    +{
    +#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
    +	// On x86-64, if CLMUL is available, it is the best for non-tiny
    +	// inputs, being over twice as fast as the generic slice-by-four
    +	// version. However, for size <= 16 it's different. In the extreme
    +	// case of size == 1 the generic version can be five times faster.
    +	// At size >= 8 the CLMUL starts to become reasonable. It
    +	// varies depending on the alignment of buf too.
    +	//
    +	// The above doesn't include the overhead of mythread_once().
    +	// At least on x86-64 GNU/Linux, pthread_once() is very fast but
    +	// it still makes lzma_crc32(buf, 1, crc) 50-100 % slower. When
    +	// size reaches 12-16 bytes the overhead becomes negligible.
    +	//
    +	// So using the generic version for size <= 16 may give better
    +	// performance with tiny inputs but if such inputs happen rarely
    +	// it's not so obvious because then the lookup table of the
    +	// generic version may not be in the processor cache.
    +#ifdef CRC_USE_GENERIC_FOR_SMALL_INPUTS
    +	if (size <= 16)
    +		return crc32_generic(buf, size, crc);
    +#endif
    +
    +/*
    +#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +	// See crc32_dispatch(). This would be the alternative which uses
    +	// locking and doesn't use crc32_dispatch(). Note that on Windows
    +	// this method needs Vista threads.
    +	mythread_once(crc64_set_func);
    +#endif
    +*/
    +	return crc32_func(buf, size, crc);
    +
    +#elif defined(CRC32_ARCH_OPTIMIZED)
    +	return crc32_arch_optimized(buf, size, crc);
    +
    +#else
    +	return crc32_generic(buf, size, crc);
    +#endif
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_small.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_small.c
    new file mode 100644
    index 00000000000..6a1bd66185e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_small.c
    @@ -0,0 +1,67 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc32_small.c
    +/// \brief      CRC32 calculation (size-optimized)
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "check.h"
    +
    +
    +uint32_t lzma_crc32_table[1][256];
    +
    +
    +#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +__attribute__((__constructor__))
    +#endif
    +static void
    +crc32_init(void)
    +{
    +	static const uint32_t poly32 = UINT32_C(0xEDB88320);
    +
    +	for (size_t b = 0; b < 256; ++b) {
    +		uint32_t r = b;
    +		for (size_t i = 0; i < 8; ++i) {
    +			if (r & 1)
    +				r = (r >> 1) ^ poly32;
    +			else
    +				r >>= 1;
    +		}
    +
    +		lzma_crc32_table[0][b] = r;
    +	}
    +
    +	return;
    +}
    +
    +
    +#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +extern void
    +lzma_crc32_init(void)
    +{
    +	mythread_once(crc32_init);
    +	return;
    +}
    +#endif
    +
    +
    +extern LZMA_API(uint32_t)
    +lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
    +{
    +#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +	lzma_crc32_init();
    +#endif
    +
    +	crc = ~crc;
    +
    +	while (size != 0) {
    +		crc = lzma_crc32_table[0][*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
    +		--size;
    +	}
    +
    +	return ~crc;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table.c
    new file mode 100644
    index 00000000000..56413eec336
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table.c
    @@ -0,0 +1,42 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc32_table.c
    +/// \brief      Precalculated CRC32 table with correct endianness
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +
    +
    +// FIXME: Compared to crc_common.h this has to check for __x86_64__ too
    +// so that in 32-bit builds crc32_x86.S won't break due to a missing table.
    +#if defined(HAVE_USABLE_CLMUL) && ((defined(__x86_64__) && defined(__SSSE3__) \
    +			&& defined(__SSE4_1__) && defined(__PCLMUL__)) \
    +		|| (defined(__e2k__) && __iset__ >= 6))
    +#	define NO_CRC32_TABLE
    +
    +#elif defined(HAVE_ARM64_CRC32) \
    +		&& !defined(WORDS_BIGENDIAN) \
    +		&& defined(__ARM_FEATURE_CRC32)
    +#	define NO_CRC32_TABLE
    +#endif
    +
    +
    +#if !defined(HAVE_ENCODERS) && defined(NO_CRC32_TABLE)
    +// No table needed. Use a typedef to avoid an empty translation unit.
    +typedef void lzma_crc32_dummy;
    +
    +#else
    +// Having the declaration here silences clang -Wmissing-variable-declarations.
    +extern const uint32_t lzma_crc32_table[8][256];
    +
    +#	ifdef WORDS_BIGENDIAN
    +#		include "crc32_table_be.h"
    +#	else
    +#		include "crc32_table_le.h"
    +#	endif
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_be.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_be.h
    new file mode 100644
    index 00000000000..505c23074c1
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_be.h
    @@ -0,0 +1,527 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +// This file has been generated by crc32_tablegen.c.
    +
    +const uint32_t lzma_crc32_table[8][256] = {
    +	{
    +		0x00000000, 0x96300777, 0x2C610EEE, 0xBA510999,
    +		0x19C46D07, 0x8FF46A70, 0x35A563E9, 0xA395649E,
    +		0x3288DB0E, 0xA4B8DC79, 0x1EE9D5E0, 0x88D9D297,
    +		0x2B4CB609, 0xBD7CB17E, 0x072DB8E7, 0x911DBF90,
    +		0x6410B71D, 0xF220B06A, 0x4871B9F3, 0xDE41BE84,
    +		0x7DD4DA1A, 0xEBE4DD6D, 0x51B5D4F4, 0xC785D383,
    +		0x56986C13, 0xC0A86B64, 0x7AF962FD, 0xECC9658A,
    +		0x4F5C0114, 0xD96C0663, 0x633D0FFA, 0xF50D088D,
    +		0xC8206E3B, 0x5E10694C, 0xE44160D5, 0x727167A2,
    +		0xD1E4033C, 0x47D4044B, 0xFD850DD2, 0x6BB50AA5,
    +		0xFAA8B535, 0x6C98B242, 0xD6C9BBDB, 0x40F9BCAC,
    +		0xE36CD832, 0x755CDF45, 0xCF0DD6DC, 0x593DD1AB,
    +		0xAC30D926, 0x3A00DE51, 0x8051D7C8, 0x1661D0BF,
    +		0xB5F4B421, 0x23C4B356, 0x9995BACF, 0x0FA5BDB8,
    +		0x9EB80228, 0x0888055F, 0xB2D90CC6, 0x24E90BB1,
    +		0x877C6F2F, 0x114C6858, 0xAB1D61C1, 0x3D2D66B6,
    +		0x9041DC76, 0x0671DB01, 0xBC20D298, 0x2A10D5EF,
    +		0x8985B171, 0x1FB5B606, 0xA5E4BF9F, 0x33D4B8E8,
    +		0xA2C90778, 0x34F9000F, 0x8EA80996, 0x18980EE1,
    +		0xBB0D6A7F, 0x2D3D6D08, 0x976C6491, 0x015C63E6,
    +		0xF4516B6B, 0x62616C1C, 0xD8306585, 0x4E0062F2,
    +		0xED95066C, 0x7BA5011B, 0xC1F40882, 0x57C40FF5,
    +		0xC6D9B065, 0x50E9B712, 0xEAB8BE8B, 0x7C88B9FC,
    +		0xDF1DDD62, 0x492DDA15, 0xF37CD38C, 0x654CD4FB,
    +		0x5861B24D, 0xCE51B53A, 0x7400BCA3, 0xE230BBD4,
    +		0x41A5DF4A, 0xD795D83D, 0x6DC4D1A4, 0xFBF4D6D3,
    +		0x6AE96943, 0xFCD96E34, 0x468867AD, 0xD0B860DA,
    +		0x732D0444, 0xE51D0333, 0x5F4C0AAA, 0xC97C0DDD,
    +		0x3C710550, 0xAA410227, 0x10100BBE, 0x86200CC9,
    +		0x25B56857, 0xB3856F20, 0x09D466B9, 0x9FE461CE,
    +		0x0EF9DE5E, 0x98C9D929, 0x2298D0B0, 0xB4A8D7C7,
    +		0x173DB359, 0x810DB42E, 0x3B5CBDB7, 0xAD6CBAC0,
    +		0x2083B8ED, 0xB6B3BF9A, 0x0CE2B603, 0x9AD2B174,
    +		0x3947D5EA, 0xAF77D29D, 0x1526DB04, 0x8316DC73,
    +		0x120B63E3, 0x843B6494, 0x3E6A6D0D, 0xA85A6A7A,
    +		0x0BCF0EE4, 0x9DFF0993, 0x27AE000A, 0xB19E077D,
    +		0x44930FF0, 0xD2A30887, 0x68F2011E, 0xFEC20669,
    +		0x5D5762F7, 0xCB676580, 0x71366C19, 0xE7066B6E,
    +		0x761BD4FE, 0xE02BD389, 0x5A7ADA10, 0xCC4ADD67,
    +		0x6FDFB9F9, 0xF9EFBE8E, 0x43BEB717, 0xD58EB060,
    +		0xE8A3D6D6, 0x7E93D1A1, 0xC4C2D838, 0x52F2DF4F,
    +		0xF167BBD1, 0x6757BCA6, 0xDD06B53F, 0x4B36B248,
    +		0xDA2B0DD8, 0x4C1B0AAF, 0xF64A0336, 0x607A0441,
    +		0xC3EF60DF, 0x55DF67A8, 0xEF8E6E31, 0x79BE6946,
    +		0x8CB361CB, 0x1A8366BC, 0xA0D26F25, 0x36E26852,
    +		0x95770CCC, 0x03470BBB, 0xB9160222, 0x2F260555,
    +		0xBE3BBAC5, 0x280BBDB2, 0x925AB42B, 0x046AB35C,
    +		0xA7FFD7C2, 0x31CFD0B5, 0x8B9ED92C, 0x1DAEDE5B,
    +		0xB0C2649B, 0x26F263EC, 0x9CA36A75, 0x0A936D02,
    +		0xA906099C, 0x3F360EEB, 0x85670772, 0x13570005,
    +		0x824ABF95, 0x147AB8E2, 0xAE2BB17B, 0x381BB60C,
    +		0x9B8ED292, 0x0DBED5E5, 0xB7EFDC7C, 0x21DFDB0B,
    +		0xD4D2D386, 0x42E2D4F1, 0xF8B3DD68, 0x6E83DA1F,
    +		0xCD16BE81, 0x5B26B9F6, 0xE177B06F, 0x7747B718,
    +		0xE65A0888, 0x706A0FFF, 0xCA3B0666, 0x5C0B0111,
    +		0xFF9E658F, 0x69AE62F8, 0xD3FF6B61, 0x45CF6C16,
    +		0x78E20AA0, 0xEED20DD7, 0x5483044E, 0xC2B30339,
    +		0x612667A7, 0xF71660D0, 0x4D476949, 0xDB776E3E,
    +		0x4A6AD1AE, 0xDC5AD6D9, 0x660BDF40, 0xF03BD837,
    +		0x53AEBCA9, 0xC59EBBDE, 0x7FCFB247, 0xE9FFB530,
    +		0x1CF2BDBD, 0x8AC2BACA, 0x3093B353, 0xA6A3B424,
    +		0x0536D0BA, 0x9306D7CD, 0x2957DE54, 0xBF67D923,
    +		0x2E7A66B3, 0xB84A61C4, 0x021B685D, 0x942B6F2A,
    +		0x37BE0BB4, 0xA18E0CC3, 0x1BDF055A, 0x8DEF022D
    +	}, {
    +		0x00000000, 0x41311B19, 0x82623632, 0xC3532D2B,
    +		0x04C56C64, 0x45F4777D, 0x86A75A56, 0xC796414F,
    +		0x088AD9C8, 0x49BBC2D1, 0x8AE8EFFA, 0xCBD9F4E3,
    +		0x0C4FB5AC, 0x4D7EAEB5, 0x8E2D839E, 0xCF1C9887,
    +		0x5112C24A, 0x1023D953, 0xD370F478, 0x9241EF61,
    +		0x55D7AE2E, 0x14E6B537, 0xD7B5981C, 0x96848305,
    +		0x59981B82, 0x18A9009B, 0xDBFA2DB0, 0x9ACB36A9,
    +		0x5D5D77E6, 0x1C6C6CFF, 0xDF3F41D4, 0x9E0E5ACD,
    +		0xA2248495, 0xE3159F8C, 0x2046B2A7, 0x6177A9BE,
    +		0xA6E1E8F1, 0xE7D0F3E8, 0x2483DEC3, 0x65B2C5DA,
    +		0xAAAE5D5D, 0xEB9F4644, 0x28CC6B6F, 0x69FD7076,
    +		0xAE6B3139, 0xEF5A2A20, 0x2C09070B, 0x6D381C12,
    +		0xF33646DF, 0xB2075DC6, 0x715470ED, 0x30656BF4,
    +		0xF7F32ABB, 0xB6C231A2, 0x75911C89, 0x34A00790,
    +		0xFBBC9F17, 0xBA8D840E, 0x79DEA925, 0x38EFB23C,
    +		0xFF79F373, 0xBE48E86A, 0x7D1BC541, 0x3C2ADE58,
    +		0x054F79F0, 0x447E62E9, 0x872D4FC2, 0xC61C54DB,
    +		0x018A1594, 0x40BB0E8D, 0x83E823A6, 0xC2D938BF,
    +		0x0DC5A038, 0x4CF4BB21, 0x8FA7960A, 0xCE968D13,
    +		0x0900CC5C, 0x4831D745, 0x8B62FA6E, 0xCA53E177,
    +		0x545DBBBA, 0x156CA0A3, 0xD63F8D88, 0x970E9691,
    +		0x5098D7DE, 0x11A9CCC7, 0xD2FAE1EC, 0x93CBFAF5,
    +		0x5CD76272, 0x1DE6796B, 0xDEB55440, 0x9F844F59,
    +		0x58120E16, 0x1923150F, 0xDA703824, 0x9B41233D,
    +		0xA76BFD65, 0xE65AE67C, 0x2509CB57, 0x6438D04E,
    +		0xA3AE9101, 0xE29F8A18, 0x21CCA733, 0x60FDBC2A,
    +		0xAFE124AD, 0xEED03FB4, 0x2D83129F, 0x6CB20986,
    +		0xAB2448C9, 0xEA1553D0, 0x29467EFB, 0x687765E2,
    +		0xF6793F2F, 0xB7482436, 0x741B091D, 0x352A1204,
    +		0xF2BC534B, 0xB38D4852, 0x70DE6579, 0x31EF7E60,
    +		0xFEF3E6E7, 0xBFC2FDFE, 0x7C91D0D5, 0x3DA0CBCC,
    +		0xFA368A83, 0xBB07919A, 0x7854BCB1, 0x3965A7A8,
    +		0x4B98833B, 0x0AA99822, 0xC9FAB509, 0x88CBAE10,
    +		0x4F5DEF5F, 0x0E6CF446, 0xCD3FD96D, 0x8C0EC274,
    +		0x43125AF3, 0x022341EA, 0xC1706CC1, 0x804177D8,
    +		0x47D73697, 0x06E62D8E, 0xC5B500A5, 0x84841BBC,
    +		0x1A8A4171, 0x5BBB5A68, 0x98E87743, 0xD9D96C5A,
    +		0x1E4F2D15, 0x5F7E360C, 0x9C2D1B27, 0xDD1C003E,
    +		0x120098B9, 0x533183A0, 0x9062AE8B, 0xD153B592,
    +		0x16C5F4DD, 0x57F4EFC4, 0x94A7C2EF, 0xD596D9F6,
    +		0xE9BC07AE, 0xA88D1CB7, 0x6BDE319C, 0x2AEF2A85,
    +		0xED796BCA, 0xAC4870D3, 0x6F1B5DF8, 0x2E2A46E1,
    +		0xE136DE66, 0xA007C57F, 0x6354E854, 0x2265F34D,
    +		0xE5F3B202, 0xA4C2A91B, 0x67918430, 0x26A09F29,
    +		0xB8AEC5E4, 0xF99FDEFD, 0x3ACCF3D6, 0x7BFDE8CF,
    +		0xBC6BA980, 0xFD5AB299, 0x3E099FB2, 0x7F3884AB,
    +		0xB0241C2C, 0xF1150735, 0x32462A1E, 0x73773107,
    +		0xB4E17048, 0xF5D06B51, 0x3683467A, 0x77B25D63,
    +		0x4ED7FACB, 0x0FE6E1D2, 0xCCB5CCF9, 0x8D84D7E0,
    +		0x4A1296AF, 0x0B238DB6, 0xC870A09D, 0x8941BB84,
    +		0x465D2303, 0x076C381A, 0xC43F1531, 0x850E0E28,
    +		0x42984F67, 0x03A9547E, 0xC0FA7955, 0x81CB624C,
    +		0x1FC53881, 0x5EF42398, 0x9DA70EB3, 0xDC9615AA,
    +		0x1B0054E5, 0x5A314FFC, 0x996262D7, 0xD85379CE,
    +		0x174FE149, 0x567EFA50, 0x952DD77B, 0xD41CCC62,
    +		0x138A8D2D, 0x52BB9634, 0x91E8BB1F, 0xD0D9A006,
    +		0xECF37E5E, 0xADC26547, 0x6E91486C, 0x2FA05375,
    +		0xE836123A, 0xA9070923, 0x6A542408, 0x2B653F11,
    +		0xE479A796, 0xA548BC8F, 0x661B91A4, 0x272A8ABD,
    +		0xE0BCCBF2, 0xA18DD0EB, 0x62DEFDC0, 0x23EFE6D9,
    +		0xBDE1BC14, 0xFCD0A70D, 0x3F838A26, 0x7EB2913F,
    +		0xB924D070, 0xF815CB69, 0x3B46E642, 0x7A77FD5B,
    +		0xB56B65DC, 0xF45A7EC5, 0x370953EE, 0x763848F7,
    +		0xB1AE09B8, 0xF09F12A1, 0x33CC3F8A, 0x72FD2493
    +	}, {
    +		0x00000000, 0x376AC201, 0x6ED48403, 0x59BE4602,
    +		0xDCA80907, 0xEBC2CB06, 0xB27C8D04, 0x85164F05,
    +		0xB851130E, 0x8F3BD10F, 0xD685970D, 0xE1EF550C,
    +		0x64F91A09, 0x5393D808, 0x0A2D9E0A, 0x3D475C0B,
    +		0x70A3261C, 0x47C9E41D, 0x1E77A21F, 0x291D601E,
    +		0xAC0B2F1B, 0x9B61ED1A, 0xC2DFAB18, 0xF5B56919,
    +		0xC8F23512, 0xFF98F713, 0xA626B111, 0x914C7310,
    +		0x145A3C15, 0x2330FE14, 0x7A8EB816, 0x4DE47A17,
    +		0xE0464D38, 0xD72C8F39, 0x8E92C93B, 0xB9F80B3A,
    +		0x3CEE443F, 0x0B84863E, 0x523AC03C, 0x6550023D,
    +		0x58175E36, 0x6F7D9C37, 0x36C3DA35, 0x01A91834,
    +		0x84BF5731, 0xB3D59530, 0xEA6BD332, 0xDD011133,
    +		0x90E56B24, 0xA78FA925, 0xFE31EF27, 0xC95B2D26,
    +		0x4C4D6223, 0x7B27A022, 0x2299E620, 0x15F32421,
    +		0x28B4782A, 0x1FDEBA2B, 0x4660FC29, 0x710A3E28,
    +		0xF41C712D, 0xC376B32C, 0x9AC8F52E, 0xADA2372F,
    +		0xC08D9A70, 0xF7E75871, 0xAE591E73, 0x9933DC72,
    +		0x1C259377, 0x2B4F5176, 0x72F11774, 0x459BD575,
    +		0x78DC897E, 0x4FB64B7F, 0x16080D7D, 0x2162CF7C,
    +		0xA4748079, 0x931E4278, 0xCAA0047A, 0xFDCAC67B,
    +		0xB02EBC6C, 0x87447E6D, 0xDEFA386F, 0xE990FA6E,
    +		0x6C86B56B, 0x5BEC776A, 0x02523168, 0x3538F369,
    +		0x087FAF62, 0x3F156D63, 0x66AB2B61, 0x51C1E960,
    +		0xD4D7A665, 0xE3BD6464, 0xBA032266, 0x8D69E067,
    +		0x20CBD748, 0x17A11549, 0x4E1F534B, 0x7975914A,
    +		0xFC63DE4F, 0xCB091C4E, 0x92B75A4C, 0xA5DD984D,
    +		0x989AC446, 0xAFF00647, 0xF64E4045, 0xC1248244,
    +		0x4432CD41, 0x73580F40, 0x2AE64942, 0x1D8C8B43,
    +		0x5068F154, 0x67023355, 0x3EBC7557, 0x09D6B756,
    +		0x8CC0F853, 0xBBAA3A52, 0xE2147C50, 0xD57EBE51,
    +		0xE839E25A, 0xDF53205B, 0x86ED6659, 0xB187A458,
    +		0x3491EB5D, 0x03FB295C, 0x5A456F5E, 0x6D2FAD5F,
    +		0x801B35E1, 0xB771F7E0, 0xEECFB1E2, 0xD9A573E3,
    +		0x5CB33CE6, 0x6BD9FEE7, 0x3267B8E5, 0x050D7AE4,
    +		0x384A26EF, 0x0F20E4EE, 0x569EA2EC, 0x61F460ED,
    +		0xE4E22FE8, 0xD388EDE9, 0x8A36ABEB, 0xBD5C69EA,
    +		0xF0B813FD, 0xC7D2D1FC, 0x9E6C97FE, 0xA90655FF,
    +		0x2C101AFA, 0x1B7AD8FB, 0x42C49EF9, 0x75AE5CF8,
    +		0x48E900F3, 0x7F83C2F2, 0x263D84F0, 0x115746F1,
    +		0x944109F4, 0xA32BCBF5, 0xFA958DF7, 0xCDFF4FF6,
    +		0x605D78D9, 0x5737BAD8, 0x0E89FCDA, 0x39E33EDB,
    +		0xBCF571DE, 0x8B9FB3DF, 0xD221F5DD, 0xE54B37DC,
    +		0xD80C6BD7, 0xEF66A9D6, 0xB6D8EFD4, 0x81B22DD5,
    +		0x04A462D0, 0x33CEA0D1, 0x6A70E6D3, 0x5D1A24D2,
    +		0x10FE5EC5, 0x27949CC4, 0x7E2ADAC6, 0x494018C7,
    +		0xCC5657C2, 0xFB3C95C3, 0xA282D3C1, 0x95E811C0,
    +		0xA8AF4DCB, 0x9FC58FCA, 0xC67BC9C8, 0xF1110BC9,
    +		0x740744CC, 0x436D86CD, 0x1AD3C0CF, 0x2DB902CE,
    +		0x4096AF91, 0x77FC6D90, 0x2E422B92, 0x1928E993,
    +		0x9C3EA696, 0xAB546497, 0xF2EA2295, 0xC580E094,
    +		0xF8C7BC9F, 0xCFAD7E9E, 0x9613389C, 0xA179FA9D,
    +		0x246FB598, 0x13057799, 0x4ABB319B, 0x7DD1F39A,
    +		0x3035898D, 0x075F4B8C, 0x5EE10D8E, 0x698BCF8F,
    +		0xEC9D808A, 0xDBF7428B, 0x82490489, 0xB523C688,
    +		0x88649A83, 0xBF0E5882, 0xE6B01E80, 0xD1DADC81,
    +		0x54CC9384, 0x63A65185, 0x3A181787, 0x0D72D586,
    +		0xA0D0E2A9, 0x97BA20A8, 0xCE0466AA, 0xF96EA4AB,
    +		0x7C78EBAE, 0x4B1229AF, 0x12AC6FAD, 0x25C6ADAC,
    +		0x1881F1A7, 0x2FEB33A6, 0x765575A4, 0x413FB7A5,
    +		0xC429F8A0, 0xF3433AA1, 0xAAFD7CA3, 0x9D97BEA2,
    +		0xD073C4B5, 0xE71906B4, 0xBEA740B6, 0x89CD82B7,
    +		0x0CDBCDB2, 0x3BB10FB3, 0x620F49B1, 0x55658BB0,
    +		0x6822D7BB, 0x5F4815BA, 0x06F653B8, 0x319C91B9,
    +		0xB48ADEBC, 0x83E01CBD, 0xDA5E5ABF, 0xED3498BE
    +	}, {
    +		0x00000000, 0x6567BCB8, 0x8BC809AA, 0xEEAFB512,
    +		0x5797628F, 0x32F0DE37, 0xDC5F6B25, 0xB938D79D,
    +		0xEF28B4C5, 0x8A4F087D, 0x64E0BD6F, 0x018701D7,
    +		0xB8BFD64A, 0xDDD86AF2, 0x3377DFE0, 0x56106358,
    +		0x9F571950, 0xFA30A5E8, 0x149F10FA, 0x71F8AC42,
    +		0xC8C07BDF, 0xADA7C767, 0x43087275, 0x266FCECD,
    +		0x707FAD95, 0x1518112D, 0xFBB7A43F, 0x9ED01887,
    +		0x27E8CF1A, 0x428F73A2, 0xAC20C6B0, 0xC9477A08,
    +		0x3EAF32A0, 0x5BC88E18, 0xB5673B0A, 0xD00087B2,
    +		0x6938502F, 0x0C5FEC97, 0xE2F05985, 0x8797E53D,
    +		0xD1878665, 0xB4E03ADD, 0x5A4F8FCF, 0x3F283377,
    +		0x8610E4EA, 0xE3775852, 0x0DD8ED40, 0x68BF51F8,
    +		0xA1F82BF0, 0xC49F9748, 0x2A30225A, 0x4F579EE2,
    +		0xF66F497F, 0x9308F5C7, 0x7DA740D5, 0x18C0FC6D,
    +		0x4ED09F35, 0x2BB7238D, 0xC518969F, 0xA07F2A27,
    +		0x1947FDBA, 0x7C204102, 0x928FF410, 0xF7E848A8,
    +		0x3D58149B, 0x583FA823, 0xB6901D31, 0xD3F7A189,
    +		0x6ACF7614, 0x0FA8CAAC, 0xE1077FBE, 0x8460C306,
    +		0xD270A05E, 0xB7171CE6, 0x59B8A9F4, 0x3CDF154C,
    +		0x85E7C2D1, 0xE0807E69, 0x0E2FCB7B, 0x6B4877C3,
    +		0xA20F0DCB, 0xC768B173, 0x29C70461, 0x4CA0B8D9,
    +		0xF5986F44, 0x90FFD3FC, 0x7E5066EE, 0x1B37DA56,
    +		0x4D27B90E, 0x284005B6, 0xC6EFB0A4, 0xA3880C1C,
    +		0x1AB0DB81, 0x7FD76739, 0x9178D22B, 0xF41F6E93,
    +		0x03F7263B, 0x66909A83, 0x883F2F91, 0xED589329,
    +		0x546044B4, 0x3107F80C, 0xDFA84D1E, 0xBACFF1A6,
    +		0xECDF92FE, 0x89B82E46, 0x67179B54, 0x027027EC,
    +		0xBB48F071, 0xDE2F4CC9, 0x3080F9DB, 0x55E74563,
    +		0x9CA03F6B, 0xF9C783D3, 0x176836C1, 0x720F8A79,
    +		0xCB375DE4, 0xAE50E15C, 0x40FF544E, 0x2598E8F6,
    +		0x73888BAE, 0x16EF3716, 0xF8408204, 0x9D273EBC,
    +		0x241FE921, 0x41785599, 0xAFD7E08B, 0xCAB05C33,
    +		0x3BB659ED, 0x5ED1E555, 0xB07E5047, 0xD519ECFF,
    +		0x6C213B62, 0x094687DA, 0xE7E932C8, 0x828E8E70,
    +		0xD49EED28, 0xB1F95190, 0x5F56E482, 0x3A31583A,
    +		0x83098FA7, 0xE66E331F, 0x08C1860D, 0x6DA63AB5,
    +		0xA4E140BD, 0xC186FC05, 0x2F294917, 0x4A4EF5AF,
    +		0xF3762232, 0x96119E8A, 0x78BE2B98, 0x1DD99720,
    +		0x4BC9F478, 0x2EAE48C0, 0xC001FDD2, 0xA566416A,
    +		0x1C5E96F7, 0x79392A4F, 0x97969F5D, 0xF2F123E5,
    +		0x05196B4D, 0x607ED7F5, 0x8ED162E7, 0xEBB6DE5F,
    +		0x528E09C2, 0x37E9B57A, 0xD9460068, 0xBC21BCD0,
    +		0xEA31DF88, 0x8F566330, 0x61F9D622, 0x049E6A9A,
    +		0xBDA6BD07, 0xD8C101BF, 0x366EB4AD, 0x53090815,
    +		0x9A4E721D, 0xFF29CEA5, 0x11867BB7, 0x74E1C70F,
    +		0xCDD91092, 0xA8BEAC2A, 0x46111938, 0x2376A580,
    +		0x7566C6D8, 0x10017A60, 0xFEAECF72, 0x9BC973CA,
    +		0x22F1A457, 0x479618EF, 0xA939ADFD, 0xCC5E1145,
    +		0x06EE4D76, 0x6389F1CE, 0x8D2644DC, 0xE841F864,
    +		0x51792FF9, 0x341E9341, 0xDAB12653, 0xBFD69AEB,
    +		0xE9C6F9B3, 0x8CA1450B, 0x620EF019, 0x07694CA1,
    +		0xBE519B3C, 0xDB362784, 0x35999296, 0x50FE2E2E,
    +		0x99B95426, 0xFCDEE89E, 0x12715D8C, 0x7716E134,
    +		0xCE2E36A9, 0xAB498A11, 0x45E63F03, 0x208183BB,
    +		0x7691E0E3, 0x13F65C5B, 0xFD59E949, 0x983E55F1,
    +		0x2106826C, 0x44613ED4, 0xAACE8BC6, 0xCFA9377E,
    +		0x38417FD6, 0x5D26C36E, 0xB389767C, 0xD6EECAC4,
    +		0x6FD61D59, 0x0AB1A1E1, 0xE41E14F3, 0x8179A84B,
    +		0xD769CB13, 0xB20E77AB, 0x5CA1C2B9, 0x39C67E01,
    +		0x80FEA99C, 0xE5991524, 0x0B36A036, 0x6E511C8E,
    +		0xA7166686, 0xC271DA3E, 0x2CDE6F2C, 0x49B9D394,
    +		0xF0810409, 0x95E6B8B1, 0x7B490DA3, 0x1E2EB11B,
    +		0x483ED243, 0x2D596EFB, 0xC3F6DBE9, 0xA6916751,
    +		0x1FA9B0CC, 0x7ACE0C74, 0x9461B966, 0xF10605DE
    +	}, {
    +		0x00000000, 0xB029603D, 0x6053C07A, 0xD07AA047,
    +		0xC0A680F5, 0x708FE0C8, 0xA0F5408F, 0x10DC20B2,
    +		0xC14B7030, 0x7162100D, 0xA118B04A, 0x1131D077,
    +		0x01EDF0C5, 0xB1C490F8, 0x61BE30BF, 0xD1975082,
    +		0x8297E060, 0x32BE805D, 0xE2C4201A, 0x52ED4027,
    +		0x42316095, 0xF21800A8, 0x2262A0EF, 0x924BC0D2,
    +		0x43DC9050, 0xF3F5F06D, 0x238F502A, 0x93A63017,
    +		0x837A10A5, 0x33537098, 0xE329D0DF, 0x5300B0E2,
    +		0x042FC1C1, 0xB406A1FC, 0x647C01BB, 0xD4556186,
    +		0xC4894134, 0x74A02109, 0xA4DA814E, 0x14F3E173,
    +		0xC564B1F1, 0x754DD1CC, 0xA537718B, 0x151E11B6,
    +		0x05C23104, 0xB5EB5139, 0x6591F17E, 0xD5B89143,
    +		0x86B821A1, 0x3691419C, 0xE6EBE1DB, 0x56C281E6,
    +		0x461EA154, 0xF637C169, 0x264D612E, 0x96640113,
    +		0x47F35191, 0xF7DA31AC, 0x27A091EB, 0x9789F1D6,
    +		0x8755D164, 0x377CB159, 0xE706111E, 0x572F7123,
    +		0x4958F358, 0xF9719365, 0x290B3322, 0x9922531F,
    +		0x89FE73AD, 0x39D71390, 0xE9ADB3D7, 0x5984D3EA,
    +		0x88138368, 0x383AE355, 0xE8404312, 0x5869232F,
    +		0x48B5039D, 0xF89C63A0, 0x28E6C3E7, 0x98CFA3DA,
    +		0xCBCF1338, 0x7BE67305, 0xAB9CD342, 0x1BB5B37F,
    +		0x0B6993CD, 0xBB40F3F0, 0x6B3A53B7, 0xDB13338A,
    +		0x0A846308, 0xBAAD0335, 0x6AD7A372, 0xDAFEC34F,
    +		0xCA22E3FD, 0x7A0B83C0, 0xAA712387, 0x1A5843BA,
    +		0x4D773299, 0xFD5E52A4, 0x2D24F2E3, 0x9D0D92DE,
    +		0x8DD1B26C, 0x3DF8D251, 0xED827216, 0x5DAB122B,
    +		0x8C3C42A9, 0x3C152294, 0xEC6F82D3, 0x5C46E2EE,
    +		0x4C9AC25C, 0xFCB3A261, 0x2CC90226, 0x9CE0621B,
    +		0xCFE0D2F9, 0x7FC9B2C4, 0xAFB31283, 0x1F9A72BE,
    +		0x0F46520C, 0xBF6F3231, 0x6F159276, 0xDF3CF24B,
    +		0x0EABA2C9, 0xBE82C2F4, 0x6EF862B3, 0xDED1028E,
    +		0xCE0D223C, 0x7E244201, 0xAE5EE246, 0x1E77827B,
    +		0x92B0E6B1, 0x2299868C, 0xF2E326CB, 0x42CA46F6,
    +		0x52166644, 0xE23F0679, 0x3245A63E, 0x826CC603,
    +		0x53FB9681, 0xE3D2F6BC, 0x33A856FB, 0x838136C6,
    +		0x935D1674, 0x23747649, 0xF30ED60E, 0x4327B633,
    +		0x102706D1, 0xA00E66EC, 0x7074C6AB, 0xC05DA696,
    +		0xD0818624, 0x60A8E619, 0xB0D2465E, 0x00FB2663,
    +		0xD16C76E1, 0x614516DC, 0xB13FB69B, 0x0116D6A6,
    +		0x11CAF614, 0xA1E39629, 0x7199366E, 0xC1B05653,
    +		0x969F2770, 0x26B6474D, 0xF6CCE70A, 0x46E58737,
    +		0x5639A785, 0xE610C7B8, 0x366A67FF, 0x864307C2,
    +		0x57D45740, 0xE7FD377D, 0x3787973A, 0x87AEF707,
    +		0x9772D7B5, 0x275BB788, 0xF72117CF, 0x470877F2,
    +		0x1408C710, 0xA421A72D, 0x745B076A, 0xC4726757,
    +		0xD4AE47E5, 0x648727D8, 0xB4FD879F, 0x04D4E7A2,
    +		0xD543B720, 0x656AD71D, 0xB510775A, 0x05391767,
    +		0x15E537D5, 0xA5CC57E8, 0x75B6F7AF, 0xC59F9792,
    +		0xDBE815E9, 0x6BC175D4, 0xBBBBD593, 0x0B92B5AE,
    +		0x1B4E951C, 0xAB67F521, 0x7B1D5566, 0xCB34355B,
    +		0x1AA365D9, 0xAA8A05E4, 0x7AF0A5A3, 0xCAD9C59E,
    +		0xDA05E52C, 0x6A2C8511, 0xBA562556, 0x0A7F456B,
    +		0x597FF589, 0xE95695B4, 0x392C35F3, 0x890555CE,
    +		0x99D9757C, 0x29F01541, 0xF98AB506, 0x49A3D53B,
    +		0x983485B9, 0x281DE584, 0xF86745C3, 0x484E25FE,
    +		0x5892054C, 0xE8BB6571, 0x38C1C536, 0x88E8A50B,
    +		0xDFC7D428, 0x6FEEB415, 0xBF941452, 0x0FBD746F,
    +		0x1F6154DD, 0xAF4834E0, 0x7F3294A7, 0xCF1BF49A,
    +		0x1E8CA418, 0xAEA5C425, 0x7EDF6462, 0xCEF6045F,
    +		0xDE2A24ED, 0x6E0344D0, 0xBE79E497, 0x0E5084AA,
    +		0x5D503448, 0xED795475, 0x3D03F432, 0x8D2A940F,
    +		0x9DF6B4BD, 0x2DDFD480, 0xFDA574C7, 0x4D8C14FA,
    +		0x9C1B4478, 0x2C322445, 0xFC488402, 0x4C61E43F,
    +		0x5CBDC48D, 0xEC94A4B0, 0x3CEE04F7, 0x8CC764CA
    +	}, {
    +		0x00000000, 0xA5D35CCB, 0x0BA1C84D, 0xAE729486,
    +		0x1642919B, 0xB391CD50, 0x1DE359D6, 0xB830051D,
    +		0x6D8253EC, 0xC8510F27, 0x66239BA1, 0xC3F0C76A,
    +		0x7BC0C277, 0xDE139EBC, 0x70610A3A, 0xD5B256F1,
    +		0x9B02D603, 0x3ED18AC8, 0x90A31E4E, 0x35704285,
    +		0x8D404798, 0x28931B53, 0x86E18FD5, 0x2332D31E,
    +		0xF68085EF, 0x5353D924, 0xFD214DA2, 0x58F21169,
    +		0xE0C21474, 0x451148BF, 0xEB63DC39, 0x4EB080F2,
    +		0x3605AC07, 0x93D6F0CC, 0x3DA4644A, 0x98773881,
    +		0x20473D9C, 0x85946157, 0x2BE6F5D1, 0x8E35A91A,
    +		0x5B87FFEB, 0xFE54A320, 0x502637A6, 0xF5F56B6D,
    +		0x4DC56E70, 0xE81632BB, 0x4664A63D, 0xE3B7FAF6,
    +		0xAD077A04, 0x08D426CF, 0xA6A6B249, 0x0375EE82,
    +		0xBB45EB9F, 0x1E96B754, 0xB0E423D2, 0x15377F19,
    +		0xC08529E8, 0x65567523, 0xCB24E1A5, 0x6EF7BD6E,
    +		0xD6C7B873, 0x7314E4B8, 0xDD66703E, 0x78B52CF5,
    +		0x6C0A580F, 0xC9D904C4, 0x67AB9042, 0xC278CC89,
    +		0x7A48C994, 0xDF9B955F, 0x71E901D9, 0xD43A5D12,
    +		0x01880BE3, 0xA45B5728, 0x0A29C3AE, 0xAFFA9F65,
    +		0x17CA9A78, 0xB219C6B3, 0x1C6B5235, 0xB9B80EFE,
    +		0xF7088E0C, 0x52DBD2C7, 0xFCA94641, 0x597A1A8A,
    +		0xE14A1F97, 0x4499435C, 0xEAEBD7DA, 0x4F388B11,
    +		0x9A8ADDE0, 0x3F59812B, 0x912B15AD, 0x34F84966,
    +		0x8CC84C7B, 0x291B10B0, 0x87698436, 0x22BAD8FD,
    +		0x5A0FF408, 0xFFDCA8C3, 0x51AE3C45, 0xF47D608E,
    +		0x4C4D6593, 0xE99E3958, 0x47ECADDE, 0xE23FF115,
    +		0x378DA7E4, 0x925EFB2F, 0x3C2C6FA9, 0x99FF3362,
    +		0x21CF367F, 0x841C6AB4, 0x2A6EFE32, 0x8FBDA2F9,
    +		0xC10D220B, 0x64DE7EC0, 0xCAACEA46, 0x6F7FB68D,
    +		0xD74FB390, 0x729CEF5B, 0xDCEE7BDD, 0x793D2716,
    +		0xAC8F71E7, 0x095C2D2C, 0xA72EB9AA, 0x02FDE561,
    +		0xBACDE07C, 0x1F1EBCB7, 0xB16C2831, 0x14BF74FA,
    +		0xD814B01E, 0x7DC7ECD5, 0xD3B57853, 0x76662498,
    +		0xCE562185, 0x6B857D4E, 0xC5F7E9C8, 0x6024B503,
    +		0xB596E3F2, 0x1045BF39, 0xBE372BBF, 0x1BE47774,
    +		0xA3D47269, 0x06072EA2, 0xA875BA24, 0x0DA6E6EF,
    +		0x4316661D, 0xE6C53AD6, 0x48B7AE50, 0xED64F29B,
    +		0x5554F786, 0xF087AB4D, 0x5EF53FCB, 0xFB266300,
    +		0x2E9435F1, 0x8B47693A, 0x2535FDBC, 0x80E6A177,
    +		0x38D6A46A, 0x9D05F8A1, 0x33776C27, 0x96A430EC,
    +		0xEE111C19, 0x4BC240D2, 0xE5B0D454, 0x4063889F,
    +		0xF8538D82, 0x5D80D149, 0xF3F245CF, 0x56211904,
    +		0x83934FF5, 0x2640133E, 0x883287B8, 0x2DE1DB73,
    +		0x95D1DE6E, 0x300282A5, 0x9E701623, 0x3BA34AE8,
    +		0x7513CA1A, 0xD0C096D1, 0x7EB20257, 0xDB615E9C,
    +		0x63515B81, 0xC682074A, 0x68F093CC, 0xCD23CF07,
    +		0x189199F6, 0xBD42C53D, 0x133051BB, 0xB6E30D70,
    +		0x0ED3086D, 0xAB0054A6, 0x0572C020, 0xA0A19CEB,
    +		0xB41EE811, 0x11CDB4DA, 0xBFBF205C, 0x1A6C7C97,
    +		0xA25C798A, 0x078F2541, 0xA9FDB1C7, 0x0C2EED0C,
    +		0xD99CBBFD, 0x7C4FE736, 0xD23D73B0, 0x77EE2F7B,
    +		0xCFDE2A66, 0x6A0D76AD, 0xC47FE22B, 0x61ACBEE0,
    +		0x2F1C3E12, 0x8ACF62D9, 0x24BDF65F, 0x816EAA94,
    +		0x395EAF89, 0x9C8DF342, 0x32FF67C4, 0x972C3B0F,
    +		0x429E6DFE, 0xE74D3135, 0x493FA5B3, 0xECECF978,
    +		0x54DCFC65, 0xF10FA0AE, 0x5F7D3428, 0xFAAE68E3,
    +		0x821B4416, 0x27C818DD, 0x89BA8C5B, 0x2C69D090,
    +		0x9459D58D, 0x318A8946, 0x9FF81DC0, 0x3A2B410B,
    +		0xEF9917FA, 0x4A4A4B31, 0xE438DFB7, 0x41EB837C,
    +		0xF9DB8661, 0x5C08DAAA, 0xF27A4E2C, 0x57A912E7,
    +		0x19199215, 0xBCCACEDE, 0x12B85A58, 0xB76B0693,
    +		0x0F5B038E, 0xAA885F45, 0x04FACBC3, 0xA1299708,
    +		0x749BC1F9, 0xD1489D32, 0x7F3A09B4, 0xDAE9557F,
    +		0x62D95062, 0xC70A0CA9, 0x6978982F, 0xCCABC4E4
    +	}, {
    +		0x00000000, 0xB40B77A6, 0x29119F97, 0x9D1AE831,
    +		0x13244FF4, 0xA72F3852, 0x3A35D063, 0x8E3EA7C5,
    +		0x674EEF33, 0xD3459895, 0x4E5F70A4, 0xFA540702,
    +		0x746AA0C7, 0xC061D761, 0x5D7B3F50, 0xE97048F6,
    +		0xCE9CDE67, 0x7A97A9C1, 0xE78D41F0, 0x53863656,
    +		0xDDB89193, 0x69B3E635, 0xF4A90E04, 0x40A279A2,
    +		0xA9D23154, 0x1DD946F2, 0x80C3AEC3, 0x34C8D965,
    +		0xBAF67EA0, 0x0EFD0906, 0x93E7E137, 0x27EC9691,
    +		0x9C39BDCF, 0x2832CA69, 0xB5282258, 0x012355FE,
    +		0x8F1DF23B, 0x3B16859D, 0xA60C6DAC, 0x12071A0A,
    +		0xFB7752FC, 0x4F7C255A, 0xD266CD6B, 0x666DBACD,
    +		0xE8531D08, 0x5C586AAE, 0xC142829F, 0x7549F539,
    +		0x52A563A8, 0xE6AE140E, 0x7BB4FC3F, 0xCFBF8B99,
    +		0x41812C5C, 0xF58A5BFA, 0x6890B3CB, 0xDC9BC46D,
    +		0x35EB8C9B, 0x81E0FB3D, 0x1CFA130C, 0xA8F164AA,
    +		0x26CFC36F, 0x92C4B4C9, 0x0FDE5CF8, 0xBBD52B5E,
    +		0x79750B44, 0xCD7E7CE2, 0x506494D3, 0xE46FE375,
    +		0x6A5144B0, 0xDE5A3316, 0x4340DB27, 0xF74BAC81,
    +		0x1E3BE477, 0xAA3093D1, 0x372A7BE0, 0x83210C46,
    +		0x0D1FAB83, 0xB914DC25, 0x240E3414, 0x900543B2,
    +		0xB7E9D523, 0x03E2A285, 0x9EF84AB4, 0x2AF33D12,
    +		0xA4CD9AD7, 0x10C6ED71, 0x8DDC0540, 0x39D772E6,
    +		0xD0A73A10, 0x64AC4DB6, 0xF9B6A587, 0x4DBDD221,
    +		0xC38375E4, 0x77880242, 0xEA92EA73, 0x5E999DD5,
    +		0xE54CB68B, 0x5147C12D, 0xCC5D291C, 0x78565EBA,
    +		0xF668F97F, 0x42638ED9, 0xDF7966E8, 0x6B72114E,
    +		0x820259B8, 0x36092E1E, 0xAB13C62F, 0x1F18B189,
    +		0x9126164C, 0x252D61EA, 0xB83789DB, 0x0C3CFE7D,
    +		0x2BD068EC, 0x9FDB1F4A, 0x02C1F77B, 0xB6CA80DD,
    +		0x38F42718, 0x8CFF50BE, 0x11E5B88F, 0xA5EECF29,
    +		0x4C9E87DF, 0xF895F079, 0x658F1848, 0xD1846FEE,
    +		0x5FBAC82B, 0xEBB1BF8D, 0x76AB57BC, 0xC2A0201A,
    +		0xF2EA1688, 0x46E1612E, 0xDBFB891F, 0x6FF0FEB9,
    +		0xE1CE597C, 0x55C52EDA, 0xC8DFC6EB, 0x7CD4B14D,
    +		0x95A4F9BB, 0x21AF8E1D, 0xBCB5662C, 0x08BE118A,
    +		0x8680B64F, 0x328BC1E9, 0xAF9129D8, 0x1B9A5E7E,
    +		0x3C76C8EF, 0x887DBF49, 0x15675778, 0xA16C20DE,
    +		0x2F52871B, 0x9B59F0BD, 0x0643188C, 0xB2486F2A,
    +		0x5B3827DC, 0xEF33507A, 0x7229B84B, 0xC622CFED,
    +		0x481C6828, 0xFC171F8E, 0x610DF7BF, 0xD5068019,
    +		0x6ED3AB47, 0xDAD8DCE1, 0x47C234D0, 0xF3C94376,
    +		0x7DF7E4B3, 0xC9FC9315, 0x54E67B24, 0xE0ED0C82,
    +		0x099D4474, 0xBD9633D2, 0x208CDBE3, 0x9487AC45,
    +		0x1AB90B80, 0xAEB27C26, 0x33A89417, 0x87A3E3B1,
    +		0xA04F7520, 0x14440286, 0x895EEAB7, 0x3D559D11,
    +		0xB36B3AD4, 0x07604D72, 0x9A7AA543, 0x2E71D2E5,
    +		0xC7019A13, 0x730AEDB5, 0xEE100584, 0x5A1B7222,
    +		0xD425D5E7, 0x602EA241, 0xFD344A70, 0x493F3DD6,
    +		0x8B9F1DCC, 0x3F946A6A, 0xA28E825B, 0x1685F5FD,
    +		0x98BB5238, 0x2CB0259E, 0xB1AACDAF, 0x05A1BA09,
    +		0xECD1F2FF, 0x58DA8559, 0xC5C06D68, 0x71CB1ACE,
    +		0xFFF5BD0B, 0x4BFECAAD, 0xD6E4229C, 0x62EF553A,
    +		0x4503C3AB, 0xF108B40D, 0x6C125C3C, 0xD8192B9A,
    +		0x56278C5F, 0xE22CFBF9, 0x7F3613C8, 0xCB3D646E,
    +		0x224D2C98, 0x96465B3E, 0x0B5CB30F, 0xBF57C4A9,
    +		0x3169636C, 0x856214CA, 0x1878FCFB, 0xAC738B5D,
    +		0x17A6A003, 0xA3ADD7A5, 0x3EB73F94, 0x8ABC4832,
    +		0x0482EFF7, 0xB0899851, 0x2D937060, 0x999807C6,
    +		0x70E84F30, 0xC4E33896, 0x59F9D0A7, 0xEDF2A701,
    +		0x63CC00C4, 0xD7C77762, 0x4ADD9F53, 0xFED6E8F5,
    +		0xD93A7E64, 0x6D3109C2, 0xF02BE1F3, 0x44209655,
    +		0xCA1E3190, 0x7E154636, 0xE30FAE07, 0x5704D9A1,
    +		0xBE749157, 0x0A7FE6F1, 0x97650EC0, 0x236E7966,
    +		0xAD50DEA3, 0x195BA905, 0x84414134, 0x304A3692
    +	}, {
    +		0x00000000, 0x9E00AACC, 0x7D072542, 0xE3078F8E,
    +		0xFA0E4A84, 0x640EE048, 0x87096FC6, 0x1909C50A,
    +		0xB51BE5D3, 0x2B1B4F1F, 0xC81CC091, 0x561C6A5D,
    +		0x4F15AF57, 0xD115059B, 0x32128A15, 0xAC1220D9,
    +		0x2B31BB7C, 0xB53111B0, 0x56369E3E, 0xC83634F2,
    +		0xD13FF1F8, 0x4F3F5B34, 0xAC38D4BA, 0x32387E76,
    +		0x9E2A5EAF, 0x002AF463, 0xE32D7BED, 0x7D2DD121,
    +		0x6424142B, 0xFA24BEE7, 0x19233169, 0x87239BA5,
    +		0x566276F9, 0xC862DC35, 0x2B6553BB, 0xB565F977,
    +		0xAC6C3C7D, 0x326C96B1, 0xD16B193F, 0x4F6BB3F3,
    +		0xE379932A, 0x7D7939E6, 0x9E7EB668, 0x007E1CA4,
    +		0x1977D9AE, 0x87777362, 0x6470FCEC, 0xFA705620,
    +		0x7D53CD85, 0xE3536749, 0x0054E8C7, 0x9E54420B,
    +		0x875D8701, 0x195D2DCD, 0xFA5AA243, 0x645A088F,
    +		0xC8482856, 0x5648829A, 0xB54F0D14, 0x2B4FA7D8,
    +		0x324662D2, 0xAC46C81E, 0x4F414790, 0xD141ED5C,
    +		0xEDC29D29, 0x73C237E5, 0x90C5B86B, 0x0EC512A7,
    +		0x17CCD7AD, 0x89CC7D61, 0x6ACBF2EF, 0xF4CB5823,
    +		0x58D978FA, 0xC6D9D236, 0x25DE5DB8, 0xBBDEF774,
    +		0xA2D7327E, 0x3CD798B2, 0xDFD0173C, 0x41D0BDF0,
    +		0xC6F32655, 0x58F38C99, 0xBBF40317, 0x25F4A9DB,
    +		0x3CFD6CD1, 0xA2FDC61D, 0x41FA4993, 0xDFFAE35F,
    +		0x73E8C386, 0xEDE8694A, 0x0EEFE6C4, 0x90EF4C08,
    +		0x89E68902, 0x17E623CE, 0xF4E1AC40, 0x6AE1068C,
    +		0xBBA0EBD0, 0x25A0411C, 0xC6A7CE92, 0x58A7645E,
    +		0x41AEA154, 0xDFAE0B98, 0x3CA98416, 0xA2A92EDA,
    +		0x0EBB0E03, 0x90BBA4CF, 0x73BC2B41, 0xEDBC818D,
    +		0xF4B54487, 0x6AB5EE4B, 0x89B261C5, 0x17B2CB09,
    +		0x909150AC, 0x0E91FA60, 0xED9675EE, 0x7396DF22,
    +		0x6A9F1A28, 0xF49FB0E4, 0x17983F6A, 0x899895A6,
    +		0x258AB57F, 0xBB8A1FB3, 0x588D903D, 0xC68D3AF1,
    +		0xDF84FFFB, 0x41845537, 0xA283DAB9, 0x3C837075,
    +		0xDA853B53, 0x4485919F, 0xA7821E11, 0x3982B4DD,
    +		0x208B71D7, 0xBE8BDB1B, 0x5D8C5495, 0xC38CFE59,
    +		0x6F9EDE80, 0xF19E744C, 0x1299FBC2, 0x8C99510E,
    +		0x95909404, 0x0B903EC8, 0xE897B146, 0x76971B8A,
    +		0xF1B4802F, 0x6FB42AE3, 0x8CB3A56D, 0x12B30FA1,
    +		0x0BBACAAB, 0x95BA6067, 0x76BDEFE9, 0xE8BD4525,
    +		0x44AF65FC, 0xDAAFCF30, 0x39A840BE, 0xA7A8EA72,
    +		0xBEA12F78, 0x20A185B4, 0xC3A60A3A, 0x5DA6A0F6,
    +		0x8CE74DAA, 0x12E7E766, 0xF1E068E8, 0x6FE0C224,
    +		0x76E9072E, 0xE8E9ADE2, 0x0BEE226C, 0x95EE88A0,
    +		0x39FCA879, 0xA7FC02B5, 0x44FB8D3B, 0xDAFB27F7,
    +		0xC3F2E2FD, 0x5DF24831, 0xBEF5C7BF, 0x20F56D73,
    +		0xA7D6F6D6, 0x39D65C1A, 0xDAD1D394, 0x44D17958,
    +		0x5DD8BC52, 0xC3D8169E, 0x20DF9910, 0xBEDF33DC,
    +		0x12CD1305, 0x8CCDB9C9, 0x6FCA3647, 0xF1CA9C8B,
    +		0xE8C35981, 0x76C3F34D, 0x95C47CC3, 0x0BC4D60F,
    +		0x3747A67A, 0xA9470CB6, 0x4A408338, 0xD44029F4,
    +		0xCD49ECFE, 0x53494632, 0xB04EC9BC, 0x2E4E6370,
    +		0x825C43A9, 0x1C5CE965, 0xFF5B66EB, 0x615BCC27,
    +		0x7852092D, 0xE652A3E1, 0x05552C6F, 0x9B5586A3,
    +		0x1C761D06, 0x8276B7CA, 0x61713844, 0xFF719288,
    +		0xE6785782, 0x7878FD4E, 0x9B7F72C0, 0x057FD80C,
    +		0xA96DF8D5, 0x376D5219, 0xD46ADD97, 0x4A6A775B,
    +		0x5363B251, 0xCD63189D, 0x2E649713, 0xB0643DDF,
    +		0x6125D083, 0xFF257A4F, 0x1C22F5C1, 0x82225F0D,
    +		0x9B2B9A07, 0x052B30CB, 0xE62CBF45, 0x782C1589,
    +		0xD43E3550, 0x4A3E9F9C, 0xA9391012, 0x3739BADE,
    +		0x2E307FD4, 0xB030D518, 0x53375A96, 0xCD37F05A,
    +		0x4A146BFF, 0xD414C133, 0x37134EBD, 0xA913E471,
    +		0xB01A217B, 0x2E1A8BB7, 0xCD1D0439, 0x531DAEF5,
    +		0xFF0F8E2C, 0x610F24E0, 0x8208AB6E, 0x1C0801A2,
    +		0x0501C4A8, 0x9B016E64, 0x7806E1EA, 0xE6064B26
    +	}
    +};
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_le.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_le.h
    new file mode 100644
    index 00000000000..e89c21a7b23
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_le.h
    @@ -0,0 +1,527 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +// This file has been generated by crc32_tablegen.c.
    +
    +const uint32_t lzma_crc32_table[8][256] = {
    +	{
    +		0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
    +		0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
    +		0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
    +		0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
    +		0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
    +		0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
    +		0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
    +		0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
    +		0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
    +		0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
    +		0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
    +		0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
    +		0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
    +		0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
    +		0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
    +		0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
    +		0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
    +		0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
    +		0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
    +		0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
    +		0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
    +		0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
    +		0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
    +		0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
    +		0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
    +		0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
    +		0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
    +		0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
    +		0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
    +		0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
    +		0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
    +		0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
    +		0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
    +		0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
    +		0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
    +		0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
    +		0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
    +		0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
    +		0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
    +		0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
    +		0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
    +		0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
    +		0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
    +		0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
    +		0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
    +		0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
    +		0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
    +		0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
    +		0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
    +		0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
    +		0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
    +		0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
    +		0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
    +		0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
    +		0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
    +		0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
    +		0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
    +		0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
    +		0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
    +		0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
    +		0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
    +		0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
    +		0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
    +		0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
    +	}, {
    +		0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3,
    +		0x646CC504, 0x7D77F445, 0x565AA786, 0x4F4196C7,
    +		0xC8D98A08, 0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB,
    +		0xACB54F0C, 0xB5AE7E4D, 0x9E832D8E, 0x87981CCF,
    +		0x4AC21251, 0x53D92310, 0x78F470D3, 0x61EF4192,
    +		0x2EAED755, 0x37B5E614, 0x1C98B5D7, 0x05838496,
    +		0x821B9859, 0x9B00A918, 0xB02DFADB, 0xA936CB9A,
    +		0xE6775D5D, 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E,
    +		0x958424A2, 0x8C9F15E3, 0xA7B24620, 0xBEA97761,
    +		0xF1E8E1A6, 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265,
    +		0x5D5DAEAA, 0x44469FEB, 0x6F6BCC28, 0x7670FD69,
    +		0x39316BAE, 0x202A5AEF, 0x0B07092C, 0x121C386D,
    +		0xDF4636F3, 0xC65D07B2, 0xED705471, 0xF46B6530,
    +		0xBB2AF3F7, 0xA231C2B6, 0x891C9175, 0x9007A034,
    +		0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38,
    +		0x73F379FF, 0x6AE848BE, 0x41C51B7D, 0x58DE2A3C,
    +		0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6,
    +		0x94158A01, 0x8D0EBB40, 0xA623E883, 0xBF38D9C2,
    +		0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE,
    +		0x5CCC0009, 0x45D73148, 0x6EFA628B, 0x77E153CA,
    +		0xBABB5D54, 0xA3A06C15, 0x888D3FD6, 0x91960E97,
    +		0xDED79850, 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93,
    +		0x7262D75C, 0x6B79E61D, 0x4054B5DE, 0x594F849F,
    +		0x160E1258, 0x0F152319, 0x243870DA, 0x3D23419B,
    +		0x65FD6BA7, 0x7CE65AE6, 0x57CB0925, 0x4ED03864,
    +		0x0191AEA3, 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60,
    +		0xAD24E1AF, 0xB43FD0EE, 0x9F12832D, 0x8609B26C,
    +		0xC94824AB, 0xD05315EA, 0xFB7E4629, 0xE2657768,
    +		0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35,
    +		0x4B53BCF2, 0x52488DB3, 0x7965DE70, 0x607EEF31,
    +		0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D,
    +		0x838A36FA, 0x9A9107BB, 0xB1BC5478, 0xA8A76539,
    +		0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88,
    +		0x5FEF5D4F, 0x46F46C0E, 0x6DD93FCD, 0x74C20E8C,
    +		0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180,
    +		0x9736D747, 0x8E2DE606, 0xA500B5C5, 0xBC1B8484,
    +		0x71418A1A, 0x685ABB5B, 0x4377E898, 0x5A6CD9D9,
    +		0x152D4F1E, 0x0C367E5F, 0x271B2D9C, 0x3E001CDD,
    +		0xB9980012, 0xA0833153, 0x8BAE6290, 0x92B553D1,
    +		0xDDF4C516, 0xC4EFF457, 0xEFC2A794, 0xF6D996D5,
    +		0xAE07BCE9, 0xB71C8DA8, 0x9C31DE6B, 0x852AEF2A,
    +		0xCA6B79ED, 0xD37048AC, 0xF85D1B6F, 0xE1462A2E,
    +		0x66DE36E1, 0x7FC507A0, 0x54E85463, 0x4DF36522,
    +		0x02B2F3E5, 0x1BA9C2A4, 0x30849167, 0x299FA026,
    +		0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B,
    +		0x80A96BBC, 0x99B25AFD, 0xB29F093E, 0xAB84387F,
    +		0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773,
    +		0x4870E1B4, 0x516BD0F5, 0x7A468336, 0x635DB277,
    +		0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D,
    +		0xAF96124A, 0xB68D230B, 0x9DA070C8, 0x84BB4189,
    +		0x03235D46, 0x1A386C07, 0x31153FC4, 0x280E0E85,
    +		0x674F9842, 0x7E54A903, 0x5579FAC0, 0x4C62CB81,
    +		0x8138C51F, 0x9823F45E, 0xB30EA79D, 0xAA1596DC,
    +		0xE554001B, 0xFC4F315A, 0xD7626299, 0xCE7953D8,
    +		0x49E14F17, 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4,
    +		0x2D8D8A13, 0x3496BB52, 0x1FBBE891, 0x06A0D9D0,
    +		0x5E7EF3EC, 0x4765C2AD, 0x6C48916E, 0x7553A02F,
    +		0x3A1236E8, 0x230907A9, 0x0824546A, 0x113F652B,
    +		0x96A779E4, 0x8FBC48A5, 0xA4911B66, 0xBD8A2A27,
    +		0xF2CBBCE0, 0xEBD08DA1, 0xC0FDDE62, 0xD9E6EF23,
    +		0x14BCE1BD, 0x0DA7D0FC, 0x268A833F, 0x3F91B27E,
    +		0x70D024B9, 0x69CB15F8, 0x42E6463B, 0x5BFD777A,
    +		0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876,
    +		0xB809AEB1, 0xA1129FF0, 0x8A3FCC33, 0x9324FD72
    +	}, {
    +		0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59,
    +		0x0709A8DC, 0x06CBC2EB, 0x048D7CB2, 0x054F1685,
    +		0x0E1351B8, 0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1,
    +		0x091AF964, 0x08D89353, 0x0A9E2D0A, 0x0B5C473D,
    +		0x1C26A370, 0x1DE4C947, 0x1FA2771E, 0x1E601D29,
    +		0x1B2F0BAC, 0x1AED619B, 0x18ABDFC2, 0x1969B5F5,
    +		0x1235F2C8, 0x13F798FF, 0x11B126A6, 0x10734C91,
    +		0x153C5A14, 0x14FE3023, 0x16B88E7A, 0x177AE44D,
    +		0x384D46E0, 0x398F2CD7, 0x3BC9928E, 0x3A0BF8B9,
    +		0x3F44EE3C, 0x3E86840B, 0x3CC03A52, 0x3D025065,
    +		0x365E1758, 0x379C7D6F, 0x35DAC336, 0x3418A901,
    +		0x3157BF84, 0x3095D5B3, 0x32D36BEA, 0x331101DD,
    +		0x246BE590, 0x25A98FA7, 0x27EF31FE, 0x262D5BC9,
    +		0x23624D4C, 0x22A0277B, 0x20E69922, 0x2124F315,
    +		0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71,
    +		0x2D711CF4, 0x2CB376C3, 0x2EF5C89A, 0x2F37A2AD,
    +		0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399,
    +		0x7793251C, 0x76514F2B, 0x7417F172, 0x75D59B45,
    +		0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221,
    +		0x798074A4, 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD,
    +		0x6CBC2EB0, 0x6D7E4487, 0x6F38FADE, 0x6EFA90E9,
    +		0x6BB5866C, 0x6A77EC5B, 0x68315202, 0x69F33835,
    +		0x62AF7F08, 0x636D153F, 0x612BAB66, 0x60E9C151,
    +		0x65A6D7D4, 0x6464BDE3, 0x662203BA, 0x67E0698D,
    +		0x48D7CB20, 0x4915A117, 0x4B531F4E, 0x4A917579,
    +		0x4FDE63FC, 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5,
    +		0x46C49A98, 0x4706F0AF, 0x45404EF6, 0x448224C1,
    +		0x41CD3244, 0x400F5873, 0x4249E62A, 0x438B8C1D,
    +		0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609,
    +		0x53F8C08C, 0x523AAABB, 0x507C14E2, 0x51BE7ED5,
    +		0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1,
    +		0x5DEB9134, 0x5C29FB03, 0x5E6F455A, 0x5FAD2F6D,
    +		0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9,
    +		0xE63CB35C, 0xE7FED96B, 0xE5B86732, 0xE47A0D05,
    +		0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461,
    +		0xE82FE2E4, 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD,
    +		0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, 0xFF5506A9,
    +		0xFA1A102C, 0xFBD87A1B, 0xF99EC442, 0xF85CAE75,
    +		0xF300E948, 0xF2C2837F, 0xF0843D26, 0xF1465711,
    +		0xF4094194, 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD,
    +		0xD9785D60, 0xD8BA3757, 0xDAFC890E, 0xDB3EE339,
    +		0xDE71F5BC, 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5,
    +		0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6, 0xD52DB281,
    +		0xD062A404, 0xD1A0CE33, 0xD3E6706A, 0xD2241A5D,
    +		0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049,
    +		0xC25756CC, 0xC3953CFB, 0xC1D382A2, 0xC011E895,
    +		0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1,
    +		0xCC440774, 0xCD866D43, 0xCFC0D31A, 0xCE02B92D,
    +		0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819,
    +		0x96A63E9C, 0x976454AB, 0x9522EAF2, 0x94E080C5,
    +		0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, 0x9DFA79A1,
    +		0x98B56F24, 0x99770513, 0x9B31BB4A, 0x9AF3D17D,
    +		0x8D893530, 0x8C4B5F07, 0x8E0DE15E, 0x8FCF8B69,
    +		0x8A809DEC, 0x8B42F7DB, 0x89044982, 0x88C623B5,
    +		0x839A6488, 0x82580EBF, 0x801EB0E6, 0x81DCDAD1,
    +		0x8493CC54, 0x8551A663, 0x8717183A, 0x86D5720D,
    +		0xA9E2D0A0, 0xA820BA97, 0xAA6604CE, 0xABA46EF9,
    +		0xAEEB787C, 0xAF29124B, 0xAD6FAC12, 0xACADC625,
    +		0xA7F18118, 0xA633EB2F, 0xA4755576, 0xA5B73F41,
    +		0xA0F829C4, 0xA13A43F3, 0xA37CFDAA, 0xA2BE979D,
    +		0xB5C473D0, 0xB40619E7, 0xB640A7BE, 0xB782CD89,
    +		0xB2CDDB0C, 0xB30FB13B, 0xB1490F62, 0xB08B6555,
    +		0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31,
    +		0xBCDE8AB4, 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED
    +	}, {
    +		0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE,
    +		0x8F629757, 0x37DEF032, 0x256B5FDC, 0x9DD738B9,
    +		0xC5B428EF, 0x7D084F8A, 0x6FBDE064, 0xD7018701,
    +		0x4AD6BFB8, 0xF26AD8DD, 0xE0DF7733, 0x58631056,
    +		0x5019579F, 0xE8A530FA, 0xFA109F14, 0x42ACF871,
    +		0xDF7BC0C8, 0x67C7A7AD, 0x75720843, 0xCDCE6F26,
    +		0x95AD7F70, 0x2D111815, 0x3FA4B7FB, 0x8718D09E,
    +		0x1ACFE827, 0xA2738F42, 0xB0C620AC, 0x087A47C9,
    +		0xA032AF3E, 0x188EC85B, 0x0A3B67B5, 0xB28700D0,
    +		0x2F503869, 0x97EC5F0C, 0x8559F0E2, 0x3DE59787,
    +		0x658687D1, 0xDD3AE0B4, 0xCF8F4F5A, 0x7733283F,
    +		0xEAE41086, 0x525877E3, 0x40EDD80D, 0xF851BF68,
    +		0xF02BF8A1, 0x48979FC4, 0x5A22302A, 0xE29E574F,
    +		0x7F496FF6, 0xC7F50893, 0xD540A77D, 0x6DFCC018,
    +		0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0,
    +		0xBAFD4719, 0x0241207C, 0x10F48F92, 0xA848E8F7,
    +		0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3,
    +		0x1476CF6A, 0xACCAA80F, 0xBE7F07E1, 0x06C36084,
    +		0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C,
    +		0xD1C2E785, 0x697E80E0, 0x7BCB2F0E, 0xC377486B,
    +		0xCB0D0FA2, 0x73B168C7, 0x6104C729, 0xD9B8A04C,
    +		0x446F98F5, 0xFCD3FF90, 0xEE66507E, 0x56DA371B,
    +		0x0EB9274D, 0xB6054028, 0xA4B0EFC6, 0x1C0C88A3,
    +		0x81DBB01A, 0x3967D77F, 0x2BD27891, 0x936E1FF4,
    +		0x3B26F703, 0x839A9066, 0x912F3F88, 0x299358ED,
    +		0xB4446054, 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA,
    +		0xFE92DFEC, 0x462EB889, 0x549B1767, 0xEC277002,
    +		0x71F048BB, 0xC94C2FDE, 0xDBF98030, 0x6345E755,
    +		0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72,
    +		0xE45D37CB, 0x5CE150AE, 0x4E54FF40, 0xF6E89825,
    +		0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D,
    +		0x21E91F24, 0x99557841, 0x8BE0D7AF, 0x335CB0CA,
    +		0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5,
    +		0x623B216C, 0xDA874609, 0xC832E9E7, 0x708E8E82,
    +		0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A,
    +		0xA78F0983, 0x1F336EE6, 0x0D86C108, 0xB53AA66D,
    +		0xBD40E1A4, 0x05FC86C1, 0x1749292F, 0xAFF54E4A,
    +		0x322276F3, 0x8A9E1196, 0x982BBE78, 0x2097D91D,
    +		0x78F4C94B, 0xC048AE2E, 0xD2FD01C0, 0x6A4166A5,
    +		0xF7965E1C, 0x4F2A3979, 0x5D9F9697, 0xE523F1F2,
    +		0x4D6B1905, 0xF5D77E60, 0xE762D18E, 0x5FDEB6EB,
    +		0xC2098E52, 0x7AB5E937, 0x680046D9, 0xD0BC21BC,
    +		0x88DF31EA, 0x3063568F, 0x22D6F961, 0x9A6A9E04,
    +		0x07BDA6BD, 0xBF01C1D8, 0xADB46E36, 0x15080953,
    +		0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174,
    +		0x9210D9CD, 0x2AACBEA8, 0x38191146, 0x80A57623,
    +		0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B,
    +		0x57A4F122, 0xEF189647, 0xFDAD39A9, 0x45115ECC,
    +		0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8,
    +		0xF92F7951, 0x41931E34, 0x5326B1DA, 0xEB9AD6BF,
    +		0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, 0xA14C6907,
    +		0x3C9B51BE, 0x842736DB, 0x96929935, 0x2E2EFE50,
    +		0x2654B999, 0x9EE8DEFC, 0x8C5D7112, 0x34E11677,
    +		0xA9362ECE, 0x118A49AB, 0x033FE645, 0xBB838120,
    +		0xE3E09176, 0x5B5CF613, 0x49E959FD, 0xF1553E98,
    +		0x6C820621, 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF,
    +		0xD67F4138, 0x6EC3265D, 0x7C7689B3, 0xC4CAEED6,
    +		0x591DD66F, 0xE1A1B10A, 0xF3141EE4, 0x4BA87981,
    +		0x13CB69D7, 0xAB770EB2, 0xB9C2A15C, 0x017EC639,
    +		0x9CA9FE80, 0x241599E5, 0x36A0360B, 0x8E1C516E,
    +		0x866616A7, 0x3EDA71C2, 0x2C6FDE2C, 0x94D3B949,
    +		0x090481F0, 0xB1B8E695, 0xA30D497B, 0x1BB12E1E,
    +		0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6,
    +		0xCCB0A91F, 0x740CCE7A, 0x66B96194, 0xDE0506F1
    +	}, {
    +		0x00000000, 0x3D6029B0, 0x7AC05360, 0x47A07AD0,
    +		0xF580A6C0, 0xC8E08F70, 0x8F40F5A0, 0xB220DC10,
    +		0x30704BC1, 0x0D106271, 0x4AB018A1, 0x77D03111,
    +		0xC5F0ED01, 0xF890C4B1, 0xBF30BE61, 0x825097D1,
    +		0x60E09782, 0x5D80BE32, 0x1A20C4E2, 0x2740ED52,
    +		0x95603142, 0xA80018F2, 0xEFA06222, 0xD2C04B92,
    +		0x5090DC43, 0x6DF0F5F3, 0x2A508F23, 0x1730A693,
    +		0xA5107A83, 0x98705333, 0xDFD029E3, 0xE2B00053,
    +		0xC1C12F04, 0xFCA106B4, 0xBB017C64, 0x866155D4,
    +		0x344189C4, 0x0921A074, 0x4E81DAA4, 0x73E1F314,
    +		0xF1B164C5, 0xCCD14D75, 0x8B7137A5, 0xB6111E15,
    +		0x0431C205, 0x3951EBB5, 0x7EF19165, 0x4391B8D5,
    +		0xA121B886, 0x9C419136, 0xDBE1EBE6, 0xE681C256,
    +		0x54A11E46, 0x69C137F6, 0x2E614D26, 0x13016496,
    +		0x9151F347, 0xAC31DAF7, 0xEB91A027, 0xD6F18997,
    +		0x64D15587, 0x59B17C37, 0x1E1106E7, 0x23712F57,
    +		0x58F35849, 0x659371F9, 0x22330B29, 0x1F532299,
    +		0xAD73FE89, 0x9013D739, 0xD7B3ADE9, 0xEAD38459,
    +		0x68831388, 0x55E33A38, 0x124340E8, 0x2F236958,
    +		0x9D03B548, 0xA0639CF8, 0xE7C3E628, 0xDAA3CF98,
    +		0x3813CFCB, 0x0573E67B, 0x42D39CAB, 0x7FB3B51B,
    +		0xCD93690B, 0xF0F340BB, 0xB7533A6B, 0x8A3313DB,
    +		0x0863840A, 0x3503ADBA, 0x72A3D76A, 0x4FC3FEDA,
    +		0xFDE322CA, 0xC0830B7A, 0x872371AA, 0xBA43581A,
    +		0x9932774D, 0xA4525EFD, 0xE3F2242D, 0xDE920D9D,
    +		0x6CB2D18D, 0x51D2F83D, 0x167282ED, 0x2B12AB5D,
    +		0xA9423C8C, 0x9422153C, 0xD3826FEC, 0xEEE2465C,
    +		0x5CC29A4C, 0x61A2B3FC, 0x2602C92C, 0x1B62E09C,
    +		0xF9D2E0CF, 0xC4B2C97F, 0x8312B3AF, 0xBE729A1F,
    +		0x0C52460F, 0x31326FBF, 0x7692156F, 0x4BF23CDF,
    +		0xC9A2AB0E, 0xF4C282BE, 0xB362F86E, 0x8E02D1DE,
    +		0x3C220DCE, 0x0142247E, 0x46E25EAE, 0x7B82771E,
    +		0xB1E6B092, 0x8C869922, 0xCB26E3F2, 0xF646CA42,
    +		0x44661652, 0x79063FE2, 0x3EA64532, 0x03C66C82,
    +		0x8196FB53, 0xBCF6D2E3, 0xFB56A833, 0xC6368183,
    +		0x74165D93, 0x49767423, 0x0ED60EF3, 0x33B62743,
    +		0xD1062710, 0xEC660EA0, 0xABC67470, 0x96A65DC0,
    +		0x248681D0, 0x19E6A860, 0x5E46D2B0, 0x6326FB00,
    +		0xE1766CD1, 0xDC164561, 0x9BB63FB1, 0xA6D61601,
    +		0x14F6CA11, 0x2996E3A1, 0x6E369971, 0x5356B0C1,
    +		0x70279F96, 0x4D47B626, 0x0AE7CCF6, 0x3787E546,
    +		0x85A73956, 0xB8C710E6, 0xFF676A36, 0xC2074386,
    +		0x4057D457, 0x7D37FDE7, 0x3A978737, 0x07F7AE87,
    +		0xB5D77297, 0x88B75B27, 0xCF1721F7, 0xF2770847,
    +		0x10C70814, 0x2DA721A4, 0x6A075B74, 0x576772C4,
    +		0xE547AED4, 0xD8278764, 0x9F87FDB4, 0xA2E7D404,
    +		0x20B743D5, 0x1DD76A65, 0x5A7710B5, 0x67173905,
    +		0xD537E515, 0xE857CCA5, 0xAFF7B675, 0x92979FC5,
    +		0xE915E8DB, 0xD475C16B, 0x93D5BBBB, 0xAEB5920B,
    +		0x1C954E1B, 0x21F567AB, 0x66551D7B, 0x5B3534CB,
    +		0xD965A31A, 0xE4058AAA, 0xA3A5F07A, 0x9EC5D9CA,
    +		0x2CE505DA, 0x11852C6A, 0x562556BA, 0x6B457F0A,
    +		0x89F57F59, 0xB49556E9, 0xF3352C39, 0xCE550589,
    +		0x7C75D999, 0x4115F029, 0x06B58AF9, 0x3BD5A349,
    +		0xB9853498, 0x84E51D28, 0xC34567F8, 0xFE254E48,
    +		0x4C059258, 0x7165BBE8, 0x36C5C138, 0x0BA5E888,
    +		0x28D4C7DF, 0x15B4EE6F, 0x521494BF, 0x6F74BD0F,
    +		0xDD54611F, 0xE03448AF, 0xA794327F, 0x9AF41BCF,
    +		0x18A48C1E, 0x25C4A5AE, 0x6264DF7E, 0x5F04F6CE,
    +		0xED242ADE, 0xD044036E, 0x97E479BE, 0xAA84500E,
    +		0x4834505D, 0x755479ED, 0x32F4033D, 0x0F942A8D,
    +		0xBDB4F69D, 0x80D4DF2D, 0xC774A5FD, 0xFA148C4D,
    +		0x78441B9C, 0x4524322C, 0x028448FC, 0x3FE4614C,
    +		0x8DC4BD5C, 0xB0A494EC, 0xF704EE3C, 0xCA64C78C
    +	}, {
    +		0x00000000, 0xCB5CD3A5, 0x4DC8A10B, 0x869472AE,
    +		0x9B914216, 0x50CD91B3, 0xD659E31D, 0x1D0530B8,
    +		0xEC53826D, 0x270F51C8, 0xA19B2366, 0x6AC7F0C3,
    +		0x77C2C07B, 0xBC9E13DE, 0x3A0A6170, 0xF156B2D5,
    +		0x03D6029B, 0xC88AD13E, 0x4E1EA390, 0x85427035,
    +		0x9847408D, 0x531B9328, 0xD58FE186, 0x1ED33223,
    +		0xEF8580F6, 0x24D95353, 0xA24D21FD, 0x6911F258,
    +		0x7414C2E0, 0xBF481145, 0x39DC63EB, 0xF280B04E,
    +		0x07AC0536, 0xCCF0D693, 0x4A64A43D, 0x81387798,
    +		0x9C3D4720, 0x57619485, 0xD1F5E62B, 0x1AA9358E,
    +		0xEBFF875B, 0x20A354FE, 0xA6372650, 0x6D6BF5F5,
    +		0x706EC54D, 0xBB3216E8, 0x3DA66446, 0xF6FAB7E3,
    +		0x047A07AD, 0xCF26D408, 0x49B2A6A6, 0x82EE7503,
    +		0x9FEB45BB, 0x54B7961E, 0xD223E4B0, 0x197F3715,
    +		0xE82985C0, 0x23755665, 0xA5E124CB, 0x6EBDF76E,
    +		0x73B8C7D6, 0xB8E41473, 0x3E7066DD, 0xF52CB578,
    +		0x0F580A6C, 0xC404D9C9, 0x4290AB67, 0x89CC78C2,
    +		0x94C9487A, 0x5F959BDF, 0xD901E971, 0x125D3AD4,
    +		0xE30B8801, 0x28575BA4, 0xAEC3290A, 0x659FFAAF,
    +		0x789ACA17, 0xB3C619B2, 0x35526B1C, 0xFE0EB8B9,
    +		0x0C8E08F7, 0xC7D2DB52, 0x4146A9FC, 0x8A1A7A59,
    +		0x971F4AE1, 0x5C439944, 0xDAD7EBEA, 0x118B384F,
    +		0xE0DD8A9A, 0x2B81593F, 0xAD152B91, 0x6649F834,
    +		0x7B4CC88C, 0xB0101B29, 0x36846987, 0xFDD8BA22,
    +		0x08F40F5A, 0xC3A8DCFF, 0x453CAE51, 0x8E607DF4,
    +		0x93654D4C, 0x58399EE9, 0xDEADEC47, 0x15F13FE2,
    +		0xE4A78D37, 0x2FFB5E92, 0xA96F2C3C, 0x6233FF99,
    +		0x7F36CF21, 0xB46A1C84, 0x32FE6E2A, 0xF9A2BD8F,
    +		0x0B220DC1, 0xC07EDE64, 0x46EAACCA, 0x8DB67F6F,
    +		0x90B34FD7, 0x5BEF9C72, 0xDD7BEEDC, 0x16273D79,
    +		0xE7718FAC, 0x2C2D5C09, 0xAAB92EA7, 0x61E5FD02,
    +		0x7CE0CDBA, 0xB7BC1E1F, 0x31286CB1, 0xFA74BF14,
    +		0x1EB014D8, 0xD5ECC77D, 0x5378B5D3, 0x98246676,
    +		0x852156CE, 0x4E7D856B, 0xC8E9F7C5, 0x03B52460,
    +		0xF2E396B5, 0x39BF4510, 0xBF2B37BE, 0x7477E41B,
    +		0x6972D4A3, 0xA22E0706, 0x24BA75A8, 0xEFE6A60D,
    +		0x1D661643, 0xD63AC5E6, 0x50AEB748, 0x9BF264ED,
    +		0x86F75455, 0x4DAB87F0, 0xCB3FF55E, 0x006326FB,
    +		0xF135942E, 0x3A69478B, 0xBCFD3525, 0x77A1E680,
    +		0x6AA4D638, 0xA1F8059D, 0x276C7733, 0xEC30A496,
    +		0x191C11EE, 0xD240C24B, 0x54D4B0E5, 0x9F886340,
    +		0x828D53F8, 0x49D1805D, 0xCF45F2F3, 0x04192156,
    +		0xF54F9383, 0x3E134026, 0xB8873288, 0x73DBE12D,
    +		0x6EDED195, 0xA5820230, 0x2316709E, 0xE84AA33B,
    +		0x1ACA1375, 0xD196C0D0, 0x5702B27E, 0x9C5E61DB,
    +		0x815B5163, 0x4A0782C6, 0xCC93F068, 0x07CF23CD,
    +		0xF6999118, 0x3DC542BD, 0xBB513013, 0x700DE3B6,
    +		0x6D08D30E, 0xA65400AB, 0x20C07205, 0xEB9CA1A0,
    +		0x11E81EB4, 0xDAB4CD11, 0x5C20BFBF, 0x977C6C1A,
    +		0x8A795CA2, 0x41258F07, 0xC7B1FDA9, 0x0CED2E0C,
    +		0xFDBB9CD9, 0x36E74F7C, 0xB0733DD2, 0x7B2FEE77,
    +		0x662ADECF, 0xAD760D6A, 0x2BE27FC4, 0xE0BEAC61,
    +		0x123E1C2F, 0xD962CF8A, 0x5FF6BD24, 0x94AA6E81,
    +		0x89AF5E39, 0x42F38D9C, 0xC467FF32, 0x0F3B2C97,
    +		0xFE6D9E42, 0x35314DE7, 0xB3A53F49, 0x78F9ECEC,
    +		0x65FCDC54, 0xAEA00FF1, 0x28347D5F, 0xE368AEFA,
    +		0x16441B82, 0xDD18C827, 0x5B8CBA89, 0x90D0692C,
    +		0x8DD55994, 0x46898A31, 0xC01DF89F, 0x0B412B3A,
    +		0xFA1799EF, 0x314B4A4A, 0xB7DF38E4, 0x7C83EB41,
    +		0x6186DBF9, 0xAADA085C, 0x2C4E7AF2, 0xE712A957,
    +		0x15921919, 0xDECECABC, 0x585AB812, 0x93066BB7,
    +		0x8E035B0F, 0x455F88AA, 0xC3CBFA04, 0x089729A1,
    +		0xF9C19B74, 0x329D48D1, 0xB4093A7F, 0x7F55E9DA,
    +		0x6250D962, 0xA90C0AC7, 0x2F987869, 0xE4C4ABCC
    +	}, {
    +		0x00000000, 0xA6770BB4, 0x979F1129, 0x31E81A9D,
    +		0xF44F2413, 0x52382FA7, 0x63D0353A, 0xC5A73E8E,
    +		0x33EF4E67, 0x959845D3, 0xA4705F4E, 0x020754FA,
    +		0xC7A06A74, 0x61D761C0, 0x503F7B5D, 0xF64870E9,
    +		0x67DE9CCE, 0xC1A9977A, 0xF0418DE7, 0x56368653,
    +		0x9391B8DD, 0x35E6B369, 0x040EA9F4, 0xA279A240,
    +		0x5431D2A9, 0xF246D91D, 0xC3AEC380, 0x65D9C834,
    +		0xA07EF6BA, 0x0609FD0E, 0x37E1E793, 0x9196EC27,
    +		0xCFBD399C, 0x69CA3228, 0x582228B5, 0xFE552301,
    +		0x3BF21D8F, 0x9D85163B, 0xAC6D0CA6, 0x0A1A0712,
    +		0xFC5277FB, 0x5A257C4F, 0x6BCD66D2, 0xCDBA6D66,
    +		0x081D53E8, 0xAE6A585C, 0x9F8242C1, 0x39F54975,
    +		0xA863A552, 0x0E14AEE6, 0x3FFCB47B, 0x998BBFCF,
    +		0x5C2C8141, 0xFA5B8AF5, 0xCBB39068, 0x6DC49BDC,
    +		0x9B8CEB35, 0x3DFBE081, 0x0C13FA1C, 0xAA64F1A8,
    +		0x6FC3CF26, 0xC9B4C492, 0xF85CDE0F, 0x5E2BD5BB,
    +		0x440B7579, 0xE27C7ECD, 0xD3946450, 0x75E36FE4,
    +		0xB044516A, 0x16335ADE, 0x27DB4043, 0x81AC4BF7,
    +		0x77E43B1E, 0xD19330AA, 0xE07B2A37, 0x460C2183,
    +		0x83AB1F0D, 0x25DC14B9, 0x14340E24, 0xB2430590,
    +		0x23D5E9B7, 0x85A2E203, 0xB44AF89E, 0x123DF32A,
    +		0xD79ACDA4, 0x71EDC610, 0x4005DC8D, 0xE672D739,
    +		0x103AA7D0, 0xB64DAC64, 0x87A5B6F9, 0x21D2BD4D,
    +		0xE47583C3, 0x42028877, 0x73EA92EA, 0xD59D995E,
    +		0x8BB64CE5, 0x2DC14751, 0x1C295DCC, 0xBA5E5678,
    +		0x7FF968F6, 0xD98E6342, 0xE86679DF, 0x4E11726B,
    +		0xB8590282, 0x1E2E0936, 0x2FC613AB, 0x89B1181F,
    +		0x4C162691, 0xEA612D25, 0xDB8937B8, 0x7DFE3C0C,
    +		0xEC68D02B, 0x4A1FDB9F, 0x7BF7C102, 0xDD80CAB6,
    +		0x1827F438, 0xBE50FF8C, 0x8FB8E511, 0x29CFEEA5,
    +		0xDF879E4C, 0x79F095F8, 0x48188F65, 0xEE6F84D1,
    +		0x2BC8BA5F, 0x8DBFB1EB, 0xBC57AB76, 0x1A20A0C2,
    +		0x8816EAF2, 0x2E61E146, 0x1F89FBDB, 0xB9FEF06F,
    +		0x7C59CEE1, 0xDA2EC555, 0xEBC6DFC8, 0x4DB1D47C,
    +		0xBBF9A495, 0x1D8EAF21, 0x2C66B5BC, 0x8A11BE08,
    +		0x4FB68086, 0xE9C18B32, 0xD82991AF, 0x7E5E9A1B,
    +		0xEFC8763C, 0x49BF7D88, 0x78576715, 0xDE206CA1,
    +		0x1B87522F, 0xBDF0599B, 0x8C184306, 0x2A6F48B2,
    +		0xDC27385B, 0x7A5033EF, 0x4BB82972, 0xEDCF22C6,
    +		0x28681C48, 0x8E1F17FC, 0xBFF70D61, 0x198006D5,
    +		0x47ABD36E, 0xE1DCD8DA, 0xD034C247, 0x7643C9F3,
    +		0xB3E4F77D, 0x1593FCC9, 0x247BE654, 0x820CEDE0,
    +		0x74449D09, 0xD23396BD, 0xE3DB8C20, 0x45AC8794,
    +		0x800BB91A, 0x267CB2AE, 0x1794A833, 0xB1E3A387,
    +		0x20754FA0, 0x86024414, 0xB7EA5E89, 0x119D553D,
    +		0xD43A6BB3, 0x724D6007, 0x43A57A9A, 0xE5D2712E,
    +		0x139A01C7, 0xB5ED0A73, 0x840510EE, 0x22721B5A,
    +		0xE7D525D4, 0x41A22E60, 0x704A34FD, 0xD63D3F49,
    +		0xCC1D9F8B, 0x6A6A943F, 0x5B828EA2, 0xFDF58516,
    +		0x3852BB98, 0x9E25B02C, 0xAFCDAAB1, 0x09BAA105,
    +		0xFFF2D1EC, 0x5985DA58, 0x686DC0C5, 0xCE1ACB71,
    +		0x0BBDF5FF, 0xADCAFE4B, 0x9C22E4D6, 0x3A55EF62,
    +		0xABC30345, 0x0DB408F1, 0x3C5C126C, 0x9A2B19D8,
    +		0x5F8C2756, 0xF9FB2CE2, 0xC813367F, 0x6E643DCB,
    +		0x982C4D22, 0x3E5B4696, 0x0FB35C0B, 0xA9C457BF,
    +		0x6C636931, 0xCA146285, 0xFBFC7818, 0x5D8B73AC,
    +		0x03A0A617, 0xA5D7ADA3, 0x943FB73E, 0x3248BC8A,
    +		0xF7EF8204, 0x519889B0, 0x6070932D, 0xC6079899,
    +		0x304FE870, 0x9638E3C4, 0xA7D0F959, 0x01A7F2ED,
    +		0xC400CC63, 0x6277C7D7, 0x539FDD4A, 0xF5E8D6FE,
    +		0x647E3AD9, 0xC209316D, 0xF3E12BF0, 0x55962044,
    +		0x90311ECA, 0x3646157E, 0x07AE0FE3, 0xA1D90457,
    +		0x579174BE, 0xF1E67F0A, 0xC00E6597, 0x66796E23,
    +		0xA3DE50AD, 0x05A95B19, 0x34414184, 0x92364A30
    +	}, {
    +		0x00000000, 0xCCAA009E, 0x4225077D, 0x8E8F07E3,
    +		0x844A0EFA, 0x48E00E64, 0xC66F0987, 0x0AC50919,
    +		0xD3E51BB5, 0x1F4F1B2B, 0x91C01CC8, 0x5D6A1C56,
    +		0x57AF154F, 0x9B0515D1, 0x158A1232, 0xD92012AC,
    +		0x7CBB312B, 0xB01131B5, 0x3E9E3656, 0xF23436C8,
    +		0xF8F13FD1, 0x345B3F4F, 0xBAD438AC, 0x767E3832,
    +		0xAF5E2A9E, 0x63F42A00, 0xED7B2DE3, 0x21D12D7D,
    +		0x2B142464, 0xE7BE24FA, 0x69312319, 0xA59B2387,
    +		0xF9766256, 0x35DC62C8, 0xBB53652B, 0x77F965B5,
    +		0x7D3C6CAC, 0xB1966C32, 0x3F196BD1, 0xF3B36B4F,
    +		0x2A9379E3, 0xE639797D, 0x68B67E9E, 0xA41C7E00,
    +		0xAED97719, 0x62737787, 0xECFC7064, 0x205670FA,
    +		0x85CD537D, 0x496753E3, 0xC7E85400, 0x0B42549E,
    +		0x01875D87, 0xCD2D5D19, 0x43A25AFA, 0x8F085A64,
    +		0x562848C8, 0x9A824856, 0x140D4FB5, 0xD8A74F2B,
    +		0xD2624632, 0x1EC846AC, 0x9047414F, 0x5CED41D1,
    +		0x299DC2ED, 0xE537C273, 0x6BB8C590, 0xA712C50E,
    +		0xADD7CC17, 0x617DCC89, 0xEFF2CB6A, 0x2358CBF4,
    +		0xFA78D958, 0x36D2D9C6, 0xB85DDE25, 0x74F7DEBB,
    +		0x7E32D7A2, 0xB298D73C, 0x3C17D0DF, 0xF0BDD041,
    +		0x5526F3C6, 0x998CF358, 0x1703F4BB, 0xDBA9F425,
    +		0xD16CFD3C, 0x1DC6FDA2, 0x9349FA41, 0x5FE3FADF,
    +		0x86C3E873, 0x4A69E8ED, 0xC4E6EF0E, 0x084CEF90,
    +		0x0289E689, 0xCE23E617, 0x40ACE1F4, 0x8C06E16A,
    +		0xD0EBA0BB, 0x1C41A025, 0x92CEA7C6, 0x5E64A758,
    +		0x54A1AE41, 0x980BAEDF, 0x1684A93C, 0xDA2EA9A2,
    +		0x030EBB0E, 0xCFA4BB90, 0x412BBC73, 0x8D81BCED,
    +		0x8744B5F4, 0x4BEEB56A, 0xC561B289, 0x09CBB217,
    +		0xAC509190, 0x60FA910E, 0xEE7596ED, 0x22DF9673,
    +		0x281A9F6A, 0xE4B09FF4, 0x6A3F9817, 0xA6959889,
    +		0x7FB58A25, 0xB31F8ABB, 0x3D908D58, 0xF13A8DC6,
    +		0xFBFF84DF, 0x37558441, 0xB9DA83A2, 0x7570833C,
    +		0x533B85DA, 0x9F918544, 0x111E82A7, 0xDDB48239,
    +		0xD7718B20, 0x1BDB8BBE, 0x95548C5D, 0x59FE8CC3,
    +		0x80DE9E6F, 0x4C749EF1, 0xC2FB9912, 0x0E51998C,
    +		0x04949095, 0xC83E900B, 0x46B197E8, 0x8A1B9776,
    +		0x2F80B4F1, 0xE32AB46F, 0x6DA5B38C, 0xA10FB312,
    +		0xABCABA0B, 0x6760BA95, 0xE9EFBD76, 0x2545BDE8,
    +		0xFC65AF44, 0x30CFAFDA, 0xBE40A839, 0x72EAA8A7,
    +		0x782FA1BE, 0xB485A120, 0x3A0AA6C3, 0xF6A0A65D,
    +		0xAA4DE78C, 0x66E7E712, 0xE868E0F1, 0x24C2E06F,
    +		0x2E07E976, 0xE2ADE9E8, 0x6C22EE0B, 0xA088EE95,
    +		0x79A8FC39, 0xB502FCA7, 0x3B8DFB44, 0xF727FBDA,
    +		0xFDE2F2C3, 0x3148F25D, 0xBFC7F5BE, 0x736DF520,
    +		0xD6F6D6A7, 0x1A5CD639, 0x94D3D1DA, 0x5879D144,
    +		0x52BCD85D, 0x9E16D8C3, 0x1099DF20, 0xDC33DFBE,
    +		0x0513CD12, 0xC9B9CD8C, 0x4736CA6F, 0x8B9CCAF1,
    +		0x8159C3E8, 0x4DF3C376, 0xC37CC495, 0x0FD6C40B,
    +		0x7AA64737, 0xB60C47A9, 0x3883404A, 0xF42940D4,
    +		0xFEEC49CD, 0x32464953, 0xBCC94EB0, 0x70634E2E,
    +		0xA9435C82, 0x65E95C1C, 0xEB665BFF, 0x27CC5B61,
    +		0x2D095278, 0xE1A352E6, 0x6F2C5505, 0xA386559B,
    +		0x061D761C, 0xCAB77682, 0x44387161, 0x889271FF,
    +		0x825778E6, 0x4EFD7878, 0xC0727F9B, 0x0CD87F05,
    +		0xD5F86DA9, 0x19526D37, 0x97DD6AD4, 0x5B776A4A,
    +		0x51B26353, 0x9D1863CD, 0x1397642E, 0xDF3D64B0,
    +		0x83D02561, 0x4F7A25FF, 0xC1F5221C, 0x0D5F2282,
    +		0x079A2B9B, 0xCB302B05, 0x45BF2CE6, 0x89152C78,
    +		0x50353ED4, 0x9C9F3E4A, 0x121039A9, 0xDEBA3937,
    +		0xD47F302E, 0x18D530B0, 0x965A3753, 0x5AF037CD,
    +		0xFF6B144A, 0x33C114D4, 0xBD4E1337, 0x71E413A9,
    +		0x7B211AB0, 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53,
    +		0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C,
    +		0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6
    +	}
    +};
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_tablegen.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_tablegen.c
    new file mode 100644
    index 00000000000..b8cf459f8e7
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_tablegen.c
    @@ -0,0 +1,120 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc32_tablegen.c
    +/// \brief      Generate crc32_table_le.h and crc32_table_be.h
    +///
    +/// Compiling: gcc -std=c99 -o crc32_tablegen crc32_tablegen.c
    +/// Add -DWORDS_BIGENDIAN to generate big endian table.
    +/// Add -DLZ_HASH_TABLE to generate lz_encoder_hash_table.h (little endian).
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include 
    +#include "../../common/tuklib_integer.h"
    +
    +
    +static uint32_t crc32_table[8][256];
    +
    +
    +static void
    +init_crc32_table(void)
    +{
    +	static const uint32_t poly32 = UINT32_C(0xEDB88320);
    +
    +	for (size_t s = 0; s < 8; ++s) {
    +		for (size_t b = 0; b < 256; ++b) {
    +			uint32_t r = s == 0 ? b : crc32_table[s - 1][b];
    +
    +			for (size_t i = 0; i < 8; ++i) {
    +				if (r & 1)
    +					r = (r >> 1) ^ poly32;
    +				else
    +					r >>= 1;
    +			}
    +
    +			crc32_table[s][b] = r;
    +		}
    +	}
    +
    +#ifdef WORDS_BIGENDIAN
    +	for (size_t s = 0; s < 8; ++s)
    +		for (size_t b = 0; b < 256; ++b)
    +			crc32_table[s][b] = byteswap32(crc32_table[s][b]);
    +#endif
    +
    +	return;
    +}
    +
    +
    +static void
    +print_crc32_table(void)
    +{
    +	// Split the SPDX string so that it won't accidentally match
    +	// when tools search for the string.
    +	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
    +		"// This file has been generated by crc32_tablegen.c.\n\n"
    +		"const uint32_t lzma_crc32_table[8][256] = {\n\t{");
    +
    +	for (size_t s = 0; s < 8; ++s) {
    +		for (size_t b = 0; b < 256; ++b) {
    +			if ((b % 4) == 0)
    +				printf("\n\t\t");
    +
    +			printf("0x%08" PRIX32, crc32_table[s][b]);
    +
    +			if (b != 255)
    +				printf(",%s", (b+1) % 4 == 0 ? "" : " ");
    +		}
    +
    +		if (s == 7)
    +			printf("\n\t}\n};\n");
    +		else
    +			printf("\n\t}, {");
    +	}
    +
    +	return;
    +}
    +
    +
    +static void
    +print_lz_table(void)
    +{
    +	// Split the SPDX string so that it won't accidentally match
    +	// when tools search for the string.
    +	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
    +		"// This file has been generated by crc32_tablegen.c.\n\n"
    +		"const uint32_t lzma_lz_hash_table[256] = {");
    +
    +	for (size_t b = 0; b < 256; ++b) {
    +		if ((b % 4) == 0)
    +			printf("\n\t");
    +
    +		printf("0x%08" PRIX32, crc32_table[0][b]);
    +
    +		if (b != 255)
    +			printf(",%s", (b+1) % 4 == 0 ? "" : " ");
    +	}
    +
    +	printf("\n};\n");
    +
    +	return;
    +}
    +
    +
    +int
    +main(void)
    +{
    +	init_crc32_table();
    +
    +#ifdef LZ_HASH_TABLE
    +	print_lz_table();
    +#else
    +	print_crc32_table();
    +#endif
    +
    +	return 0;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_x86.S b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_x86.S
    new file mode 100644
    index 00000000000..ddc3cee6ea5
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_x86.S
    @@ -0,0 +1,312 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/*
    + * Speed-optimized CRC32 using slicing-by-eight algorithm
    + *
    + * This uses only i386 instructions, but it is optimized for i686 and later
    + * (including e.g. Pentium II/III/IV, Athlon XP, and Core 2). For i586
    + * (e.g. Pentium), slicing-by-four would be better, and even the C version
    + * of slicing-by-eight built with gcc -march=i586 tends to be a little bit
    + * better than this. Very few probably run this code on i586 or older x86
    + * so this shouldn't be a problem in practice.
    + *
    + * Authors: Igor Pavlov (original version)
    + *          Lasse Collin (AT&T syntax, PIC support, better portability)
    + *
    + * This code needs lzma_crc32_table, which can be created using the
    + * following C code:
    +
    +uint32_t lzma_crc32_table[8][256];
    +
    +void
    +init_table(void)
    +{
    +	// IEEE-802.3
    +	static const uint32_t poly32 = UINT32_C(0xEDB88320);
    +
    +	// Castagnoli
    +	// static const uint32_t poly32 = UINT32_C(0x82F63B78);
    +
    +	// Koopman
    +	// static const uint32_t poly32 = UINT32_C(0xEB31D82E);
    +
    +	for (size_t s = 0; s < 8; ++s) {
    +		for (size_t b = 0; b < 256; ++b) {
    +			uint32_t r = s == 0 ? b : lzma_crc32_table[s - 1][b];
    +
    +			for (size_t i = 0; i < 8; ++i) {
    +				if (r & 1)
    +					r = (r >> 1) ^ poly32;
    +				else
    +					r >>= 1;
    +			}
    +
    +			lzma_crc32_table[s][b] = r;
    +		}
    +	}
    +}
    +
    + * The prototype of the CRC32 function:
    + * extern uint32_t lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc);
    + */
    +
    +/* When Intel CET is enabled, include  in assembly code to mark
    +   Intel CET support.  */
    +#ifdef __CET__
    +# include 
    +#else
    +# define _CET_ENDBR
    +#endif
    +
    +/*
    + * On some systems, the functions need to be prefixed. The prefix is
    + * usually an underscore.
    + */
    +#ifndef __USER_LABEL_PREFIX__
    +#	define __USER_LABEL_PREFIX__
    +#endif
    +#define MAKE_SYM_CAT(prefix, sym) prefix ## sym
    +#define MAKE_SYM(prefix, sym) MAKE_SYM_CAT(prefix, sym)
    +#define LZMA_CRC32 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc32)
    +#define LZMA_CRC32_TABLE MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc32_table)
    +
    +/*
    + * Solaris assembler doesn't have .p2align, and Darwin uses .align
    + * differently than GNU/Linux and Solaris.
    + */
    +#if defined(__APPLE__) || defined(__MSDOS__)
    +#	define ALIGN(pow2, abs) .align pow2
    +#else
    +#	define ALIGN(pow2, abs) .align abs
    +#endif
    +
    +	.text
    +	.globl	LZMA_CRC32
    +
    +#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) \
    +		&& !defined(__MSDOS__)
    +	.type	LZMA_CRC32, @function
    +#endif
    +
    +	ALIGN(4, 16)
    +LZMA_CRC32:
    +	_CET_ENDBR
    +	/*
    +	 * Register usage:
    +	 * %eax crc
    +	 * %esi buf
    +	 * %edi size or buf + size
    +	 * %ebx lzma_crc32_table
    +	 * %ebp Table index
    +	 * %ecx Temporary
    +	 * %edx Temporary
    +	 */
    +	pushl	%ebx
    +	pushl	%esi
    +	pushl	%edi
    +	pushl	%ebp
    +	movl	0x14(%esp), %esi /* buf */
    +	movl	0x18(%esp), %edi /* size */
    +	movl	0x1C(%esp), %eax /* crc */
    +
    +	/*
    +	 * Store the address of lzma_crc32_table to %ebx. This is needed to
    +	 * get position-independent code (PIC).
    +	 *
    +	 * The PIC macro is defined by libtool, while __PIC__ is defined
    +	 * by GCC but only on some systems. Testing for both makes it simpler
    +	 * to test this code without libtool, and keeps the code working also
    +	 * when built with libtool but using something else than GCC.
    +	 *
    +	 * I understood that libtool may define PIC on Windows even though
    +	 * the code in Windows DLLs is not PIC in sense that it is in ELF
    +	 * binaries, so we need a separate check to always use the non-PIC
    +	 * code on Windows.
    +	 */
    +#if (!defined(PIC) && !defined(__PIC__)) \
    +		|| (defined(_WIN32) || defined(__CYGWIN__))
    +	/* Not PIC */
    +	movl	$ LZMA_CRC32_TABLE, %ebx
    +#elif defined(__APPLE__)
    +	/* Mach-O */
    +	call	.L_get_pc
    +.L_pic:
    +	leal	.L_lzma_crc32_table$non_lazy_ptr-.L_pic(%ebx), %ebx
    +	movl	(%ebx), %ebx
    +#else
    +	/* ELF */
    +	call	.L_get_pc
    +	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
    +	movl	LZMA_CRC32_TABLE@GOT(%ebx), %ebx
    +#endif
    +
    +	/* Complement the initial value. */
    +	notl	%eax
    +
    +	ALIGN(4, 16)
    +.L_align:
    +	/*
    +	 * Check if there is enough input to use slicing-by-eight.
    +	 * We need 16 bytes, because the loop pre-reads eight bytes.
    +	 */
    +	cmpl	$16, %edi
    +	jb	.L_rest
    +
    +	/* Check if we have reached alignment of eight bytes. */
    +	testl	$7, %esi
    +	jz	.L_slice
    +
    +	/* Calculate CRC of the next input byte. */
    +	movzbl	(%esi), %ebp
    +	incl	%esi
    +	movzbl	%al, %ecx
    +	xorl	%ecx, %ebp
    +	shrl	$8, %eax
    +	xorl	(%ebx, %ebp, 4), %eax
    +	decl	%edi
    +	jmp	.L_align
    +
    +	ALIGN(2, 4)
    +.L_slice:
    +	/*
    +	 * If we get here, there's at least 16 bytes of aligned input
    +	 * available. Make %edi multiple of eight bytes. Store the possible
    +	 * remainder over the "size" variable in the argument stack.
    +	 */
    +	movl	%edi, 0x18(%esp)
    +	andl	$-8, %edi
    +	subl	%edi, 0x18(%esp)
    +
    +	/*
    +	 * Let %edi be buf + size - 8 while running the main loop. This way
    +	 * we can compare for equality to determine when exit the loop.
    +	 */
    +	addl	%esi, %edi
    +	subl	$8, %edi
    +
    +	/* Read in the first eight aligned bytes. */
    +	xorl	(%esi), %eax
    +	movl	4(%esi), %ecx
    +	movzbl	%cl, %ebp
    +
    +.L_loop:
    +	movl	0x0C00(%ebx, %ebp, 4), %edx
    +	movzbl	%ch, %ebp
    +	xorl	0x0800(%ebx, %ebp, 4), %edx
    +	shrl	$16, %ecx
    +	xorl	8(%esi), %edx
    +	movzbl	%cl, %ebp
    +	xorl	0x0400(%ebx, %ebp, 4), %edx
    +	movzbl	%ch, %ebp
    +	xorl	(%ebx, %ebp, 4), %edx
    +	movzbl	%al, %ebp
    +
    +	/*
    +	 * Read the next four bytes, for which the CRC is calculated
    +	 * on the next iteration of the loop.
    +	 */
    +	movl	12(%esi), %ecx
    +
    +	xorl	0x1C00(%ebx, %ebp, 4), %edx
    +	movzbl	%ah, %ebp
    +	shrl	$16, %eax
    +	xorl	0x1800(%ebx, %ebp, 4), %edx
    +	movzbl	%ah, %ebp
    +	movzbl	%al, %eax
    +	movl	0x1400(%ebx, %eax, 4), %eax
    +	addl	$8, %esi
    +	xorl	%edx, %eax
    +	xorl	0x1000(%ebx, %ebp, 4), %eax
    +
    +	/* Check for end of aligned input. */
    +	cmpl	%edi, %esi
    +	movzbl	%cl, %ebp
    +	jne	.L_loop
    +
    +	/*
    +	 * Process the remaining eight bytes, which we have already
    +	 * copied to %ecx and %edx.
    +	 */
    +	movl	0x0C00(%ebx, %ebp, 4), %edx
    +	movzbl	%ch, %ebp
    +	xorl	0x0800(%ebx, %ebp, 4), %edx
    +	shrl	$16, %ecx
    +	movzbl	%cl, %ebp
    +	xorl	0x0400(%ebx, %ebp, 4), %edx
    +	movzbl	%ch, %ebp
    +	xorl	(%ebx, %ebp, 4), %edx
    +	movzbl	%al, %ebp
    +
    +	xorl	0x1C00(%ebx, %ebp, 4), %edx
    +	movzbl	%ah, %ebp
    +	shrl	$16, %eax
    +	xorl	0x1800(%ebx, %ebp, 4), %edx
    +	movzbl	%ah, %ebp
    +	movzbl	%al, %eax
    +	movl	0x1400(%ebx, %eax, 4), %eax
    +	addl	$8, %esi
    +	xorl	%edx, %eax
    +	xorl	0x1000(%ebx, %ebp, 4), %eax
    +
    +	/* Copy the number of remaining bytes to %edi. */
    +	movl	0x18(%esp), %edi
    +
    +.L_rest:
    +	/* Check for end of input. */
    +	testl	%edi, %edi
    +	jz	.L_return
    +
    +	/* Calculate CRC of the next input byte. */
    +	movzbl	(%esi), %ebp
    +	incl	%esi
    +	movzbl	%al, %ecx
    +	xorl	%ecx, %ebp
    +	shrl	$8, %eax
    +	xorl	(%ebx, %ebp, 4), %eax
    +	decl	%edi
    +	jmp	.L_rest
    +
    +.L_return:
    +	/* Complement the final value. */
    +	notl	%eax
    +
    +	popl	%ebp
    +	popl	%edi
    +	popl	%esi
    +	popl	%ebx
    +	ret
    +
    +#if defined(PIC) || defined(__PIC__)
    +	ALIGN(4, 16)
    +.L_get_pc:
    +	movl	(%esp), %ebx
    +	ret
    +#endif
    +
    +#if defined(__APPLE__) && (defined(PIC) || defined(__PIC__))
    +	/* Mach-O PIC */
    +	.section __IMPORT,__pointers,non_lazy_symbol_pointers
    +.L_lzma_crc32_table$non_lazy_ptr:
    +	.indirect_symbol LZMA_CRC32_TABLE
    +	.long 0
    +
    +#elif defined(_WIN32) || defined(__CYGWIN__)
    +#	ifdef DLL_EXPORT
    +	/* This is equivalent of __declspec(dllexport). */
    +	.section .drectve
    +	.ascii " -export:lzma_crc32"
    +#	endif
    +
    +#elif !defined(__MSDOS__)
    +	/* ELF */
    +	.size	LZMA_CRC32, .-LZMA_CRC32
    +#endif
    +
    +/*
    + * This is needed to support non-executable stack. It's ugly to
    + * use __FreeBSD__ and __linux__ here, but I don't know a way to detect when
    + * we are using GNU assembler.
    + */
    +#if defined(__ELF__) && (defined(__FreeBSD__) || defined(__linux__))
    +	.section	.note.GNU-stack,"",@progbits
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_fast.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_fast.c
    new file mode 100644
    index 00000000000..0ce83fe4ad3
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_fast.c
    @@ -0,0 +1,156 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc64.c
    +/// \brief      CRC64 calculation
    +//
    +//  Authors:    Lasse Collin
    +//              Ilya Kurdyukov
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "check.h"
    +#include "crc_common.h"
    +
    +#if defined(CRC_X86_CLMUL)
    +#	define BUILDING_CRC64_CLMUL
    +#	include "crc_x86_clmul.h"
    +#endif
    +
    +
    +#ifdef CRC64_GENERIC
    +
    +/////////////////////////////////
    +// Generic slice-by-four CRC64 //
    +/////////////////////////////////
    +
    +#ifdef WORDS_BIGENDIAN
    +#	define A1(x) ((x) >> 56)
    +#else
    +#	define A1 A
    +#endif
    +
    +
    +// See the comments in crc32_fast.c. They aren't duplicated here.
    +static uint64_t
    +crc64_generic(const uint8_t *buf, size_t size, uint64_t crc)
    +{
    +	crc = ~crc;
    +
    +#ifdef WORDS_BIGENDIAN
    +	crc = byteswap64(crc);
    +#endif
    +
    +	if (size > 4) {
    +		while ((uintptr_t)(buf) & 3) {
    +			crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);
    +			--size;
    +		}
    +
    +		const uint8_t *const limit = buf + (size & ~(size_t)(3));
    +		size &= (size_t)(3);
    +
    +		while (buf < limit) {
    +#ifdef WORDS_BIGENDIAN
    +			const uint32_t tmp = (uint32_t)(crc >> 32)
    +					^ aligned_read32ne(buf);
    +#else
    +			const uint32_t tmp = (uint32_t)crc
    +					^ aligned_read32ne(buf);
    +#endif
    +			buf += 4;
    +
    +			crc = lzma_crc64_table[3][A(tmp)]
    +			    ^ lzma_crc64_table[2][B(tmp)]
    +			    ^ S32(crc)
    +			    ^ lzma_crc64_table[1][C(tmp)]
    +			    ^ lzma_crc64_table[0][D(tmp)];
    +		}
    +	}
    +
    +	while (size-- != 0)
    +		crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);
    +
    +#ifdef WORDS_BIGENDIAN
    +	crc = byteswap64(crc);
    +#endif
    +
    +	return ~crc;
    +}
    +#endif
    +
    +
    +#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)
    +
    +//////////////////////////
    +// Function dispatching //
    +//////////////////////////
    +
    +// If both the generic and arch-optimized implementations are usable, then
    +// the function that is used is selected at runtime. See crc32_fast.c.
    +
    +typedef uint64_t (*crc64_func_type)(
    +		const uint8_t *buf, size_t size, uint64_t crc);
    +
    +static crc64_func_type
    +crc64_resolve(void)
    +{
    +	return is_arch_extension_supported()
    +			? &crc64_arch_optimized : &crc64_generic;
    +}
    +
    +#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +#	define CRC64_SET_FUNC_ATTR __attribute__((__constructor__))
    +static crc64_func_type crc64_func;
    +#else
    +#	define CRC64_SET_FUNC_ATTR
    +static uint64_t crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc);
    +static crc64_func_type crc64_func = &crc64_dispatch;
    +#endif
    +
    +
    +CRC64_SET_FUNC_ATTR
    +static void
    +crc64_set_func(void)
    +{
    +	crc64_func = crc64_resolve();
    +	return;
    +}
    +
    +
    +#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +static uint64_t
    +crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc)
    +{
    +	crc64_set_func();
    +	return crc64_func(buf, size, crc);
    +}
    +#endif
    +#endif
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
    +{
    +#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)
    +
    +#ifdef CRC_USE_GENERIC_FOR_SMALL_INPUTS
    +	if (size <= 16)
    +		return crc64_generic(buf, size, crc);
    +#endif
    +	return crc64_func(buf, size, crc);
    +
    +#elif defined(CRC64_ARCH_OPTIMIZED)
    +	// If arch-optimized version is used unconditionally without runtime
    +	// CPU detection then omitting the generic version and its 8 KiB
    +	// lookup table makes the library smaller.
    +	//
    +	// FIXME: Lookup table isn't currently omitted on 32-bit x86,
    +	// see crc64_table.c.
    +	return crc64_arch_optimized(buf, size, crc);
    +
    +#else
    +	return crc64_generic(buf, size, crc);
    +#endif
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_small.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_small.c
    new file mode 100644
    index 00000000000..ee4ea26f67d
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_small.c
    @@ -0,0 +1,57 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc64_small.c
    +/// \brief      CRC64 calculation (size-optimized)
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "check.h"
    +
    +
    +static uint64_t crc64_table[256];
    +
    +
    +#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +__attribute__((__constructor__))
    +#endif
    +static void
    +crc64_init(void)
    +{
    +	static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
    +
    +	for (size_t b = 0; b < 256; ++b) {
    +		uint64_t r = b;
    +		for (size_t i = 0; i < 8; ++i) {
    +			if (r & 1)
    +				r = (r >> 1) ^ poly64;
    +			else
    +				r >>= 1;
    +		}
    +
    +		crc64_table[b] = r;
    +	}
    +
    +	return;
    +}
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
    +{
    +#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
    +	mythread_once(crc64_init);
    +#endif
    +
    +	crc = ~crc;
    +
    +	while (size != 0) {
    +		crc = crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
    +		--size;
    +	}
    +
    +	return ~crc;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table.c
    new file mode 100644
    index 00000000000..78e427597ce
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table.c
    @@ -0,0 +1,37 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc64_table.c
    +/// \brief      Precalculated CRC64 table with correct endianness
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +
    +
    +// FIXME: Compared to crc_common.h this has to check for __x86_64__ too
    +// so that in 32-bit builds crc64_x86.S won't break due to a missing table.
    +#if defined(HAVE_USABLE_CLMUL) && ((defined(__x86_64__) && defined(__SSSE3__) \
    +			&& defined(__SSE4_1__) && defined(__PCLMUL__)) \
    +		|| (defined(__e2k__) && __iset__ >= 6))
    +#	define NO_CRC64_TABLE
    +#endif
    +
    +
    +#ifdef NO_CRC64_TABLE
    +// No table needed. Use a typedef to avoid an empty translation unit.
    +typedef void lzma_crc64_dummy;
    +
    +#else
    +// Having the declaration here silences clang -Wmissing-variable-declarations.
    +extern const uint64_t lzma_crc64_table[4][256];
    +
    +#	if defined(WORDS_BIGENDIAN)
    +#		include "crc64_table_be.h"
    +#	else
    +#		include "crc64_table_le.h"
    +#	endif
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_be.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_be.h
    new file mode 100644
    index 00000000000..db76cc70e07
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_be.h
    @@ -0,0 +1,523 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +// This file has been generated by crc64_tablegen.c.
    +
    +const uint64_t lzma_crc64_table[4][256] = {
    +	{
    +		UINT64_C(0x0000000000000000), UINT64_C(0x6F5FA703BE4C2EB3),
    +		UINT64_C(0x5BA040A8573684F4), UINT64_C(0x34FFE7ABE97AAA47),
    +		UINT64_C(0x335E8FFF84C3D07B), UINT64_C(0x5C0128FC3A8FFEC8),
    +		UINT64_C(0x68FECF57D3F5548F), UINT64_C(0x07A168546DB97A3C),
    +		UINT64_C(0x66BC1EFF0987A1F7), UINT64_C(0x09E3B9FCB7CB8F44),
    +		UINT64_C(0x3D1C5E575EB12503), UINT64_C(0x5243F954E0FD0BB0),
    +		UINT64_C(0x55E291008D44718C), UINT64_C(0x3ABD360333085F3F),
    +		UINT64_C(0x0E42D1A8DA72F578), UINT64_C(0x611D76AB643EDBCB),
    +		UINT64_C(0x4966335138A19B7D), UINT64_C(0x2639945286EDB5CE),
    +		UINT64_C(0x12C673F96F971F89), UINT64_C(0x7D99D4FAD1DB313A),
    +		UINT64_C(0x7A38BCAEBC624B06), UINT64_C(0x15671BAD022E65B5),
    +		UINT64_C(0x2198FC06EB54CFF2), UINT64_C(0x4EC75B055518E141),
    +		UINT64_C(0x2FDA2DAE31263A8A), UINT64_C(0x40858AAD8F6A1439),
    +		UINT64_C(0x747A6D066610BE7E), UINT64_C(0x1B25CA05D85C90CD),
    +		UINT64_C(0x1C84A251B5E5EAF1), UINT64_C(0x73DB05520BA9C442),
    +		UINT64_C(0x4724E2F9E2D36E05), UINT64_C(0x287B45FA5C9F40B6),
    +		UINT64_C(0x92CC66A2704237FB), UINT64_C(0xFD93C1A1CE0E1948),
    +		UINT64_C(0xC96C260A2774B30F), UINT64_C(0xA633810999389DBC),
    +		UINT64_C(0xA192E95DF481E780), UINT64_C(0xCECD4E5E4ACDC933),
    +		UINT64_C(0xFA32A9F5A3B76374), UINT64_C(0x956D0EF61DFB4DC7),
    +		UINT64_C(0xF470785D79C5960C), UINT64_C(0x9B2FDF5EC789B8BF),
    +		UINT64_C(0xAFD038F52EF312F8), UINT64_C(0xC08F9FF690BF3C4B),
    +		UINT64_C(0xC72EF7A2FD064677), UINT64_C(0xA87150A1434A68C4),
    +		UINT64_C(0x9C8EB70AAA30C283), UINT64_C(0xF3D11009147CEC30),
    +		UINT64_C(0xDBAA55F348E3AC86), UINT64_C(0xB4F5F2F0F6AF8235),
    +		UINT64_C(0x800A155B1FD52872), UINT64_C(0xEF55B258A19906C1),
    +		UINT64_C(0xE8F4DA0CCC207CFD), UINT64_C(0x87AB7D0F726C524E),
    +		UINT64_C(0xB3549AA49B16F809), UINT64_C(0xDC0B3DA7255AD6BA),
    +		UINT64_C(0xBD164B0C41640D71), UINT64_C(0xD249EC0FFF2823C2),
    +		UINT64_C(0xE6B60BA416528985), UINT64_C(0x89E9ACA7A81EA736),
    +		UINT64_C(0x8E48C4F3C5A7DD0A), UINT64_C(0xE11763F07BEBF3B9),
    +		UINT64_C(0xD5E8845B929159FE), UINT64_C(0xBAB723582CDD774D),
    +		UINT64_C(0xA187C3EBCA2BB664), UINT64_C(0xCED864E8746798D7),
    +		UINT64_C(0xFA2783439D1D3290), UINT64_C(0x9578244023511C23),
    +		UINT64_C(0x92D94C144EE8661F), UINT64_C(0xFD86EB17F0A448AC),
    +		UINT64_C(0xC9790CBC19DEE2EB), UINT64_C(0xA626ABBFA792CC58),
    +		UINT64_C(0xC73BDD14C3AC1793), UINT64_C(0xA8647A177DE03920),
    +		UINT64_C(0x9C9B9DBC949A9367), UINT64_C(0xF3C43ABF2AD6BDD4),
    +		UINT64_C(0xF46552EB476FC7E8), UINT64_C(0x9B3AF5E8F923E95B),
    +		UINT64_C(0xAFC512431059431C), UINT64_C(0xC09AB540AE156DAF),
    +		UINT64_C(0xE8E1F0BAF28A2D19), UINT64_C(0x87BE57B94CC603AA),
    +		UINT64_C(0xB341B012A5BCA9ED), UINT64_C(0xDC1E17111BF0875E),
    +		UINT64_C(0xDBBF7F457649FD62), UINT64_C(0xB4E0D846C805D3D1),
    +		UINT64_C(0x801F3FED217F7996), UINT64_C(0xEF4098EE9F335725),
    +		UINT64_C(0x8E5DEE45FB0D8CEE), UINT64_C(0xE10249464541A25D),
    +		UINT64_C(0xD5FDAEEDAC3B081A), UINT64_C(0xBAA209EE127726A9),
    +		UINT64_C(0xBD0361BA7FCE5C95), UINT64_C(0xD25CC6B9C1827226),
    +		UINT64_C(0xE6A3211228F8D861), UINT64_C(0x89FC861196B4F6D2),
    +		UINT64_C(0x334BA549BA69819F), UINT64_C(0x5C14024A0425AF2C),
    +		UINT64_C(0x68EBE5E1ED5F056B), UINT64_C(0x07B442E253132BD8),
    +		UINT64_C(0x00152AB63EAA51E4), UINT64_C(0x6F4A8DB580E67F57),
    +		UINT64_C(0x5BB56A1E699CD510), UINT64_C(0x34EACD1DD7D0FBA3),
    +		UINT64_C(0x55F7BBB6B3EE2068), UINT64_C(0x3AA81CB50DA20EDB),
    +		UINT64_C(0x0E57FB1EE4D8A49C), UINT64_C(0x61085C1D5A948A2F),
    +		UINT64_C(0x66A93449372DF013), UINT64_C(0x09F6934A8961DEA0),
    +		UINT64_C(0x3D0974E1601B74E7), UINT64_C(0x5256D3E2DE575A54),
    +		UINT64_C(0x7A2D961882C81AE2), UINT64_C(0x1572311B3C843451),
    +		UINT64_C(0x218DD6B0D5FE9E16), UINT64_C(0x4ED271B36BB2B0A5),
    +		UINT64_C(0x497319E7060BCA99), UINT64_C(0x262CBEE4B847E42A),
    +		UINT64_C(0x12D3594F513D4E6D), UINT64_C(0x7D8CFE4CEF7160DE),
    +		UINT64_C(0x1C9188E78B4FBB15), UINT64_C(0x73CE2FE4350395A6),
    +		UINT64_C(0x4731C84FDC793FE1), UINT64_C(0x286E6F4C62351152),
    +		UINT64_C(0x2FCF07180F8C6B6E), UINT64_C(0x4090A01BB1C045DD),
    +		UINT64_C(0x746F47B058BAEF9A), UINT64_C(0x1B30E0B3E6F6C129),
    +		UINT64_C(0x420F87D795576CC9), UINT64_C(0x2D5020D42B1B427A),
    +		UINT64_C(0x19AFC77FC261E83D), UINT64_C(0x76F0607C7C2DC68E),
    +		UINT64_C(0x715108281194BCB2), UINT64_C(0x1E0EAF2BAFD89201),
    +		UINT64_C(0x2AF1488046A23846), UINT64_C(0x45AEEF83F8EE16F5),
    +		UINT64_C(0x24B399289CD0CD3E), UINT64_C(0x4BEC3E2B229CE38D),
    +		UINT64_C(0x7F13D980CBE649CA), UINT64_C(0x104C7E8375AA6779),
    +		UINT64_C(0x17ED16D718131D45), UINT64_C(0x78B2B1D4A65F33F6),
    +		UINT64_C(0x4C4D567F4F2599B1), UINT64_C(0x2312F17CF169B702),
    +		UINT64_C(0x0B69B486ADF6F7B4), UINT64_C(0x6436138513BAD907),
    +		UINT64_C(0x50C9F42EFAC07340), UINT64_C(0x3F96532D448C5DF3),
    +		UINT64_C(0x38373B79293527CF), UINT64_C(0x57689C7A9779097C),
    +		UINT64_C(0x63977BD17E03A33B), UINT64_C(0x0CC8DCD2C04F8D88),
    +		UINT64_C(0x6DD5AA79A4715643), UINT64_C(0x028A0D7A1A3D78F0),
    +		UINT64_C(0x3675EAD1F347D2B7), UINT64_C(0x592A4DD24D0BFC04),
    +		UINT64_C(0x5E8B258620B28638), UINT64_C(0x31D482859EFEA88B),
    +		UINT64_C(0x052B652E778402CC), UINT64_C(0x6A74C22DC9C82C7F),
    +		UINT64_C(0xD0C3E175E5155B32), UINT64_C(0xBF9C46765B597581),
    +		UINT64_C(0x8B63A1DDB223DFC6), UINT64_C(0xE43C06DE0C6FF175),
    +		UINT64_C(0xE39D6E8A61D68B49), UINT64_C(0x8CC2C989DF9AA5FA),
    +		UINT64_C(0xB83D2E2236E00FBD), UINT64_C(0xD762892188AC210E),
    +		UINT64_C(0xB67FFF8AEC92FAC5), UINT64_C(0xD920588952DED476),
    +		UINT64_C(0xEDDFBF22BBA47E31), UINT64_C(0x8280182105E85082),
    +		UINT64_C(0x8521707568512ABE), UINT64_C(0xEA7ED776D61D040D),
    +		UINT64_C(0xDE8130DD3F67AE4A), UINT64_C(0xB1DE97DE812B80F9),
    +		UINT64_C(0x99A5D224DDB4C04F), UINT64_C(0xF6FA752763F8EEFC),
    +		UINT64_C(0xC205928C8A8244BB), UINT64_C(0xAD5A358F34CE6A08),
    +		UINT64_C(0xAAFB5DDB59771034), UINT64_C(0xC5A4FAD8E73B3E87),
    +		UINT64_C(0xF15B1D730E4194C0), UINT64_C(0x9E04BA70B00DBA73),
    +		UINT64_C(0xFF19CCDBD43361B8), UINT64_C(0x90466BD86A7F4F0B),
    +		UINT64_C(0xA4B98C738305E54C), UINT64_C(0xCBE62B703D49CBFF),
    +		UINT64_C(0xCC47432450F0B1C3), UINT64_C(0xA318E427EEBC9F70),
    +		UINT64_C(0x97E7038C07C63537), UINT64_C(0xF8B8A48FB98A1B84),
    +		UINT64_C(0xE388443C5F7CDAAD), UINT64_C(0x8CD7E33FE130F41E),
    +		UINT64_C(0xB8280494084A5E59), UINT64_C(0xD777A397B60670EA),
    +		UINT64_C(0xD0D6CBC3DBBF0AD6), UINT64_C(0xBF896CC065F32465),
    +		UINT64_C(0x8B768B6B8C898E22), UINT64_C(0xE4292C6832C5A091),
    +		UINT64_C(0x85345AC356FB7B5A), UINT64_C(0xEA6BFDC0E8B755E9),
    +		UINT64_C(0xDE941A6B01CDFFAE), UINT64_C(0xB1CBBD68BF81D11D),
    +		UINT64_C(0xB66AD53CD238AB21), UINT64_C(0xD935723F6C748592),
    +		UINT64_C(0xEDCA9594850E2FD5), UINT64_C(0x829532973B420166),
    +		UINT64_C(0xAAEE776D67DD41D0), UINT64_C(0xC5B1D06ED9916F63),
    +		UINT64_C(0xF14E37C530EBC524), UINT64_C(0x9E1190C68EA7EB97),
    +		UINT64_C(0x99B0F892E31E91AB), UINT64_C(0xF6EF5F915D52BF18),
    +		UINT64_C(0xC210B83AB428155F), UINT64_C(0xAD4F1F390A643BEC),
    +		UINT64_C(0xCC5269926E5AE027), UINT64_C(0xA30DCE91D016CE94),
    +		UINT64_C(0x97F2293A396C64D3), UINT64_C(0xF8AD8E3987204A60),
    +		UINT64_C(0xFF0CE66DEA99305C), UINT64_C(0x9053416E54D51EEF),
    +		UINT64_C(0xA4ACA6C5BDAFB4A8), UINT64_C(0xCBF301C603E39A1B),
    +		UINT64_C(0x7144229E2F3EED56), UINT64_C(0x1E1B859D9172C3E5),
    +		UINT64_C(0x2AE46236780869A2), UINT64_C(0x45BBC535C6444711),
    +		UINT64_C(0x421AAD61ABFD3D2D), UINT64_C(0x2D450A6215B1139E),
    +		UINT64_C(0x19BAEDC9FCCBB9D9), UINT64_C(0x76E54ACA4287976A),
    +		UINT64_C(0x17F83C6126B94CA1), UINT64_C(0x78A79B6298F56212),
    +		UINT64_C(0x4C587CC9718FC855), UINT64_C(0x2307DBCACFC3E6E6),
    +		UINT64_C(0x24A6B39EA27A9CDA), UINT64_C(0x4BF9149D1C36B269),
    +		UINT64_C(0x7F06F336F54C182E), UINT64_C(0x105954354B00369D),
    +		UINT64_C(0x382211CF179F762B), UINT64_C(0x577DB6CCA9D35898),
    +		UINT64_C(0x6382516740A9F2DF), UINT64_C(0x0CDDF664FEE5DC6C),
    +		UINT64_C(0x0B7C9E30935CA650), UINT64_C(0x642339332D1088E3),
    +		UINT64_C(0x50DCDE98C46A22A4), UINT64_C(0x3F83799B7A260C17),
    +		UINT64_C(0x5E9E0F301E18D7DC), UINT64_C(0x31C1A833A054F96F),
    +		UINT64_C(0x053E4F98492E5328), UINT64_C(0x6A61E89BF7627D9B),
    +		UINT64_C(0x6DC080CF9ADB07A7), UINT64_C(0x029F27CC24972914),
    +		UINT64_C(0x3660C067CDED8353), UINT64_C(0x593F676473A1ADE0)
    +	}, {
    +		UINT64_C(0x0000000000000000), UINT64_C(0x0DF1D05C9279E954),
    +		UINT64_C(0x1AE2A1B924F3D2A9), UINT64_C(0x171371E5B68A3BFD),
    +		UINT64_C(0xB1DA4DDC62497DC1), UINT64_C(0xBC2B9D80F0309495),
    +		UINT64_C(0xAB38EC6546BAAF68), UINT64_C(0xA6C93C39D4C3463C),
    +		UINT64_C(0xE7AB9517EE3D2210), UINT64_C(0xEA5A454B7C44CB44),
    +		UINT64_C(0xFD4934AECACEF0B9), UINT64_C(0xF0B8E4F258B719ED),
    +		UINT64_C(0x5671D8CB8C745FD1), UINT64_C(0x5B8008971E0DB685),
    +		UINT64_C(0x4C937972A8878D78), UINT64_C(0x4162A92E3AFE642C),
    +		UINT64_C(0xCE572B2FDC7B4420), UINT64_C(0xC3A6FB734E02AD74),
    +		UINT64_C(0xD4B58A96F8889689), UINT64_C(0xD9445ACA6AF17FDD),
    +		UINT64_C(0x7F8D66F3BE3239E1), UINT64_C(0x727CB6AF2C4BD0B5),
    +		UINT64_C(0x656FC74A9AC1EB48), UINT64_C(0x689E171608B8021C),
    +		UINT64_C(0x29FCBE3832466630), UINT64_C(0x240D6E64A03F8F64),
    +		UINT64_C(0x331E1F8116B5B499), UINT64_C(0x3EEFCFDD84CC5DCD),
    +		UINT64_C(0x9826F3E4500F1BF1), UINT64_C(0x95D723B8C276F2A5),
    +		UINT64_C(0x82C4525D74FCC958), UINT64_C(0x8F358201E685200C),
    +		UINT64_C(0x9CAF565EB8F78840), UINT64_C(0x915E86022A8E6114),
    +		UINT64_C(0x864DF7E79C045AE9), UINT64_C(0x8BBC27BB0E7DB3BD),
    +		UINT64_C(0x2D751B82DABEF581), UINT64_C(0x2084CBDE48C71CD5),
    +		UINT64_C(0x3797BA3BFE4D2728), UINT64_C(0x3A666A676C34CE7C),
    +		UINT64_C(0x7B04C34956CAAA50), UINT64_C(0x76F51315C4B34304),
    +		UINT64_C(0x61E662F0723978F9), UINT64_C(0x6C17B2ACE04091AD),
    +		UINT64_C(0xCADE8E953483D791), UINT64_C(0xC72F5EC9A6FA3EC5),
    +		UINT64_C(0xD03C2F2C10700538), UINT64_C(0xDDCDFF708209EC6C),
    +		UINT64_C(0x52F87D71648CCC60), UINT64_C(0x5F09AD2DF6F52534),
    +		UINT64_C(0x481ADCC8407F1EC9), UINT64_C(0x45EB0C94D206F79D),
    +		UINT64_C(0xE32230AD06C5B1A1), UINT64_C(0xEED3E0F194BC58F5),
    +		UINT64_C(0xF9C0911422366308), UINT64_C(0xF4314148B04F8A5C),
    +		UINT64_C(0xB553E8668AB1EE70), UINT64_C(0xB8A2383A18C80724),
    +		UINT64_C(0xAFB149DFAE423CD9), UINT64_C(0xA24099833C3BD58D),
    +		UINT64_C(0x0489A5BAE8F893B1), UINT64_C(0x097875E67A817AE5),
    +		UINT64_C(0x1E6B0403CC0B4118), UINT64_C(0x139AD45F5E72A84C),
    +		UINT64_C(0x385FADBC70EF1181), UINT64_C(0x35AE7DE0E296F8D5),
    +		UINT64_C(0x22BD0C05541CC328), UINT64_C(0x2F4CDC59C6652A7C),
    +		UINT64_C(0x8985E06012A66C40), UINT64_C(0x8474303C80DF8514),
    +		UINT64_C(0x936741D93655BEE9), UINT64_C(0x9E969185A42C57BD),
    +		UINT64_C(0xDFF438AB9ED23391), UINT64_C(0xD205E8F70CABDAC5),
    +		UINT64_C(0xC5169912BA21E138), UINT64_C(0xC8E7494E2858086C),
    +		UINT64_C(0x6E2E7577FC9B4E50), UINT64_C(0x63DFA52B6EE2A704),
    +		UINT64_C(0x74CCD4CED8689CF9), UINT64_C(0x793D04924A1175AD),
    +		UINT64_C(0xF6088693AC9455A1), UINT64_C(0xFBF956CF3EEDBCF5),
    +		UINT64_C(0xECEA272A88678708), UINT64_C(0xE11BF7761A1E6E5C),
    +		UINT64_C(0x47D2CB4FCEDD2860), UINT64_C(0x4A231B135CA4C134),
    +		UINT64_C(0x5D306AF6EA2EFAC9), UINT64_C(0x50C1BAAA7857139D),
    +		UINT64_C(0x11A3138442A977B1), UINT64_C(0x1C52C3D8D0D09EE5),
    +		UINT64_C(0x0B41B23D665AA518), UINT64_C(0x06B06261F4234C4C),
    +		UINT64_C(0xA0795E5820E00A70), UINT64_C(0xAD888E04B299E324),
    +		UINT64_C(0xBA9BFFE10413D8D9), UINT64_C(0xB76A2FBD966A318D),
    +		UINT64_C(0xA4F0FBE2C81899C1), UINT64_C(0xA9012BBE5A617095),
    +		UINT64_C(0xBE125A5BECEB4B68), UINT64_C(0xB3E38A077E92A23C),
    +		UINT64_C(0x152AB63EAA51E400), UINT64_C(0x18DB666238280D54),
    +		UINT64_C(0x0FC817878EA236A9), UINT64_C(0x0239C7DB1CDBDFFD),
    +		UINT64_C(0x435B6EF52625BBD1), UINT64_C(0x4EAABEA9B45C5285),
    +		UINT64_C(0x59B9CF4C02D66978), UINT64_C(0x54481F1090AF802C),
    +		UINT64_C(0xF2812329446CC610), UINT64_C(0xFF70F375D6152F44),
    +		UINT64_C(0xE8638290609F14B9), UINT64_C(0xE59252CCF2E6FDED),
    +		UINT64_C(0x6AA7D0CD1463DDE1), UINT64_C(0x67560091861A34B5),
    +		UINT64_C(0x7045717430900F48), UINT64_C(0x7DB4A128A2E9E61C),
    +		UINT64_C(0xDB7D9D11762AA020), UINT64_C(0xD68C4D4DE4534974),
    +		UINT64_C(0xC19F3CA852D97289), UINT64_C(0xCC6EECF4C0A09BDD),
    +		UINT64_C(0x8D0C45DAFA5EFFF1), UINT64_C(0x80FD9586682716A5),
    +		UINT64_C(0x97EEE463DEAD2D58), UINT64_C(0x9A1F343F4CD4C40C),
    +		UINT64_C(0x3CD6080698178230), UINT64_C(0x3127D85A0A6E6B64),
    +		UINT64_C(0x2634A9BFBCE45099), UINT64_C(0x2BC579E32E9DB9CD),
    +		UINT64_C(0xF5A054D6CA71FB90), UINT64_C(0xF851848A580812C4),
    +		UINT64_C(0xEF42F56FEE822939), UINT64_C(0xE2B325337CFBC06D),
    +		UINT64_C(0x447A190AA8388651), UINT64_C(0x498BC9563A416F05),
    +		UINT64_C(0x5E98B8B38CCB54F8), UINT64_C(0x536968EF1EB2BDAC),
    +		UINT64_C(0x120BC1C1244CD980), UINT64_C(0x1FFA119DB63530D4),
    +		UINT64_C(0x08E9607800BF0B29), UINT64_C(0x0518B02492C6E27D),
    +		UINT64_C(0xA3D18C1D4605A441), UINT64_C(0xAE205C41D47C4D15),
    +		UINT64_C(0xB9332DA462F676E8), UINT64_C(0xB4C2FDF8F08F9FBC),
    +		UINT64_C(0x3BF77FF9160ABFB0), UINT64_C(0x3606AFA5847356E4),
    +		UINT64_C(0x2115DE4032F96D19), UINT64_C(0x2CE40E1CA080844D),
    +		UINT64_C(0x8A2D32257443C271), UINT64_C(0x87DCE279E63A2B25),
    +		UINT64_C(0x90CF939C50B010D8), UINT64_C(0x9D3E43C0C2C9F98C),
    +		UINT64_C(0xDC5CEAEEF8379DA0), UINT64_C(0xD1AD3AB26A4E74F4),
    +		UINT64_C(0xC6BE4B57DCC44F09), UINT64_C(0xCB4F9B0B4EBDA65D),
    +		UINT64_C(0x6D86A7329A7EE061), UINT64_C(0x6077776E08070935),
    +		UINT64_C(0x7764068BBE8D32C8), UINT64_C(0x7A95D6D72CF4DB9C),
    +		UINT64_C(0x690F0288728673D0), UINT64_C(0x64FED2D4E0FF9A84),
    +		UINT64_C(0x73EDA3315675A179), UINT64_C(0x7E1C736DC40C482D),
    +		UINT64_C(0xD8D54F5410CF0E11), UINT64_C(0xD5249F0882B6E745),
    +		UINT64_C(0xC237EEED343CDCB8), UINT64_C(0xCFC63EB1A64535EC),
    +		UINT64_C(0x8EA4979F9CBB51C0), UINT64_C(0x835547C30EC2B894),
    +		UINT64_C(0x94463626B8488369), UINT64_C(0x99B7E67A2A316A3D),
    +		UINT64_C(0x3F7EDA43FEF22C01), UINT64_C(0x328F0A1F6C8BC555),
    +		UINT64_C(0x259C7BFADA01FEA8), UINT64_C(0x286DABA6487817FC),
    +		UINT64_C(0xA75829A7AEFD37F0), UINT64_C(0xAAA9F9FB3C84DEA4),
    +		UINT64_C(0xBDBA881E8A0EE559), UINT64_C(0xB04B584218770C0D),
    +		UINT64_C(0x1682647BCCB44A31), UINT64_C(0x1B73B4275ECDA365),
    +		UINT64_C(0x0C60C5C2E8479898), UINT64_C(0x0191159E7A3E71CC),
    +		UINT64_C(0x40F3BCB040C015E0), UINT64_C(0x4D026CECD2B9FCB4),
    +		UINT64_C(0x5A111D096433C749), UINT64_C(0x57E0CD55F64A2E1D),
    +		UINT64_C(0xF129F16C22896821), UINT64_C(0xFCD82130B0F08175),
    +		UINT64_C(0xEBCB50D5067ABA88), UINT64_C(0xE63A8089940353DC),
    +		UINT64_C(0xCDFFF96ABA9EEA11), UINT64_C(0xC00E293628E70345),
    +		UINT64_C(0xD71D58D39E6D38B8), UINT64_C(0xDAEC888F0C14D1EC),
    +		UINT64_C(0x7C25B4B6D8D797D0), UINT64_C(0x71D464EA4AAE7E84),
    +		UINT64_C(0x66C7150FFC244579), UINT64_C(0x6B36C5536E5DAC2D),
    +		UINT64_C(0x2A546C7D54A3C801), UINT64_C(0x27A5BC21C6DA2155),
    +		UINT64_C(0x30B6CDC470501AA8), UINT64_C(0x3D471D98E229F3FC),
    +		UINT64_C(0x9B8E21A136EAB5C0), UINT64_C(0x967FF1FDA4935C94),
    +		UINT64_C(0x816C801812196769), UINT64_C(0x8C9D504480608E3D),
    +		UINT64_C(0x03A8D24566E5AE31), UINT64_C(0x0E590219F49C4765),
    +		UINT64_C(0x194A73FC42167C98), UINT64_C(0x14BBA3A0D06F95CC),
    +		UINT64_C(0xB2729F9904ACD3F0), UINT64_C(0xBF834FC596D53AA4),
    +		UINT64_C(0xA8903E20205F0159), UINT64_C(0xA561EE7CB226E80D),
    +		UINT64_C(0xE403475288D88C21), UINT64_C(0xE9F2970E1AA16575),
    +		UINT64_C(0xFEE1E6EBAC2B5E88), UINT64_C(0xF31036B73E52B7DC),
    +		UINT64_C(0x55D90A8EEA91F1E0), UINT64_C(0x5828DAD278E818B4),
    +		UINT64_C(0x4F3BAB37CE622349), UINT64_C(0x42CA7B6B5C1BCA1D),
    +		UINT64_C(0x5150AF3402696251), UINT64_C(0x5CA17F6890108B05),
    +		UINT64_C(0x4BB20E8D269AB0F8), UINT64_C(0x4643DED1B4E359AC),
    +		UINT64_C(0xE08AE2E860201F90), UINT64_C(0xED7B32B4F259F6C4),
    +		UINT64_C(0xFA68435144D3CD39), UINT64_C(0xF799930DD6AA246D),
    +		UINT64_C(0xB6FB3A23EC544041), UINT64_C(0xBB0AEA7F7E2DA915),
    +		UINT64_C(0xAC199B9AC8A792E8), UINT64_C(0xA1E84BC65ADE7BBC),
    +		UINT64_C(0x072177FF8E1D3D80), UINT64_C(0x0AD0A7A31C64D4D4),
    +		UINT64_C(0x1DC3D646AAEEEF29), UINT64_C(0x1032061A3897067D),
    +		UINT64_C(0x9F07841BDE122671), UINT64_C(0x92F654474C6BCF25),
    +		UINT64_C(0x85E525A2FAE1F4D8), UINT64_C(0x8814F5FE68981D8C),
    +		UINT64_C(0x2EDDC9C7BC5B5BB0), UINT64_C(0x232C199B2E22B2E4),
    +		UINT64_C(0x343F687E98A88919), UINT64_C(0x39CEB8220AD1604D),
    +		UINT64_C(0x78AC110C302F0461), UINT64_C(0x755DC150A256ED35),
    +		UINT64_C(0x624EB0B514DCD6C8), UINT64_C(0x6FBF60E986A53F9C),
    +		UINT64_C(0xC9765CD0526679A0), UINT64_C(0xC4878C8CC01F90F4),
    +		UINT64_C(0xD394FD697695AB09), UINT64_C(0xDE652D35E4EC425D)
    +	}, {
    +		UINT64_C(0x0000000000000000), UINT64_C(0xCB6D6A914AE10B3F),
    +		UINT64_C(0x96DBD42295C2177E), UINT64_C(0x5DB6BEB3DF231C41),
    +		UINT64_C(0x2CB7A9452A852FFC), UINT64_C(0xE7DAC3D4606424C3),
    +		UINT64_C(0xBA6C7D67BF473882), UINT64_C(0x710117F6F5A633BD),
    +		UINT64_C(0xDD705D247FA5876A), UINT64_C(0x161D37B535448C55),
    +		UINT64_C(0x4BAB8906EA679014), UINT64_C(0x80C6E397A0869B2B),
    +		UINT64_C(0xF1C7F4615520A896), UINT64_C(0x3AAA9EF01FC1A3A9),
    +		UINT64_C(0x671C2043C0E2BFE8), UINT64_C(0xAC714AD28A03B4D7),
    +		UINT64_C(0xBAE1BA48FE4A0FD5), UINT64_C(0x718CD0D9B4AB04EA),
    +		UINT64_C(0x2C3A6E6A6B8818AB), UINT64_C(0xE75704FB21691394),
    +		UINT64_C(0x9656130DD4CF2029), UINT64_C(0x5D3B799C9E2E2B16),
    +		UINT64_C(0x008DC72F410D3757), UINT64_C(0xCBE0ADBE0BEC3C68),
    +		UINT64_C(0x6791E76C81EF88BF), UINT64_C(0xACFC8DFDCB0E8380),
    +		UINT64_C(0xF14A334E142D9FC1), UINT64_C(0x3A2759DF5ECC94FE),
    +		UINT64_C(0x4B264E29AB6AA743), UINT64_C(0x804B24B8E18BAC7C),
    +		UINT64_C(0xDDFD9A0B3EA8B03D), UINT64_C(0x1690F09A7449BB02),
    +		UINT64_C(0xF1DD7B3ED73AC638), UINT64_C(0x3AB011AF9DDBCD07),
    +		UINT64_C(0x6706AF1C42F8D146), UINT64_C(0xAC6BC58D0819DA79),
    +		UINT64_C(0xDD6AD27BFDBFE9C4), UINT64_C(0x1607B8EAB75EE2FB),
    +		UINT64_C(0x4BB10659687DFEBA), UINT64_C(0x80DC6CC8229CF585),
    +		UINT64_C(0x2CAD261AA89F4152), UINT64_C(0xE7C04C8BE27E4A6D),
    +		UINT64_C(0xBA76F2383D5D562C), UINT64_C(0x711B98A977BC5D13),
    +		UINT64_C(0x001A8F5F821A6EAE), UINT64_C(0xCB77E5CEC8FB6591),
    +		UINT64_C(0x96C15B7D17D879D0), UINT64_C(0x5DAC31EC5D3972EF),
    +		UINT64_C(0x4B3CC1762970C9ED), UINT64_C(0x8051ABE76391C2D2),
    +		UINT64_C(0xDDE71554BCB2DE93), UINT64_C(0x168A7FC5F653D5AC),
    +		UINT64_C(0x678B683303F5E611), UINT64_C(0xACE602A24914ED2E),
    +		UINT64_C(0xF150BC119637F16F), UINT64_C(0x3A3DD680DCD6FA50),
    +		UINT64_C(0x964C9C5256D54E87), UINT64_C(0x5D21F6C31C3445B8),
    +		UINT64_C(0x00974870C31759F9), UINT64_C(0xCBFA22E189F652C6),
    +		UINT64_C(0xBAFB35177C50617B), UINT64_C(0x71965F8636B16A44),
    +		UINT64_C(0x2C20E135E9927605), UINT64_C(0xE74D8BA4A3737D3A),
    +		UINT64_C(0xE2BBF77CAE758C71), UINT64_C(0x29D69DEDE494874E),
    +		UINT64_C(0x7460235E3BB79B0F), UINT64_C(0xBF0D49CF71569030),
    +		UINT64_C(0xCE0C5E3984F0A38D), UINT64_C(0x056134A8CE11A8B2),
    +		UINT64_C(0x58D78A1B1132B4F3), UINT64_C(0x93BAE08A5BD3BFCC),
    +		UINT64_C(0x3FCBAA58D1D00B1B), UINT64_C(0xF4A6C0C99B310024),
    +		UINT64_C(0xA9107E7A44121C65), UINT64_C(0x627D14EB0EF3175A),
    +		UINT64_C(0x137C031DFB5524E7), UINT64_C(0xD811698CB1B42FD8),
    +		UINT64_C(0x85A7D73F6E973399), UINT64_C(0x4ECABDAE247638A6),
    +		UINT64_C(0x585A4D34503F83A4), UINT64_C(0x933727A51ADE889B),
    +		UINT64_C(0xCE819916C5FD94DA), UINT64_C(0x05ECF3878F1C9FE5),
    +		UINT64_C(0x74EDE4717ABAAC58), UINT64_C(0xBF808EE0305BA767),
    +		UINT64_C(0xE2363053EF78BB26), UINT64_C(0x295B5AC2A599B019),
    +		UINT64_C(0x852A10102F9A04CE), UINT64_C(0x4E477A81657B0FF1),
    +		UINT64_C(0x13F1C432BA5813B0), UINT64_C(0xD89CAEA3F0B9188F),
    +		UINT64_C(0xA99DB955051F2B32), UINT64_C(0x62F0D3C44FFE200D),
    +		UINT64_C(0x3F466D7790DD3C4C), UINT64_C(0xF42B07E6DA3C3773),
    +		UINT64_C(0x13668C42794F4A49), UINT64_C(0xD80BE6D333AE4176),
    +		UINT64_C(0x85BD5860EC8D5D37), UINT64_C(0x4ED032F1A66C5608),
    +		UINT64_C(0x3FD1250753CA65B5), UINT64_C(0xF4BC4F96192B6E8A),
    +		UINT64_C(0xA90AF125C60872CB), UINT64_C(0x62679BB48CE979F4),
    +		UINT64_C(0xCE16D16606EACD23), UINT64_C(0x057BBBF74C0BC61C),
    +		UINT64_C(0x58CD05449328DA5D), UINT64_C(0x93A06FD5D9C9D162),
    +		UINT64_C(0xE2A178232C6FE2DF), UINT64_C(0x29CC12B2668EE9E0),
    +		UINT64_C(0x747AAC01B9ADF5A1), UINT64_C(0xBF17C690F34CFE9E),
    +		UINT64_C(0xA987360A8705459C), UINT64_C(0x62EA5C9BCDE44EA3),
    +		UINT64_C(0x3F5CE22812C752E2), UINT64_C(0xF43188B9582659DD),
    +		UINT64_C(0x85309F4FAD806A60), UINT64_C(0x4E5DF5DEE761615F),
    +		UINT64_C(0x13EB4B6D38427D1E), UINT64_C(0xD88621FC72A37621),
    +		UINT64_C(0x74F76B2EF8A0C2F6), UINT64_C(0xBF9A01BFB241C9C9),
    +		UINT64_C(0xE22CBF0C6D62D588), UINT64_C(0x2941D59D2783DEB7),
    +		UINT64_C(0x5840C26BD225ED0A), UINT64_C(0x932DA8FA98C4E635),
    +		UINT64_C(0xCE9B164947E7FA74), UINT64_C(0x05F67CD80D06F14B),
    +		UINT64_C(0xC477EFF95CEB18E3), UINT64_C(0x0F1A8568160A13DC),
    +		UINT64_C(0x52AC3BDBC9290F9D), UINT64_C(0x99C1514A83C804A2),
    +		UINT64_C(0xE8C046BC766E371F), UINT64_C(0x23AD2C2D3C8F3C20),
    +		UINT64_C(0x7E1B929EE3AC2061), UINT64_C(0xB576F80FA94D2B5E),
    +		UINT64_C(0x1907B2DD234E9F89), UINT64_C(0xD26AD84C69AF94B6),
    +		UINT64_C(0x8FDC66FFB68C88F7), UINT64_C(0x44B10C6EFC6D83C8),
    +		UINT64_C(0x35B01B9809CBB075), UINT64_C(0xFEDD7109432ABB4A),
    +		UINT64_C(0xA36BCFBA9C09A70B), UINT64_C(0x6806A52BD6E8AC34),
    +		UINT64_C(0x7E9655B1A2A11736), UINT64_C(0xB5FB3F20E8401C09),
    +		UINT64_C(0xE84D819337630048), UINT64_C(0x2320EB027D820B77),
    +		UINT64_C(0x5221FCF4882438CA), UINT64_C(0x994C9665C2C533F5),
    +		UINT64_C(0xC4FA28D61DE62FB4), UINT64_C(0x0F9742475707248B),
    +		UINT64_C(0xA3E60895DD04905C), UINT64_C(0x688B620497E59B63),
    +		UINT64_C(0x353DDCB748C68722), UINT64_C(0xFE50B62602278C1D),
    +		UINT64_C(0x8F51A1D0F781BFA0), UINT64_C(0x443CCB41BD60B49F),
    +		UINT64_C(0x198A75F26243A8DE), UINT64_C(0xD2E71F6328A2A3E1),
    +		UINT64_C(0x35AA94C78BD1DEDB), UINT64_C(0xFEC7FE56C130D5E4),
    +		UINT64_C(0xA37140E51E13C9A5), UINT64_C(0x681C2A7454F2C29A),
    +		UINT64_C(0x191D3D82A154F127), UINT64_C(0xD2705713EBB5FA18),
    +		UINT64_C(0x8FC6E9A03496E659), UINT64_C(0x44AB83317E77ED66),
    +		UINT64_C(0xE8DAC9E3F47459B1), UINT64_C(0x23B7A372BE95528E),
    +		UINT64_C(0x7E011DC161B64ECF), UINT64_C(0xB56C77502B5745F0),
    +		UINT64_C(0xC46D60A6DEF1764D), UINT64_C(0x0F000A3794107D72),
    +		UINT64_C(0x52B6B4844B336133), UINT64_C(0x99DBDE1501D26A0C),
    +		UINT64_C(0x8F4B2E8F759BD10E), UINT64_C(0x4426441E3F7ADA31),
    +		UINT64_C(0x1990FAADE059C670), UINT64_C(0xD2FD903CAAB8CD4F),
    +		UINT64_C(0xA3FC87CA5F1EFEF2), UINT64_C(0x6891ED5B15FFF5CD),
    +		UINT64_C(0x352753E8CADCE98C), UINT64_C(0xFE4A3979803DE2B3),
    +		UINT64_C(0x523B73AB0A3E5664), UINT64_C(0x9956193A40DF5D5B),
    +		UINT64_C(0xC4E0A7899FFC411A), UINT64_C(0x0F8DCD18D51D4A25),
    +		UINT64_C(0x7E8CDAEE20BB7998), UINT64_C(0xB5E1B07F6A5A72A7),
    +		UINT64_C(0xE8570ECCB5796EE6), UINT64_C(0x233A645DFF9865D9),
    +		UINT64_C(0x26CC1885F29E9492), UINT64_C(0xEDA17214B87F9FAD),
    +		UINT64_C(0xB017CCA7675C83EC), UINT64_C(0x7B7AA6362DBD88D3),
    +		UINT64_C(0x0A7BB1C0D81BBB6E), UINT64_C(0xC116DB5192FAB051),
    +		UINT64_C(0x9CA065E24DD9AC10), UINT64_C(0x57CD0F730738A72F),
    +		UINT64_C(0xFBBC45A18D3B13F8), UINT64_C(0x30D12F30C7DA18C7),
    +		UINT64_C(0x6D67918318F90486), UINT64_C(0xA60AFB1252180FB9),
    +		UINT64_C(0xD70BECE4A7BE3C04), UINT64_C(0x1C668675ED5F373B),
    +		UINT64_C(0x41D038C6327C2B7A), UINT64_C(0x8ABD5257789D2045),
    +		UINT64_C(0x9C2DA2CD0CD49B47), UINT64_C(0x5740C85C46359078),
    +		UINT64_C(0x0AF676EF99168C39), UINT64_C(0xC19B1C7ED3F78706),
    +		UINT64_C(0xB09A0B882651B4BB), UINT64_C(0x7BF761196CB0BF84),
    +		UINT64_C(0x2641DFAAB393A3C5), UINT64_C(0xED2CB53BF972A8FA),
    +		UINT64_C(0x415DFFE973711C2D), UINT64_C(0x8A30957839901712),
    +		UINT64_C(0xD7862BCBE6B30B53), UINT64_C(0x1CEB415AAC52006C),
    +		UINT64_C(0x6DEA56AC59F433D1), UINT64_C(0xA6873C3D131538EE),
    +		UINT64_C(0xFB31828ECC3624AF), UINT64_C(0x305CE81F86D72F90),
    +		UINT64_C(0xD71163BB25A452AA), UINT64_C(0x1C7C092A6F455995),
    +		UINT64_C(0x41CAB799B06645D4), UINT64_C(0x8AA7DD08FA874EEB),
    +		UINT64_C(0xFBA6CAFE0F217D56), UINT64_C(0x30CBA06F45C07669),
    +		UINT64_C(0x6D7D1EDC9AE36A28), UINT64_C(0xA610744DD0026117),
    +		UINT64_C(0x0A613E9F5A01D5C0), UINT64_C(0xC10C540E10E0DEFF),
    +		UINT64_C(0x9CBAEABDCFC3C2BE), UINT64_C(0x57D7802C8522C981),
    +		UINT64_C(0x26D697DA7084FA3C), UINT64_C(0xEDBBFD4B3A65F103),
    +		UINT64_C(0xB00D43F8E546ED42), UINT64_C(0x7B602969AFA7E67D),
    +		UINT64_C(0x6DF0D9F3DBEE5D7F), UINT64_C(0xA69DB362910F5640),
    +		UINT64_C(0xFB2B0DD14E2C4A01), UINT64_C(0x3046674004CD413E),
    +		UINT64_C(0x414770B6F16B7283), UINT64_C(0x8A2A1A27BB8A79BC),
    +		UINT64_C(0xD79CA49464A965FD), UINT64_C(0x1CF1CE052E486EC2),
    +		UINT64_C(0xB08084D7A44BDA15), UINT64_C(0x7BEDEE46EEAAD12A),
    +		UINT64_C(0x265B50F53189CD6B), UINT64_C(0xED363A647B68C654),
    +		UINT64_C(0x9C372D928ECEF5E9), UINT64_C(0x575A4703C42FFED6),
    +		UINT64_C(0x0AECF9B01B0CE297), UINT64_C(0xC181932151EDE9A8)
    +	}, {
    +		UINT64_C(0x0000000000000000), UINT64_C(0xDCA12C225E8AEE1D),
    +		UINT64_C(0xB8435944BC14DD3B), UINT64_C(0x64E27566E29E3326),
    +		UINT64_C(0x7087B2887829BA77), UINT64_C(0xAC269EAA26A3546A),
    +		UINT64_C(0xC8C4EBCCC43D674C), UINT64_C(0x1465C7EE9AB78951),
    +		UINT64_C(0xE00E6511F15274EF), UINT64_C(0x3CAF4933AFD89AF2),
    +		UINT64_C(0x584D3C554D46A9D4), UINT64_C(0x84EC107713CC47C9),
    +		UINT64_C(0x9089D799897BCE98), UINT64_C(0x4C28FBBBD7F12085),
    +		UINT64_C(0x28CA8EDD356F13A3), UINT64_C(0xF46BA2FF6BE5FDBE),
    +		UINT64_C(0x4503C48DC90A304C), UINT64_C(0x99A2E8AF9780DE51),
    +		UINT64_C(0xFD409DC9751EED77), UINT64_C(0x21E1B1EB2B94036A),
    +		UINT64_C(0x35847605B1238A3B), UINT64_C(0xE9255A27EFA96426),
    +		UINT64_C(0x8DC72F410D375700), UINT64_C(0x5166036353BDB91D),
    +		UINT64_C(0xA50DA19C385844A3), UINT64_C(0x79AC8DBE66D2AABE),
    +		UINT64_C(0x1D4EF8D8844C9998), UINT64_C(0xC1EFD4FADAC67785),
    +		UINT64_C(0xD58A13144071FED4), UINT64_C(0x092B3F361EFB10C9),
    +		UINT64_C(0x6DC94A50FC6523EF), UINT64_C(0xB1686672A2EFCDF2),
    +		UINT64_C(0x8A06881B93156098), UINT64_C(0x56A7A439CD9F8E85),
    +		UINT64_C(0x3245D15F2F01BDA3), UINT64_C(0xEEE4FD7D718B53BE),
    +		UINT64_C(0xFA813A93EB3CDAEF), UINT64_C(0x262016B1B5B634F2),
    +		UINT64_C(0x42C263D7572807D4), UINT64_C(0x9E634FF509A2E9C9),
    +		UINT64_C(0x6A08ED0A62471477), UINT64_C(0xB6A9C1283CCDFA6A),
    +		UINT64_C(0xD24BB44EDE53C94C), UINT64_C(0x0EEA986C80D92751),
    +		UINT64_C(0x1A8F5F821A6EAE00), UINT64_C(0xC62E73A044E4401D),
    +		UINT64_C(0xA2CC06C6A67A733B), UINT64_C(0x7E6D2AE4F8F09D26),
    +		UINT64_C(0xCF054C965A1F50D4), UINT64_C(0x13A460B40495BEC9),
    +		UINT64_C(0x774615D2E60B8DEF), UINT64_C(0xABE739F0B88163F2),
    +		UINT64_C(0xBF82FE1E2236EAA3), UINT64_C(0x6323D23C7CBC04BE),
    +		UINT64_C(0x07C1A75A9E223798), UINT64_C(0xDB608B78C0A8D985),
    +		UINT64_C(0x2F0B2987AB4D243B), UINT64_C(0xF3AA05A5F5C7CA26),
    +		UINT64_C(0x974870C31759F900), UINT64_C(0x4BE95CE149D3171D),
    +		UINT64_C(0x5F8C9B0FD3649E4C), UINT64_C(0x832DB72D8DEE7051),
    +		UINT64_C(0xE7CFC24B6F704377), UINT64_C(0x3B6EEE6931FAAD6A),
    +		UINT64_C(0x91131E980D8418A2), UINT64_C(0x4DB232BA530EF6BF),
    +		UINT64_C(0x295047DCB190C599), UINT64_C(0xF5F16BFEEF1A2B84),
    +		UINT64_C(0xE194AC1075ADA2D5), UINT64_C(0x3D3580322B274CC8),
    +		UINT64_C(0x59D7F554C9B97FEE), UINT64_C(0x8576D976973391F3),
    +		UINT64_C(0x711D7B89FCD66C4D), UINT64_C(0xADBC57ABA25C8250),
    +		UINT64_C(0xC95E22CD40C2B176), UINT64_C(0x15FF0EEF1E485F6B),
    +		UINT64_C(0x019AC90184FFD63A), UINT64_C(0xDD3BE523DA753827),
    +		UINT64_C(0xB9D9904538EB0B01), UINT64_C(0x6578BC676661E51C),
    +		UINT64_C(0xD410DA15C48E28EE), UINT64_C(0x08B1F6379A04C6F3),
    +		UINT64_C(0x6C538351789AF5D5), UINT64_C(0xB0F2AF7326101BC8),
    +		UINT64_C(0xA497689DBCA79299), UINT64_C(0x783644BFE22D7C84),
    +		UINT64_C(0x1CD431D900B34FA2), UINT64_C(0xC0751DFB5E39A1BF),
    +		UINT64_C(0x341EBF0435DC5C01), UINT64_C(0xE8BF93266B56B21C),
    +		UINT64_C(0x8C5DE64089C8813A), UINT64_C(0x50FCCA62D7426F27),
    +		UINT64_C(0x44990D8C4DF5E676), UINT64_C(0x983821AE137F086B),
    +		UINT64_C(0xFCDA54C8F1E13B4D), UINT64_C(0x207B78EAAF6BD550),
    +		UINT64_C(0x1B1596839E91783A), UINT64_C(0xC7B4BAA1C01B9627),
    +		UINT64_C(0xA356CFC72285A501), UINT64_C(0x7FF7E3E57C0F4B1C),
    +		UINT64_C(0x6B92240BE6B8C24D), UINT64_C(0xB7330829B8322C50),
    +		UINT64_C(0xD3D17D4F5AAC1F76), UINT64_C(0x0F70516D0426F16B),
    +		UINT64_C(0xFB1BF3926FC30CD5), UINT64_C(0x27BADFB03149E2C8),
    +		UINT64_C(0x4358AAD6D3D7D1EE), UINT64_C(0x9FF986F48D5D3FF3),
    +		UINT64_C(0x8B9C411A17EAB6A2), UINT64_C(0x573D6D38496058BF),
    +		UINT64_C(0x33DF185EABFE6B99), UINT64_C(0xEF7E347CF5748584),
    +		UINT64_C(0x5E16520E579B4876), UINT64_C(0x82B77E2C0911A66B),
    +		UINT64_C(0xE6550B4AEB8F954D), UINT64_C(0x3AF42768B5057B50),
    +		UINT64_C(0x2E91E0862FB2F201), UINT64_C(0xF230CCA471381C1C),
    +		UINT64_C(0x96D2B9C293A62F3A), UINT64_C(0x4A7395E0CD2CC127),
    +		UINT64_C(0xBE18371FA6C93C99), UINT64_C(0x62B91B3DF843D284),
    +		UINT64_C(0x065B6E5B1ADDE1A2), UINT64_C(0xDAFA427944570FBF),
    +		UINT64_C(0xCE9F8597DEE086EE), UINT64_C(0x123EA9B5806A68F3),
    +		UINT64_C(0x76DCDCD362F45BD5), UINT64_C(0xAA7DF0F13C7EB5C8),
    +		UINT64_C(0xA739329F30A7E9D6), UINT64_C(0x7B981EBD6E2D07CB),
    +		UINT64_C(0x1F7A6BDB8CB334ED), UINT64_C(0xC3DB47F9D239DAF0),
    +		UINT64_C(0xD7BE8017488E53A1), UINT64_C(0x0B1FAC351604BDBC),
    +		UINT64_C(0x6FFDD953F49A8E9A), UINT64_C(0xB35CF571AA106087),
    +		UINT64_C(0x4737578EC1F59D39), UINT64_C(0x9B967BAC9F7F7324),
    +		UINT64_C(0xFF740ECA7DE14002), UINT64_C(0x23D522E8236BAE1F),
    +		UINT64_C(0x37B0E506B9DC274E), UINT64_C(0xEB11C924E756C953),
    +		UINT64_C(0x8FF3BC4205C8FA75), UINT64_C(0x535290605B421468),
    +		UINT64_C(0xE23AF612F9ADD99A), UINT64_C(0x3E9BDA30A7273787),
    +		UINT64_C(0x5A79AF5645B904A1), UINT64_C(0x86D883741B33EABC),
    +		UINT64_C(0x92BD449A818463ED), UINT64_C(0x4E1C68B8DF0E8DF0),
    +		UINT64_C(0x2AFE1DDE3D90BED6), UINT64_C(0xF65F31FC631A50CB),
    +		UINT64_C(0x0234930308FFAD75), UINT64_C(0xDE95BF2156754368),
    +		UINT64_C(0xBA77CA47B4EB704E), UINT64_C(0x66D6E665EA619E53),
    +		UINT64_C(0x72B3218B70D61702), UINT64_C(0xAE120DA92E5CF91F),
    +		UINT64_C(0xCAF078CFCCC2CA39), UINT64_C(0x165154ED92482424),
    +		UINT64_C(0x2D3FBA84A3B2894E), UINT64_C(0xF19E96A6FD386753),
    +		UINT64_C(0x957CE3C01FA65475), UINT64_C(0x49DDCFE2412CBA68),
    +		UINT64_C(0x5DB8080CDB9B3339), UINT64_C(0x8119242E8511DD24),
    +		UINT64_C(0xE5FB5148678FEE02), UINT64_C(0x395A7D6A3905001F),
    +		UINT64_C(0xCD31DF9552E0FDA1), UINT64_C(0x1190F3B70C6A13BC),
    +		UINT64_C(0x757286D1EEF4209A), UINT64_C(0xA9D3AAF3B07ECE87),
    +		UINT64_C(0xBDB66D1D2AC947D6), UINT64_C(0x6117413F7443A9CB),
    +		UINT64_C(0x05F5345996DD9AED), UINT64_C(0xD954187BC85774F0),
    +		UINT64_C(0x683C7E096AB8B902), UINT64_C(0xB49D522B3432571F),
    +		UINT64_C(0xD07F274DD6AC6439), UINT64_C(0x0CDE0B6F88268A24),
    +		UINT64_C(0x18BBCC8112910375), UINT64_C(0xC41AE0A34C1BED68),
    +		UINT64_C(0xA0F895C5AE85DE4E), UINT64_C(0x7C59B9E7F00F3053),
    +		UINT64_C(0x88321B189BEACDED), UINT64_C(0x5493373AC56023F0),
    +		UINT64_C(0x3071425C27FE10D6), UINT64_C(0xECD06E7E7974FECB),
    +		UINT64_C(0xF8B5A990E3C3779A), UINT64_C(0x241485B2BD499987),
    +		UINT64_C(0x40F6F0D45FD7AAA1), UINT64_C(0x9C57DCF6015D44BC),
    +		UINT64_C(0x362A2C073D23F174), UINT64_C(0xEA8B002563A91F69),
    +		UINT64_C(0x8E69754381372C4F), UINT64_C(0x52C85961DFBDC252),
    +		UINT64_C(0x46AD9E8F450A4B03), UINT64_C(0x9A0CB2AD1B80A51E),
    +		UINT64_C(0xFEEEC7CBF91E9638), UINT64_C(0x224FEBE9A7947825),
    +		UINT64_C(0xD6244916CC71859B), UINT64_C(0x0A85653492FB6B86),
    +		UINT64_C(0x6E671052706558A0), UINT64_C(0xB2C63C702EEFB6BD),
    +		UINT64_C(0xA6A3FB9EB4583FEC), UINT64_C(0x7A02D7BCEAD2D1F1),
    +		UINT64_C(0x1EE0A2DA084CE2D7), UINT64_C(0xC2418EF856C60CCA),
    +		UINT64_C(0x7329E88AF429C138), UINT64_C(0xAF88C4A8AAA32F25),
    +		UINT64_C(0xCB6AB1CE483D1C03), UINT64_C(0x17CB9DEC16B7F21E),
    +		UINT64_C(0x03AE5A028C007B4F), UINT64_C(0xDF0F7620D28A9552),
    +		UINT64_C(0xBBED03463014A674), UINT64_C(0x674C2F646E9E4869),
    +		UINT64_C(0x93278D9B057BB5D7), UINT64_C(0x4F86A1B95BF15BCA),
    +		UINT64_C(0x2B64D4DFB96F68EC), UINT64_C(0xF7C5F8FDE7E586F1),
    +		UINT64_C(0xE3A03F137D520FA0), UINT64_C(0x3F01133123D8E1BD),
    +		UINT64_C(0x5BE36657C146D29B), UINT64_C(0x87424A759FCC3C86),
    +		UINT64_C(0xBC2CA41CAE3691EC), UINT64_C(0x608D883EF0BC7FF1),
    +		UINT64_C(0x046FFD5812224CD7), UINT64_C(0xD8CED17A4CA8A2CA),
    +		UINT64_C(0xCCAB1694D61F2B9B), UINT64_C(0x100A3AB68895C586),
    +		UINT64_C(0x74E84FD06A0BF6A0), UINT64_C(0xA84963F2348118BD),
    +		UINT64_C(0x5C22C10D5F64E503), UINT64_C(0x8083ED2F01EE0B1E),
    +		UINT64_C(0xE4619849E3703838), UINT64_C(0x38C0B46BBDFAD625),
    +		UINT64_C(0x2CA57385274D5F74), UINT64_C(0xF0045FA779C7B169),
    +		UINT64_C(0x94E62AC19B59824F), UINT64_C(0x484706E3C5D36C52),
    +		UINT64_C(0xF92F6091673CA1A0), UINT64_C(0x258E4CB339B64FBD),
    +		UINT64_C(0x416C39D5DB287C9B), UINT64_C(0x9DCD15F785A29286),
    +		UINT64_C(0x89A8D2191F151BD7), UINT64_C(0x5509FE3B419FF5CA),
    +		UINT64_C(0x31EB8B5DA301C6EC), UINT64_C(0xED4AA77FFD8B28F1),
    +		UINT64_C(0x19210580966ED54F), UINT64_C(0xC58029A2C8E43B52),
    +		UINT64_C(0xA1625CC42A7A0874), UINT64_C(0x7DC370E674F0E669),
    +		UINT64_C(0x69A6B708EE476F38), UINT64_C(0xB5079B2AB0CD8125),
    +		UINT64_C(0xD1E5EE4C5253B203), UINT64_C(0x0D44C26E0CD95C1E)
    +	}
    +};
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_le.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_le.h
    new file mode 100644
    index 00000000000..e40a8c82105
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_le.h
    @@ -0,0 +1,523 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +// This file has been generated by crc64_tablegen.c.
    +
    +const uint64_t lzma_crc64_table[4][256] = {
    +	{
    +		UINT64_C(0x0000000000000000), UINT64_C(0xB32E4CBE03A75F6F),
    +		UINT64_C(0xF4843657A840A05B), UINT64_C(0x47AA7AE9ABE7FF34),
    +		UINT64_C(0x7BD0C384FF8F5E33), UINT64_C(0xC8FE8F3AFC28015C),
    +		UINT64_C(0x8F54F5D357CFFE68), UINT64_C(0x3C7AB96D5468A107),
    +		UINT64_C(0xF7A18709FF1EBC66), UINT64_C(0x448FCBB7FCB9E309),
    +		UINT64_C(0x0325B15E575E1C3D), UINT64_C(0xB00BFDE054F94352),
    +		UINT64_C(0x8C71448D0091E255), UINT64_C(0x3F5F08330336BD3A),
    +		UINT64_C(0x78F572DAA8D1420E), UINT64_C(0xCBDB3E64AB761D61),
    +		UINT64_C(0x7D9BA13851336649), UINT64_C(0xCEB5ED8652943926),
    +		UINT64_C(0x891F976FF973C612), UINT64_C(0x3A31DBD1FAD4997D),
    +		UINT64_C(0x064B62BCAEBC387A), UINT64_C(0xB5652E02AD1B6715),
    +		UINT64_C(0xF2CF54EB06FC9821), UINT64_C(0x41E11855055BC74E),
    +		UINT64_C(0x8A3A2631AE2DDA2F), UINT64_C(0x39146A8FAD8A8540),
    +		UINT64_C(0x7EBE1066066D7A74), UINT64_C(0xCD905CD805CA251B),
    +		UINT64_C(0xF1EAE5B551A2841C), UINT64_C(0x42C4A90B5205DB73),
    +		UINT64_C(0x056ED3E2F9E22447), UINT64_C(0xB6409F5CFA457B28),
    +		UINT64_C(0xFB374270A266CC92), UINT64_C(0x48190ECEA1C193FD),
    +		UINT64_C(0x0FB374270A266CC9), UINT64_C(0xBC9D3899098133A6),
    +		UINT64_C(0x80E781F45DE992A1), UINT64_C(0x33C9CD4A5E4ECDCE),
    +		UINT64_C(0x7463B7A3F5A932FA), UINT64_C(0xC74DFB1DF60E6D95),
    +		UINT64_C(0x0C96C5795D7870F4), UINT64_C(0xBFB889C75EDF2F9B),
    +		UINT64_C(0xF812F32EF538D0AF), UINT64_C(0x4B3CBF90F69F8FC0),
    +		UINT64_C(0x774606FDA2F72EC7), UINT64_C(0xC4684A43A15071A8),
    +		UINT64_C(0x83C230AA0AB78E9C), UINT64_C(0x30EC7C140910D1F3),
    +		UINT64_C(0x86ACE348F355AADB), UINT64_C(0x3582AFF6F0F2F5B4),
    +		UINT64_C(0x7228D51F5B150A80), UINT64_C(0xC10699A158B255EF),
    +		UINT64_C(0xFD7C20CC0CDAF4E8), UINT64_C(0x4E526C720F7DAB87),
    +		UINT64_C(0x09F8169BA49A54B3), UINT64_C(0xBAD65A25A73D0BDC),
    +		UINT64_C(0x710D64410C4B16BD), UINT64_C(0xC22328FF0FEC49D2),
    +		UINT64_C(0x85895216A40BB6E6), UINT64_C(0x36A71EA8A7ACE989),
    +		UINT64_C(0x0ADDA7C5F3C4488E), UINT64_C(0xB9F3EB7BF06317E1),
    +		UINT64_C(0xFE5991925B84E8D5), UINT64_C(0x4D77DD2C5823B7BA),
    +		UINT64_C(0x64B62BCAEBC387A1), UINT64_C(0xD7986774E864D8CE),
    +		UINT64_C(0x90321D9D438327FA), UINT64_C(0x231C512340247895),
    +		UINT64_C(0x1F66E84E144CD992), UINT64_C(0xAC48A4F017EB86FD),
    +		UINT64_C(0xEBE2DE19BC0C79C9), UINT64_C(0x58CC92A7BFAB26A6),
    +		UINT64_C(0x9317ACC314DD3BC7), UINT64_C(0x2039E07D177A64A8),
    +		UINT64_C(0x67939A94BC9D9B9C), UINT64_C(0xD4BDD62ABF3AC4F3),
    +		UINT64_C(0xE8C76F47EB5265F4), UINT64_C(0x5BE923F9E8F53A9B),
    +		UINT64_C(0x1C4359104312C5AF), UINT64_C(0xAF6D15AE40B59AC0),
    +		UINT64_C(0x192D8AF2BAF0E1E8), UINT64_C(0xAA03C64CB957BE87),
    +		UINT64_C(0xEDA9BCA512B041B3), UINT64_C(0x5E87F01B11171EDC),
    +		UINT64_C(0x62FD4976457FBFDB), UINT64_C(0xD1D305C846D8E0B4),
    +		UINT64_C(0x96797F21ED3F1F80), UINT64_C(0x2557339FEE9840EF),
    +		UINT64_C(0xEE8C0DFB45EE5D8E), UINT64_C(0x5DA24145464902E1),
    +		UINT64_C(0x1A083BACEDAEFDD5), UINT64_C(0xA9267712EE09A2BA),
    +		UINT64_C(0x955CCE7FBA6103BD), UINT64_C(0x267282C1B9C65CD2),
    +		UINT64_C(0x61D8F8281221A3E6), UINT64_C(0xD2F6B4961186FC89),
    +		UINT64_C(0x9F8169BA49A54B33), UINT64_C(0x2CAF25044A02145C),
    +		UINT64_C(0x6B055FEDE1E5EB68), UINT64_C(0xD82B1353E242B407),
    +		UINT64_C(0xE451AA3EB62A1500), UINT64_C(0x577FE680B58D4A6F),
    +		UINT64_C(0x10D59C691E6AB55B), UINT64_C(0xA3FBD0D71DCDEA34),
    +		UINT64_C(0x6820EEB3B6BBF755), UINT64_C(0xDB0EA20DB51CA83A),
    +		UINT64_C(0x9CA4D8E41EFB570E), UINT64_C(0x2F8A945A1D5C0861),
    +		UINT64_C(0x13F02D374934A966), UINT64_C(0xA0DE61894A93F609),
    +		UINT64_C(0xE7741B60E174093D), UINT64_C(0x545A57DEE2D35652),
    +		UINT64_C(0xE21AC88218962D7A), UINT64_C(0x5134843C1B317215),
    +		UINT64_C(0x169EFED5B0D68D21), UINT64_C(0xA5B0B26BB371D24E),
    +		UINT64_C(0x99CA0B06E7197349), UINT64_C(0x2AE447B8E4BE2C26),
    +		UINT64_C(0x6D4E3D514F59D312), UINT64_C(0xDE6071EF4CFE8C7D),
    +		UINT64_C(0x15BB4F8BE788911C), UINT64_C(0xA6950335E42FCE73),
    +		UINT64_C(0xE13F79DC4FC83147), UINT64_C(0x521135624C6F6E28),
    +		UINT64_C(0x6E6B8C0F1807CF2F), UINT64_C(0xDD45C0B11BA09040),
    +		UINT64_C(0x9AEFBA58B0476F74), UINT64_C(0x29C1F6E6B3E0301B),
    +		UINT64_C(0xC96C5795D7870F42), UINT64_C(0x7A421B2BD420502D),
    +		UINT64_C(0x3DE861C27FC7AF19), UINT64_C(0x8EC62D7C7C60F076),
    +		UINT64_C(0xB2BC941128085171), UINT64_C(0x0192D8AF2BAF0E1E),
    +		UINT64_C(0x4638A2468048F12A), UINT64_C(0xF516EEF883EFAE45),
    +		UINT64_C(0x3ECDD09C2899B324), UINT64_C(0x8DE39C222B3EEC4B),
    +		UINT64_C(0xCA49E6CB80D9137F), UINT64_C(0x7967AA75837E4C10),
    +		UINT64_C(0x451D1318D716ED17), UINT64_C(0xF6335FA6D4B1B278),
    +		UINT64_C(0xB199254F7F564D4C), UINT64_C(0x02B769F17CF11223),
    +		UINT64_C(0xB4F7F6AD86B4690B), UINT64_C(0x07D9BA1385133664),
    +		UINT64_C(0x4073C0FA2EF4C950), UINT64_C(0xF35D8C442D53963F),
    +		UINT64_C(0xCF273529793B3738), UINT64_C(0x7C0979977A9C6857),
    +		UINT64_C(0x3BA3037ED17B9763), UINT64_C(0x888D4FC0D2DCC80C),
    +		UINT64_C(0x435671A479AAD56D), UINT64_C(0xF0783D1A7A0D8A02),
    +		UINT64_C(0xB7D247F3D1EA7536), UINT64_C(0x04FC0B4DD24D2A59),
    +		UINT64_C(0x3886B22086258B5E), UINT64_C(0x8BA8FE9E8582D431),
    +		UINT64_C(0xCC0284772E652B05), UINT64_C(0x7F2CC8C92DC2746A),
    +		UINT64_C(0x325B15E575E1C3D0), UINT64_C(0x8175595B76469CBF),
    +		UINT64_C(0xC6DF23B2DDA1638B), UINT64_C(0x75F16F0CDE063CE4),
    +		UINT64_C(0x498BD6618A6E9DE3), UINT64_C(0xFAA59ADF89C9C28C),
    +		UINT64_C(0xBD0FE036222E3DB8), UINT64_C(0x0E21AC88218962D7),
    +		UINT64_C(0xC5FA92EC8AFF7FB6), UINT64_C(0x76D4DE52895820D9),
    +		UINT64_C(0x317EA4BB22BFDFED), UINT64_C(0x8250E80521188082),
    +		UINT64_C(0xBE2A516875702185), UINT64_C(0x0D041DD676D77EEA),
    +		UINT64_C(0x4AAE673FDD3081DE), UINT64_C(0xF9802B81DE97DEB1),
    +		UINT64_C(0x4FC0B4DD24D2A599), UINT64_C(0xFCEEF8632775FAF6),
    +		UINT64_C(0xBB44828A8C9205C2), UINT64_C(0x086ACE348F355AAD),
    +		UINT64_C(0x34107759DB5DFBAA), UINT64_C(0x873E3BE7D8FAA4C5),
    +		UINT64_C(0xC094410E731D5BF1), UINT64_C(0x73BA0DB070BA049E),
    +		UINT64_C(0xB86133D4DBCC19FF), UINT64_C(0x0B4F7F6AD86B4690),
    +		UINT64_C(0x4CE50583738CB9A4), UINT64_C(0xFFCB493D702BE6CB),
    +		UINT64_C(0xC3B1F050244347CC), UINT64_C(0x709FBCEE27E418A3),
    +		UINT64_C(0x3735C6078C03E797), UINT64_C(0x841B8AB98FA4B8F8),
    +		UINT64_C(0xADDA7C5F3C4488E3), UINT64_C(0x1EF430E13FE3D78C),
    +		UINT64_C(0x595E4A08940428B8), UINT64_C(0xEA7006B697A377D7),
    +		UINT64_C(0xD60ABFDBC3CBD6D0), UINT64_C(0x6524F365C06C89BF),
    +		UINT64_C(0x228E898C6B8B768B), UINT64_C(0x91A0C532682C29E4),
    +		UINT64_C(0x5A7BFB56C35A3485), UINT64_C(0xE955B7E8C0FD6BEA),
    +		UINT64_C(0xAEFFCD016B1A94DE), UINT64_C(0x1DD181BF68BDCBB1),
    +		UINT64_C(0x21AB38D23CD56AB6), UINT64_C(0x9285746C3F7235D9),
    +		UINT64_C(0xD52F0E859495CAED), UINT64_C(0x6601423B97329582),
    +		UINT64_C(0xD041DD676D77EEAA), UINT64_C(0x636F91D96ED0B1C5),
    +		UINT64_C(0x24C5EB30C5374EF1), UINT64_C(0x97EBA78EC690119E),
    +		UINT64_C(0xAB911EE392F8B099), UINT64_C(0x18BF525D915FEFF6),
    +		UINT64_C(0x5F1528B43AB810C2), UINT64_C(0xEC3B640A391F4FAD),
    +		UINT64_C(0x27E05A6E926952CC), UINT64_C(0x94CE16D091CE0DA3),
    +		UINT64_C(0xD3646C393A29F297), UINT64_C(0x604A2087398EADF8),
    +		UINT64_C(0x5C3099EA6DE60CFF), UINT64_C(0xEF1ED5546E415390),
    +		UINT64_C(0xA8B4AFBDC5A6ACA4), UINT64_C(0x1B9AE303C601F3CB),
    +		UINT64_C(0x56ED3E2F9E224471), UINT64_C(0xE5C372919D851B1E),
    +		UINT64_C(0xA26908783662E42A), UINT64_C(0x114744C635C5BB45),
    +		UINT64_C(0x2D3DFDAB61AD1A42), UINT64_C(0x9E13B115620A452D),
    +		UINT64_C(0xD9B9CBFCC9EDBA19), UINT64_C(0x6A978742CA4AE576),
    +		UINT64_C(0xA14CB926613CF817), UINT64_C(0x1262F598629BA778),
    +		UINT64_C(0x55C88F71C97C584C), UINT64_C(0xE6E6C3CFCADB0723),
    +		UINT64_C(0xDA9C7AA29EB3A624), UINT64_C(0x69B2361C9D14F94B),
    +		UINT64_C(0x2E184CF536F3067F), UINT64_C(0x9D36004B35545910),
    +		UINT64_C(0x2B769F17CF112238), UINT64_C(0x9858D3A9CCB67D57),
    +		UINT64_C(0xDFF2A94067518263), UINT64_C(0x6CDCE5FE64F6DD0C),
    +		UINT64_C(0x50A65C93309E7C0B), UINT64_C(0xE388102D33392364),
    +		UINT64_C(0xA4226AC498DEDC50), UINT64_C(0x170C267A9B79833F),
    +		UINT64_C(0xDCD7181E300F9E5E), UINT64_C(0x6FF954A033A8C131),
    +		UINT64_C(0x28532E49984F3E05), UINT64_C(0x9B7D62F79BE8616A),
    +		UINT64_C(0xA707DB9ACF80C06D), UINT64_C(0x14299724CC279F02),
    +		UINT64_C(0x5383EDCD67C06036), UINT64_C(0xE0ADA17364673F59)
    +	}, {
    +		UINT64_C(0x0000000000000000), UINT64_C(0x54E979925CD0F10D),
    +		UINT64_C(0xA9D2F324B9A1E21A), UINT64_C(0xFD3B8AB6E5711317),
    +		UINT64_C(0xC17D4962DC4DDAB1), UINT64_C(0x959430F0809D2BBC),
    +		UINT64_C(0x68AFBA4665EC38AB), UINT64_C(0x3C46C3D4393CC9A6),
    +		UINT64_C(0x10223DEE1795ABE7), UINT64_C(0x44CB447C4B455AEA),
    +		UINT64_C(0xB9F0CECAAE3449FD), UINT64_C(0xED19B758F2E4B8F0),
    +		UINT64_C(0xD15F748CCBD87156), UINT64_C(0x85B60D1E9708805B),
    +		UINT64_C(0x788D87A87279934C), UINT64_C(0x2C64FE3A2EA96241),
    +		UINT64_C(0x20447BDC2F2B57CE), UINT64_C(0x74AD024E73FBA6C3),
    +		UINT64_C(0x899688F8968AB5D4), UINT64_C(0xDD7FF16ACA5A44D9),
    +		UINT64_C(0xE13932BEF3668D7F), UINT64_C(0xB5D04B2CAFB67C72),
    +		UINT64_C(0x48EBC19A4AC76F65), UINT64_C(0x1C02B80816179E68),
    +		UINT64_C(0x3066463238BEFC29), UINT64_C(0x648F3FA0646E0D24),
    +		UINT64_C(0x99B4B516811F1E33), UINT64_C(0xCD5DCC84DDCFEF3E),
    +		UINT64_C(0xF11B0F50E4F32698), UINT64_C(0xA5F276C2B823D795),
    +		UINT64_C(0x58C9FC745D52C482), UINT64_C(0x0C2085E60182358F),
    +		UINT64_C(0x4088F7B85E56AF9C), UINT64_C(0x14618E2A02865E91),
    +		UINT64_C(0xE95A049CE7F74D86), UINT64_C(0xBDB37D0EBB27BC8B),
    +		UINT64_C(0x81F5BEDA821B752D), UINT64_C(0xD51CC748DECB8420),
    +		UINT64_C(0x28274DFE3BBA9737), UINT64_C(0x7CCE346C676A663A),
    +		UINT64_C(0x50AACA5649C3047B), UINT64_C(0x0443B3C41513F576),
    +		UINT64_C(0xF9783972F062E661), UINT64_C(0xAD9140E0ACB2176C),
    +		UINT64_C(0x91D78334958EDECA), UINT64_C(0xC53EFAA6C95E2FC7),
    +		UINT64_C(0x380570102C2F3CD0), UINT64_C(0x6CEC098270FFCDDD),
    +		UINT64_C(0x60CC8C64717DF852), UINT64_C(0x3425F5F62DAD095F),
    +		UINT64_C(0xC91E7F40C8DC1A48), UINT64_C(0x9DF706D2940CEB45),
    +		UINT64_C(0xA1B1C506AD3022E3), UINT64_C(0xF558BC94F1E0D3EE),
    +		UINT64_C(0x086336221491C0F9), UINT64_C(0x5C8A4FB0484131F4),
    +		UINT64_C(0x70EEB18A66E853B5), UINT64_C(0x2407C8183A38A2B8),
    +		UINT64_C(0xD93C42AEDF49B1AF), UINT64_C(0x8DD53B3C839940A2),
    +		UINT64_C(0xB193F8E8BAA58904), UINT64_C(0xE57A817AE6757809),
    +		UINT64_C(0x18410BCC03046B1E), UINT64_C(0x4CA8725E5FD49A13),
    +		UINT64_C(0x8111EF70BCAD5F38), UINT64_C(0xD5F896E2E07DAE35),
    +		UINT64_C(0x28C31C54050CBD22), UINT64_C(0x7C2A65C659DC4C2F),
    +		UINT64_C(0x406CA61260E08589), UINT64_C(0x1485DF803C307484),
    +		UINT64_C(0xE9BE5536D9416793), UINT64_C(0xBD572CA48591969E),
    +		UINT64_C(0x9133D29EAB38F4DF), UINT64_C(0xC5DAAB0CF7E805D2),
    +		UINT64_C(0x38E121BA129916C5), UINT64_C(0x6C0858284E49E7C8),
    +		UINT64_C(0x504E9BFC77752E6E), UINT64_C(0x04A7E26E2BA5DF63),
    +		UINT64_C(0xF99C68D8CED4CC74), UINT64_C(0xAD75114A92043D79),
    +		UINT64_C(0xA15594AC938608F6), UINT64_C(0xF5BCED3ECF56F9FB),
    +		UINT64_C(0x088767882A27EAEC), UINT64_C(0x5C6E1E1A76F71BE1),
    +		UINT64_C(0x6028DDCE4FCBD247), UINT64_C(0x34C1A45C131B234A),
    +		UINT64_C(0xC9FA2EEAF66A305D), UINT64_C(0x9D135778AABAC150),
    +		UINT64_C(0xB177A9428413A311), UINT64_C(0xE59ED0D0D8C3521C),
    +		UINT64_C(0x18A55A663DB2410B), UINT64_C(0x4C4C23F46162B006),
    +		UINT64_C(0x700AE020585E79A0), UINT64_C(0x24E399B2048E88AD),
    +		UINT64_C(0xD9D81304E1FF9BBA), UINT64_C(0x8D316A96BD2F6AB7),
    +		UINT64_C(0xC19918C8E2FBF0A4), UINT64_C(0x9570615ABE2B01A9),
    +		UINT64_C(0x684BEBEC5B5A12BE), UINT64_C(0x3CA2927E078AE3B3),
    +		UINT64_C(0x00E451AA3EB62A15), UINT64_C(0x540D28386266DB18),
    +		UINT64_C(0xA936A28E8717C80F), UINT64_C(0xFDDFDB1CDBC73902),
    +		UINT64_C(0xD1BB2526F56E5B43), UINT64_C(0x85525CB4A9BEAA4E),
    +		UINT64_C(0x7869D6024CCFB959), UINT64_C(0x2C80AF90101F4854),
    +		UINT64_C(0x10C66C44292381F2), UINT64_C(0x442F15D675F370FF),
    +		UINT64_C(0xB9149F60908263E8), UINT64_C(0xEDFDE6F2CC5292E5),
    +		UINT64_C(0xE1DD6314CDD0A76A), UINT64_C(0xB5341A8691005667),
    +		UINT64_C(0x480F903074714570), UINT64_C(0x1CE6E9A228A1B47D),
    +		UINT64_C(0x20A02A76119D7DDB), UINT64_C(0x744953E44D4D8CD6),
    +		UINT64_C(0x8972D952A83C9FC1), UINT64_C(0xDD9BA0C0F4EC6ECC),
    +		UINT64_C(0xF1FF5EFADA450C8D), UINT64_C(0xA51627688695FD80),
    +		UINT64_C(0x582DADDE63E4EE97), UINT64_C(0x0CC4D44C3F341F9A),
    +		UINT64_C(0x308217980608D63C), UINT64_C(0x646B6E0A5AD82731),
    +		UINT64_C(0x9950E4BCBFA93426), UINT64_C(0xCDB99D2EE379C52B),
    +		UINT64_C(0x90FB71CAD654A0F5), UINT64_C(0xC41208588A8451F8),
    +		UINT64_C(0x392982EE6FF542EF), UINT64_C(0x6DC0FB7C3325B3E2),
    +		UINT64_C(0x518638A80A197A44), UINT64_C(0x056F413A56C98B49),
    +		UINT64_C(0xF854CB8CB3B8985E), UINT64_C(0xACBDB21EEF686953),
    +		UINT64_C(0x80D94C24C1C10B12), UINT64_C(0xD43035B69D11FA1F),
    +		UINT64_C(0x290BBF007860E908), UINT64_C(0x7DE2C69224B01805),
    +		UINT64_C(0x41A405461D8CD1A3), UINT64_C(0x154D7CD4415C20AE),
    +		UINT64_C(0xE876F662A42D33B9), UINT64_C(0xBC9F8FF0F8FDC2B4),
    +		UINT64_C(0xB0BF0A16F97FF73B), UINT64_C(0xE4567384A5AF0636),
    +		UINT64_C(0x196DF93240DE1521), UINT64_C(0x4D8480A01C0EE42C),
    +		UINT64_C(0x71C2437425322D8A), UINT64_C(0x252B3AE679E2DC87),
    +		UINT64_C(0xD810B0509C93CF90), UINT64_C(0x8CF9C9C2C0433E9D),
    +		UINT64_C(0xA09D37F8EEEA5CDC), UINT64_C(0xF4744E6AB23AADD1),
    +		UINT64_C(0x094FC4DC574BBEC6), UINT64_C(0x5DA6BD4E0B9B4FCB),
    +		UINT64_C(0x61E07E9A32A7866D), UINT64_C(0x350907086E777760),
    +		UINT64_C(0xC8328DBE8B066477), UINT64_C(0x9CDBF42CD7D6957A),
    +		UINT64_C(0xD073867288020F69), UINT64_C(0x849AFFE0D4D2FE64),
    +		UINT64_C(0x79A1755631A3ED73), UINT64_C(0x2D480CC46D731C7E),
    +		UINT64_C(0x110ECF10544FD5D8), UINT64_C(0x45E7B682089F24D5),
    +		UINT64_C(0xB8DC3C34EDEE37C2), UINT64_C(0xEC3545A6B13EC6CF),
    +		UINT64_C(0xC051BB9C9F97A48E), UINT64_C(0x94B8C20EC3475583),
    +		UINT64_C(0x698348B826364694), UINT64_C(0x3D6A312A7AE6B799),
    +		UINT64_C(0x012CF2FE43DA7E3F), UINT64_C(0x55C58B6C1F0A8F32),
    +		UINT64_C(0xA8FE01DAFA7B9C25), UINT64_C(0xFC177848A6AB6D28),
    +		UINT64_C(0xF037FDAEA72958A7), UINT64_C(0xA4DE843CFBF9A9AA),
    +		UINT64_C(0x59E50E8A1E88BABD), UINT64_C(0x0D0C771842584BB0),
    +		UINT64_C(0x314AB4CC7B648216), UINT64_C(0x65A3CD5E27B4731B),
    +		UINT64_C(0x989847E8C2C5600C), UINT64_C(0xCC713E7A9E159101),
    +		UINT64_C(0xE015C040B0BCF340), UINT64_C(0xB4FCB9D2EC6C024D),
    +		UINT64_C(0x49C73364091D115A), UINT64_C(0x1D2E4AF655CDE057),
    +		UINT64_C(0x216889226CF129F1), UINT64_C(0x7581F0B03021D8FC),
    +		UINT64_C(0x88BA7A06D550CBEB), UINT64_C(0xDC53039489803AE6),
    +		UINT64_C(0x11EA9EBA6AF9FFCD), UINT64_C(0x4503E72836290EC0),
    +		UINT64_C(0xB8386D9ED3581DD7), UINT64_C(0xECD1140C8F88ECDA),
    +		UINT64_C(0xD097D7D8B6B4257C), UINT64_C(0x847EAE4AEA64D471),
    +		UINT64_C(0x794524FC0F15C766), UINT64_C(0x2DAC5D6E53C5366B),
    +		UINT64_C(0x01C8A3547D6C542A), UINT64_C(0x5521DAC621BCA527),
    +		UINT64_C(0xA81A5070C4CDB630), UINT64_C(0xFCF329E2981D473D),
    +		UINT64_C(0xC0B5EA36A1218E9B), UINT64_C(0x945C93A4FDF17F96),
    +		UINT64_C(0x6967191218806C81), UINT64_C(0x3D8E608044509D8C),
    +		UINT64_C(0x31AEE56645D2A803), UINT64_C(0x65479CF41902590E),
    +		UINT64_C(0x987C1642FC734A19), UINT64_C(0xCC956FD0A0A3BB14),
    +		UINT64_C(0xF0D3AC04999F72B2), UINT64_C(0xA43AD596C54F83BF),
    +		UINT64_C(0x59015F20203E90A8), UINT64_C(0x0DE826B27CEE61A5),
    +		UINT64_C(0x218CD888524703E4), UINT64_C(0x7565A11A0E97F2E9),
    +		UINT64_C(0x885E2BACEBE6E1FE), UINT64_C(0xDCB7523EB73610F3),
    +		UINT64_C(0xE0F191EA8E0AD955), UINT64_C(0xB418E878D2DA2858),
    +		UINT64_C(0x492362CE37AB3B4F), UINT64_C(0x1DCA1B5C6B7BCA42),
    +		UINT64_C(0x5162690234AF5051), UINT64_C(0x058B1090687FA15C),
    +		UINT64_C(0xF8B09A268D0EB24B), UINT64_C(0xAC59E3B4D1DE4346),
    +		UINT64_C(0x901F2060E8E28AE0), UINT64_C(0xC4F659F2B4327BED),
    +		UINT64_C(0x39CDD344514368FA), UINT64_C(0x6D24AAD60D9399F7),
    +		UINT64_C(0x414054EC233AFBB6), UINT64_C(0x15A92D7E7FEA0ABB),
    +		UINT64_C(0xE892A7C89A9B19AC), UINT64_C(0xBC7BDE5AC64BE8A1),
    +		UINT64_C(0x803D1D8EFF772107), UINT64_C(0xD4D4641CA3A7D00A),
    +		UINT64_C(0x29EFEEAA46D6C31D), UINT64_C(0x7D0697381A063210),
    +		UINT64_C(0x712612DE1B84079F), UINT64_C(0x25CF6B4C4754F692),
    +		UINT64_C(0xD8F4E1FAA225E585), UINT64_C(0x8C1D9868FEF51488),
    +		UINT64_C(0xB05B5BBCC7C9DD2E), UINT64_C(0xE4B2222E9B192C23),
    +		UINT64_C(0x1989A8987E683F34), UINT64_C(0x4D60D10A22B8CE39),
    +		UINT64_C(0x61042F300C11AC78), UINT64_C(0x35ED56A250C15D75),
    +		UINT64_C(0xC8D6DC14B5B04E62), UINT64_C(0x9C3FA586E960BF6F),
    +		UINT64_C(0xA0796652D05C76C9), UINT64_C(0xF4901FC08C8C87C4),
    +		UINT64_C(0x09AB957669FD94D3), UINT64_C(0x5D42ECE4352D65DE)
    +	}, {
    +		UINT64_C(0x0000000000000000), UINT64_C(0x3F0BE14A916A6DCB),
    +		UINT64_C(0x7E17C29522D4DB96), UINT64_C(0x411C23DFB3BEB65D),
    +		UINT64_C(0xFC2F852A45A9B72C), UINT64_C(0xC3246460D4C3DAE7),
    +		UINT64_C(0x823847BF677D6CBA), UINT64_C(0xBD33A6F5F6170171),
    +		UINT64_C(0x6A87A57F245D70DD), UINT64_C(0x558C4435B5371D16),
    +		UINT64_C(0x149067EA0689AB4B), UINT64_C(0x2B9B86A097E3C680),
    +		UINT64_C(0x96A8205561F4C7F1), UINT64_C(0xA9A3C11FF09EAA3A),
    +		UINT64_C(0xE8BFE2C043201C67), UINT64_C(0xD7B4038AD24A71AC),
    +		UINT64_C(0xD50F4AFE48BAE1BA), UINT64_C(0xEA04ABB4D9D08C71),
    +		UINT64_C(0xAB18886B6A6E3A2C), UINT64_C(0x94136921FB0457E7),
    +		UINT64_C(0x2920CFD40D135696), UINT64_C(0x162B2E9E9C793B5D),
    +		UINT64_C(0x57370D412FC78D00), UINT64_C(0x683CEC0BBEADE0CB),
    +		UINT64_C(0xBF88EF816CE79167), UINT64_C(0x80830ECBFD8DFCAC),
    +		UINT64_C(0xC19F2D144E334AF1), UINT64_C(0xFE94CC5EDF59273A),
    +		UINT64_C(0x43A76AAB294E264B), UINT64_C(0x7CAC8BE1B8244B80),
    +		UINT64_C(0x3DB0A83E0B9AFDDD), UINT64_C(0x02BB49749AF09016),
    +		UINT64_C(0x38C63AD73E7BDDF1), UINT64_C(0x07CDDB9DAF11B03A),
    +		UINT64_C(0x46D1F8421CAF0667), UINT64_C(0x79DA19088DC56BAC),
    +		UINT64_C(0xC4E9BFFD7BD26ADD), UINT64_C(0xFBE25EB7EAB80716),
    +		UINT64_C(0xBAFE7D685906B14B), UINT64_C(0x85F59C22C86CDC80),
    +		UINT64_C(0x52419FA81A26AD2C), UINT64_C(0x6D4A7EE28B4CC0E7),
    +		UINT64_C(0x2C565D3D38F276BA), UINT64_C(0x135DBC77A9981B71),
    +		UINT64_C(0xAE6E1A825F8F1A00), UINT64_C(0x9165FBC8CEE577CB),
    +		UINT64_C(0xD079D8177D5BC196), UINT64_C(0xEF72395DEC31AC5D),
    +		UINT64_C(0xEDC9702976C13C4B), UINT64_C(0xD2C29163E7AB5180),
    +		UINT64_C(0x93DEB2BC5415E7DD), UINT64_C(0xACD553F6C57F8A16),
    +		UINT64_C(0x11E6F50333688B67), UINT64_C(0x2EED1449A202E6AC),
    +		UINT64_C(0x6FF1379611BC50F1), UINT64_C(0x50FAD6DC80D63D3A),
    +		UINT64_C(0x874ED556529C4C96), UINT64_C(0xB845341CC3F6215D),
    +		UINT64_C(0xF95917C370489700), UINT64_C(0xC652F689E122FACB),
    +		UINT64_C(0x7B61507C1735FBBA), UINT64_C(0x446AB136865F9671),
    +		UINT64_C(0x057692E935E1202C), UINT64_C(0x3A7D73A3A48B4DE7),
    +		UINT64_C(0x718C75AE7CF7BBE2), UINT64_C(0x4E8794E4ED9DD629),
    +		UINT64_C(0x0F9BB73B5E236074), UINT64_C(0x30905671CF490DBF),
    +		UINT64_C(0x8DA3F084395E0CCE), UINT64_C(0xB2A811CEA8346105),
    +		UINT64_C(0xF3B432111B8AD758), UINT64_C(0xCCBFD35B8AE0BA93),
    +		UINT64_C(0x1B0BD0D158AACB3F), UINT64_C(0x2400319BC9C0A6F4),
    +		UINT64_C(0x651C12447A7E10A9), UINT64_C(0x5A17F30EEB147D62),
    +		UINT64_C(0xE72455FB1D037C13), UINT64_C(0xD82FB4B18C6911D8),
    +		UINT64_C(0x9933976E3FD7A785), UINT64_C(0xA6387624AEBDCA4E),
    +		UINT64_C(0xA4833F50344D5A58), UINT64_C(0x9B88DE1AA5273793),
    +		UINT64_C(0xDA94FDC5169981CE), UINT64_C(0xE59F1C8F87F3EC05),
    +		UINT64_C(0x58ACBA7A71E4ED74), UINT64_C(0x67A75B30E08E80BF),
    +		UINT64_C(0x26BB78EF533036E2), UINT64_C(0x19B099A5C25A5B29),
    +		UINT64_C(0xCE049A2F10102A85), UINT64_C(0xF10F7B65817A474E),
    +		UINT64_C(0xB01358BA32C4F113), UINT64_C(0x8F18B9F0A3AE9CD8),
    +		UINT64_C(0x322B1F0555B99DA9), UINT64_C(0x0D20FE4FC4D3F062),
    +		UINT64_C(0x4C3CDD90776D463F), UINT64_C(0x73373CDAE6072BF4),
    +		UINT64_C(0x494A4F79428C6613), UINT64_C(0x7641AE33D3E60BD8),
    +		UINT64_C(0x375D8DEC6058BD85), UINT64_C(0x08566CA6F132D04E),
    +		UINT64_C(0xB565CA530725D13F), UINT64_C(0x8A6E2B19964FBCF4),
    +		UINT64_C(0xCB7208C625F10AA9), UINT64_C(0xF479E98CB49B6762),
    +		UINT64_C(0x23CDEA0666D116CE), UINT64_C(0x1CC60B4CF7BB7B05),
    +		UINT64_C(0x5DDA28934405CD58), UINT64_C(0x62D1C9D9D56FA093),
    +		UINT64_C(0xDFE26F2C2378A1E2), UINT64_C(0xE0E98E66B212CC29),
    +		UINT64_C(0xA1F5ADB901AC7A74), UINT64_C(0x9EFE4CF390C617BF),
    +		UINT64_C(0x9C4505870A3687A9), UINT64_C(0xA34EE4CD9B5CEA62),
    +		UINT64_C(0xE252C71228E25C3F), UINT64_C(0xDD592658B98831F4),
    +		UINT64_C(0x606A80AD4F9F3085), UINT64_C(0x5F6161E7DEF55D4E),
    +		UINT64_C(0x1E7D42386D4BEB13), UINT64_C(0x2176A372FC2186D8),
    +		UINT64_C(0xF6C2A0F82E6BF774), UINT64_C(0xC9C941B2BF019ABF),
    +		UINT64_C(0x88D5626D0CBF2CE2), UINT64_C(0xB7DE83279DD54129),
    +		UINT64_C(0x0AED25D26BC24058), UINT64_C(0x35E6C498FAA82D93),
    +		UINT64_C(0x74FAE74749169BCE), UINT64_C(0x4BF1060DD87CF605),
    +		UINT64_C(0xE318EB5CF9EF77C4), UINT64_C(0xDC130A1668851A0F),
    +		UINT64_C(0x9D0F29C9DB3BAC52), UINT64_C(0xA204C8834A51C199),
    +		UINT64_C(0x1F376E76BC46C0E8), UINT64_C(0x203C8F3C2D2CAD23),
    +		UINT64_C(0x6120ACE39E921B7E), UINT64_C(0x5E2B4DA90FF876B5),
    +		UINT64_C(0x899F4E23DDB20719), UINT64_C(0xB694AF694CD86AD2),
    +		UINT64_C(0xF7888CB6FF66DC8F), UINT64_C(0xC8836DFC6E0CB144),
    +		UINT64_C(0x75B0CB09981BB035), UINT64_C(0x4ABB2A430971DDFE),
    +		UINT64_C(0x0BA7099CBACF6BA3), UINT64_C(0x34ACE8D62BA50668),
    +		UINT64_C(0x3617A1A2B155967E), UINT64_C(0x091C40E8203FFBB5),
    +		UINT64_C(0x4800633793814DE8), UINT64_C(0x770B827D02EB2023),
    +		UINT64_C(0xCA382488F4FC2152), UINT64_C(0xF533C5C265964C99),
    +		UINT64_C(0xB42FE61DD628FAC4), UINT64_C(0x8B2407574742970F),
    +		UINT64_C(0x5C9004DD9508E6A3), UINT64_C(0x639BE59704628B68),
    +		UINT64_C(0x2287C648B7DC3D35), UINT64_C(0x1D8C270226B650FE),
    +		UINT64_C(0xA0BF81F7D0A1518F), UINT64_C(0x9FB460BD41CB3C44),
    +		UINT64_C(0xDEA84362F2758A19), UINT64_C(0xE1A3A228631FE7D2),
    +		UINT64_C(0xDBDED18BC794AA35), UINT64_C(0xE4D530C156FEC7FE),
    +		UINT64_C(0xA5C9131EE54071A3), UINT64_C(0x9AC2F254742A1C68),
    +		UINT64_C(0x27F154A1823D1D19), UINT64_C(0x18FAB5EB135770D2),
    +		UINT64_C(0x59E69634A0E9C68F), UINT64_C(0x66ED777E3183AB44),
    +		UINT64_C(0xB15974F4E3C9DAE8), UINT64_C(0x8E5295BE72A3B723),
    +		UINT64_C(0xCF4EB661C11D017E), UINT64_C(0xF045572B50776CB5),
    +		UINT64_C(0x4D76F1DEA6606DC4), UINT64_C(0x727D1094370A000F),
    +		UINT64_C(0x3361334B84B4B652), UINT64_C(0x0C6AD20115DEDB99),
    +		UINT64_C(0x0ED19B758F2E4B8F), UINT64_C(0x31DA7A3F1E442644),
    +		UINT64_C(0x70C659E0ADFA9019), UINT64_C(0x4FCDB8AA3C90FDD2),
    +		UINT64_C(0xF2FE1E5FCA87FCA3), UINT64_C(0xCDF5FF155BED9168),
    +		UINT64_C(0x8CE9DCCAE8532735), UINT64_C(0xB3E23D8079394AFE),
    +		UINT64_C(0x64563E0AAB733B52), UINT64_C(0x5B5DDF403A195699),
    +		UINT64_C(0x1A41FC9F89A7E0C4), UINT64_C(0x254A1DD518CD8D0F),
    +		UINT64_C(0x9879BB20EEDA8C7E), UINT64_C(0xA7725A6A7FB0E1B5),
    +		UINT64_C(0xE66E79B5CC0E57E8), UINT64_C(0xD96598FF5D643A23),
    +		UINT64_C(0x92949EF28518CC26), UINT64_C(0xAD9F7FB81472A1ED),
    +		UINT64_C(0xEC835C67A7CC17B0), UINT64_C(0xD388BD2D36A67A7B),
    +		UINT64_C(0x6EBB1BD8C0B17B0A), UINT64_C(0x51B0FA9251DB16C1),
    +		UINT64_C(0x10ACD94DE265A09C), UINT64_C(0x2FA73807730FCD57),
    +		UINT64_C(0xF8133B8DA145BCFB), UINT64_C(0xC718DAC7302FD130),
    +		UINT64_C(0x8604F9188391676D), UINT64_C(0xB90F185212FB0AA6),
    +		UINT64_C(0x043CBEA7E4EC0BD7), UINT64_C(0x3B375FED7586661C),
    +		UINT64_C(0x7A2B7C32C638D041), UINT64_C(0x45209D785752BD8A),
    +		UINT64_C(0x479BD40CCDA22D9C), UINT64_C(0x789035465CC84057),
    +		UINT64_C(0x398C1699EF76F60A), UINT64_C(0x0687F7D37E1C9BC1),
    +		UINT64_C(0xBBB45126880B9AB0), UINT64_C(0x84BFB06C1961F77B),
    +		UINT64_C(0xC5A393B3AADF4126), UINT64_C(0xFAA872F93BB52CED),
    +		UINT64_C(0x2D1C7173E9FF5D41), UINT64_C(0x121790397895308A),
    +		UINT64_C(0x530BB3E6CB2B86D7), UINT64_C(0x6C0052AC5A41EB1C),
    +		UINT64_C(0xD133F459AC56EA6D), UINT64_C(0xEE3815133D3C87A6),
    +		UINT64_C(0xAF2436CC8E8231FB), UINT64_C(0x902FD7861FE85C30),
    +		UINT64_C(0xAA52A425BB6311D7), UINT64_C(0x9559456F2A097C1C),
    +		UINT64_C(0xD44566B099B7CA41), UINT64_C(0xEB4E87FA08DDA78A),
    +		UINT64_C(0x567D210FFECAA6FB), UINT64_C(0x6976C0456FA0CB30),
    +		UINT64_C(0x286AE39ADC1E7D6D), UINT64_C(0x176102D04D7410A6),
    +		UINT64_C(0xC0D5015A9F3E610A), UINT64_C(0xFFDEE0100E540CC1),
    +		UINT64_C(0xBEC2C3CFBDEABA9C), UINT64_C(0x81C922852C80D757),
    +		UINT64_C(0x3CFA8470DA97D626), UINT64_C(0x03F1653A4BFDBBED),
    +		UINT64_C(0x42ED46E5F8430DB0), UINT64_C(0x7DE6A7AF6929607B),
    +		UINT64_C(0x7F5DEEDBF3D9F06D), UINT64_C(0x40560F9162B39DA6),
    +		UINT64_C(0x014A2C4ED10D2BFB), UINT64_C(0x3E41CD0440674630),
    +		UINT64_C(0x83726BF1B6704741), UINT64_C(0xBC798ABB271A2A8A),
    +		UINT64_C(0xFD65A96494A49CD7), UINT64_C(0xC26E482E05CEF11C),
    +		UINT64_C(0x15DA4BA4D78480B0), UINT64_C(0x2AD1AAEE46EEED7B),
    +		UINT64_C(0x6BCD8931F5505B26), UINT64_C(0x54C6687B643A36ED),
    +		UINT64_C(0xE9F5CE8E922D379C), UINT64_C(0xD6FE2FC403475A57),
    +		UINT64_C(0x97E20C1BB0F9EC0A), UINT64_C(0xA8E9ED51219381C1)
    +	}, {
    +		UINT64_C(0x0000000000000000), UINT64_C(0x1DEE8A5E222CA1DC),
    +		UINT64_C(0x3BDD14BC445943B8), UINT64_C(0x26339EE26675E264),
    +		UINT64_C(0x77BA297888B28770), UINT64_C(0x6A54A326AA9E26AC),
    +		UINT64_C(0x4C673DC4CCEBC4C8), UINT64_C(0x5189B79AEEC76514),
    +		UINT64_C(0xEF7452F111650EE0), UINT64_C(0xF29AD8AF3349AF3C),
    +		UINT64_C(0xD4A9464D553C4D58), UINT64_C(0xC947CC137710EC84),
    +		UINT64_C(0x98CE7B8999D78990), UINT64_C(0x8520F1D7BBFB284C),
    +		UINT64_C(0xA3136F35DD8ECA28), UINT64_C(0xBEFDE56BFFA26BF4),
    +		UINT64_C(0x4C300AC98DC40345), UINT64_C(0x51DE8097AFE8A299),
    +		UINT64_C(0x77ED1E75C99D40FD), UINT64_C(0x6A03942BEBB1E121),
    +		UINT64_C(0x3B8A23B105768435), UINT64_C(0x2664A9EF275A25E9),
    +		UINT64_C(0x0057370D412FC78D), UINT64_C(0x1DB9BD5363036651),
    +		UINT64_C(0xA34458389CA10DA5), UINT64_C(0xBEAAD266BE8DAC79),
    +		UINT64_C(0x98994C84D8F84E1D), UINT64_C(0x8577C6DAFAD4EFC1),
    +		UINT64_C(0xD4FE714014138AD5), UINT64_C(0xC910FB1E363F2B09),
    +		UINT64_C(0xEF2365FC504AC96D), UINT64_C(0xF2CDEFA2726668B1),
    +		UINT64_C(0x986015931B88068A), UINT64_C(0x858E9FCD39A4A756),
    +		UINT64_C(0xA3BD012F5FD14532), UINT64_C(0xBE538B717DFDE4EE),
    +		UINT64_C(0xEFDA3CEB933A81FA), UINT64_C(0xF234B6B5B1162026),
    +		UINT64_C(0xD4072857D763C242), UINT64_C(0xC9E9A209F54F639E),
    +		UINT64_C(0x771447620AED086A), UINT64_C(0x6AFACD3C28C1A9B6),
    +		UINT64_C(0x4CC953DE4EB44BD2), UINT64_C(0x5127D9806C98EA0E),
    +		UINT64_C(0x00AE6E1A825F8F1A), UINT64_C(0x1D40E444A0732EC6),
    +		UINT64_C(0x3B737AA6C606CCA2), UINT64_C(0x269DF0F8E42A6D7E),
    +		UINT64_C(0xD4501F5A964C05CF), UINT64_C(0xC9BE9504B460A413),
    +		UINT64_C(0xEF8D0BE6D2154677), UINT64_C(0xF26381B8F039E7AB),
    +		UINT64_C(0xA3EA36221EFE82BF), UINT64_C(0xBE04BC7C3CD22363),
    +		UINT64_C(0x9837229E5AA7C107), UINT64_C(0x85D9A8C0788B60DB),
    +		UINT64_C(0x3B244DAB87290B2F), UINT64_C(0x26CAC7F5A505AAF3),
    +		UINT64_C(0x00F95917C3704897), UINT64_C(0x1D17D349E15CE94B),
    +		UINT64_C(0x4C9E64D30F9B8C5F), UINT64_C(0x5170EE8D2DB72D83),
    +		UINT64_C(0x7743706F4BC2CFE7), UINT64_C(0x6AADFA3169EE6E3B),
    +		UINT64_C(0xA218840D981E1391), UINT64_C(0xBFF60E53BA32B24D),
    +		UINT64_C(0x99C590B1DC475029), UINT64_C(0x842B1AEFFE6BF1F5),
    +		UINT64_C(0xD5A2AD7510AC94E1), UINT64_C(0xC84C272B3280353D),
    +		UINT64_C(0xEE7FB9C954F5D759), UINT64_C(0xF391339776D97685),
    +		UINT64_C(0x4D6CD6FC897B1D71), UINT64_C(0x50825CA2AB57BCAD),
    +		UINT64_C(0x76B1C240CD225EC9), UINT64_C(0x6B5F481EEF0EFF15),
    +		UINT64_C(0x3AD6FF8401C99A01), UINT64_C(0x273875DA23E53BDD),
    +		UINT64_C(0x010BEB384590D9B9), UINT64_C(0x1CE5616667BC7865),
    +		UINT64_C(0xEE288EC415DA10D4), UINT64_C(0xF3C6049A37F6B108),
    +		UINT64_C(0xD5F59A785183536C), UINT64_C(0xC81B102673AFF2B0),
    +		UINT64_C(0x9992A7BC9D6897A4), UINT64_C(0x847C2DE2BF443678),
    +		UINT64_C(0xA24FB300D931D41C), UINT64_C(0xBFA1395EFB1D75C0),
    +		UINT64_C(0x015CDC3504BF1E34), UINT64_C(0x1CB2566B2693BFE8),
    +		UINT64_C(0x3A81C88940E65D8C), UINT64_C(0x276F42D762CAFC50),
    +		UINT64_C(0x76E6F54D8C0D9944), UINT64_C(0x6B087F13AE213898),
    +		UINT64_C(0x4D3BE1F1C854DAFC), UINT64_C(0x50D56BAFEA787B20),
    +		UINT64_C(0x3A78919E8396151B), UINT64_C(0x27961BC0A1BAB4C7),
    +		UINT64_C(0x01A58522C7CF56A3), UINT64_C(0x1C4B0F7CE5E3F77F),
    +		UINT64_C(0x4DC2B8E60B24926B), UINT64_C(0x502C32B8290833B7),
    +		UINT64_C(0x761FAC5A4F7DD1D3), UINT64_C(0x6BF126046D51700F),
    +		UINT64_C(0xD50CC36F92F31BFB), UINT64_C(0xC8E24931B0DFBA27),
    +		UINT64_C(0xEED1D7D3D6AA5843), UINT64_C(0xF33F5D8DF486F99F),
    +		UINT64_C(0xA2B6EA171A419C8B), UINT64_C(0xBF586049386D3D57),
    +		UINT64_C(0x996BFEAB5E18DF33), UINT64_C(0x848574F57C347EEF),
    +		UINT64_C(0x76489B570E52165E), UINT64_C(0x6BA611092C7EB782),
    +		UINT64_C(0x4D958FEB4A0B55E6), UINT64_C(0x507B05B56827F43A),
    +		UINT64_C(0x01F2B22F86E0912E), UINT64_C(0x1C1C3871A4CC30F2),
    +		UINT64_C(0x3A2FA693C2B9D296), UINT64_C(0x27C12CCDE095734A),
    +		UINT64_C(0x993CC9A61F3718BE), UINT64_C(0x84D243F83D1BB962),
    +		UINT64_C(0xA2E1DD1A5B6E5B06), UINT64_C(0xBF0F57447942FADA),
    +		UINT64_C(0xEE86E0DE97859FCE), UINT64_C(0xF3686A80B5A93E12),
    +		UINT64_C(0xD55BF462D3DCDC76), UINT64_C(0xC8B57E3CF1F07DAA),
    +		UINT64_C(0xD6E9A7309F3239A7), UINT64_C(0xCB072D6EBD1E987B),
    +		UINT64_C(0xED34B38CDB6B7A1F), UINT64_C(0xF0DA39D2F947DBC3),
    +		UINT64_C(0xA1538E481780BED7), UINT64_C(0xBCBD041635AC1F0B),
    +		UINT64_C(0x9A8E9AF453D9FD6F), UINT64_C(0x876010AA71F55CB3),
    +		UINT64_C(0x399DF5C18E573747), UINT64_C(0x24737F9FAC7B969B),
    +		UINT64_C(0x0240E17DCA0E74FF), UINT64_C(0x1FAE6B23E822D523),
    +		UINT64_C(0x4E27DCB906E5B037), UINT64_C(0x53C956E724C911EB),
    +		UINT64_C(0x75FAC80542BCF38F), UINT64_C(0x6814425B60905253),
    +		UINT64_C(0x9AD9ADF912F63AE2), UINT64_C(0x873727A730DA9B3E),
    +		UINT64_C(0xA104B94556AF795A), UINT64_C(0xBCEA331B7483D886),
    +		UINT64_C(0xED6384819A44BD92), UINT64_C(0xF08D0EDFB8681C4E),
    +		UINT64_C(0xD6BE903DDE1DFE2A), UINT64_C(0xCB501A63FC315FF6),
    +		UINT64_C(0x75ADFF0803933402), UINT64_C(0x6843755621BF95DE),
    +		UINT64_C(0x4E70EBB447CA77BA), UINT64_C(0x539E61EA65E6D666),
    +		UINT64_C(0x0217D6708B21B372), UINT64_C(0x1FF95C2EA90D12AE),
    +		UINT64_C(0x39CAC2CCCF78F0CA), UINT64_C(0x24244892ED545116),
    +		UINT64_C(0x4E89B2A384BA3F2D), UINT64_C(0x536738FDA6969EF1),
    +		UINT64_C(0x7554A61FC0E37C95), UINT64_C(0x68BA2C41E2CFDD49),
    +		UINT64_C(0x39339BDB0C08B85D), UINT64_C(0x24DD11852E241981),
    +		UINT64_C(0x02EE8F674851FBE5), UINT64_C(0x1F0005396A7D5A39),
    +		UINT64_C(0xA1FDE05295DF31CD), UINT64_C(0xBC136A0CB7F39011),
    +		UINT64_C(0x9A20F4EED1867275), UINT64_C(0x87CE7EB0F3AAD3A9),
    +		UINT64_C(0xD647C92A1D6DB6BD), UINT64_C(0xCBA943743F411761),
    +		UINT64_C(0xED9ADD965934F505), UINT64_C(0xF07457C87B1854D9),
    +		UINT64_C(0x02B9B86A097E3C68), UINT64_C(0x1F5732342B529DB4),
    +		UINT64_C(0x3964ACD64D277FD0), UINT64_C(0x248A26886F0BDE0C),
    +		UINT64_C(0x7503911281CCBB18), UINT64_C(0x68ED1B4CA3E01AC4),
    +		UINT64_C(0x4EDE85AEC595F8A0), UINT64_C(0x53300FF0E7B9597C),
    +		UINT64_C(0xEDCDEA9B181B3288), UINT64_C(0xF02360C53A379354),
    +		UINT64_C(0xD610FE275C427130), UINT64_C(0xCBFE74797E6ED0EC),
    +		UINT64_C(0x9A77C3E390A9B5F8), UINT64_C(0x879949BDB2851424),
    +		UINT64_C(0xA1AAD75FD4F0F640), UINT64_C(0xBC445D01F6DC579C),
    +		UINT64_C(0x74F1233D072C2A36), UINT64_C(0x691FA96325008BEA),
    +		UINT64_C(0x4F2C37814375698E), UINT64_C(0x52C2BDDF6159C852),
    +		UINT64_C(0x034B0A458F9EAD46), UINT64_C(0x1EA5801BADB20C9A),
    +		UINT64_C(0x38961EF9CBC7EEFE), UINT64_C(0x257894A7E9EB4F22),
    +		UINT64_C(0x9B8571CC164924D6), UINT64_C(0x866BFB923465850A),
    +		UINT64_C(0xA05865705210676E), UINT64_C(0xBDB6EF2E703CC6B2),
    +		UINT64_C(0xEC3F58B49EFBA3A6), UINT64_C(0xF1D1D2EABCD7027A),
    +		UINT64_C(0xD7E24C08DAA2E01E), UINT64_C(0xCA0CC656F88E41C2),
    +		UINT64_C(0x38C129F48AE82973), UINT64_C(0x252FA3AAA8C488AF),
    +		UINT64_C(0x031C3D48CEB16ACB), UINT64_C(0x1EF2B716EC9DCB17),
    +		UINT64_C(0x4F7B008C025AAE03), UINT64_C(0x52958AD220760FDF),
    +		UINT64_C(0x74A614304603EDBB), UINT64_C(0x69489E6E642F4C67),
    +		UINT64_C(0xD7B57B059B8D2793), UINT64_C(0xCA5BF15BB9A1864F),
    +		UINT64_C(0xEC686FB9DFD4642B), UINT64_C(0xF186E5E7FDF8C5F7),
    +		UINT64_C(0xA00F527D133FA0E3), UINT64_C(0xBDE1D8233113013F),
    +		UINT64_C(0x9BD246C15766E35B), UINT64_C(0x863CCC9F754A4287),
    +		UINT64_C(0xEC9136AE1CA42CBC), UINT64_C(0xF17FBCF03E888D60),
    +		UINT64_C(0xD74C221258FD6F04), UINT64_C(0xCAA2A84C7AD1CED8),
    +		UINT64_C(0x9B2B1FD69416ABCC), UINT64_C(0x86C59588B63A0A10),
    +		UINT64_C(0xA0F60B6AD04FE874), UINT64_C(0xBD188134F26349A8),
    +		UINT64_C(0x03E5645F0DC1225C), UINT64_C(0x1E0BEE012FED8380),
    +		UINT64_C(0x383870E3499861E4), UINT64_C(0x25D6FABD6BB4C038),
    +		UINT64_C(0x745F4D278573A52C), UINT64_C(0x69B1C779A75F04F0),
    +		UINT64_C(0x4F82599BC12AE694), UINT64_C(0x526CD3C5E3064748),
    +		UINT64_C(0xA0A13C6791602FF9), UINT64_C(0xBD4FB639B34C8E25),
    +		UINT64_C(0x9B7C28DBD5396C41), UINT64_C(0x8692A285F715CD9D),
    +		UINT64_C(0xD71B151F19D2A889), UINT64_C(0xCAF59F413BFE0955),
    +		UINT64_C(0xECC601A35D8BEB31), UINT64_C(0xF1288BFD7FA74AED),
    +		UINT64_C(0x4FD56E9680052119), UINT64_C(0x523BE4C8A22980C5),
    +		UINT64_C(0x74087A2AC45C62A1), UINT64_C(0x69E6F074E670C37D),
    +		UINT64_C(0x386F47EE08B7A669), UINT64_C(0x2581CDB02A9B07B5),
    +		UINT64_C(0x03B253524CEEE5D1), UINT64_C(0x1E5CD90C6EC2440D)
    +	}
    +};
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_tablegen.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_tablegen.c
    new file mode 100644
    index 00000000000..2035127a112
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_tablegen.c
    @@ -0,0 +1,89 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc64_tablegen.c
    +/// \brief      Generate crc64_table_le.h and crc64_table_be.h
    +///
    +/// Compiling: gcc -std=c99 -o crc64_tablegen crc64_tablegen.c
    +/// Add -DWORDS_BIGENDIAN to generate big endian table.
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include 
    +#include "../../common/tuklib_integer.h"
    +
    +
    +static uint64_t crc64_table[4][256];
    +
    +
    +extern void
    +init_crc64_table(void)
    +{
    +	static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
    +
    +	for (size_t s = 0; s < 4; ++s) {
    +		for (size_t b = 0; b < 256; ++b) {
    +			uint64_t r = s == 0 ? b : crc64_table[s - 1][b];
    +
    +			for (size_t i = 0; i < 8; ++i) {
    +				if (r & 1)
    +					r = (r >> 1) ^ poly64;
    +				else
    +					r >>= 1;
    +			}
    +
    +			crc64_table[s][b] = r;
    +		}
    +	}
    +
    +#ifdef WORDS_BIGENDIAN
    +	for (size_t s = 0; s < 4; ++s)
    +		for (size_t b = 0; b < 256; ++b)
    +			crc64_table[s][b] = byteswap64(crc64_table[s][b]);
    +#endif
    +
    +	return;
    +}
    +
    +
    +static void
    +print_crc64_table(void)
    +{
    +	// Split the SPDX string so that it won't accidentally match
    +	// when tools search for the string.
    +	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
    +		"// This file has been generated by crc64_tablegen.c.\n\n"
    +		"const uint64_t lzma_crc64_table[4][256] = {\n\t{");
    +
    +	for (size_t s = 0; s < 4; ++s) {
    +		for (size_t b = 0; b < 256; ++b) {
    +			if ((b % 2) == 0)
    +				printf("\n\t\t");
    +
    +			printf("UINT64_C(0x%016" PRIX64 ")",
    +					crc64_table[s][b]);
    +
    +			if (b != 255)
    +				printf(",%s", (b+1) % 2 == 0 ? "" : " ");
    +		}
    +
    +		if (s == 3)
    +			printf("\n\t}\n};\n");
    +		else
    +			printf("\n\t}, {");
    +	}
    +
    +	return;
    +}
    +
    +
    +int
    +main(void)
    +{
    +	init_crc64_table();
    +	print_crc64_table();
    +	return 0;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_x86.S b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_x86.S
    new file mode 100644
    index 00000000000..47f608181ea
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_x86.S
    @@ -0,0 +1,295 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +/*
    + * Speed-optimized CRC64 using slicing-by-four algorithm
    + *
    + * This uses only i386 instructions, but it is optimized for i686 and later
    + * (including e.g. Pentium II/III/IV, Athlon XP, and Core 2).
    + *
    + * Authors: Igor Pavlov (original CRC32 assembly code)
    + *          Lasse Collin (CRC64 adaptation of the modified CRC32 code)
    + *
    + * This code needs lzma_crc64_table, which can be created using the
    + * following C code:
    +
    +uint64_t lzma_crc64_table[4][256];
    +
    +void
    +init_table(void)
    +{
    +	// ECMA-182
    +	static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
    +
    +	for (size_t s = 0; s < 4; ++s) {
    +		for (size_t b = 0; b < 256; ++b) {
    +			uint64_t r = s == 0 ? b : lzma_crc64_table[s - 1][b];
    +
    +			for (size_t i = 0; i < 8; ++i) {
    +				if (r & 1)
    +					r = (r >> 1) ^ poly64;
    +				else
    +					r >>= 1;
    +			}
    +
    +			lzma_crc64_table[s][b] = r;
    +		}
    +	}
    +}
    +
    + * The prototype of the CRC64 function:
    + * extern uint64_t lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc);
    + */
    +
    +/* When Intel CET is enabled, include  in assembly code to mark
    +   Intel CET support.  */
    +#ifdef __CET__
    +# include 
    +#else
    +# define _CET_ENDBR
    +#endif
    +
    +/*
    + * On some systems, the functions need to be prefixed. The prefix is
    + * usually an underscore.
    + */
    +#ifndef __USER_LABEL_PREFIX__
    +#	define __USER_LABEL_PREFIX__
    +#endif
    +#define MAKE_SYM_CAT(prefix, sym) prefix ## sym
    +#define MAKE_SYM(prefix, sym) MAKE_SYM_CAT(prefix, sym)
    +#define LZMA_CRC64 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64)
    +#define LZMA_CRC64_TABLE MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64_table)
    +
    +/*
    + * Solaris assembler doesn't have .p2align, and Darwin uses .align
    + * differently than GNU/Linux and Solaris.
    + */
    +#if defined(__APPLE__) || defined(__MSDOS__)
    +#	define ALIGN(pow2, abs) .align pow2
    +#else
    +#	define ALIGN(pow2, abs) .align abs
    +#endif
    +
    +	.text
    +	.globl	LZMA_CRC64
    +
    +#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) \
    +		&& !defined(__MSDOS__)
    +	.type	LZMA_CRC64, @function
    +#endif
    +
    +	ALIGN(4, 16)
    +LZMA_CRC64:
    +	_CET_ENDBR
    +	/*
    +	 * Register usage:
    +	 * %eax crc LSB
    +	 * %edx crc MSB
    +	 * %esi buf
    +	 * %edi size or buf + size
    +	 * %ebx lzma_crc64_table
    +	 * %ebp Table index
    +	 * %ecx Temporary
    +	 */
    +	pushl	%ebx
    +	pushl	%esi
    +	pushl	%edi
    +	pushl	%ebp
    +	movl	0x14(%esp), %esi /* buf */
    +	movl	0x18(%esp), %edi /* size */
    +	movl	0x1C(%esp), %eax /* crc LSB */
    +	movl	0x20(%esp), %edx /* crc MSB */
    +
    +	/*
    +	 * Store the address of lzma_crc64_table to %ebx. This is needed to
    +	 * get position-independent code (PIC).
    +	 *
    +	 * The PIC macro is defined by libtool, while __PIC__ is defined
    +	 * by GCC but only on some systems. Testing for both makes it simpler
    +	 * to test this code without libtool, and keeps the code working also
    +	 * when built with libtool but using something else than GCC.
    +	 *
    +	 * I understood that libtool may define PIC on Windows even though
    +	 * the code in Windows DLLs is not PIC in sense that it is in ELF
    +	 * binaries, so we need a separate check to always use the non-PIC
    +	 * code on Windows.
    +	 */
    +#if (!defined(PIC) && !defined(__PIC__)) \
    +		|| (defined(_WIN32) || defined(__CYGWIN__))
    +	/* Not PIC */
    +	movl	$ LZMA_CRC64_TABLE, %ebx
    +#elif defined(__APPLE__)
    +	/* Mach-O */
    +	call	.L_get_pc
    +.L_pic:
    +	leal	.L_lzma_crc64_table$non_lazy_ptr-.L_pic(%ebx), %ebx
    +	movl	(%ebx), %ebx
    +#else
    +	/* ELF */
    +	call	.L_get_pc
    +	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
    +	movl	LZMA_CRC64_TABLE@GOT(%ebx), %ebx
    +#endif
    +
    +	/* Complement the initial value. */
    +	notl	%eax
    +	notl	%edx
    +
    +.L_align:
    +	/*
    +	 * Check if there is enough input to use slicing-by-four.
    +	 * We need eight bytes, because the loop pre-reads four bytes.
    +	 */
    +	cmpl	$8, %edi
    +	jb	.L_rest
    +
    +	/* Check if we have reached alignment of four bytes. */
    +	testl	$3, %esi
    +	jz	.L_slice
    +
    +	/* Calculate CRC of the next input byte. */
    +	movzbl	(%esi), %ebp
    +	incl	%esi
    +	movzbl	%al, %ecx
    +	xorl	%ecx, %ebp
    +	shrdl	$8, %edx, %eax
    +	xorl	(%ebx, %ebp, 8), %eax
    +	shrl	$8, %edx
    +	xorl	4(%ebx, %ebp, 8), %edx
    +	decl	%edi
    +	jmp	.L_align
    +
    +.L_slice:
    +	/*
    +	 * If we get here, there's at least eight bytes of aligned input
    +	 * available. Make %edi multiple of four bytes. Store the possible
    +	 * remainder over the "size" variable in the argument stack.
    +	 */
    +	movl	%edi, 0x18(%esp)
    +	andl	$-4, %edi
    +	subl	%edi, 0x18(%esp)
    +
    +	/*
    +	 * Let %edi be buf + size - 4 while running the main loop. This way
    +	 * we can compare for equality to determine when exit the loop.
    +	 */
    +	addl	%esi, %edi
    +	subl	$4, %edi
    +
    +	/* Read in the first four aligned bytes. */
    +	movl	(%esi), %ecx
    +
    +.L_loop:
    +	xorl	%eax, %ecx
    +	movzbl	%cl, %ebp
    +	movl	0x1800(%ebx, %ebp, 8), %eax
    +	xorl	%edx, %eax
    +	movl	0x1804(%ebx, %ebp, 8), %edx
    +	movzbl	%ch, %ebp
    +	xorl	0x1000(%ebx, %ebp, 8), %eax
    +	xorl	0x1004(%ebx, %ebp, 8), %edx
    +	shrl	$16, %ecx
    +	movzbl	%cl, %ebp
    +	xorl	0x0800(%ebx, %ebp, 8), %eax
    +	xorl	0x0804(%ebx, %ebp, 8), %edx
    +	movzbl	%ch, %ebp
    +	addl	$4, %esi
    +	xorl	(%ebx, %ebp, 8), %eax
    +	xorl	4(%ebx, %ebp, 8), %edx
    +
    +	/* Check for end of aligned input. */
    +	cmpl	%edi, %esi
    +
    +	/*
    +	 * Copy the next input byte to %ecx. It is slightly faster to
    +	 * read it here than at the top of the loop.
    +	 */
    +	movl	(%esi), %ecx
    +	jb	.L_loop
    +
    +	/*
    +	 * Process the remaining four bytes, which we have already
    +	 * copied to %ecx.
    +	 */
    +	xorl	%eax, %ecx
    +	movzbl	%cl, %ebp
    +	movl	0x1800(%ebx, %ebp, 8), %eax
    +	xorl	%edx, %eax
    +	movl	0x1804(%ebx, %ebp, 8), %edx
    +	movzbl	%ch, %ebp
    +	xorl	0x1000(%ebx, %ebp, 8), %eax
    +	xorl	0x1004(%ebx, %ebp, 8), %edx
    +	shrl	$16, %ecx
    +	movzbl	%cl, %ebp
    +	xorl	0x0800(%ebx, %ebp, 8), %eax
    +	xorl	0x0804(%ebx, %ebp, 8), %edx
    +	movzbl	%ch, %ebp
    +	addl	$4, %esi
    +	xorl	(%ebx, %ebp, 8), %eax
    +	xorl	4(%ebx, %ebp, 8), %edx
    +
    +	/* Copy the number of remaining bytes to %edi. */
    +	movl	0x18(%esp), %edi
    +
    +.L_rest:
    +	/* Check for end of input. */
    +	testl	%edi, %edi
    +	jz	.L_return
    +
    +	/* Calculate CRC of the next input byte. */
    +	movzbl	(%esi), %ebp
    +	incl	%esi
    +	movzbl	%al, %ecx
    +	xorl	%ecx, %ebp
    +	shrdl	$8, %edx, %eax
    +	xorl	(%ebx, %ebp, 8), %eax
    +	shrl	$8, %edx
    +	xorl	4(%ebx, %ebp, 8), %edx
    +	decl	%edi
    +	jmp	.L_rest
    +
    +.L_return:
    +	/* Complement the final value. */
    +	notl	%eax
    +	notl	%edx
    +
    +	popl	%ebp
    +	popl	%edi
    +	popl	%esi
    +	popl	%ebx
    +	ret
    +
    +#if defined(PIC) || defined(__PIC__)
    +	ALIGN(4, 16)
    +.L_get_pc:
    +	movl	(%esp), %ebx
    +	ret
    +#endif
    +
    +#if defined(__APPLE__) && (defined(PIC) || defined(__PIC__))
    +	/* Mach-O PIC */
    +	.section __IMPORT,__pointers,non_lazy_symbol_pointers
    +.L_lzma_crc64_table$non_lazy_ptr:
    +	.indirect_symbol LZMA_CRC64_TABLE
    +	.long 0
    +
    +#elif defined(_WIN32) || defined(__CYGWIN__)
    +#	ifdef DLL_EXPORT
    +	/* This is equivalent of __declspec(dllexport). */
    +	.section .drectve
    +	.ascii " -export:lzma_crc64"
    +#	endif
    +
    +#elif !defined(__MSDOS__)
    +	/* ELF */
    +	.size	LZMA_CRC64, .-LZMA_CRC64
    +#endif
    +
    +/*
    + * This is needed to support non-executable stack. It's ugly to
    + * use __FreeBSD__ and __linux__ here, but I don't know a way to detect when
    + * we are using GNU assembler.
    + */
    +#if defined(__ELF__) && (defined(__FreeBSD__) || defined(__linux__))
    +	.section	.note.GNU-stack,"",@progbits
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_common.h
    new file mode 100644
    index 00000000000..c15d4c675c8
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_common.h
    @@ -0,0 +1,137 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc_common.h
    +/// \brief      Some functions and macros for CRC32 and CRC64
    +//
    +//  Authors:    Lasse Collin
    +//              Ilya Kurdyukov
    +//              Hans Jansen
    +//              Jia Tan
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_CRC_COMMON_H
    +#define LZMA_CRC_COMMON_H
    +
    +#include "common.h"
    +
    +
    +#ifdef WORDS_BIGENDIAN
    +#	define A(x) ((x) >> 24)
    +#	define B(x) (((x) >> 16) & 0xFF)
    +#	define C(x) (((x) >> 8) & 0xFF)
    +#	define D(x) ((x) & 0xFF)
    +
    +#	define S8(x) ((x) << 8)
    +#	define S32(x) ((x) << 32)
    +
    +#else
    +#	define A(x) ((x) & 0xFF)
    +#	define B(x) (((x) >> 8) & 0xFF)
    +#	define C(x) (((x) >> 16) & 0xFF)
    +#	define D(x) ((x) >> 24)
    +
    +#	define S8(x) ((x) >> 8)
    +#	define S32(x) ((x) >> 32)
    +#endif
    +
    +
    +// CRC CLMUL code needs this because accessing input buffers that aren't
    +// aligned to the vector size will inherently trip the address sanitizer.
    +#if lzma_has_attribute(__no_sanitize_address__)
    +#	define crc_attr_no_sanitize_address \
    +			__attribute__((__no_sanitize_address__))
    +#else
    +#	define crc_attr_no_sanitize_address
    +#endif
    +
    +// Keep this in sync with changes to crc32_arm64.h
    +#if defined(_WIN32) || defined(HAVE_GETAUXVAL) \
    +		|| defined(HAVE_ELF_AUX_INFO) \
    +		|| (defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME))
    +#	define ARM64_RUNTIME_DETECTION 1
    +#endif
    +
    +
    +#undef CRC32_GENERIC
    +#undef CRC64_GENERIC
    +
    +#undef CRC32_ARCH_OPTIMIZED
    +#undef CRC64_ARCH_OPTIMIZED
    +
    +// The x86 CLMUL is used for both CRC32 and CRC64.
    +#undef CRC_X86_CLMUL
    +
    +#undef CRC32_ARM64
    +#undef CRC64_ARM64_CLMUL
    +
    +#undef CRC_USE_GENERIC_FOR_SMALL_INPUTS
    +
    +// ARM64 CRC32 instruction is only useful for CRC32. Currently, only
    +// little endian is supported since we were unable to test on a big
    +// endian machine.
    +//
    +// NOTE: Keep this and the next check in sync with the macro
    +//       NO_CRC32_TABLE in crc32_table.c
    +#if defined(HAVE_ARM64_CRC32) && !defined(WORDS_BIGENDIAN)
    +	// Allow ARM64 CRC32 instruction without a runtime check if
    +	// __ARM_FEATURE_CRC32 is defined. GCC and Clang only define
    +	// this if the proper compiler options are used.
    +#	if defined(__ARM_FEATURE_CRC32)
    +#		define CRC32_ARCH_OPTIMIZED 1
    +#		define CRC32_ARM64 1
    +#	elif defined(ARM64_RUNTIME_DETECTION)
    +#		define CRC32_ARCH_OPTIMIZED 1
    +#		define CRC32_ARM64 1
    +#		define CRC32_GENERIC 1
    +#	endif
    +#endif
    +
    +#if defined(HAVE_USABLE_CLMUL)
    +// If CLMUL is allowed unconditionally in the compiler options then the
    +// generic version can be omitted. Note that this doesn't work with MSVC
    +// as I don't know how to detect the features here.
    +//
    +// NOTE: Keep this in sync with the NO_CRC32_TABLE macro in crc32_table.c
    +// and NO_CRC64_TABLE in crc64_table.c.
    +#	if (defined(__SSSE3__) && defined(__SSE4_1__) && defined(__PCLMUL__)) \
    +		|| (defined(__e2k__) && __iset__ >= 6)
    +#		define CRC32_ARCH_OPTIMIZED 1
    +#		define CRC64_ARCH_OPTIMIZED 1
    +#		define CRC_X86_CLMUL 1
    +#	else
    +#		define CRC32_GENERIC 1
    +#		define CRC64_GENERIC 1
    +#		define CRC32_ARCH_OPTIMIZED 1
    +#		define CRC64_ARCH_OPTIMIZED 1
    +#		define CRC_X86_CLMUL 1
    +
    +/*
    +		// The generic code is much faster with 1-8-byte inputs and
    +		// has similar performance up to 16 bytes  at least in
    +		// microbenchmarks (it depends on input buffer alignment
    +		// too). If both versions are built, this #define will use
    +		// the generic version for inputs up to 16 bytes and CLMUL
    +		// for bigger inputs. It saves a little in code size since
    +		// the special cases for 0-16-byte inputs will be omitted
    +		// from the CLMUL code.
    +#		define CRC_USE_GENERIC_FOR_SMALL_INPUTS 1
    +*/
    +#	endif
    +#endif
    +
    +// For CRC32 use the generic slice-by-eight implementation if no optimized
    +// version is available.
    +#if !defined(CRC32_ARCH_OPTIMIZED) && !defined(CRC32_GENERIC)
    +#	define CRC32_GENERIC 1
    +#endif
    +
    +// For CRC64 use the generic slice-by-four implementation if no optimized
    +// version is available.
    +#if !defined(CRC64_ARCH_OPTIMIZED) && !defined(CRC64_GENERIC)
    +#	define CRC64_GENERIC 1
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_x86_clmul.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_x86_clmul.h
    new file mode 100644
    index 00000000000..50306e49a72
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_x86_clmul.h
    @@ -0,0 +1,432 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       crc_x86_clmul.h
    +/// \brief      CRC32 and CRC64 implementations using CLMUL instructions.
    +///
    +/// The CRC32 and CRC64 implementations use 32/64-bit x86 SSSE3, SSE4.1, and
    +/// CLMUL instructions. This is compatible with Elbrus 2000 (E2K) too.
    +///
    +/// They were derived from
    +/// https://www.researchgate.net/publication/263424619_Fast_CRC_computation
    +/// and the public domain code from https://github.com/rawrunprotected/crc
    +/// (URLs were checked on 2023-10-14).
    +///
    +/// While this file has both CRC32 and CRC64 implementations, only one
    +/// should be built at a time to ensure that crc_simd_body() is inlined
    +/// even with compilers with which lzma_always_inline expands to plain inline.
    +/// The version to build is selected by defining BUILDING_CRC32_CLMUL or
    +/// BUILDING_CRC64_CLMUL before including this file.
    +///
    +/// FIXME: Builds for 32-bit x86 use the assembly .S files by default
    +/// unless configured with --disable-assembler. Even then the lookup table
    +/// isn't omitted in crc64_table.c since it doesn't know that assembly
    +/// code has been disabled.
    +//
    +//  Authors:    Ilya Kurdyukov
    +//              Hans Jansen
    +//              Lasse Collin
    +//              Jia Tan
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +// This file must not be included more than once.
    +#ifdef LZMA_CRC_X86_CLMUL_H
    +#	error crc_x86_clmul.h was included twice.
    +#endif
    +#define LZMA_CRC_X86_CLMUL_H
    +
    +#include 
    +
    +#if defined(_MSC_VER)
    +#	include 
    +#elif defined(HAVE_CPUID_H)
    +#	include 
    +#endif
    +
    +
    +// EDG-based compilers (Intel's classic compiler and compiler for E2K) can
    +// define __GNUC__ but the attribute must not be used with them.
    +// The new Clang-based ICX needs the attribute.
    +//
    +// NOTE: Build systems check for this too, keep them in sync with this.
    +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__EDG__)
    +#	define crc_attr_target \
    +		__attribute__((__target__("ssse3,sse4.1,pclmul")))
    +#else
    +#	define crc_attr_target
    +#endif
    +
    +
    +#define MASK_L(in, mask, r) r = _mm_shuffle_epi8(in, mask)
    +
    +#define MASK_H(in, mask, r) \
    +	r = _mm_shuffle_epi8(in, _mm_xor_si128(mask, vsign))
    +
    +#define MASK_LH(in, mask, low, high) \
    +	MASK_L(in, mask, low); \
    +	MASK_H(in, mask, high)
    +
    +
    +crc_attr_target
    +crc_attr_no_sanitize_address
    +static lzma_always_inline void
    +crc_simd_body(const uint8_t *buf, const size_t size, __m128i *v0, __m128i *v1,
    +		const __m128i vfold16, const __m128i initial_crc)
    +{
    +	// Create a vector with 8-bit values 0 to 15. This is used to
    +	// construct control masks for _mm_blendv_epi8 and _mm_shuffle_epi8.
    +	const __m128i vramp = _mm_setr_epi32(
    +			0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c);
    +
    +	// This is used to inverse the control mask of _mm_shuffle_epi8
    +	// so that bytes that wouldn't be picked with the original mask
    +	// will be picked and vice versa.
    +	const __m128i vsign = _mm_set1_epi8(-0x80);
    +
    +	// Memory addresses A to D and the distances between them:
    +	//
    +	//     A           B     C         D
    +	//     [skip_start][size][skip_end]
    +	//     [     size2      ]
    +	//
    +	// A and D are 16-byte aligned. B and C are 1-byte aligned.
    +	// skip_start and skip_end are 0-15 bytes. size is at least 1 byte.
    +	//
    +	// A = aligned_buf will initially point to this address.
    +	// B = The address pointed by the caller-supplied buf.
    +	// C = buf + size == aligned_buf + size2
    +	// D = buf + size + skip_end == aligned_buf + size2 + skip_end
    +	const size_t skip_start = (size_t)((uintptr_t)buf & 15);
    +	const size_t skip_end = (size_t)((0U - (uintptr_t)(buf + size)) & 15);
    +	const __m128i *aligned_buf = (const __m128i *)(
    +			(uintptr_t)buf & ~(uintptr_t)15);
    +
    +	// If size2 <= 16 then the whole input fits into a single 16-byte
    +	// vector. If size2 > 16 then at least two 16-byte vectors must
    +	// be processed. If size2 > 16 && size <= 16 then there is only
    +	// one 16-byte vector's worth of input but it is unaligned in memory.
    +	//
    +	// NOTE: There is no integer overflow here if the arguments
    +	// are valid. If this overflowed, buf + size would too.
    +	const size_t size2 = skip_start + size;
    +
    +	// Masks to be used with _mm_blendv_epi8 and _mm_shuffle_epi8:
    +	// The first skip_start or skip_end bytes in the vectors will have
    +	// the high bit (0x80) set. _mm_blendv_epi8 and _mm_shuffle_epi8
    +	// will produce zeros for these positions. (Bitwise-xor of these
    +	// masks with vsign will produce the opposite behavior.)
    +	const __m128i mask_start
    +			= _mm_sub_epi8(vramp, _mm_set1_epi8((char)skip_start));
    +	const __m128i mask_end
    +			= _mm_sub_epi8(vramp, _mm_set1_epi8((char)skip_end));
    +
    +	// Get the first 1-16 bytes into data0. If loading less than 16
    +	// bytes, the bytes are loaded to the high bits of the vector and
    +	// the least significant positions are filled with zeros.
    +	const __m128i data0 = _mm_blendv_epi8(_mm_load_si128(aligned_buf),
    +			_mm_setzero_si128(), mask_start);
    +	aligned_buf++;
    +
    +	__m128i v2, v3;
    +
    +#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS
    +	if (size <= 16) {
    +		// Right-shift initial_crc by 1-16 bytes based on "size"
    +		// and store the result in v1 (high bytes) and v0 (low bytes).
    +		//
    +		// NOTE: The highest 8 bytes of initial_crc are zeros so
    +		// v1 will be filled with zeros if size >= 8. The highest
    +		// 8 bytes of v1 will always become zeros.
    +		//
    +		// [      v1      ][      v0      ]
    +		//  [ initial_crc  ]                  size == 1
    +		//   [ initial_crc  ]                 size == 2
    +		//                [ initial_crc  ]    size == 15
    +		//                 [ initial_crc  ]   size == 16 (all in v0)
    +		const __m128i mask_low = _mm_add_epi8(
    +				vramp, _mm_set1_epi8((char)(size - 16)));
    +		MASK_LH(initial_crc, mask_low, *v0, *v1);
    +
    +		if (size2 <= 16) {
    +			// There are 1-16 bytes of input and it is all
    +			// in data0. Copy the input bytes to v3. If there
    +			// are fewer than 16 bytes, the low bytes in v3
    +			// will be filled with zeros. That is, the input
    +			// bytes are stored to the same position as
    +			// (part of) initial_crc is in v0.
    +			MASK_L(data0, mask_end, v3);
    +		} else {
    +			// There are 2-16 bytes of input but not all bytes
    +			// are in data0.
    +			const __m128i data1 = _mm_load_si128(aligned_buf);
    +
    +			// Collect the 2-16 input bytes from data0 and data1
    +			// to v2 and v3, and bitwise-xor them with the
    +			// low bits of initial_crc in v0. Note that the
    +			// the second xor is below this else-block as it
    +			// is shared with the other branch.
    +			MASK_H(data0, mask_end, v2);
    +			MASK_L(data1, mask_end, v3);
    +			*v0 = _mm_xor_si128(*v0, v2);
    +		}
    +
    +		*v0 = _mm_xor_si128(*v0, v3);
    +		*v1 = _mm_alignr_epi8(*v1, *v0, 8);
    +	} else
    +#endif
    +	{
    +		// There is more than 16 bytes of input.
    +		const __m128i data1 = _mm_load_si128(aligned_buf);
    +		const __m128i *end = (const __m128i*)(
    +				(const char *)aligned_buf - 16 + size2);
    +		aligned_buf++;
    +
    +		MASK_LH(initial_crc, mask_start, *v0, *v1);
    +		*v0 = _mm_xor_si128(*v0, data0);
    +		*v1 = _mm_xor_si128(*v1, data1);
    +
    +		while (aligned_buf < end) {
    +			*v1 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
    +					*v0, vfold16, 0x00));
    +			*v0 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
    +					*v0, vfold16, 0x11));
    +			*v1 = _mm_load_si128(aligned_buf++);
    +		}
    +
    +		if (aligned_buf != end) {
    +			MASK_H(*v0, mask_end, v2);
    +			MASK_L(*v0, mask_end, *v0);
    +			MASK_L(*v1, mask_end, v3);
    +			*v1 = _mm_or_si128(v2, v3);
    +		}
    +
    +		*v1 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
    +				*v0, vfold16, 0x00));
    +		*v0 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
    +				*v0, vfold16, 0x11));
    +		*v1 = _mm_srli_si128(*v0, 8);
    +	}
    +}
    +
    +
    +/////////////////////
    +// x86 CLMUL CRC32 //
    +/////////////////////
    +
    +/*
    +// These functions were used to generate the constants
    +// at the top of crc32_arch_optimized().
    +static uint64_t
    +calc_lo(uint64_t p, uint64_t a, int n)
    +{
    +	uint64_t b = 0; int i;
    +	for (i = 0; i < n; i++) {
    +		b = b >> 1 | (a & 1) << (n - 1);
    +		a = (a >> 1) ^ ((0 - (a & 1)) & p);
    +	}
    +	return b;
    +}
    +
    +// same as ~crc(&a, sizeof(a), ~0)
    +static uint64_t
    +calc_hi(uint64_t p, uint64_t a, int n)
    +{
    +	int i;
    +	for (i = 0; i < n; i++)
    +		a = (a >> 1) ^ ((0 - (a & 1)) & p);
    +	return a;
    +}
    +*/
    +
    +#ifdef BUILDING_CRC32_CLMUL
    +
    +crc_attr_target
    +crc_attr_no_sanitize_address
    +static uint32_t
    +crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)
    +{
    +#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS
    +	// The code assumes that there is at least one byte of input.
    +	if (size == 0)
    +		return crc;
    +#endif
    +
    +	// uint32_t poly = 0xedb88320;
    +	const int64_t p = 0x1db710640; // p << 1
    +	const int64_t mu = 0x1f7011641; // calc_lo(p, p, 32) << 1 | 1
    +	const int64_t k5 = 0x163cd6124; // calc_hi(p, p, 32) << 1
    +	const int64_t k4 = 0x0ccaa009e; // calc_hi(p, p, 64) << 1
    +	const int64_t k3 = 0x1751997d0; // calc_hi(p, p, 128) << 1
    +
    +	const __m128i vfold4 = _mm_set_epi64x(mu, p);
    +	const __m128i vfold8 = _mm_set_epi64x(0, k5);
    +	const __m128i vfold16 = _mm_set_epi64x(k4, k3);
    +
    +	__m128i v0, v1, v2;
    +
    +	crc_simd_body(buf, size, &v0, &v1, vfold16,
    +			_mm_cvtsi32_si128((int32_t)~crc));
    +
    +	v1 = _mm_xor_si128(
    +			_mm_clmulepi64_si128(v0, vfold16, 0x10), v1); // xxx0
    +	v2 = _mm_shuffle_epi32(v1, 0xe7); // 0xx0
    +	v0 = _mm_slli_epi64(v1, 32);  // [0]
    +	v0 = _mm_clmulepi64_si128(v0, vfold8, 0x00);
    +	v0 = _mm_xor_si128(v0, v2);   // [1] [2]
    +	v2 = _mm_clmulepi64_si128(v0, vfold4, 0x10);
    +	v2 = _mm_clmulepi64_si128(v2, vfold4, 0x00);
    +	v0 = _mm_xor_si128(v0, v2);   // [2]
    +	return ~(uint32_t)_mm_extract_epi32(v0, 2);
    +}
    +#endif // BUILDING_CRC32_CLMUL
    +
    +
    +/////////////////////
    +// x86 CLMUL CRC64 //
    +/////////////////////
    +
    +/*
    +// These functions were used to generate the constants
    +// at the top of crc64_arch_optimized().
    +static uint64_t
    +calc_lo(uint64_t poly)
    +{
    +	uint64_t a = poly;
    +	uint64_t b = 0;
    +
    +	for (unsigned i = 0; i < 64; ++i) {
    +		b = (b >> 1) | (a << 63);
    +		a = (a >> 1) ^ (a & 1 ? poly : 0);
    +	}
    +
    +	return b;
    +}
    +
    +static uint64_t
    +calc_hi(uint64_t poly, uint64_t a)
    +{
    +	for (unsigned i = 0; i < 64; ++i)
    +		a = (a >> 1) ^ (a & 1 ? poly : 0);
    +
    +	return a;
    +}
    +*/
    +
    +#ifdef BUILDING_CRC64_CLMUL
    +
    +// MSVC (VS2015 - VS2022) produces bad 32-bit x86 code from the CLMUL CRC
    +// code when optimizations are enabled (release build). According to the bug
    +// report, the ebx register is corrupted and the calculated result is wrong.
    +// Trying to workaround the problem with "__asm mov ebx, ebx" didn't help.
    +// The following pragma works and performance is still good. x86-64 builds
    +// and CRC32 CLMUL aren't affected by this problem. The problem does not
    +// happen in crc_simd_body() either (which is shared with CRC32 CLMUL anyway).
    +//
    +// NOTE: Another pragma after crc64_arch_optimized() restores
    +// the optimizations. If the #if condition here is updated,
    +// the other one must be updated too.
    +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \
    +		&& defined(_M_IX86)
    +#	pragma optimize("g", off)
    +#endif
    +
    +crc_attr_target
    +crc_attr_no_sanitize_address
    +static uint64_t
    +crc64_arch_optimized(const uint8_t *buf, size_t size, uint64_t crc)
    +{
    +#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS
    +	// The code assumes that there is at least one byte of input.
    +	if (size == 0)
    +		return crc;
    +#endif
    +
    +	// const uint64_t poly = 0xc96c5795d7870f42; // CRC polynomial
    +	const uint64_t p  = 0x92d8af2baf0e1e85; // (poly << 1) | 1
    +	const uint64_t mu = 0x9c3e466c172963d5; // (calc_lo(poly) << 1) | 1
    +	const uint64_t k2 = 0xdabe95afc7875f40; // calc_hi(poly, 1)
    +	const uint64_t k1 = 0xe05dd497ca393ae4; // calc_hi(poly, k2)
    +
    +	const __m128i vfold8 = _mm_set_epi64x((int64_t)p, (int64_t)mu);
    +	const __m128i vfold16 = _mm_set_epi64x((int64_t)k2, (int64_t)k1);
    +
    +	__m128i v0, v1, v2;
    +
    +#if defined(__i386__) || defined(_M_IX86)
    +	crc_simd_body(buf, size, &v0, &v1, vfold16,
    +			_mm_set_epi64x(0, (int64_t)~crc));
    +#else
    +	// GCC and Clang would produce good code with _mm_set_epi64x
    +	// but MSVC needs _mm_cvtsi64_si128 on x86-64.
    +	crc_simd_body(buf, size, &v0, &v1, vfold16,
    +			_mm_cvtsi64_si128((int64_t)~crc));
    +#endif
    +
    +	v1 = _mm_xor_si128(_mm_clmulepi64_si128(v0, vfold16, 0x10), v1);
    +	v0 = _mm_clmulepi64_si128(v1, vfold8, 0x00);
    +	v2 = _mm_clmulepi64_si128(v0, vfold8, 0x10);
    +	v0 = _mm_xor_si128(_mm_xor_si128(v1, _mm_slli_si128(v0, 8)), v2);
    +
    +#if defined(__i386__) || defined(_M_IX86)
    +	return ~(((uint64_t)(uint32_t)_mm_extract_epi32(v0, 3) << 32) |
    +			(uint64_t)(uint32_t)_mm_extract_epi32(v0, 2));
    +#else
    +	return ~(uint64_t)_mm_extract_epi64(v0, 1);
    +#endif
    +}
    +
    +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \
    +		&& defined(_M_IX86)
    +#	pragma optimize("", on)
    +#endif
    +
    +#endif // BUILDING_CRC64_CLMUL
    +
    +
    +// Even though this is an inline function, compile it only when needed.
    +// This way it won't appear in E2K builds at all.
    +#if defined(CRC32_GENERIC) || defined(CRC64_GENERIC)
    +// Inlining this function duplicates the function body in crc32_resolve() and
    +// crc64_resolve(), but this is acceptable because this is a tiny function.
    +static inline bool
    +is_arch_extension_supported(void)
    +{
    +	int success = 1;
    +	uint32_t r[4]; // eax, ebx, ecx, edx
    +
    +#if defined(_MSC_VER)
    +	// This needs  with MSVC. ICC has it as a built-in
    +	// on all platforms.
    +	__cpuid(r, 1);
    +#elif defined(HAVE_CPUID_H)
    +	// Compared to just using __asm__ to run CPUID, this also checks
    +	// that CPUID is supported and saves and restores ebx as that is
    +	// needed with GCC < 5 with position-independent code (PIC).
    +	success = __get_cpuid(1, &r[0], &r[1], &r[2], &r[3]);
    +#else
    +	// Just a fallback that shouldn't be needed.
    +	__asm__("cpuid\n\t"
    +			: "=a"(r[0]), "=b"(r[1]), "=c"(r[2]), "=d"(r[3])
    +			: "a"(1), "c"(0));
    +#endif
    +
    +	// Returns true if these are supported:
    +	// CLMUL (bit 1 in ecx)
    +	// SSSE3 (bit 9 in ecx)
    +	// SSE4.1 (bit 19 in ecx)
    +	const uint32_t ecx_mask = (1 << 1) | (1 << 9) | (1 << 19);
    +	return success && (r[2] & ecx_mask) == ecx_mask;
    +
    +	// Alternative methods that weren't used:
    +	//   - ICC's _may_i_use_cpu_feature: the other methods should work too.
    +	//   - GCC >= 6 / Clang / ICX __builtin_cpu_supports("pclmul")
    +	//
    +	// CPUID decoding is needed with MSVC anyway and older GCC. This keeps
    +	// the feature checks in the build system simpler too. The nice thing
    +	// about __builtin_cpu_supports would be that it generates very short
    +	// code as is it only reads a variable set at startup but a few bytes
    +	// doesn't matter here.
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/sha256.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/sha256.c
    new file mode 100644
    index 00000000000..c067a3a693f
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/sha256.c
    @@ -0,0 +1,189 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       sha256.c
    +/// \brief      SHA-256
    +//
    +//  The C code is based on the public domain SHA-256 code found from
    +//  Crypto++ Library 5.5.1 released in 2007: https://www.cryptopp.com/
    +//  A few minor tweaks have been made in liblzma.
    +//
    +//  Authors:    Wei Dai
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "check.h"
    +
    +// Rotate a uint32_t. GCC can optimize this to a rotate instruction
    +// at least on x86.
    +static inline uint32_t
    +rotr_32(uint32_t num, unsigned amount)
    +{
    +	return (num >> amount) | (num << (32 - amount));
    +}
    +
    +#define blk0(i) (W[i] = conv32be(data[i]))
    +#define blk2(i) (W[i & 15] += s1(W[(i - 2) & 15]) + W[(i - 7) & 15] \
    +		+ s0(W[(i - 15) & 15]))
    +
    +#define Ch(x, y, z) (z ^ (x & (y ^ z)))
    +#define Maj(x, y, z) ((x & (y ^ z)) + (y & z))
    +
    +#define a(i) T[(0 - i) & 7]
    +#define b(i) T[(1 - i) & 7]
    +#define c(i) T[(2 - i) & 7]
    +#define d(i) T[(3 - i) & 7]
    +#define e(i) T[(4 - i) & 7]
    +#define f(i) T[(5 - i) & 7]
    +#define g(i) T[(6 - i) & 7]
    +#define h(i) T[(7 - i) & 7]
    +
    +#define R(i, j, blk) \
    +	h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + SHA256_K[i + j] + blk; \
    +	d(i) += h(i); \
    +	h(i) += S0(a(i)) + Maj(a(i), b(i), c(i))
    +#define R0(i) R(i, 0, blk0(i))
    +#define R2(i) R(i, j, blk2(i))
    +
    +#define S0(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 9), 11), 2)
    +#define S1(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 14), 5), 6)
    +#define s0(x) (rotr_32(x ^ rotr_32(x, 11), 7) ^ (x >> 3))
    +#define s1(x) (rotr_32(x ^ rotr_32(x, 2), 17) ^ (x >> 10))
    +
    +
    +static const uint32_t SHA256_K[64] = {
    +	0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
    +	0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
    +	0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
    +	0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
    +	0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
    +	0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
    +	0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
    +	0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
    +	0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
    +	0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
    +	0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
    +	0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
    +	0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
    +	0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
    +	0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
    +	0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
    +};
    +
    +
    +static void
    +transform(uint32_t state[8], const uint32_t data[16])
    +{
    +	uint32_t W[16];
    +	uint32_t T[8];
    +
    +	// Copy state[] to working vars.
    +	memcpy(T, state, sizeof(T));
    +
    +	// The first 16 operations unrolled
    +	R0( 0); R0( 1); R0( 2); R0( 3);
    +	R0( 4); R0( 5); R0( 6); R0( 7);
    +	R0( 8); R0( 9); R0(10); R0(11);
    +	R0(12); R0(13); R0(14); R0(15);
    +
    +	// The remaining 48 operations partially unrolled
    +	for (unsigned int j = 16; j < 64; j += 16) {
    +		R2( 0); R2( 1); R2( 2); R2( 3);
    +		R2( 4); R2( 5); R2( 6); R2( 7);
    +		R2( 8); R2( 9); R2(10); R2(11);
    +		R2(12); R2(13); R2(14); R2(15);
    +	}
    +
    +	// Add the working vars back into state[].
    +	state[0] += a(0);
    +	state[1] += b(0);
    +	state[2] += c(0);
    +	state[3] += d(0);
    +	state[4] += e(0);
    +	state[5] += f(0);
    +	state[6] += g(0);
    +	state[7] += h(0);
    +}
    +
    +
    +static void
    +process(lzma_check_state *check)
    +{
    +	transform(check->state.sha256.state, check->buffer.u32);
    +	return;
    +}
    +
    +
    +extern void
    +lzma_sha256_init(lzma_check_state *check)
    +{
    +	static const uint32_t s[8] = {
    +		0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
    +		0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
    +	};
    +
    +	memcpy(check->state.sha256.state, s, sizeof(s));
    +	check->state.sha256.size = 0;
    +
    +	return;
    +}
    +
    +
    +extern void
    +lzma_sha256_update(const uint8_t *buf, size_t size, lzma_check_state *check)
    +{
    +	// Copy the input data into a properly aligned temporary buffer.
    +	// This way we can be called with arbitrarily sized buffers
    +	// (no need to be multiple of 64 bytes), and the code works also
    +	// on architectures that don't allow unaligned memory access.
    +	while (size > 0) {
    +		const size_t copy_start = check->state.sha256.size & 0x3F;
    +		size_t copy_size = 64 - copy_start;
    +		if (copy_size > size)
    +			copy_size = size;
    +
    +		memcpy(check->buffer.u8 + copy_start, buf, copy_size);
    +
    +		buf += copy_size;
    +		size -= copy_size;
    +		check->state.sha256.size += copy_size;
    +
    +		if ((check->state.sha256.size & 0x3F) == 0)
    +			process(check);
    +	}
    +
    +	return;
    +}
    +
    +
    +extern void
    +lzma_sha256_finish(lzma_check_state *check)
    +{
    +	// Add padding as described in RFC 3174 (it describes SHA-1 but
    +	// the same padding style is used for SHA-256 too).
    +	size_t pos = check->state.sha256.size & 0x3F;
    +	check->buffer.u8[pos++] = 0x80;
    +
    +	while (pos != 64 - 8) {
    +		if (pos == 64) {
    +			process(check);
    +			pos = 0;
    +		}
    +
    +		check->buffer.u8[pos++] = 0x00;
    +	}
    +
    +	// Convert the message size from bytes to bits.
    +	check->state.sha256.size *= 8;
    +
    +	check->buffer.u64[(64 - 8) / 8] = conv64be(check->state.sha256.size);
    +
    +	process(check);
    +
    +	for (size_t i = 0; i < 8; ++i)
    +		check->buffer.u32[i] = conv32be(check->state.sha256.state[i]);
    +
    +	return;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.c
    new file mode 100644
    index 00000000000..78af651578f
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.c
    @@ -0,0 +1,248 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       alone_decoder.c
    +/// \brief      Decoder for LZMA_Alone files
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "alone_decoder.h"
    +#include "lzma_decoder.h"
    +#include "lz_decoder.h"
    +
    +
    +typedef struct {
    +	lzma_next_coder next;
    +
    +	enum {
    +		SEQ_PROPERTIES,
    +		SEQ_DICTIONARY_SIZE,
    +		SEQ_UNCOMPRESSED_SIZE,
    +		SEQ_CODER_INIT,
    +		SEQ_CODE,
    +	} sequence;
    +
    +	/// If true, reject files that are unlikely to be .lzma files.
    +	/// If false, more non-.lzma files get accepted and will give
    +	/// LZMA_DATA_ERROR either immediately or after a few output bytes.
    +	bool picky;
    +
    +	/// Position in the header fields
    +	size_t pos;
    +
    +	/// Uncompressed size decoded from the header
    +	lzma_vli uncompressed_size;
    +
    +	/// Memory usage limit
    +	uint64_t memlimit;
    +
    +	/// Amount of memory actually needed (only an estimate)
    +	uint64_t memusage;
    +
    +	/// Options decoded from the header needed to initialize
    +	/// the LZMA decoder
    +	lzma_options_lzma options;
    +} lzma_alone_coder;
    +
    +
    +static lzma_ret
    +alone_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size,
    +		lzma_action action)
    +{
    +	lzma_alone_coder *coder = coder_ptr;
    +
    +	while (*out_pos < out_size
    +			&& (coder->sequence == SEQ_CODE || *in_pos < in_size))
    +	switch (coder->sequence) {
    +	case SEQ_PROPERTIES:
    +		if (lzma_lzma_lclppb_decode(&coder->options, in[*in_pos]))
    +			return LZMA_FORMAT_ERROR;
    +
    +		coder->sequence = SEQ_DICTIONARY_SIZE;
    +		++*in_pos;
    +		break;
    +
    +	case SEQ_DICTIONARY_SIZE:
    +		coder->options.dict_size
    +				|= (size_t)(in[*in_pos]) << (coder->pos * 8);
    +
    +		if (++coder->pos == 4) {
    +			if (coder->picky && coder->options.dict_size
    +					!= UINT32_MAX) {
    +				// A hack to ditch tons of false positives:
    +				// We allow only dictionary sizes that are
    +				// 2^n or 2^n + 2^(n-1). LZMA_Alone created
    +				// only files with 2^n, but accepts any
    +				// dictionary size.
    +				uint32_t d = coder->options.dict_size - 1;
    +				d |= d >> 2;
    +				d |= d >> 3;
    +				d |= d >> 4;
    +				d |= d >> 8;
    +				d |= d >> 16;
    +				++d;
    +
    +				if (d != coder->options.dict_size)
    +					return LZMA_FORMAT_ERROR;
    +			}
    +
    +			coder->pos = 0;
    +			coder->sequence = SEQ_UNCOMPRESSED_SIZE;
    +		}
    +
    +		++*in_pos;
    +		break;
    +
    +	case SEQ_UNCOMPRESSED_SIZE:
    +		coder->uncompressed_size
    +				|= (lzma_vli)(in[*in_pos]) << (coder->pos * 8);
    +		++*in_pos;
    +		if (++coder->pos < 8)
    +			break;
    +
    +		// Another hack to ditch false positives: Assume that
    +		// if the uncompressed size is known, it must be less
    +		// than 256 GiB.
    +		//
    +		// FIXME? Without picky we allow > LZMA_VLI_MAX which doesn't
    +		// really matter in this specific situation (> LZMA_VLI_MAX is
    +		// safe in the LZMA decoder) but it's somewhat weird still.
    +		if (coder->picky
    +				&& coder->uncompressed_size != LZMA_VLI_UNKNOWN
    +				&& coder->uncompressed_size
    +					>= (LZMA_VLI_C(1) << 38))
    +			return LZMA_FORMAT_ERROR;
    +
    +		// Use LZMA_FILTER_LZMA1EXT features to specify the
    +		// uncompressed size and that the end marker is allowed
    +		// even when the uncompressed size is known. Both .lzma
    +		// header and LZMA1EXT use UINT64_MAX indicate that size
    +		// is unknown.
    +		coder->options.ext_flags = LZMA_LZMA1EXT_ALLOW_EOPM;
    +		lzma_set_ext_size(coder->options, coder->uncompressed_size);
    +
    +		// Calculate the memory usage so that it is ready
    +		// for SEQ_CODER_INIT.
    +		coder->memusage = lzma_lzma_decoder_memusage(&coder->options)
    +				+ LZMA_MEMUSAGE_BASE;
    +
    +		coder->pos = 0;
    +		coder->sequence = SEQ_CODER_INIT;
    +
    +	// Fall through
    +
    +	case SEQ_CODER_INIT: {
    +		if (coder->memusage > coder->memlimit)
    +			return LZMA_MEMLIMIT_ERROR;
    +
    +		lzma_filter_info filters[2] = {
    +			{
    +				.id = LZMA_FILTER_LZMA1EXT,
    +				.init = &lzma_lzma_decoder_init,
    +				.options = &coder->options,
    +			}, {
    +				.init = NULL,
    +			}
    +		};
    +
    +		return_if_error(lzma_next_filter_init(&coder->next,
    +				allocator, filters));
    +
    +		coder->sequence = SEQ_CODE;
    +		break;
    +	}
    +
    +	case SEQ_CODE: {
    +		return coder->next.code(coder->next.coder,
    +				allocator, in, in_pos, in_size,
    +				out, out_pos, out_size, action);
    +	}
    +
    +	default:
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +alone_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_alone_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->next, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +alone_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
    +		uint64_t *old_memlimit, uint64_t new_memlimit)
    +{
    +	lzma_alone_coder *coder = coder_ptr;
    +
    +	*memusage = coder->memusage;
    +	*old_memlimit = coder->memlimit;
    +
    +	if (new_memlimit != 0) {
    +		if (new_memlimit < coder->memusage)
    +			return LZMA_MEMLIMIT_ERROR;
    +
    +		coder->memlimit = new_memlimit;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_ret
    +lzma_alone_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		uint64_t memlimit, bool picky)
    +{
    +	lzma_next_coder_init(&lzma_alone_decoder_init, next, allocator);
    +
    +	lzma_alone_coder *coder = next->coder;
    +
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &alone_decode;
    +		next->end = &alone_decoder_end;
    +		next->memconfig = &alone_decoder_memconfig;
    +		coder->next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	coder->sequence = SEQ_PROPERTIES;
    +	coder->picky = picky;
    +	coder->pos = 0;
    +	coder->options.dict_size = 0;
    +	coder->options.preset_dict = NULL;
    +	coder->options.preset_dict_size = 0;
    +	coder->uncompressed_size = 0;
    +	coder->memlimit = my_max(1, memlimit);
    +	coder->memusage = LZMA_MEMUSAGE_BASE;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit)
    +{
    +	lzma_next_strm_init(lzma_alone_decoder_init, strm, memlimit, false);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.h
    new file mode 100644
    index 00000000000..61ee24d97fe
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.h
    @@ -0,0 +1,22 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       alone_decoder.h
    +/// \brief      Decoder for LZMA_Alone files
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_ALONE_DECODER_H
    +#define LZMA_ALONE_DECODER_H
    +
    +#include "common.h"
    +
    +
    +extern lzma_ret lzma_alone_decoder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		uint64_t memlimit, bool picky);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_encoder.c
    new file mode 100644
    index 00000000000..21b039509ae
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_encoder.c
    @@ -0,0 +1,151 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       alone_encoder.c
    +/// \brief      Encoder for LZMA_Alone files
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +#include "lzma_encoder.h"
    +
    +
    +#define ALONE_HEADER_SIZE (1 + 4 + 8)
    +
    +
    +typedef struct {
    +	lzma_next_coder next;
    +
    +	enum {
    +		SEQ_HEADER,
    +		SEQ_CODE,
    +	} sequence;
    +
    +	size_t header_pos;
    +	uint8_t header[ALONE_HEADER_SIZE];
    +} lzma_alone_coder;
    +
    +
    +static lzma_ret
    +alone_encode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size,
    +		lzma_action action)
    +{
    +	lzma_alone_coder *coder = coder_ptr;
    +
    +	while (*out_pos < out_size)
    +	switch (coder->sequence) {
    +	case SEQ_HEADER:
    +		lzma_bufcpy(coder->header, &coder->header_pos,
    +				ALONE_HEADER_SIZE,
    +				out, out_pos, out_size);
    +		if (coder->header_pos < ALONE_HEADER_SIZE)
    +			return LZMA_OK;
    +
    +		coder->sequence = SEQ_CODE;
    +		break;
    +
    +	case SEQ_CODE:
    +		return coder->next.code(coder->next.coder,
    +				allocator, in, in_pos, in_size,
    +				out, out_pos, out_size, action);
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +alone_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_alone_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->next, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +alone_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_options_lzma *options)
    +{
    +	lzma_next_coder_init(&alone_encoder_init, next, allocator);
    +
    +	lzma_alone_coder *coder = next->coder;
    +
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &alone_encode;
    +		next->end = &alone_encoder_end;
    +		coder->next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	// Basic initializations
    +	coder->sequence = SEQ_HEADER;
    +	coder->header_pos = 0;
    +
    +	// Encode the header:
    +	// - Properties (1 byte)
    +	if (lzma_lzma_lclppb_encode(options, coder->header))
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// - Dictionary size (4 bytes)
    +	if (options->dict_size < LZMA_DICT_SIZE_MIN)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Round up to the next 2^n or 2^n + 2^(n - 1) depending on which
    +	// one is the next unless it is UINT32_MAX. While the header would
    +	// allow any 32-bit integer, we do this to keep the decoder of liblzma
    +	// accepting the resulting files.
    +	uint32_t d = options->dict_size - 1;
    +	d |= d >> 2;
    +	d |= d >> 3;
    +	d |= d >> 4;
    +	d |= d >> 8;
    +	d |= d >> 16;
    +	if (d != UINT32_MAX)
    +		++d;
    +
    +	write32le(coder->header + 1, d);
    +
    +	// - Uncompressed size (always unknown and using EOPM)
    +	memset(coder->header + 1 + 4, 0xFF, 8);
    +
    +	// Initialize the LZMA encoder.
    +	const lzma_filter_info filters[2] = {
    +		{
    +			.id = LZMA_FILTER_LZMA1,
    +			.init = &lzma_lzma_encoder_init,
    +			.options = (void *)(options),
    +		}, {
    +			.init = NULL,
    +		}
    +	};
    +
    +	return lzma_next_filter_init(&coder->next, allocator, filters);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_alone_encoder(lzma_stream *strm, const lzma_options_lzma *options)
    +{
    +	lzma_next_strm_init(alone_encoder_init, strm, options);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/auto_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/auto_decoder.c
    new file mode 100644
    index 00000000000..fdd520f905c
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/auto_decoder.c
    @@ -0,0 +1,205 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       auto_decoder.c
    +/// \brief      Autodetect between .xz, .lzma (LZMA_Alone), and .lz (lzip)
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "stream_decoder.h"
    +#include "alone_decoder.h"
    +#ifdef HAVE_LZIP_DECODER
    +#	include "lzip_decoder.h"
    +#endif
    +
    +
    +typedef struct {
    +	/// .xz Stream decoder, LZMA_Alone decoder, or lzip decoder
    +	lzma_next_coder next;
    +
    +	uint64_t memlimit;
    +	uint32_t flags;
    +
    +	enum {
    +		SEQ_INIT,
    +		SEQ_CODE,
    +		SEQ_FINISH,
    +	} sequence;
    +} lzma_auto_coder;
    +
    +
    +static lzma_ret
    +auto_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_auto_coder *coder = coder_ptr;
    +
    +	switch (coder->sequence) {
    +	case SEQ_INIT:
    +		if (*in_pos >= in_size)
    +			return LZMA_OK;
    +
    +		// Update the sequence now, because we want to continue from
    +		// SEQ_CODE even if we return some LZMA_*_CHECK.
    +		coder->sequence = SEQ_CODE;
    +
    +		// Detect the file format. .xz files start with 0xFD which
    +		// cannot be the first byte of .lzma (LZMA_Alone) format.
    +		// The .lz format starts with 0x4C which could be the
    +		// first byte of a .lzma file but luckily it would mean
    +		// lc/lp/pb being 4/3/1 which liblzma doesn't support because
    +		// lc + lp > 4. So using just 0x4C to detect .lz is OK here.
    +		if (in[*in_pos] == 0xFD) {
    +			return_if_error(lzma_stream_decoder_init(
    +					&coder->next, allocator,
    +					coder->memlimit, coder->flags));
    +#ifdef HAVE_LZIP_DECODER
    +		} else if (in[*in_pos] == 0x4C) {
    +			return_if_error(lzma_lzip_decoder_init(
    +					&coder->next, allocator,
    +					coder->memlimit, coder->flags));
    +#endif
    +		} else {
    +			return_if_error(lzma_alone_decoder_init(&coder->next,
    +					allocator, coder->memlimit, true));
    +
    +			// If the application wants to know about missing
    +			// integrity check or about the check in general, we
    +			// need to handle it here, because LZMA_Alone decoder
    +			// doesn't accept any flags.
    +			if (coder->flags & LZMA_TELL_NO_CHECK)
    +				return LZMA_NO_CHECK;
    +
    +			if (coder->flags & LZMA_TELL_ANY_CHECK)
    +				return LZMA_GET_CHECK;
    +		}
    +
    +	// Fall through
    +
    +	case SEQ_CODE: {
    +		const lzma_ret ret = coder->next.code(
    +				coder->next.coder, allocator,
    +				in, in_pos, in_size,
    +				out, out_pos, out_size, action);
    +		if (ret != LZMA_STREAM_END
    +				|| (coder->flags & LZMA_CONCATENATED) == 0)
    +			return ret;
    +
    +		coder->sequence = SEQ_FINISH;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_FINISH:
    +		// When LZMA_CONCATENATED was used and we were decoding
    +		// a LZMA_Alone file, we need to check that there is no
    +		// trailing garbage and wait for LZMA_FINISH.
    +		if (*in_pos < in_size)
    +			return LZMA_DATA_ERROR;
    +
    +		return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +}
    +
    +
    +static void
    +auto_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_auto_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->next, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_check
    +auto_decoder_get_check(const void *coder_ptr)
    +{
    +	const lzma_auto_coder *coder = coder_ptr;
    +
    +	// It is LZMA_Alone if get_check is NULL.
    +	return coder->next.get_check == NULL ? LZMA_CHECK_NONE
    +			: coder->next.get_check(coder->next.coder);
    +}
    +
    +
    +static lzma_ret
    +auto_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
    +		uint64_t *old_memlimit, uint64_t new_memlimit)
    +{
    +	lzma_auto_coder *coder = coder_ptr;
    +
    +	lzma_ret ret;
    +
    +	if (coder->next.memconfig != NULL) {
    +		ret = coder->next.memconfig(coder->next.coder,
    +				memusage, old_memlimit, new_memlimit);
    +		assert(*old_memlimit == coder->memlimit);
    +	} else {
    +		// No coder is configured yet. Use the base value as
    +		// the current memory usage.
    +		*memusage = LZMA_MEMUSAGE_BASE;
    +		*old_memlimit = coder->memlimit;
    +
    +		ret = LZMA_OK;
    +		if (new_memlimit != 0 && new_memlimit < *memusage)
    +			ret = LZMA_MEMLIMIT_ERROR;
    +	}
    +
    +	if (ret == LZMA_OK && new_memlimit != 0)
    +		coder->memlimit = new_memlimit;
    +
    +	return ret;
    +}
    +
    +
    +static lzma_ret
    +auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		uint64_t memlimit, uint32_t flags)
    +{
    +	lzma_next_coder_init(&auto_decoder_init, next, allocator);
    +
    +	if (flags & ~LZMA_SUPPORTED_FLAGS)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	lzma_auto_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_auto_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &auto_decode;
    +		next->end = &auto_decoder_end;
    +		next->get_check = &auto_decoder_get_check;
    +		next->memconfig = &auto_decoder_memconfig;
    +		coder->next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	coder->memlimit = my_max(1, memlimit);
    +	coder->flags = flags;
    +	coder->sequence = SEQ_INIT;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
    +{
    +	lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_decoder.c
    new file mode 100644
    index 00000000000..55566cd2f2b
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_decoder.c
    @@ -0,0 +1,79 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_buffer_decoder.c
    +/// \brief      Single-call .xz Block decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "block_decoder.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_block_buffer_decode(lzma_block *block, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	if (in_pos == NULL || (in == NULL && *in_pos != in_size)
    +			|| *in_pos > in_size || out_pos == NULL
    +			|| (out == NULL && *out_pos != out_size)
    +			|| *out_pos > out_size)
    +		return LZMA_PROG_ERROR;
    +
    +	// Initialize the Block decoder.
    +	lzma_next_coder block_decoder = LZMA_NEXT_CODER_INIT;
    +	lzma_ret ret = lzma_block_decoder_init(
    +			&block_decoder, allocator, block);
    +
    +	if (ret == LZMA_OK) {
    +		// Save the positions so that we can restore them in case
    +		// an error occurs.
    +		const size_t in_start = *in_pos;
    +		const size_t out_start = *out_pos;
    +
    +		// Do the actual decoding.
    +		ret = block_decoder.code(block_decoder.coder, allocator,
    +				in, in_pos, in_size, out, out_pos, out_size,
    +				LZMA_FINISH);
    +
    +		if (ret == LZMA_STREAM_END) {
    +			ret = LZMA_OK;
    +		} else {
    +			if (ret == LZMA_OK) {
    +				// Either the input was truncated or the
    +				// output buffer was too small.
    +				assert(*in_pos == in_size
    +						|| *out_pos == out_size);
    +
    +				// If all the input was consumed, then the
    +				// input is truncated, even if the output
    +				// buffer is also full. This is because
    +				// processing the last byte of the Block
    +				// never produces output.
    +				//
    +				// NOTE: This assumption may break when new
    +				// filters are added, if the end marker of
    +				// the filter doesn't consume at least one
    +				// complete byte.
    +				if (*in_pos == in_size)
    +					ret = LZMA_DATA_ERROR;
    +				else
    +					ret = LZMA_BUF_ERROR;
    +			}
    +
    +			// Restore the positions.
    +			*in_pos = in_start;
    +			*out_pos = out_start;
    +		}
    +	}
    +
    +	// Free the decoder memory. This needs to be done even if
    +	// initialization fails, because the internal API doesn't
    +	// require the initialization function to free its memory on error.
    +	lzma_next_end(&block_decoder, allocator);
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.c
    new file mode 100644
    index 00000000000..df3b90e8a18
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.c
    @@ -0,0 +1,354 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_buffer_encoder.c
    +/// \brief      Single-call .xz Block encoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "block_buffer_encoder.h"
    +#include "block_encoder.h"
    +#include "filter_encoder.h"
    +#include "lzma2_encoder.h"
    +#include "check.h"
    +
    +
    +/// Estimate the maximum size of the Block Header and Check fields for
    +/// a Block that uses LZMA2 uncompressed chunks. We could use
    +/// lzma_block_header_size() but this is simpler.
    +///
    +/// Block Header Size + Block Flags + Compressed Size
    +/// + Uncompressed Size + Filter Flags for LZMA2 + CRC32 + Check
    +/// and round up to the next multiple of four to take Header Padding
    +/// into account.
    +#define HEADERS_BOUND ((1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 3 + 4 \
    +		+ LZMA_CHECK_SIZE_MAX + 3) & ~3)
    +
    +
    +static uint64_t
    +lzma2_bound(uint64_t uncompressed_size)
    +{
    +	// Prevent integer overflow in overhead calculation.
    +	if (uncompressed_size > COMPRESSED_SIZE_MAX)
    +		return 0;
    +
    +	// Calculate the exact overhead of the LZMA2 headers: Round
    +	// uncompressed_size up to the next multiple of LZMA2_CHUNK_MAX,
    +	// multiply by the size of per-chunk header, and add one byte for
    +	// the end marker.
    +	const uint64_t overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1)
    +				/ LZMA2_CHUNK_MAX)
    +			* LZMA2_HEADER_UNCOMPRESSED + 1;
    +
    +	// Catch the possible integer overflow.
    +	if (COMPRESSED_SIZE_MAX - overhead < uncompressed_size)
    +		return 0;
    +
    +	return uncompressed_size + overhead;
    +}
    +
    +
    +extern uint64_t
    +lzma_block_buffer_bound64(uint64_t uncompressed_size)
    +{
    +	// If the data doesn't compress, we always use uncompressed
    +	// LZMA2 chunks.
    +	uint64_t lzma2_size = lzma2_bound(uncompressed_size);
    +	if (lzma2_size == 0)
    +		return 0;
    +
    +	// Take Block Padding into account.
    +	lzma2_size = (lzma2_size + 3) & ~UINT64_C(3);
    +
    +	// No risk of integer overflow because lzma2_bound() already takes
    +	// into account the size of the headers in the Block.
    +	return HEADERS_BOUND + lzma2_size;
    +}
    +
    +
    +extern LZMA_API(size_t)
    +lzma_block_buffer_bound(size_t uncompressed_size)
    +{
    +	uint64_t ret = lzma_block_buffer_bound64(uncompressed_size);
    +
    +#if SIZE_MAX < UINT64_MAX
    +	// Catch the possible integer overflow on 32-bit systems.
    +	if (ret > SIZE_MAX)
    +		return 0;
    +#endif
    +
    +	return ret;
    +}
    +
    +
    +static lzma_ret
    +block_encode_uncompressed(lzma_block *block, const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	// Use LZMA2 uncompressed chunks. We wouldn't need a dictionary at
    +	// all, but LZMA2 always requires a dictionary, so use the minimum
    +	// value to minimize memory usage of the decoder.
    +	lzma_options_lzma lzma2 = {
    +		.dict_size = LZMA_DICT_SIZE_MIN,
    +	};
    +
    +	lzma_filter filters[2];
    +	filters[0].id = LZMA_FILTER_LZMA2;
    +	filters[0].options = &lzma2;
    +	filters[1].id = LZMA_VLI_UNKNOWN;
    +
    +	// Set the above filter options to *block temporarily so that we can
    +	// encode the Block Header.
    +	lzma_filter *filters_orig = block->filters;
    +	block->filters = filters;
    +
    +	if (lzma_block_header_size(block) != LZMA_OK) {
    +		block->filters = filters_orig;
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	// Check that there's enough output space. The caller has already
    +	// set block->compressed_size to what lzma2_bound() has returned,
    +	// so we can reuse that value. We know that compressed_size is a
    +	// known valid VLI and header_size is a small value so their sum
    +	// will never overflow.
    +	assert(block->compressed_size == lzma2_bound(in_size));
    +	if (out_size - *out_pos
    +			< block->header_size + block->compressed_size) {
    +		block->filters = filters_orig;
    +		return LZMA_BUF_ERROR;
    +	}
    +
    +	if (lzma_block_header_encode(block, out + *out_pos) != LZMA_OK) {
    +		block->filters = filters_orig;
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	block->filters = filters_orig;
    +	*out_pos += block->header_size;
    +
    +	// Encode the data using LZMA2 uncompressed chunks.
    +	size_t in_pos = 0;
    +	uint8_t control = 0x01; // Dictionary reset
    +
    +	while (in_pos < in_size) {
    +		// Control byte: Indicate uncompressed chunk, of which
    +		// the first resets the dictionary.
    +		out[(*out_pos)++] = control;
    +		control = 0x02; // No dictionary reset
    +
    +		// Size of the uncompressed chunk
    +		const size_t copy_size
    +				= my_min(in_size - in_pos, LZMA2_CHUNK_MAX);
    +		out[(*out_pos)++] = (copy_size - 1) >> 8;
    +		out[(*out_pos)++] = (copy_size - 1) & 0xFF;
    +
    +		// The actual data
    +		assert(*out_pos + copy_size <= out_size);
    +		memcpy(out + *out_pos, in + in_pos, copy_size);
    +
    +		in_pos += copy_size;
    +		*out_pos += copy_size;
    +	}
    +
    +	// End marker
    +	out[(*out_pos)++] = 0x00;
    +	assert(*out_pos <= out_size);
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static lzma_ret
    +block_encode_normal(lzma_block *block, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	// Find out the size of the Block Header.
    +	return_if_error(lzma_block_header_size(block));
    +
    +	// Reserve space for the Block Header and skip it for now.
    +	if (out_size - *out_pos <= block->header_size)
    +		return LZMA_BUF_ERROR;
    +
    +	const size_t out_start = *out_pos;
    +	*out_pos += block->header_size;
    +
    +	// Limit out_size so that we stop encoding if the output would grow
    +	// bigger than what uncompressed Block would be.
    +	if (out_size - *out_pos > block->compressed_size)
    +		out_size = *out_pos + block->compressed_size;
    +
    +	// TODO: In many common cases this could be optimized to use
    +	// significantly less memory.
    +	lzma_next_coder raw_encoder = LZMA_NEXT_CODER_INIT;
    +	lzma_ret ret = lzma_raw_encoder_init(
    +			&raw_encoder, allocator, block->filters);
    +
    +	if (ret == LZMA_OK) {
    +		size_t in_pos = 0;
    +		ret = raw_encoder.code(raw_encoder.coder, allocator,
    +				in, &in_pos, in_size, out, out_pos, out_size,
    +				LZMA_FINISH);
    +	}
    +
    +	// NOTE: This needs to be run even if lzma_raw_encoder_init() failed.
    +	lzma_next_end(&raw_encoder, allocator);
    +
    +	if (ret == LZMA_STREAM_END) {
    +		// Compression was successful. Write the Block Header.
    +		block->compressed_size
    +				= *out_pos - (out_start + block->header_size);
    +		ret = lzma_block_header_encode(block, out + out_start);
    +		if (ret != LZMA_OK)
    +			ret = LZMA_PROG_ERROR;
    +
    +	} else if (ret == LZMA_OK) {
    +		// Output buffer became full.
    +		ret = LZMA_BUF_ERROR;
    +	}
    +
    +	// Reset *out_pos if something went wrong.
    +	if (ret != LZMA_OK)
    +		*out_pos = out_start;
    +
    +	return ret;
    +}
    +
    +
    +static lzma_ret
    +block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size,
    +		bool try_to_compress)
    +{
    +	// Validate the arguments.
    +	if (block == NULL || (in == NULL && in_size != 0) || out == NULL
    +			|| out_pos == NULL || *out_pos > out_size)
    +		return LZMA_PROG_ERROR;
    +
    +	// The contents of the structure may depend on the version so
    +	// check the version before validating the contents of *block.
    +	if (block->version > 1)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX
    +			|| (try_to_compress && block->filters == NULL))
    +		return LZMA_PROG_ERROR;
    +
    +	if (!lzma_check_is_supported(block->check))
    +		return LZMA_UNSUPPORTED_CHECK;
    +
    +	// Size of a Block has to be a multiple of four, so limit the size
    +	// here already. This way we don't need to check it again when adding
    +	// Block Padding.
    +	out_size -= (out_size - *out_pos) & 3;
    +
    +	// Get the size of the Check field.
    +	const size_t check_size = lzma_check_size(block->check);
    +	assert(check_size != UINT32_MAX);
    +
    +	// Reserve space for the Check field.
    +	if (out_size - *out_pos <= check_size)
    +		return LZMA_BUF_ERROR;
    +
    +	out_size -= check_size;
    +
    +	// Initialize block->uncompressed_size and calculate the worst-case
    +	// value for block->compressed_size.
    +	block->uncompressed_size = in_size;
    +	block->compressed_size = lzma2_bound(in_size);
    +	if (block->compressed_size == 0)
    +		return LZMA_DATA_ERROR;
    +
    +	// Do the actual compression.
    +	lzma_ret ret = LZMA_BUF_ERROR;
    +	if (try_to_compress)
    +		ret = block_encode_normal(block, allocator,
    +				in, in_size, out, out_pos, out_size);
    +
    +	if (ret != LZMA_OK) {
    +		// If the error was something else than output buffer
    +		// becoming full, return the error now.
    +		if (ret != LZMA_BUF_ERROR)
    +			return ret;
    +
    +		// The data was incompressible (at least with the options
    +		// given to us) or the output buffer was too small. Use the
    +		// uncompressed chunks of LZMA2 to wrap the data into a valid
    +		// Block. If we haven't been given enough output space, even
    +		// this may fail.
    +		return_if_error(block_encode_uncompressed(block, in, in_size,
    +				out, out_pos, out_size));
    +	}
    +
    +	assert(*out_pos <= out_size);
    +
    +	// Block Padding. No buffer overflow here, because we already adjusted
    +	// out_size so that (out_size - out_start) is a multiple of four.
    +	// Thus, if the buffer is full, the loop body can never run.
    +	for (size_t i = (size_t)(block->compressed_size); i & 3; ++i) {
    +		assert(*out_pos < out_size);
    +		out[(*out_pos)++] = 0x00;
    +	}
    +
    +	// If there's no Check field, we are done now.
    +	if (check_size > 0) {
    +		// Calculate the integrity check. We reserved space for
    +		// the Check field earlier so we don't need to check for
    +		// available output space here.
    +		lzma_check_state check;
    +		lzma_check_init(&check, block->check);
    +		lzma_check_update(&check, block->check, in, in_size);
    +		lzma_check_finish(&check, block->check);
    +
    +		memcpy(block->raw_check, check.buffer.u8, check_size);
    +		memcpy(out + *out_pos, check.buffer.u8, check_size);
    +		*out_pos += check_size;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	return block_buffer_encode(block, allocator,
    +			in, in_size, out, out_pos, out_size, true);
    +}
    +
    +
    +#ifdef HAVE_SYMBOL_VERSIONS_LINUX
    +// This is for compatibility with binaries linked against liblzma that
    +// has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
    +LZMA_SYMVER_API("lzma_block_uncomp_encode@XZ_5.2.2",
    +	lzma_ret, lzma_block_uncomp_encode_522)(lzma_block *block,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +		lzma_nothrow lzma_attr_warn_unused_result
    +		__attribute__((__alias__("lzma_block_uncomp_encode_52")));
    +
    +LZMA_SYMVER_API("lzma_block_uncomp_encode@@XZ_5.2",
    +	lzma_ret, lzma_block_uncomp_encode_52)(lzma_block *block,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +#define lzma_block_uncomp_encode lzma_block_uncomp_encode_52
    +#endif
    +extern LZMA_API(lzma_ret)
    +lzma_block_uncomp_encode(lzma_block *block,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	// It won't allocate any memory from heap so no need
    +	// for lzma_allocator.
    +	return block_buffer_encode(block, NULL,
    +			in, in_size, out, out_pos, out_size, false);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.h
    new file mode 100644
    index 00000000000..5274ac40d3a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.h
    @@ -0,0 +1,23 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_buffer_encoder.h
    +/// \brief      Single-call .xz Block encoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_BLOCK_BUFFER_ENCODER_H
    +#define LZMA_BLOCK_BUFFER_ENCODER_H
    +
    +#include "common.h"
    +
    +
    +/// uint64_t version of lzma_block_buffer_bound(). It is used by
    +/// stream_encoder_mt.c. Probably the original lzma_block_buffer_bound()
    +/// should have been 64-bit, but fixing it would break the ABI.
    +extern uint64_t lzma_block_buffer_bound64(uint64_t uncompressed_size);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.c
    new file mode 100644
    index 00000000000..2e369d316bd
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.c
    @@ -0,0 +1,288 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_decoder.c
    +/// \brief      Decodes .xz Blocks
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "block_decoder.h"
    +#include "filter_decoder.h"
    +#include "check.h"
    +
    +
    +typedef struct {
    +	enum {
    +		SEQ_CODE,
    +		SEQ_PADDING,
    +		SEQ_CHECK,
    +	} sequence;
    +
    +	/// The filters in the chain; initialized with lzma_raw_decoder_init().
    +	lzma_next_coder next;
    +
    +	/// Decoding options; we also write Compressed Size and Uncompressed
    +	/// Size back to this structure when the decoding has been finished.
    +	lzma_block *block;
    +
    +	/// Compressed Size calculated while decoding
    +	lzma_vli compressed_size;
    +
    +	/// Uncompressed Size calculated while decoding
    +	lzma_vli uncompressed_size;
    +
    +	/// Maximum allowed Compressed Size; this takes into account the
    +	/// size of the Block Header and Check fields when Compressed Size
    +	/// is unknown.
    +	lzma_vli compressed_limit;
    +
    +	/// Maximum allowed Uncompressed Size.
    +	lzma_vli uncompressed_limit;
    +
    +	/// Position when reading the Check field
    +	size_t check_pos;
    +
    +	/// Check of the uncompressed data
    +	lzma_check_state check;
    +
    +	/// True if the integrity check won't be calculated and verified.
    +	bool ignore_check;
    +} lzma_block_coder;
    +
    +
    +static inline bool
    +is_size_valid(lzma_vli size, lzma_vli reference)
    +{
    +	return reference == LZMA_VLI_UNKNOWN || reference == size;
    +}
    +
    +
    +static lzma_ret
    +block_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_block_coder *coder = coder_ptr;
    +
    +	switch (coder->sequence) {
    +	case SEQ_CODE: {
    +		const size_t in_start = *in_pos;
    +		const size_t out_start = *out_pos;
    +
    +		// Limit the amount of input and output space that we give
    +		// to the raw decoder based on the information we have
    +		// (or don't have) from Block Header.
    +		const size_t in_stop = *in_pos + (size_t)my_min(
    +			in_size - *in_pos,
    +			coder->compressed_limit - coder->compressed_size);
    +		const size_t out_stop = *out_pos + (size_t)my_min(
    +			out_size - *out_pos,
    +			coder->uncompressed_limit - coder->uncompressed_size);
    +
    +		const lzma_ret ret = coder->next.code(coder->next.coder,
    +				allocator, in, in_pos, in_stop,
    +				out, out_pos, out_stop, action);
    +
    +		const size_t in_used = *in_pos - in_start;
    +		const size_t out_used = *out_pos - out_start;
    +
    +		// Because we have limited the input and output sizes,
    +		// we know that these cannot grow too big or overflow.
    +		coder->compressed_size += in_used;
    +		coder->uncompressed_size += out_used;
    +
    +		if (ret == LZMA_OK) {
    +			const bool comp_done = coder->compressed_size
    +					== coder->block->compressed_size;
    +			const bool uncomp_done = coder->uncompressed_size
    +					== coder->block->uncompressed_size;
    +
    +			// If both input and output amounts match the sizes
    +			// in Block Header but we still got LZMA_OK instead
    +			// of LZMA_STREAM_END, the file is broken.
    +			if (comp_done && uncomp_done)
    +				return LZMA_DATA_ERROR;
    +
    +			// If the decoder has consumed all the input that it
    +			// needs but it still couldn't fill the output buffer
    +			// or return LZMA_STREAM_END, the file is broken.
    +			if (comp_done && *out_pos < out_size)
    +				return LZMA_DATA_ERROR;
    +
    +			// If the decoder has produced all the output but
    +			// it still didn't return LZMA_STREAM_END or consume
    +			// more input (for example, detecting an end of
    +			// payload marker may need more input but produce
    +			// no output) the file is broken.
    +			if (uncomp_done && *in_pos < in_size)
    +				return LZMA_DATA_ERROR;
    +		}
    +
    +		// Don't waste time updating the integrity check if it will be
    +		// ignored. Also skip it if no new output was produced. This
    +		// avoids null pointer + 0 (undefined behavior) when out == 0.
    +		if (!coder->ignore_check && out_used > 0)
    +			lzma_check_update(&coder->check, coder->block->check,
    +					out + out_start, out_used);
    +
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +
    +		// Compressed and Uncompressed Sizes are now at their final
    +		// values. Verify that they match the values given to us.
    +		if (!is_size_valid(coder->compressed_size,
    +					coder->block->compressed_size)
    +				|| !is_size_valid(coder->uncompressed_size,
    +					coder->block->uncompressed_size))
    +			return LZMA_DATA_ERROR;
    +
    +		// Copy the values into coder->block. The caller
    +		// may use this information to construct Index.
    +		coder->block->compressed_size = coder->compressed_size;
    +		coder->block->uncompressed_size = coder->uncompressed_size;
    +
    +		coder->sequence = SEQ_PADDING;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_PADDING:
    +		// Compressed Data is padded to a multiple of four bytes.
    +		while (coder->compressed_size & 3) {
    +			if (*in_pos >= in_size)
    +				return LZMA_OK;
    +
    +			// We use compressed_size here just get the Padding
    +			// right. The actual Compressed Size was stored to
    +			// coder->block already, and won't be modified by
    +			// us anymore.
    +			++coder->compressed_size;
    +
    +			if (in[(*in_pos)++] != 0x00)
    +				return LZMA_DATA_ERROR;
    +		}
    +
    +		if (coder->block->check == LZMA_CHECK_NONE)
    +			return LZMA_STREAM_END;
    +
    +		if (!coder->ignore_check)
    +			lzma_check_finish(&coder->check, coder->block->check);
    +
    +		coder->sequence = SEQ_CHECK;
    +
    +	// Fall through
    +
    +	case SEQ_CHECK: {
    +		const size_t check_size = lzma_check_size(coder->block->check);
    +		lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
    +				&coder->check_pos, check_size);
    +		if (coder->check_pos < check_size)
    +			return LZMA_OK;
    +
    +		// Validate the Check only if we support it.
    +		// coder->check.buffer may be uninitialized
    +		// when the Check ID is not supported.
    +		if (!coder->ignore_check
    +				&& lzma_check_is_supported(coder->block->check)
    +				&& memcmp(coder->block->raw_check,
    +					coder->check.buffer.u8,
    +					check_size) != 0)
    +			return LZMA_DATA_ERROR;
    +
    +		return LZMA_STREAM_END;
    +	}
    +	}
    +
    +	return LZMA_PROG_ERROR;
    +}
    +
    +
    +static void
    +block_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_block_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->next, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +extern lzma_ret
    +lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		lzma_block *block)
    +{
    +	lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
    +
    +	// Validate the options. lzma_block_unpadded_size() does that for us
    +	// except for Uncompressed Size and filters. Filters are validated
    +	// by the raw decoder.
    +	if (lzma_block_unpadded_size(block) == 0
    +			|| !lzma_vli_is_valid(block->uncompressed_size))
    +		return LZMA_PROG_ERROR;
    +
    +	// Allocate *next->coder if needed.
    +	lzma_block_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &block_decode;
    +		next->end = &block_decoder_end;
    +		coder->next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	// Basic initializations
    +	coder->sequence = SEQ_CODE;
    +	coder->block = block;
    +	coder->compressed_size = 0;
    +	coder->uncompressed_size = 0;
    +
    +	// If Compressed Size is not known, we calculate the maximum allowed
    +	// value so that encoded size of the Block (including Block Padding)
    +	// is still a valid VLI and a multiple of four.
    +	coder->compressed_limit
    +			= block->compressed_size == LZMA_VLI_UNKNOWN
    +				? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
    +					- block->header_size
    +					- lzma_check_size(block->check)
    +				: block->compressed_size;
    +
    +	// With Uncompressed Size this is simpler. If Block Header lacks
    +	// the size info, then LZMA_VLI_MAX is the maximum possible
    +	// Uncompressed Size.
    +	coder->uncompressed_limit
    +			= block->uncompressed_size == LZMA_VLI_UNKNOWN
    +				? LZMA_VLI_MAX
    +				: block->uncompressed_size;
    +
    +	// Initialize the check. It's caller's problem if the Check ID is not
    +	// supported, and the Block decoder cannot verify the Check field.
    +	// Caller can test lzma_check_is_supported(block->check).
    +	coder->check_pos = 0;
    +	lzma_check_init(&coder->check, block->check);
    +
    +	coder->ignore_check = block->version >= 1
    +			? block->ignore_check : false;
    +
    +	// Initialize the filter chain.
    +	return lzma_raw_decoder_init(&coder->next, allocator,
    +			block->filters);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_block_decoder(lzma_stream *strm, lzma_block *block)
    +{
    +	lzma_next_strm_init(lzma_block_decoder_init, strm, block);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.h
    new file mode 100644
    index 00000000000..2cbf9ba6db8
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.h
    @@ -0,0 +1,21 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_decoder.h
    +/// \brief      Decodes .xz Blocks
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_BLOCK_DECODER_H
    +#define LZMA_BLOCK_DECODER_H
    +
    +#include "common.h"
    +
    +
    +extern lzma_ret lzma_block_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator, lzma_block *block);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.c
    new file mode 100644
    index 00000000000..ce8c1de6944
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.c
    @@ -0,0 +1,226 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_encoder.c
    +/// \brief      Encodes .xz Blocks
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "block_encoder.h"
    +#include "filter_encoder.h"
    +#include "check.h"
    +
    +
    +typedef struct {
    +	/// The filters in the chain; initialized with lzma_raw_decoder_init().
    +	lzma_next_coder next;
    +
    +	/// Encoding options; we also write Unpadded Size, Compressed Size,
    +	/// and Uncompressed Size back to this structure when the encoding
    +	/// has been finished.
    +	lzma_block *block;
    +
    +	enum {
    +		SEQ_CODE,
    +		SEQ_PADDING,
    +		SEQ_CHECK,
    +	} sequence;
    +
    +	/// Compressed Size calculated while encoding
    +	lzma_vli compressed_size;
    +
    +	/// Uncompressed Size calculated while encoding
    +	lzma_vli uncompressed_size;
    +
    +	/// Position in the Check field
    +	size_t pos;
    +
    +	/// Check of the uncompressed data
    +	lzma_check_state check;
    +} lzma_block_coder;
    +
    +
    +static lzma_ret
    +block_encode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_block_coder *coder = coder_ptr;
    +
    +	// Check that our amount of input stays in proper limits.
    +	if (LZMA_VLI_MAX - coder->uncompressed_size < in_size - *in_pos)
    +		return LZMA_DATA_ERROR;
    +
    +	switch (coder->sequence) {
    +	case SEQ_CODE: {
    +		const size_t in_start = *in_pos;
    +		const size_t out_start = *out_pos;
    +
    +		const lzma_ret ret = coder->next.code(coder->next.coder,
    +				allocator, in, in_pos, in_size,
    +				out, out_pos, out_size, action);
    +
    +		const size_t in_used = *in_pos - in_start;
    +		const size_t out_used = *out_pos - out_start;
    +
    +		if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used)
    +			return LZMA_DATA_ERROR;
    +
    +		coder->compressed_size += out_used;
    +
    +		// No need to check for overflow because we have already
    +		// checked it at the beginning of this function.
    +		coder->uncompressed_size += in_used;
    +
    +		// Call lzma_check_update() only if input was consumed. This
    +		// avoids null pointer + 0 (undefined behavior) when in == 0.
    +		if (in_used > 0)
    +			lzma_check_update(&coder->check, coder->block->check,
    +					in + in_start, in_used);
    +
    +		if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
    +			return ret;
    +
    +		assert(*in_pos == in_size);
    +		assert(action == LZMA_FINISH);
    +
    +		// Copy the values into coder->block. The caller
    +		// may use this information to construct Index.
    +		coder->block->compressed_size = coder->compressed_size;
    +		coder->block->uncompressed_size = coder->uncompressed_size;
    +
    +		coder->sequence = SEQ_PADDING;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_PADDING:
    +		// Pad Compressed Data to a multiple of four bytes. We can
    +		// use coder->compressed_size for this since we don't need
    +		// it for anything else anymore.
    +		while (coder->compressed_size & 3) {
    +			if (*out_pos >= out_size)
    +				return LZMA_OK;
    +
    +			out[*out_pos] = 0x00;
    +			++*out_pos;
    +			++coder->compressed_size;
    +		}
    +
    +		if (coder->block->check == LZMA_CHECK_NONE)
    +			return LZMA_STREAM_END;
    +
    +		lzma_check_finish(&coder->check, coder->block->check);
    +
    +		coder->sequence = SEQ_CHECK;
    +
    +	// Fall through
    +
    +	case SEQ_CHECK: {
    +		const size_t check_size = lzma_check_size(coder->block->check);
    +		lzma_bufcpy(coder->check.buffer.u8, &coder->pos, check_size,
    +				out, out_pos, out_size);
    +		if (coder->pos < check_size)
    +			return LZMA_OK;
    +
    +		memcpy(coder->block->raw_check, coder->check.buffer.u8,
    +				check_size);
    +		return LZMA_STREAM_END;
    +	}
    +	}
    +
    +	return LZMA_PROG_ERROR;
    +}
    +
    +
    +static void
    +block_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_block_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->next, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +block_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
    +		const lzma_filter *filters lzma_attribute((__unused__)),
    +		const lzma_filter *reversed_filters)
    +{
    +	lzma_block_coder *coder = coder_ptr;
    +
    +	if (coder->sequence != SEQ_CODE)
    +		return LZMA_PROG_ERROR;
    +
    +	return lzma_next_filter_update(
    +			&coder->next, allocator, reversed_filters);
    +}
    +
    +
    +extern lzma_ret
    +lzma_block_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		lzma_block *block)
    +{
    +	lzma_next_coder_init(&lzma_block_encoder_init, next, allocator);
    +
    +	if (block == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	// The contents of the structure may depend on the version so
    +	// check the version first.
    +	if (block->version > 1)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// If the Check ID is not supported, we cannot calculate the check and
    +	// thus not create a proper Block.
    +	if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
    +		return LZMA_PROG_ERROR;
    +
    +	if (!lzma_check_is_supported(block->check))
    +		return LZMA_UNSUPPORTED_CHECK;
    +
    +	// Allocate and initialize *next->coder if needed.
    +	lzma_block_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &block_encode;
    +		next->end = &block_encoder_end;
    +		next->update = &block_encoder_update;
    +		coder->next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	// Basic initializations
    +	coder->sequence = SEQ_CODE;
    +	coder->block = block;
    +	coder->compressed_size = 0;
    +	coder->uncompressed_size = 0;
    +	coder->pos = 0;
    +
    +	// Initialize the check
    +	lzma_check_init(&coder->check, block->check);
    +
    +	// Initialize the requested filters.
    +	return lzma_raw_encoder_init(&coder->next, allocator, block->filters);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_block_encoder(lzma_stream *strm, lzma_block *block)
    +{
    +	lzma_next_strm_init(lzma_block_encoder_init, strm, block);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.h
    new file mode 100644
    index 00000000000..b7dfe9a0841
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.h
    @@ -0,0 +1,46 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_encoder.h
    +/// \brief      Encodes .xz Blocks
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_BLOCK_ENCODER_H
    +#define LZMA_BLOCK_ENCODER_H
    +
    +#include "common.h"
    +
    +
    +/// \brief      Biggest Compressed Size value that the Block encoder supports
    +///
    +/// The maximum size of a single Block is limited by the maximum size of
    +/// a Stream, which in theory is 2^63 - 3 bytes (i.e. LZMA_VLI_MAX - 3).
    +/// While the size is really big and no one should hit it in practice, we
    +/// take it into account in some places anyway to catch some errors e.g. if
    +/// application passes insanely big value to some function.
    +///
    +/// We could take into account the headers etc. to determine the exact
    +/// maximum size of the Compressed Data field, but the complexity would give
    +/// us nothing useful. Instead, limit the size of Compressed Data so that
    +/// even with biggest possible Block Header and Check fields the total
    +/// encoded size of the Block stays as a valid VLI. This doesn't guarantee
    +/// that the size of the Stream doesn't grow too big, but that problem is
    +/// taken care outside the Block handling code.
    +///
    +/// ~LZMA_VLI_C(3) is to guarantee that if we need padding at the end of
    +/// the Compressed Data field, it will still stay in the proper limit.
    +///
    +/// This constant is in this file because it is needed in both
    +/// block_encoder.c and block_buffer_encoder.c.
    +#define COMPRESSED_SIZE_MAX ((LZMA_VLI_MAX - LZMA_BLOCK_HEADER_SIZE_MAX \
    +		- LZMA_CHECK_SIZE_MAX) & ~LZMA_VLI_C(3))
    +
    +
    +extern lzma_ret lzma_block_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator, lzma_block *block);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_decoder.c
    new file mode 100644
    index 00000000000..f0b2fbe54d8
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_decoder.c
    @@ -0,0 +1,114 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_header_decoder.c
    +/// \brief      Decodes Block Header from .xz files
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +#include "check.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_block_header_decode(lzma_block *block,
    +		const lzma_allocator *allocator, const uint8_t *in)
    +{
    +	// NOTE: We consider the header to be corrupt not only when the
    +	// CRC32 doesn't match, but also when variable-length integers
    +	// are invalid or over 63 bits, or if the header is too small
    +	// to contain the claimed information.
    +
    +	// Catch unexpected NULL pointers.
    +	if (block == NULL || block->filters == NULL || in == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	// Initialize the filter options array. This way the caller can
    +	// safely free() the options even if an error occurs in this function.
    +	for (size_t i = 0; i <= LZMA_FILTERS_MAX; ++i) {
    +		block->filters[i].id = LZMA_VLI_UNKNOWN;
    +		block->filters[i].options = NULL;
    +	}
    +
    +	// Versions 0 and 1 are supported. If a newer version was specified,
    +	// we need to downgrade it.
    +	if (block->version > 1)
    +		block->version = 1;
    +
    +	// This isn't a Block Header option, but since the decompressor will
    +	// read it if version >= 1, it's better to initialize it here than
    +	// to expect the caller to do it since in almost all cases this
    +	// should be false.
    +	block->ignore_check = false;
    +
    +	// Validate Block Header Size and Check type. The caller must have
    +	// already set these, so it is a programming error if this test fails.
    +	if (lzma_block_header_size_decode(in[0]) != block->header_size
    +			|| (unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
    +		return LZMA_PROG_ERROR;
    +
    +	// Exclude the CRC32 field.
    +	const size_t in_size = block->header_size - 4;
    +
    +	// Verify CRC32
    +	if (lzma_crc32(in, in_size, 0) != read32le(in + in_size)) {
    +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    +		return LZMA_DATA_ERROR;
    +#endif
    +	}
    +
    +	// Check for unsupported flags.
    +	if (in[1] & 0x3C)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Start after the Block Header Size and Block Flags fields.
    +	size_t in_pos = 2;
    +
    +	// Compressed Size
    +	if (in[1] & 0x40) {
    +		return_if_error(lzma_vli_decode(&block->compressed_size,
    +				NULL, in, &in_pos, in_size));
    +
    +		// Validate Compressed Size. This checks that it isn't zero
    +		// and that the total size of the Block is a valid VLI.
    +		if (lzma_block_unpadded_size(block) == 0)
    +			return LZMA_DATA_ERROR;
    +	} else {
    +		block->compressed_size = LZMA_VLI_UNKNOWN;
    +	}
    +
    +	// Uncompressed Size
    +	if (in[1] & 0x80)
    +		return_if_error(lzma_vli_decode(&block->uncompressed_size,
    +				NULL, in, &in_pos, in_size));
    +	else
    +		block->uncompressed_size = LZMA_VLI_UNKNOWN;
    +
    +	// Filter Flags
    +	const size_t filter_count = (in[1] & 3U) + 1;
    +	for (size_t i = 0; i < filter_count; ++i) {
    +		const lzma_ret ret = lzma_filter_flags_decode(
    +				&block->filters[i], allocator,
    +				in, &in_pos, in_size);
    +		if (ret != LZMA_OK) {
    +			lzma_filters_free(block->filters, allocator);
    +			return ret;
    +		}
    +	}
    +
    +	// Padding
    +	while (in_pos < in_size) {
    +		if (in[in_pos++] != 0x00) {
    +			lzma_filters_free(block->filters, allocator);
    +
    +			// Possibly some new field present so use
    +			// LZMA_OPTIONS_ERROR instead of LZMA_DATA_ERROR.
    +			return LZMA_OPTIONS_ERROR;
    +		}
    +	}
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_encoder.c
    new file mode 100644
    index 00000000000..45e57a26aba
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_encoder.c
    @@ -0,0 +1,131 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_header_encoder.c
    +/// \brief      Encodes Block Header for .xz files
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +#include "check.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_block_header_size(lzma_block *block)
    +{
    +	if (block->version > 1)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Block Header Size + Block Flags + CRC32.
    +	uint32_t size = 1 + 1 + 4;
    +
    +	// Compressed Size
    +	if (block->compressed_size != LZMA_VLI_UNKNOWN) {
    +		const uint32_t add = lzma_vli_size(block->compressed_size);
    +		if (add == 0 || block->compressed_size == 0)
    +			return LZMA_PROG_ERROR;
    +
    +		size += add;
    +	}
    +
    +	// Uncompressed Size
    +	if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
    +		const uint32_t add = lzma_vli_size(block->uncompressed_size);
    +		if (add == 0)
    +			return LZMA_PROG_ERROR;
    +
    +		size += add;
    +	}
    +
    +	// List of Filter Flags
    +	if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
    +		return LZMA_PROG_ERROR;
    +
    +	for (size_t i = 0; block->filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
    +		// Don't allow too many filters.
    +		if (i == LZMA_FILTERS_MAX)
    +			return LZMA_PROG_ERROR;
    +
    +		uint32_t add;
    +		return_if_error(lzma_filter_flags_size(&add,
    +				block->filters + i));
    +
    +		size += add;
    +	}
    +
    +	// Pad to a multiple of four bytes.
    +	block->header_size = (size + 3) & ~UINT32_C(3);
    +
    +	// NOTE: We don't verify that the encoded size of the Block stays
    +	// within limits. This is because it is possible that we are called
    +	// with exaggerated Compressed Size (e.g. LZMA_VLI_MAX) to reserve
    +	// space for Block Header, and later called again with lower,
    +	// real values.
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_block_header_encode(const lzma_block *block, uint8_t *out)
    +{
    +	// Validate everything but filters.
    +	if (lzma_block_unpadded_size(block) == 0
    +			|| !lzma_vli_is_valid(block->uncompressed_size))
    +		return LZMA_PROG_ERROR;
    +
    +	// Indicate the size of the buffer _excluding_ the CRC32 field.
    +	const size_t out_size = block->header_size - 4;
    +
    +	// Store the Block Header Size.
    +	out[0] = out_size / 4;
    +
    +	// We write Block Flags in pieces.
    +	out[1] = 0x00;
    +	size_t out_pos = 2;
    +
    +	// Compressed Size
    +	if (block->compressed_size != LZMA_VLI_UNKNOWN) {
    +		return_if_error(lzma_vli_encode(block->compressed_size, NULL,
    +				out, &out_pos, out_size));
    +
    +		out[1] |= 0x40;
    +	}
    +
    +	// Uncompressed Size
    +	if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
    +		return_if_error(lzma_vli_encode(block->uncompressed_size, NULL,
    +				out, &out_pos, out_size));
    +
    +		out[1] |= 0x80;
    +	}
    +
    +	// Filter Flags
    +	if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
    +		return LZMA_PROG_ERROR;
    +
    +	size_t filter_count = 0;
    +	do {
    +		// There can be a maximum of four filters.
    +		if (filter_count == LZMA_FILTERS_MAX)
    +			return LZMA_PROG_ERROR;
    +
    +		return_if_error(lzma_filter_flags_encode(
    +				block->filters + filter_count,
    +				out, &out_pos, out_size));
    +
    +	} while (block->filters[++filter_count].id != LZMA_VLI_UNKNOWN);
    +
    +	out[1] |= filter_count - 1;
    +
    +	// Padding
    +	memzero(out + out_pos, out_size - out_pos);
    +
    +	// CRC32
    +	write32le(out + out_size, lzma_crc32(out, out_size, 0));
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_util.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_util.c
    new file mode 100644
    index 00000000000..191f6d444aa
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_util.c
    @@ -0,0 +1,89 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       block_util.c
    +/// \brief      Utility functions to handle lzma_block
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +#include "index.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_block_compressed_size(lzma_block *block, lzma_vli unpadded_size)
    +{
    +	// Validate everything but Uncompressed Size and filters.
    +	if (lzma_block_unpadded_size(block) == 0)
    +		return LZMA_PROG_ERROR;
    +
    +	const uint32_t container_size = block->header_size
    +			+ lzma_check_size(block->check);
    +
    +	// Validate that Compressed Size will be greater than zero.
    +	if (unpadded_size <= container_size)
    +		return LZMA_DATA_ERROR;
    +
    +	// Calculate what Compressed Size is supposed to be.
    +	// If Compressed Size was present in Block Header,
    +	// compare that the new value matches it.
    +	const lzma_vli compressed_size = unpadded_size - container_size;
    +	if (block->compressed_size != LZMA_VLI_UNKNOWN
    +			&& block->compressed_size != compressed_size)
    +		return LZMA_DATA_ERROR;
    +
    +	block->compressed_size = compressed_size;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_block_unpadded_size(const lzma_block *block)
    +{
    +	// Validate the values that we are interested in i.e. all but
    +	// Uncompressed Size and the filters.
    +	//
    +	// NOTE: This function is used for validation too, so it is
    +	// essential that these checks are always done even if
    +	// Compressed Size is unknown.
    +	if (block == NULL || block->version > 1
    +			|| block->header_size < LZMA_BLOCK_HEADER_SIZE_MIN
    +			|| block->header_size > LZMA_BLOCK_HEADER_SIZE_MAX
    +			|| (block->header_size & 3)
    +			|| !lzma_vli_is_valid(block->compressed_size)
    +			|| block->compressed_size == 0
    +			|| (unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
    +		return 0;
    +
    +	// If Compressed Size is unknown, return that we cannot know
    +	// size of the Block either.
    +	if (block->compressed_size == LZMA_VLI_UNKNOWN)
    +		return LZMA_VLI_UNKNOWN;
    +
    +	// Calculate Unpadded Size and validate it.
    +	const lzma_vli unpadded_size = block->compressed_size
    +				+ block->header_size
    +				+ lzma_check_size(block->check);
    +
    +	assert(unpadded_size >= UNPADDED_SIZE_MIN);
    +	if (unpadded_size > UNPADDED_SIZE_MAX)
    +		return 0;
    +
    +	return unpadded_size;
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_block_total_size(const lzma_block *block)
    +{
    +	lzma_vli unpadded_size = lzma_block_unpadded_size(block);
    +
    +	if (unpadded_size != LZMA_VLI_UNKNOWN)
    +		unpadded_size = vli_ceil4(unpadded_size);
    +
    +	return unpadded_size;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.c
    new file mode 100644
    index 00000000000..cc0e06a51be
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.c
    @@ -0,0 +1,480 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       common.c
    +/// \brief      Common functions needed in many places in liblzma
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +
    +
    +/////////////
    +// Version //
    +/////////////
    +
    +extern LZMA_API(uint32_t)
    +lzma_version_number(void)
    +{
    +	return LZMA_VERSION;
    +}
    +
    +
    +extern LZMA_API(const char *)
    +lzma_version_string(void)
    +{
    +	return LZMA_VERSION_STRING;
    +}
    +
    +
    +///////////////////////
    +// Memory allocation //
    +///////////////////////
    +
    +lzma_attr_alloc_size(1)
    +extern void *
    +lzma_alloc(size_t size, const lzma_allocator *allocator)
    +{
    +	// Some malloc() variants return NULL if called with size == 0.
    +	if (size == 0)
    +		size = 1;
    +
    +	void *ptr;
    +
    +	if (allocator != NULL && allocator->alloc != NULL)
    +		ptr = allocator->alloc(allocator->opaque, 1, size);
    +	else
    +		ptr = malloc(size);
    +
    +	return ptr;
    +}
    +
    +
    +lzma_attr_alloc_size(1)
    +extern void *
    +lzma_alloc_zero(size_t size, const lzma_allocator *allocator)
    +{
    +	// Some calloc() variants return NULL if called with size == 0.
    +	if (size == 0)
    +		size = 1;
    +
    +	void *ptr;
    +
    +	if (allocator != NULL && allocator->alloc != NULL) {
    +		ptr = allocator->alloc(allocator->opaque, 1, size);
    +		if (ptr != NULL)
    +			memzero(ptr, size);
    +	} else {
    +		ptr = calloc(1, size);
    +	}
    +
    +	return ptr;
    +}
    +
    +
    +extern void
    +lzma_free(void *ptr, const lzma_allocator *allocator)
    +{
    +	if (allocator != NULL && allocator->free != NULL)
    +		allocator->free(allocator->opaque, ptr);
    +	else
    +		free(ptr);
    +
    +	return;
    +}
    +
    +
    +//////////
    +// Misc //
    +//////////
    +
    +extern size_t
    +lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size)
    +{
    +	const size_t in_avail = in_size - *in_pos;
    +	const size_t out_avail = out_size - *out_pos;
    +	const size_t copy_size = my_min(in_avail, out_avail);
    +
    +	// Call memcpy() only if there is something to copy. If there is
    +	// nothing to copy, in or out might be NULL and then the memcpy()
    +	// call would trigger undefined behavior.
    +	if (copy_size > 0)
    +		memcpy(out + *out_pos, in + *in_pos, copy_size);
    +
    +	*in_pos += copy_size;
    +	*out_pos += copy_size;
    +
    +	return copy_size;
    +}
    +
    +
    +extern lzma_ret
    +lzma_next_filter_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	lzma_next_coder_init(filters[0].init, next, allocator);
    +	next->id = filters[0].id;
    +	return filters[0].init == NULL
    +			? LZMA_OK : filters[0].init(next, allocator, filters);
    +}
    +
    +
    +extern lzma_ret
    +lzma_next_filter_update(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter *reversed_filters)
    +{
    +	// Check that the application isn't trying to change the Filter ID.
    +	// End of filters is indicated with LZMA_VLI_UNKNOWN in both
    +	// reversed_filters[0].id and next->id.
    +	if (reversed_filters[0].id != next->id)
    +		return LZMA_PROG_ERROR;
    +
    +	if (reversed_filters[0].id == LZMA_VLI_UNKNOWN)
    +		return LZMA_OK;
    +
    +	assert(next->update != NULL);
    +	return next->update(next->coder, allocator, NULL, reversed_filters);
    +}
    +
    +
    +extern void
    +lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator)
    +{
    +	if (next->init != (uintptr_t)(NULL)) {
    +		// To avoid tiny end functions that simply call
    +		// lzma_free(coder, allocator), we allow leaving next->end
    +		// NULL and call lzma_free() here.
    +		if (next->end != NULL)
    +			next->end(next->coder, allocator);
    +		else
    +			lzma_free(next->coder, allocator);
    +
    +		// Reset the variables so the we don't accidentally think
    +		// that it is an already initialized coder.
    +		*next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	return;
    +}
    +
    +
    +//////////////////////////////////////
    +// External to internal API wrapper //
    +//////////////////////////////////////
    +
    +extern lzma_ret
    +lzma_strm_init(lzma_stream *strm)
    +{
    +	if (strm == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	if (strm->internal == NULL) {
    +		strm->internal = lzma_alloc(sizeof(lzma_internal),
    +				strm->allocator);
    +		if (strm->internal == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		strm->internal->next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	memzero(strm->internal->supported_actions,
    +			sizeof(strm->internal->supported_actions));
    +	strm->internal->sequence = ISEQ_RUN;
    +	strm->internal->allow_buf_error = false;
    +
    +	strm->total_in = 0;
    +	strm->total_out = 0;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_code(lzma_stream *strm, lzma_action action)
    +{
    +	// Sanity checks
    +	if ((strm->next_in == NULL && strm->avail_in != 0)
    +			|| (strm->next_out == NULL && strm->avail_out != 0)
    +			|| strm->internal == NULL
    +			|| strm->internal->next.code == NULL
    +			|| (unsigned int)(action) > LZMA_ACTION_MAX
    +			|| !strm->internal->supported_actions[action])
    +		return LZMA_PROG_ERROR;
    +
    +	// Check if unsupported members have been set to non-zero or non-NULL,
    +	// which would indicate that some new feature is wanted.
    +	if (strm->reserved_ptr1 != NULL
    +			|| strm->reserved_ptr2 != NULL
    +			|| strm->reserved_ptr3 != NULL
    +			|| strm->reserved_ptr4 != NULL
    +			|| strm->reserved_int2 != 0
    +			|| strm->reserved_int3 != 0
    +			|| strm->reserved_int4 != 0
    +			|| strm->reserved_enum1 != LZMA_RESERVED_ENUM
    +			|| strm->reserved_enum2 != LZMA_RESERVED_ENUM)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	switch (strm->internal->sequence) {
    +	case ISEQ_RUN:
    +		switch (action) {
    +		case LZMA_RUN:
    +			break;
    +
    +		case LZMA_SYNC_FLUSH:
    +			strm->internal->sequence = ISEQ_SYNC_FLUSH;
    +			break;
    +
    +		case LZMA_FULL_FLUSH:
    +			strm->internal->sequence = ISEQ_FULL_FLUSH;
    +			break;
    +
    +		case LZMA_FINISH:
    +			strm->internal->sequence = ISEQ_FINISH;
    +			break;
    +
    +		case LZMA_FULL_BARRIER:
    +			strm->internal->sequence = ISEQ_FULL_BARRIER;
    +			break;
    +		}
    +
    +		break;
    +
    +	case ISEQ_SYNC_FLUSH:
    +		// The same action must be used until we return
    +		// LZMA_STREAM_END, and the amount of input must not change.
    +		if (action != LZMA_SYNC_FLUSH
    +				|| strm->internal->avail_in != strm->avail_in)
    +			return LZMA_PROG_ERROR;
    +
    +		break;
    +
    +	case ISEQ_FULL_FLUSH:
    +		if (action != LZMA_FULL_FLUSH
    +				|| strm->internal->avail_in != strm->avail_in)
    +			return LZMA_PROG_ERROR;
    +
    +		break;
    +
    +	case ISEQ_FINISH:
    +		if (action != LZMA_FINISH
    +				|| strm->internal->avail_in != strm->avail_in)
    +			return LZMA_PROG_ERROR;
    +
    +		break;
    +
    +	case ISEQ_FULL_BARRIER:
    +		if (action != LZMA_FULL_BARRIER
    +				|| strm->internal->avail_in != strm->avail_in)
    +			return LZMA_PROG_ERROR;
    +
    +		break;
    +
    +	case ISEQ_END:
    +		return LZMA_STREAM_END;
    +
    +	case ISEQ_ERROR:
    +	default:
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	size_t in_pos = 0;
    +	size_t out_pos = 0;
    +	lzma_ret ret = strm->internal->next.code(
    +			strm->internal->next.coder, strm->allocator,
    +			strm->next_in, &in_pos, strm->avail_in,
    +			strm->next_out, &out_pos, strm->avail_out, action);
    +
    +	// Updating next_in and next_out has to be skipped when they are NULL
    +	// to avoid null pointer + 0 (undefined behavior). Do this by checking
    +	// in_pos > 0 and out_pos > 0 because this way NULL + non-zero (a bug)
    +	// will get caught one way or other.
    +	if (in_pos > 0) {
    +		strm->next_in += in_pos;
    +		strm->avail_in -= in_pos;
    +		strm->total_in += in_pos;
    +	}
    +
    +	if (out_pos > 0) {
    +		strm->next_out += out_pos;
    +		strm->avail_out -= out_pos;
    +		strm->total_out += out_pos;
    +	}
    +
    +	strm->internal->avail_in = strm->avail_in;
    +
    +	switch (ret) {
    +	case LZMA_OK:
    +		// Don't return LZMA_BUF_ERROR when it happens the first time.
    +		// This is to avoid returning LZMA_BUF_ERROR when avail_out
    +		// was zero but still there was no more data left to written
    +		// to next_out.
    +		if (out_pos == 0 && in_pos == 0) {
    +			if (strm->internal->allow_buf_error)
    +				ret = LZMA_BUF_ERROR;
    +			else
    +				strm->internal->allow_buf_error = true;
    +		} else {
    +			strm->internal->allow_buf_error = false;
    +		}
    +		break;
    +
    +	case LZMA_TIMED_OUT:
    +		strm->internal->allow_buf_error = false;
    +		ret = LZMA_OK;
    +		break;
    +
    +	case LZMA_SEEK_NEEDED:
    +		strm->internal->allow_buf_error = false;
    +
    +		// If LZMA_FINISH was used, reset it back to the
    +		// LZMA_RUN-based state so that new input can be supplied
    +		// by the application.
    +		if (strm->internal->sequence == ISEQ_FINISH)
    +			strm->internal->sequence = ISEQ_RUN;
    +
    +		break;
    +
    +	case LZMA_STREAM_END:
    +		if (strm->internal->sequence == ISEQ_SYNC_FLUSH
    +				|| strm->internal->sequence == ISEQ_FULL_FLUSH
    +				|| strm->internal->sequence
    +					== ISEQ_FULL_BARRIER)
    +			strm->internal->sequence = ISEQ_RUN;
    +		else
    +			strm->internal->sequence = ISEQ_END;
    +
    +	// Fall through
    +
    +	case LZMA_NO_CHECK:
    +	case LZMA_UNSUPPORTED_CHECK:
    +	case LZMA_GET_CHECK:
    +	case LZMA_MEMLIMIT_ERROR:
    +		// Something else than LZMA_OK, but not a fatal error,
    +		// that is, coding may be continued (except if ISEQ_END).
    +		strm->internal->allow_buf_error = false;
    +		break;
    +
    +	default:
    +		// All the other errors are fatal; coding cannot be continued.
    +		assert(ret != LZMA_BUF_ERROR);
    +		strm->internal->sequence = ISEQ_ERROR;
    +		break;
    +	}
    +
    +	return ret;
    +}
    +
    +
    +extern LZMA_API(void)
    +lzma_end(lzma_stream *strm)
    +{
    +	if (strm != NULL && strm->internal != NULL) {
    +		lzma_next_end(&strm->internal->next, strm->allocator);
    +		lzma_free(strm->internal, strm->allocator);
    +		strm->internal = NULL;
    +	}
    +
    +	return;
    +}
    +
    +
    +#ifdef HAVE_SYMBOL_VERSIONS_LINUX
    +// This is for compatibility with binaries linked against liblzma that
    +// has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
    +LZMA_SYMVER_API("lzma_get_progress@XZ_5.2.2",
    +	void, lzma_get_progress_522)(lzma_stream *strm,
    +		uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow
    +		__attribute__((__alias__("lzma_get_progress_52")));
    +
    +LZMA_SYMVER_API("lzma_get_progress@@XZ_5.2",
    +	void, lzma_get_progress_52)(lzma_stream *strm,
    +		uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow;
    +
    +#define lzma_get_progress lzma_get_progress_52
    +#endif
    +extern LZMA_API(void)
    +lzma_get_progress(lzma_stream *strm,
    +		uint64_t *progress_in, uint64_t *progress_out)
    +{
    +	if (strm->internal->next.get_progress != NULL) {
    +		strm->internal->next.get_progress(strm->internal->next.coder,
    +				progress_in, progress_out);
    +	} else {
    +		*progress_in = strm->total_in;
    +		*progress_out = strm->total_out;
    +	}
    +
    +	return;
    +}
    +
    +
    +extern LZMA_API(lzma_check)
    +lzma_get_check(const lzma_stream *strm)
    +{
    +	// Return LZMA_CHECK_NONE if we cannot know the check type.
    +	// It's a bug in the application if this happens.
    +	if (strm->internal->next.get_check == NULL)
    +		return LZMA_CHECK_NONE;
    +
    +	return strm->internal->next.get_check(strm->internal->next.coder);
    +}
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_memusage(const lzma_stream *strm)
    +{
    +	uint64_t memusage;
    +	uint64_t old_memlimit;
    +
    +	if (strm == NULL || strm->internal == NULL
    +			|| strm->internal->next.memconfig == NULL
    +			|| strm->internal->next.memconfig(
    +				strm->internal->next.coder,
    +				&memusage, &old_memlimit, 0) != LZMA_OK)
    +		return 0;
    +
    +	return memusage;
    +}
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_memlimit_get(const lzma_stream *strm)
    +{
    +	uint64_t old_memlimit;
    +	uint64_t memusage;
    +
    +	if (strm == NULL || strm->internal == NULL
    +			|| strm->internal->next.memconfig == NULL
    +			|| strm->internal->next.memconfig(
    +				strm->internal->next.coder,
    +				&memusage, &old_memlimit, 0) != LZMA_OK)
    +		return 0;
    +
    +	return old_memlimit;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_memlimit_set(lzma_stream *strm, uint64_t new_memlimit)
    +{
    +	// Dummy variables to simplify memconfig functions
    +	uint64_t old_memlimit;
    +	uint64_t memusage;
    +
    +	if (strm == NULL || strm->internal == NULL
    +			|| strm->internal->next.memconfig == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	// Zero is a special value that cannot be used as an actual limit.
    +	// If 0 was specified, use 1 instead.
    +	if (new_memlimit == 0)
    +		new_memlimit = 1;
    +
    +	return strm->internal->next.memconfig(strm->internal->next.coder,
    +			&memusage, &old_memlimit, new_memlimit);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.h
    new file mode 100644
    index 00000000000..20af32f6d6c
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.h
    @@ -0,0 +1,412 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       common.h
    +/// \brief      Definitions common to the whole liblzma library
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_COMMON_H
    +#define LZMA_COMMON_H
    +
    +#include "sysdefs.h"
    +#include "mythread.h"
    +#include "tuklib_integer.h"
    +
    +// LZMA_API_EXPORT is used to mark the exported API functions.
    +// It's used to define the LZMA_API macro.
    +//
    +// lzma_attr_visibility_hidden is used for marking *declarations* of extern
    +// variables that are internal to liblzma (-fvisibility=hidden alone is
    +// enough to hide the *definitions*). Such markings allow slightly more
    +// efficient code to accesses those variables in ELF shared libraries.
    +#if defined(_WIN32) || defined(__CYGWIN__)
    +#	ifdef DLL_EXPORT
    +#		define LZMA_API_EXPORT __declspec(dllexport)
    +#	else
    +#		define LZMA_API_EXPORT
    +#	endif
    +#	define lzma_attr_visibility_hidden
    +// Don't use ifdef or defined() below.
    +#elif HAVE_VISIBILITY
    +#	define LZMA_API_EXPORT __attribute__((__visibility__("default")))
    +#	define lzma_attr_visibility_hidden \
    +			__attribute__((__visibility__("hidden")))
    +#else
    +#	define LZMA_API_EXPORT
    +#	define lzma_attr_visibility_hidden
    +#endif
    +
    +#define LZMA_API(type) LZMA_API_EXPORT type LZMA_API_CALL
    +
    +#include "lzma.h"
    +
    +// This is for detecting modern GCC and Clang attributes
    +// like __symver__ in GCC >= 10.
    +#ifdef __has_attribute
    +#	define lzma_has_attribute(attr) __has_attribute(attr)
    +#else
    +#	define lzma_has_attribute(attr) 0
    +#endif
    +
    +// The extra symbol versioning in the C files may only be used when
    +// building a shared library. If HAVE_SYMBOL_VERSIONS_LINUX is defined
    +// to 2 then symbol versioning is done only if also PIC is defined.
    +// By default Libtool defines PIC when building a shared library and
    +// doesn't define it when building a static library but it can be
    +// overridden with --with-pic and --without-pic. configure let's rely
    +// on PIC if neither --with-pic or --without-pic was used.
    +#if defined(HAVE_SYMBOL_VERSIONS_LINUX) \
    +		&& (HAVE_SYMBOL_VERSIONS_LINUX == 2 && !defined(PIC))
    +#	undef HAVE_SYMBOL_VERSIONS_LINUX
    +#endif
    +
    +#ifdef HAVE_SYMBOL_VERSIONS_LINUX
    +// To keep link-time optimization (LTO, -flto) working with GCC,
    +// the __symver__ attribute must be used instead of __asm__(".symver ...").
    +// Otherwise the symbol versions may be lost, resulting in broken liblzma
    +// that has wrong default versions in the exported symbol list!
    +// The attribute was added in GCC 10; LTO with older GCC is not supported.
    +//
    +// To keep -Wmissing-prototypes happy, use LZMA_SYMVER_API only with function
    +// declarations (including those with __alias__ attribute) and LZMA_API with
    +// the function definitions. This means a little bit of silly copy-and-paste
    +// between declarations and definitions though.
    +//
    +// As of GCC 12.2, the __symver__ attribute supports only @ and @@ but the
    +// very convenient @@@ isn't supported (it's supported by GNU assembler
    +// since 2000). When using @@ instead of @@@, the internal name must not be
    +// the same as the external name to avoid problems in some situations. This
    +// is why "#define foo_52 foo" is needed for the default symbol versions.
    +//
    +// __has_attribute is supported before GCC 10 and it is supported in Clang 14
    +// too (which doesn't support __symver__) so use it to detect if __symver__
    +// is available. This should be far more reliable than looking at compiler
    +// version macros as nowadays especially __GNUC__ is defined by many compilers.
    +#	if lzma_has_attribute(__symver__)
    +#		define LZMA_SYMVER_API(extnamever, type, intname) \
    +			extern __attribute__((__symver__(extnamever))) \
    +					LZMA_API(type) intname
    +#	else
    +#		define LZMA_SYMVER_API(extnamever, type, intname) \
    +			__asm__(".symver " #intname "," extnamever); \
    +			extern LZMA_API(type) intname
    +#	endif
    +#endif
    +
    +// MSVC has __forceinline which shouldn't be combined with the inline keyword
    +// (results in a warning).
    +//
    +// GCC 3.1 added always_inline attribute so we don't need to check
    +// for __GNUC__ version. Similarly, all relevant Clang versions
    +// support it (at least Clang 3.0.0 does already).
    +// Other compilers might support too which also support __has_attribute
    +// (Solaris Studio) so do that check too.
    +#if defined(_MSC_VER)
    +#	define lzma_always_inline __forceinline
    +#elif defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER) \
    +		|| lzma_has_attribute(__always_inline__)
    +#	define lzma_always_inline inline __attribute__((__always_inline__))
    +#else
    +#	define lzma_always_inline inline
    +#endif
    +
    +// These allow helping the compiler in some often-executed branches, whose
    +// result is almost always the same.
    +#ifdef __GNUC__
    +#	define likely(expr) __builtin_expect(expr, true)
    +#	define unlikely(expr) __builtin_expect(expr, false)
    +#else
    +#	define likely(expr) (expr)
    +#	define unlikely(expr) (expr)
    +#endif
    +
    +
    +/// Size of temporary buffers needed in some filters
    +#define LZMA_BUFFER_SIZE 4096
    +
    +
    +/// Maximum number of worker threads within one multithreaded component.
    +/// The limit exists solely to make it simpler to prevent integer overflows
    +/// when allocating structures etc. This should be big enough for now...
    +/// the code won't scale anywhere close to this number anyway.
    +#define LZMA_THREADS_MAX 16384
    +
    +
    +/// Starting value for memory usage estimates. Instead of calculating size
    +/// of _every_ structure and taking into account malloc() overhead etc., we
    +/// add a base size to all memory usage estimates. It's not very accurate
    +/// but should be easily good enough.
    +#define LZMA_MEMUSAGE_BASE (UINT64_C(1) << 15)
    +
    +/// Start of internal Filter ID space. These IDs must never be used
    +/// in Streams.
    +#define LZMA_FILTER_RESERVED_START (LZMA_VLI_C(1) << 62)
    +
    +
    +/// Supported flags that can be passed to lzma_stream_decoder(),
    +/// lzma_auto_decoder(), or lzma_stream_decoder_mt().
    +#define LZMA_SUPPORTED_FLAGS \
    +	( LZMA_TELL_NO_CHECK \
    +	| LZMA_TELL_UNSUPPORTED_CHECK \
    +	| LZMA_TELL_ANY_CHECK \
    +	| LZMA_IGNORE_CHECK \
    +	| LZMA_CONCATENATED \
    +	| LZMA_FAIL_FAST )
    +
    +
    +/// Largest valid lzma_action value as unsigned integer.
    +#define LZMA_ACTION_MAX ((unsigned int)(LZMA_FULL_BARRIER))
    +
    +
    +/// Special return value (lzma_ret) to indicate that a timeout was reached
    +/// and lzma_code() must not return LZMA_BUF_ERROR. This is converted to
    +/// LZMA_OK in lzma_code().
    +#define LZMA_TIMED_OUT LZMA_RET_INTERNAL1
    +
    +/// Special return value (lzma_ret) for use in stream_decoder_mt.c to
    +/// indicate Index was detected instead of a Block Header.
    +#define LZMA_INDEX_DETECTED LZMA_RET_INTERNAL2
    +
    +
    +typedef struct lzma_next_coder_s lzma_next_coder;
    +
    +typedef struct lzma_filter_info_s lzma_filter_info;
    +
    +
    +/// Type of a function used to initialize a filter encoder or decoder
    +typedef lzma_ret (*lzma_init_function)(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +/// Type of a function to do some kind of coding work (filters, Stream,
    +/// Block encoders/decoders etc.). Some special coders use don't use both
    +/// input and output buffers, but for simplicity they still use this same
    +/// function prototype.
    +typedef lzma_ret (*lzma_code_function)(
    +		void *coder, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size,
    +		lzma_action action);
    +
    +/// Type of a function to free the memory allocated for the coder
    +typedef void (*lzma_end_function)(
    +		void *coder, const lzma_allocator *allocator);
    +
    +
    +/// Raw coder validates and converts an array of lzma_filter structures to
    +/// an array of lzma_filter_info structures. This array is used with
    +/// lzma_next_filter_init to initialize the filter chain.
    +struct lzma_filter_info_s {
    +	/// Filter ID. This can be used to share the same initiazation
    +	/// function *and* data structures with different Filter IDs
    +	/// (LZMA_FILTER_LZMA1EXT does it), and also by the encoder
    +	/// with lzma_filters_update() if filter chain is updated
    +	/// in the middle of a raw stream or Block (LZMA_SYNC_FLUSH).
    +	lzma_vli id;
    +
    +	/// Pointer to function used to initialize the filter.
    +	/// This is NULL to indicate end of array.
    +	lzma_init_function init;
    +
    +	/// Pointer to filter's options structure
    +	void *options;
    +};
    +
    +
    +/// Hold data and function pointers of the next filter in the chain.
    +struct lzma_next_coder_s {
    +	/// Pointer to coder-specific data
    +	void *coder;
    +
    +	/// Filter ID. This is LZMA_VLI_UNKNOWN when this structure doesn't
    +	/// point to a filter coder.
    +	lzma_vli id;
    +
    +	/// "Pointer" to init function. This is never called here.
    +	/// We need only to detect if we are initializing a coder
    +	/// that was allocated earlier. See lzma_next_coder_init and
    +	/// lzma_next_strm_init macros in this file.
    +	uintptr_t init;
    +
    +	/// Pointer to function to do the actual coding
    +	lzma_code_function code;
    +
    +	/// Pointer to function to free lzma_next_coder.coder. This can
    +	/// be NULL; in that case, lzma_free is called to free
    +	/// lzma_next_coder.coder.
    +	lzma_end_function end;
    +
    +	/// Pointer to a function to get progress information. If this is NULL,
    +	/// lzma_stream.total_in and .total_out are used instead.
    +	void (*get_progress)(void *coder,
    +			uint64_t *progress_in, uint64_t *progress_out);
    +
    +	/// Pointer to function to return the type of the integrity check.
    +	/// Most coders won't support this.
    +	lzma_check (*get_check)(const void *coder);
    +
    +	/// Pointer to function to get and/or change the memory usage limit.
    +	/// If new_memlimit == 0, the limit is not changed.
    +	lzma_ret (*memconfig)(void *coder, uint64_t *memusage,
    +			uint64_t *old_memlimit, uint64_t new_memlimit);
    +
    +	/// Update the filter-specific options or the whole filter chain
    +	/// in the encoder.
    +	lzma_ret (*update)(void *coder, const lzma_allocator *allocator,
    +			const lzma_filter *filters,
    +			const lzma_filter *reversed_filters);
    +
    +	/// Set how many bytes of output this coder may produce at maximum.
    +	/// On success LZMA_OK must be returned.
    +	/// If the filter chain as a whole cannot support this feature,
    +	/// this must return LZMA_OPTIONS_ERROR.
    +	/// If no input has been given to the coder and the requested limit
    +	/// is too small, this must return LZMA_BUF_ERROR. If input has been
    +	/// seen, LZMA_OK is allowed too.
    +	lzma_ret (*set_out_limit)(void *coder, uint64_t *uncomp_size,
    +			uint64_t out_limit);
    +};
    +
    +
    +/// Macro to initialize lzma_next_coder structure
    +#define LZMA_NEXT_CODER_INIT \
    +	(lzma_next_coder){ \
    +		.coder = NULL, \
    +		.init = (uintptr_t)(NULL), \
    +		.id = LZMA_VLI_UNKNOWN, \
    +		.code = NULL, \
    +		.end = NULL, \
    +		.get_progress = NULL, \
    +		.get_check = NULL, \
    +		.memconfig = NULL, \
    +		.update = NULL, \
    +		.set_out_limit = NULL, \
    +	}
    +
    +
    +/// Internal data for lzma_strm_init, lzma_code, and lzma_end. A pointer to
    +/// this is stored in lzma_stream.
    +struct lzma_internal_s {
    +	/// The actual coder that should do something useful
    +	lzma_next_coder next;
    +
    +	/// Track the state of the coder. This is used to validate arguments
    +	/// so that the actual coders can rely on e.g. that LZMA_SYNC_FLUSH
    +	/// is used on every call to lzma_code until next.code has returned
    +	/// LZMA_STREAM_END.
    +	enum {
    +		ISEQ_RUN,
    +		ISEQ_SYNC_FLUSH,
    +		ISEQ_FULL_FLUSH,
    +		ISEQ_FINISH,
    +		ISEQ_FULL_BARRIER,
    +		ISEQ_END,
    +		ISEQ_ERROR,
    +	} sequence;
    +
    +	/// A copy of lzma_stream avail_in. This is used to verify that the
    +	/// amount of input doesn't change once e.g. LZMA_FINISH has been
    +	/// used.
    +	size_t avail_in;
    +
    +	/// Indicates which lzma_action values are allowed by next.code.
    +	bool supported_actions[LZMA_ACTION_MAX + 1];
    +
    +	/// If true, lzma_code will return LZMA_BUF_ERROR if no progress was
    +	/// made (no input consumed and no output produced by next.code).
    +	bool allow_buf_error;
    +};
    +
    +
    +/// Allocates memory
    +lzma_attr_alloc_size(1)
    +extern void *lzma_alloc(size_t size, const lzma_allocator *allocator);
    +
    +/// Allocates memory and zeroes it (like calloc()). This can be faster
    +/// than lzma_alloc() + memzero() while being backward compatible with
    +/// custom allocators.
    +lzma_attr_alloc_size(1)
    +extern void *lzma_alloc_zero(size_t size, const lzma_allocator *allocator);
    +
    +/// Frees memory
    +extern void lzma_free(void *ptr, const lzma_allocator *allocator);
    +
    +
    +/// Allocates strm->internal if it is NULL, and initializes *strm and
    +/// strm->internal. This function is only called via lzma_next_strm_init macro.
    +extern lzma_ret lzma_strm_init(lzma_stream *strm);
    +
    +/// Initializes the next filter in the chain, if any. This takes care of
    +/// freeing the memory of previously initialized filter if it is different
    +/// than the filter being initialized now. This way the actual filter
    +/// initialization functions don't need to use lzma_next_coder_init macro.
    +extern lzma_ret lzma_next_filter_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +/// Update the next filter in the chain, if any. This checks that
    +/// the application is not trying to change the Filter IDs.
    +extern lzma_ret lzma_next_filter_update(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter *reversed_filters);
    +
    +/// Frees the memory allocated for next->coder either using next->end or,
    +/// if next->end is NULL, using lzma_free.
    +extern void lzma_next_end(lzma_next_coder *next,
    +		const lzma_allocator *allocator);
    +
    +
    +/// Copy as much data as possible from in[] to out[] and update *in_pos
    +/// and *out_pos accordingly. Returns the number of bytes copied.
    +extern size_t lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size);
    +
    +
    +/// \brief      Return if expression doesn't evaluate to LZMA_OK
    +///
    +/// There are several situations where we want to return immediately
    +/// with the value of expr if it isn't LZMA_OK. This macro shortens
    +/// the code a little.
    +#define return_if_error(expr) \
    +do { \
    +	const lzma_ret ret_ = (expr); \
    +	if (ret_ != LZMA_OK) \
    +		return ret_; \
    +} while (0)
    +
    +
    +/// If next isn't already initialized, free the previous coder. Then mark
    +/// that next is _possibly_ initialized for the coder using this macro.
    +/// "Possibly" means that if e.g. allocation of next->coder fails, the
    +/// structure isn't actually initialized for this coder, but leaving
    +/// next->init to func is still OK.
    +#define lzma_next_coder_init(func, next, allocator) \
    +do { \
    +	if ((uintptr_t)(func) != (next)->init) \
    +		lzma_next_end(next, allocator); \
    +	(next)->init = (uintptr_t)(func); \
    +} while (0)
    +
    +
    +/// Initializes lzma_strm and calls func() to initialize strm->internal->next.
    +/// (The function being called will use lzma_next_coder_init()). If
    +/// initialization fails, memory that wasn't freed by func() is freed
    +/// along strm->internal.
    +#define lzma_next_strm_init(func, strm, ...) \
    +do { \
    +	return_if_error(lzma_strm_init(strm)); \
    +	const lzma_ret ret_ = func(&(strm)->internal->next, \
    +			(strm)->allocator, __VA_ARGS__); \
    +	if (ret_ != LZMA_OK) { \
    +		lzma_end(strm); \
    +		return ret_; \
    +	} \
    +} while (0)
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_buffer_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_buffer_encoder.c
    new file mode 100644
    index 00000000000..da610cea6bf
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_buffer_encoder.c
    @@ -0,0 +1,26 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       easy_buffer_encoder.c
    +/// \brief      Easy single-call .xz Stream encoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "easy_preset.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_easy_buffer_encode(uint32_t preset, lzma_check check,
    +		const lzma_allocator *allocator, const uint8_t *in,
    +		size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	lzma_options_easy opt_easy;
    +	if (lzma_easy_preset(&opt_easy, preset))
    +		return LZMA_OPTIONS_ERROR;
    +
    +	return lzma_stream_buffer_encode(opt_easy.filters, check,
    +			allocator, in, in_size, out, out_pos, out_size);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_decoder_memusage.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_decoder_memusage.c
    new file mode 100644
    index 00000000000..0c76f10033b
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_decoder_memusage.c
    @@ -0,0 +1,23 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       easy_decoder_memusage.c
    +/// \brief      Decoder memory usage calculation to match easy encoder presets
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "easy_preset.h"
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_easy_decoder_memusage(uint32_t preset)
    +{
    +	lzma_options_easy opt_easy;
    +	if (lzma_easy_preset(&opt_easy, preset))
    +		return UINT32_MAX;
    +
    +	return lzma_raw_decoder_memusage(opt_easy.filters);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder.c
    new file mode 100644
    index 00000000000..8dfe29610f7
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder.c
    @@ -0,0 +1,23 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       easy_encoder.c
    +/// \brief      Easy .xz Stream encoder initialization
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "easy_preset.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_easy_encoder(lzma_stream *strm, uint32_t preset, lzma_check check)
    +{
    +	lzma_options_easy opt_easy;
    +	if (lzma_easy_preset(&opt_easy, preset))
    +		return LZMA_OPTIONS_ERROR;
    +
    +	return lzma_stream_encoder(strm, opt_easy.filters, check);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder_memusage.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder_memusage.c
    new file mode 100644
    index 00000000000..1184ac66542
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder_memusage.c
    @@ -0,0 +1,23 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       easy_encoder_memusage.c
    +/// \brief      Easy .xz Stream encoder memory usage calculation
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "easy_preset.h"
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_easy_encoder_memusage(uint32_t preset)
    +{
    +	lzma_options_easy opt_easy;
    +	if (lzma_easy_preset(&opt_easy, preset))
    +		return UINT32_MAX;
    +
    +	return lzma_raw_encoder_memusage(opt_easy.filters);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.c
    new file mode 100644
    index 00000000000..7908a2bb73c
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.c
    @@ -0,0 +1,26 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       easy_preset.c
    +/// \brief      Preset handling for easy encoder and decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "easy_preset.h"
    +
    +
    +extern bool
    +lzma_easy_preset(lzma_options_easy *opt_easy, uint32_t preset)
    +{
    +	if (lzma_lzma_preset(&opt_easy->opt_lzma, preset))
    +		return true;
    +
    +	opt_easy->filters[0].id = LZMA_FILTER_LZMA2;
    +	opt_easy->filters[0].options = &opt_easy->opt_lzma;
    +	opt_easy->filters[1].id = LZMA_VLI_UNKNOWN;
    +
    +	return false;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.h
    new file mode 100644
    index 00000000000..4ef6d044ad5
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.h
    @@ -0,0 +1,36 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       easy_preset.h
    +/// \brief      Preset handling for easy encoder and decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_EASY_PRESET_H
    +#define LZMA_EASY_PRESET_H
    +
    +#include "common.h"
    +
    +
    +typedef struct {
    +	/// We need to keep the filters array available in case
    +	/// LZMA_FULL_FLUSH is used.
    +	lzma_filter filters[LZMA_FILTERS_MAX + 1];
    +
    +	/// Options for LZMA2
    +	lzma_options_lzma opt_lzma;
    +
    +	// Options for more filters can be added later, so this struct
    +	// is not ready to be put into the public API.
    +
    +} lzma_options_easy;
    +
    +
    +/// Set *easy to the settings given by the preset. Returns true on error,
    +/// false on success.
    +extern bool lzma_easy_preset(lzma_options_easy *easy, uint32_t preset);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/file_info.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/file_info.c
    new file mode 100644
    index 00000000000..7c85084a706
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/file_info.c
    @@ -0,0 +1,854 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       file_info.c
    +/// \brief      Decode .xz file information into a lzma_index structure
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "index_decoder.h"
    +
    +
    +typedef struct {
    +	enum {
    +		SEQ_MAGIC_BYTES,
    +		SEQ_PADDING_SEEK,
    +		SEQ_PADDING_DECODE,
    +		SEQ_FOOTER,
    +		SEQ_INDEX_INIT,
    +		SEQ_INDEX_DECODE,
    +		SEQ_HEADER_DECODE,
    +		SEQ_HEADER_COMPARE,
    +	} sequence;
    +
    +	/// Absolute position of in[*in_pos] in the file. All code that
    +	/// modifies *in_pos also updates this. seek_to_pos() needs this
    +	/// to determine if we need to request the application to seek for
    +	/// us or if we can do the seeking internally by adjusting *in_pos.
    +	uint64_t file_cur_pos;
    +
    +	/// This refers to absolute positions of interesting parts of the
    +	/// input file. Sometimes it points to the *beginning* of a specific
    +	/// field and sometimes to the *end* of a field. The current target
    +	/// position at each moment is explained in the comments.
    +	uint64_t file_target_pos;
    +
    +	/// Size of the .xz file (from the application).
    +	uint64_t file_size;
    +
    +	/// Index decoder
    +	lzma_next_coder index_decoder;
    +
    +	/// Number of bytes remaining in the Index field that is currently
    +	/// being decoded.
    +	lzma_vli index_remaining;
    +
    +	/// The Index decoder will store the decoded Index in this pointer.
    +	lzma_index *this_index;
    +
    +	/// Amount of Stream Padding in the current Stream.
    +	lzma_vli stream_padding;
    +
    +	/// The final combined index is collected here.
    +	lzma_index *combined_index;
    +
    +	/// Pointer from the application where to store the index information
    +	/// after successful decoding.
    +	lzma_index **dest_index;
    +
    +	/// Pointer to lzma_stream.seek_pos to be used when returning
    +	/// LZMA_SEEK_NEEDED. This is set by seek_to_pos() when needed.
    +	uint64_t *external_seek_pos;
    +
    +	/// Memory usage limit
    +	uint64_t memlimit;
    +
    +	/// Stream Flags from the very beginning of the file.
    +	lzma_stream_flags first_header_flags;
    +
    +	/// Stream Flags from Stream Header of the current Stream.
    +	lzma_stream_flags header_flags;
    +
    +	/// Stream Flags from Stream Footer of the current Stream.
    +	lzma_stream_flags footer_flags;
    +
    +	size_t temp_pos;
    +	size_t temp_size;
    +	uint8_t temp[8192];
    +
    +} lzma_file_info_coder;
    +
    +
    +/// Copies data from in[*in_pos] into coder->temp until
    +/// coder->temp_pos == coder->temp_size. This also keeps coder->file_cur_pos
    +/// in sync with *in_pos. Returns true if more input is needed.
    +static bool
    +fill_temp(lzma_file_info_coder *coder, const uint8_t *restrict in,
    +		size_t *restrict in_pos, size_t in_size)
    +{
    +	coder->file_cur_pos += lzma_bufcpy(in, in_pos, in_size,
    +			coder->temp, &coder->temp_pos, coder->temp_size);
    +	return coder->temp_pos < coder->temp_size;
    +}
    +
    +
    +/// Seeks to the absolute file position specified by target_pos.
    +/// This tries to do the seeking by only modifying *in_pos, if possible.
    +/// The main benefit of this is that if one passes the whole file at once
    +/// to lzma_code(), the decoder will never need to return LZMA_SEEK_NEEDED
    +/// as all the seeking can be done by adjusting *in_pos in this function.
    +///
    +/// Returns true if an external seek is needed and the caller must return
    +/// LZMA_SEEK_NEEDED.
    +static bool
    +seek_to_pos(lzma_file_info_coder *coder, uint64_t target_pos,
    +		size_t in_start, size_t *in_pos, size_t in_size)
    +{
    +	// The input buffer doesn't extend beyond the end of the file.
    +	// This has been checked by file_info_decode() already.
    +	assert(coder->file_size - coder->file_cur_pos >= in_size - *in_pos);
    +
    +	const uint64_t pos_min = coder->file_cur_pos - (*in_pos - in_start);
    +	const uint64_t pos_max = coder->file_cur_pos + (in_size - *in_pos);
    +
    +	bool external_seek_needed;
    +
    +	if (target_pos >= pos_min && target_pos <= pos_max) {
    +		// The requested position is available in the current input
    +		// buffer or right after it. That is, in a corner case we
    +		// end up setting *in_pos == in_size and thus will immediately
    +		// need new input bytes from the application.
    +		*in_pos += (size_t)(target_pos - coder->file_cur_pos);
    +		external_seek_needed = false;
    +	} else {
    +		// Ask the application to seek the input file.
    +		*coder->external_seek_pos = target_pos;
    +		external_seek_needed = true;
    +
    +		// Mark the whole input buffer as used. This way
    +		// lzma_stream.total_in will have a better estimate
    +		// of the amount of data read. It still won't be perfect
    +		// as the value will depend on the input buffer size that
    +		// the application uses, but it should be good enough for
    +		// those few who want an estimate.
    +		*in_pos = in_size;
    +	}
    +
    +	// After seeking (internal or external) the current position
    +	// will match the requested target position.
    +	coder->file_cur_pos = target_pos;
    +
    +	return external_seek_needed;
    +}
    +
    +
    +/// The caller sets coder->file_target_pos so that it points to the *end*
    +/// of the desired file position. This function then determines how far
    +/// backwards from that position we can seek. After seeking fill_temp()
    +/// can be used to read data into coder->temp. When fill_temp() has finished,
    +/// coder->temp[coder->temp_size] will match coder->file_target_pos.
    +///
    +/// This also validates that coder->target_file_pos is sane in sense that
    +/// we aren't trying to seek too far backwards (too close or beyond the
    +/// beginning of the file).
    +static lzma_ret
    +reverse_seek(lzma_file_info_coder *coder,
    +		size_t in_start, size_t *in_pos, size_t in_size)
    +{
    +	// Check that there is enough data before the target position
    +	// to contain at least Stream Header and Stream Footer. If there
    +	// isn't, the file cannot be valid.
    +	if (coder->file_target_pos < 2 * LZMA_STREAM_HEADER_SIZE)
    +		return LZMA_DATA_ERROR;
    +
    +	coder->temp_pos = 0;
    +
    +	// The Stream Header at the very beginning of the file gets handled
    +	// specially in SEQ_MAGIC_BYTES and thus we will never need to seek
    +	// there. By not seeking to the first LZMA_STREAM_HEADER_SIZE bytes
    +	// we avoid a useless external seek after SEQ_MAGIC_BYTES if the
    +	// application uses an extremely small input buffer and the input
    +	// file is very small.
    +	if (coder->file_target_pos - LZMA_STREAM_HEADER_SIZE
    +			< sizeof(coder->temp))
    +		coder->temp_size = (size_t)(coder->file_target_pos
    +				- LZMA_STREAM_HEADER_SIZE);
    +	else
    +		coder->temp_size = sizeof(coder->temp);
    +
    +	// The above if-statements guarantee this. This is important because
    +	// the Stream Header/Footer decoders assume that there's at least
    +	// LZMA_STREAM_HEADER_SIZE bytes in coder->temp.
    +	assert(coder->temp_size >= LZMA_STREAM_HEADER_SIZE);
    +
    +	if (seek_to_pos(coder, coder->file_target_pos - coder->temp_size,
    +			in_start, in_pos, in_size))
    +		return LZMA_SEEK_NEEDED;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +/// Gets the number of zero-bytes at the end of the buffer.
    +static size_t
    +get_padding_size(const uint8_t *buf, size_t buf_size)
    +{
    +	size_t padding = 0;
    +	while (buf_size > 0 && buf[--buf_size] == 0x00)
    +		++padding;
    +
    +	return padding;
    +}
    +
    +
    +/// With the Stream Header at the very beginning of the file, LZMA_FORMAT_ERROR
    +/// is used to tell the application that Magic Bytes didn't match. In other
    +/// Stream Header/Footer fields (in the middle/end of the file) it could be
    +/// a bit confusing to return LZMA_FORMAT_ERROR as we already know that there
    +/// is a valid Stream Header at the beginning of the file. For those cases
    +/// this function is used to convert LZMA_FORMAT_ERROR to LZMA_DATA_ERROR.
    +static lzma_ret
    +hide_format_error(lzma_ret ret)
    +{
    +	if (ret == LZMA_FORMAT_ERROR)
    +		ret = LZMA_DATA_ERROR;
    +
    +	return ret;
    +}
    +
    +
    +/// Calls the Index decoder and updates coder->index_remaining.
    +/// This is a separate function because the input can be either directly
    +/// from the application or from coder->temp.
    +static lzma_ret
    +decode_index(lzma_file_info_coder *coder, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, bool update_file_cur_pos)
    +{
    +	const size_t in_start = *in_pos;
    +
    +	const lzma_ret ret = coder->index_decoder.code(
    +			coder->index_decoder.coder,
    +			allocator, in, in_pos, in_size,
    +			NULL, NULL, 0, LZMA_RUN);
    +
    +	coder->index_remaining -= *in_pos - in_start;
    +
    +	if (update_file_cur_pos)
    +		coder->file_cur_pos += *in_pos - in_start;
    +
    +	return ret;
    +}
    +
    +
    +static lzma_ret
    +file_info_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size,
    +		uint8_t *restrict out lzma_attribute((__unused__)),
    +		size_t *restrict out_pos lzma_attribute((__unused__)),
    +		size_t out_size lzma_attribute((__unused__)),
    +		lzma_action action lzma_attribute((__unused__)))
    +{
    +	lzma_file_info_coder *coder = coder_ptr;
    +	const size_t in_start = *in_pos;
    +
    +	// If the caller provides input past the end of the file, trim
    +	// the extra bytes from the buffer so that we won't read too far.
    +	assert(coder->file_size >= coder->file_cur_pos);
    +	if (coder->file_size - coder->file_cur_pos < in_size - in_start)
    +		in_size = in_start
    +			+ (size_t)(coder->file_size - coder->file_cur_pos);
    +
    +	while (true)
    +	switch (coder->sequence) {
    +	case SEQ_MAGIC_BYTES:
    +		// Decode the Stream Header at the beginning of the file
    +		// first to check if the Magic Bytes match. The flags
    +		// are stored in coder->first_header_flags so that we
    +		// don't need to seek to it again.
    +		//
    +		// Check that the file is big enough to contain at least
    +		// Stream Header.
    +		if (coder->file_size < LZMA_STREAM_HEADER_SIZE)
    +			return LZMA_FORMAT_ERROR;
    +
    +		// Read the Stream Header field into coder->temp.
    +		if (fill_temp(coder, in, in_pos, in_size))
    +			return LZMA_OK;
    +
    +		// This is the only Stream Header/Footer decoding where we
    +		// want to return LZMA_FORMAT_ERROR if the Magic Bytes don't
    +		// match. Elsewhere it will be converted to LZMA_DATA_ERROR.
    +		return_if_error(lzma_stream_header_decode(
    +				&coder->first_header_flags, coder->temp));
    +
    +		// Now that we know that the Magic Bytes match, check the
    +		// file size. It's better to do this here after checking the
    +		// Magic Bytes since this way we can give LZMA_FORMAT_ERROR
    +		// instead of LZMA_DATA_ERROR when the Magic Bytes don't
    +		// match in a file that is too big or isn't a multiple of
    +		// four bytes.
    +		if (coder->file_size > LZMA_VLI_MAX || (coder->file_size & 3))
    +			return LZMA_DATA_ERROR;
    +
    +		// Start looking for Stream Padding and Stream Footer
    +		// at the end of the file.
    +		coder->file_target_pos = coder->file_size;
    +
    +	// Fall through
    +
    +	case SEQ_PADDING_SEEK:
    +		coder->sequence = SEQ_PADDING_DECODE;
    +		return_if_error(reverse_seek(
    +				coder, in_start, in_pos, in_size));
    +
    +	// Fall through
    +
    +	case SEQ_PADDING_DECODE: {
    +		// Copy to coder->temp first. This keeps the code simpler if
    +		// the application only provides input a few bytes at a time.
    +		if (fill_temp(coder, in, in_pos, in_size))
    +			return LZMA_OK;
    +
    +		// Scan the buffer backwards to get the size of the
    +		// Stream Padding field (if any).
    +		const size_t new_padding = get_padding_size(
    +				coder->temp, coder->temp_size);
    +		coder->stream_padding += new_padding;
    +
    +		// Set the target position to the beginning of Stream Padding
    +		// that has been observed so far. If all Stream Padding has
    +		// been seen, then the target position will be at the end
    +		// of the Stream Footer field.
    +		coder->file_target_pos -= new_padding;
    +
    +		if (new_padding == coder->temp_size) {
    +			// The whole buffer was padding. Seek backwards in
    +			// the file to get more input.
    +			coder->sequence = SEQ_PADDING_SEEK;
    +			break;
    +		}
    +
    +		// Size of Stream Padding must be a multiple of 4 bytes.
    +		if (coder->stream_padding & 3)
    +			return LZMA_DATA_ERROR;
    +
    +		coder->sequence = SEQ_FOOTER;
    +
    +		// Calculate the amount of non-padding data in coder->temp.
    +		coder->temp_size -= new_padding;
    +		coder->temp_pos = coder->temp_size;
    +
    +		// We can avoid an external seek if the whole Stream Footer
    +		// is already in coder->temp. In that case SEQ_FOOTER won't
    +		// read more input and will find the Stream Footer from
    +		// coder->temp[coder->temp_size - LZMA_STREAM_HEADER_SIZE].
    +		//
    +		// Otherwise we will need to seek. The seeking is done so
    +		// that Stream Footer will be at the end of coder->temp.
    +		// This way it's likely that we also get a complete Index
    +		// field into coder->temp without needing a separate seek
    +		// for that (unless the Index field is big).
    +		if (coder->temp_size < LZMA_STREAM_HEADER_SIZE)
    +			return_if_error(reverse_seek(
    +					coder, in_start, in_pos, in_size));
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_FOOTER:
    +		// Copy the Stream Footer field into coder->temp.
    +		// If Stream Footer was already available in coder->temp
    +		// in SEQ_PADDING_DECODE, then this does nothing.
    +		if (fill_temp(coder, in, in_pos, in_size))
    +			return LZMA_OK;
    +
    +		// Make coder->file_target_pos and coder->temp_size point
    +		// to the beginning of Stream Footer and thus to the end
    +		// of the Index field. coder->temp_pos will be updated
    +		// a bit later.
    +		coder->file_target_pos -= LZMA_STREAM_HEADER_SIZE;
    +		coder->temp_size -= LZMA_STREAM_HEADER_SIZE;
    +
    +		// Decode Stream Footer.
    +		return_if_error(hide_format_error(lzma_stream_footer_decode(
    +				&coder->footer_flags,
    +				coder->temp + coder->temp_size)));
    +
    +		// Check that we won't seek past the beginning of the file.
    +		//
    +		// LZMA_STREAM_HEADER_SIZE is added because there must be
    +		// space for Stream Header too even though we won't seek
    +		// there before decoding the Index field.
    +		//
    +		// There's no risk of integer overflow here because
    +		// Backward Size cannot be greater than 2^34.
    +		if (coder->file_target_pos < coder->footer_flags.backward_size
    +				+ LZMA_STREAM_HEADER_SIZE)
    +			return LZMA_DATA_ERROR;
    +
    +		// Set the target position to the beginning of the Index field.
    +		coder->file_target_pos -= coder->footer_flags.backward_size;
    +		coder->sequence = SEQ_INDEX_INIT;
    +
    +		// We can avoid an external seek if the whole Index field is
    +		// already available in coder->temp.
    +		if (coder->temp_size >= coder->footer_flags.backward_size) {
    +			// Set coder->temp_pos to point to the beginning
    +			// of the Index.
    +			coder->temp_pos = coder->temp_size
    +					- coder->footer_flags.backward_size;
    +		} else {
    +			// These are set to zero to indicate that there's no
    +			// useful data (Index or anything else) in coder->temp.
    +			coder->temp_pos = 0;
    +			coder->temp_size = 0;
    +
    +			// Seek to the beginning of the Index field.
    +			if (seek_to_pos(coder, coder->file_target_pos,
    +					in_start, in_pos, in_size))
    +				return LZMA_SEEK_NEEDED;
    +		}
    +
    +	// Fall through
    +
    +	case SEQ_INDEX_INIT: {
    +		// Calculate the amount of memory already used by the earlier
    +		// Indexes so that we know how big memory limit to pass to
    +		// the Index decoder.
    +		//
    +		// NOTE: When there are multiple Streams, the separate
    +		// lzma_index structures can use more RAM (as measured by
    +		// lzma_index_memused()) than the final combined lzma_index.
    +		// Thus memlimit may need to be slightly higher than the final
    +		// calculated memory usage will be. This is perhaps a bit
    +		// confusing to the application, but I think it shouldn't
    +		// cause problems in practice.
    +		uint64_t memused = 0;
    +		if (coder->combined_index != NULL) {
    +			memused = lzma_index_memused(coder->combined_index);
    +			assert(memused <= coder->memlimit);
    +			if (memused > coder->memlimit) // Extra sanity check
    +				return LZMA_PROG_ERROR;
    +		}
    +
    +		// Initialize the Index decoder.
    +		return_if_error(lzma_index_decoder_init(
    +				&coder->index_decoder, allocator,
    +				&coder->this_index,
    +				coder->memlimit - memused));
    +
    +		coder->index_remaining = coder->footer_flags.backward_size;
    +		coder->sequence = SEQ_INDEX_DECODE;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_INDEX_DECODE: {
    +		// Decode (a part of) the Index. If the whole Index is already
    +		// in coder->temp, read it from there. Otherwise read from
    +		// in[*in_pos] onwards. Note that index_decode() updates
    +		// coder->index_remaining and optionally coder->file_cur_pos.
    +		lzma_ret ret;
    +		if (coder->temp_size != 0) {
    +			assert(coder->temp_size - coder->temp_pos
    +					== coder->index_remaining);
    +			ret = decode_index(coder, allocator, coder->temp,
    +					&coder->temp_pos, coder->temp_size,
    +					false);
    +		} else {
    +			// Don't give the decoder more input than the known
    +			// remaining size of the Index field.
    +			size_t in_stop = in_size;
    +			if (in_size - *in_pos > coder->index_remaining)
    +				in_stop = *in_pos
    +					+ (size_t)(coder->index_remaining);
    +
    +			ret = decode_index(coder, allocator,
    +					in, in_pos, in_stop, true);
    +		}
    +
    +		switch (ret) {
    +		case LZMA_OK:
    +			// If the Index docoder asks for more input when we
    +			// have already given it as much input as Backward Size
    +			// indicated, the file is invalid.
    +			if (coder->index_remaining == 0)
    +				return LZMA_DATA_ERROR;
    +
    +			// We cannot get here if we were reading Index from
    +			// coder->temp because when reading from coder->temp
    +			// we give the Index decoder exactly
    +			// coder->index_remaining bytes of input.
    +			assert(coder->temp_size == 0);
    +
    +			return LZMA_OK;
    +
    +		case LZMA_STREAM_END:
    +			// If the decoding seems to be successful, check also
    +			// that the Index decoder consumed as much input as
    +			// indicated by the Backward Size field.
    +			if (coder->index_remaining != 0)
    +				return LZMA_DATA_ERROR;
    +
    +			break;
    +
    +		default:
    +			return ret;
    +		}
    +
    +		// Calculate how much the Index tells us to seek backwards
    +		// (relative to the beginning of the Index): Total size of
    +		// all Blocks plus the size of the Stream Header field.
    +		// No integer overflow here because lzma_index_total_size()
    +		// cannot return a value greater than LZMA_VLI_MAX.
    +		const uint64_t seek_amount
    +				= lzma_index_total_size(coder->this_index)
    +					+ LZMA_STREAM_HEADER_SIZE;
    +
    +		// Check that Index is sane in sense that seek_amount won't
    +		// make us seek past the beginning of the file when locating
    +		// the Stream Header.
    +		//
    +		// coder->file_target_pos still points to the beginning of
    +		// the Index field.
    +		if (coder->file_target_pos < seek_amount)
    +			return LZMA_DATA_ERROR;
    +
    +		// Set the target to the beginning of Stream Header.
    +		coder->file_target_pos -= seek_amount;
    +
    +		if (coder->file_target_pos == 0) {
    +			// We would seek to the beginning of the file, but
    +			// since we already decoded that Stream Header in
    +			// SEQ_MAGIC_BYTES, we can use the cached value from
    +			// coder->first_header_flags to avoid the seek.
    +			coder->header_flags = coder->first_header_flags;
    +			coder->sequence = SEQ_HEADER_COMPARE;
    +			break;
    +		}
    +
    +		coder->sequence = SEQ_HEADER_DECODE;
    +
    +		// Make coder->file_target_pos point to the end of
    +		// the Stream Header field.
    +		coder->file_target_pos += LZMA_STREAM_HEADER_SIZE;
    +
    +		// If coder->temp_size is non-zero, it points to the end
    +		// of the Index field. Then the beginning of the Index
    +		// field is at coder->temp[coder->temp_size
    +		// - coder->footer_flags.backward_size].
    +		assert(coder->temp_size == 0 || coder->temp_size
    +				>= coder->footer_flags.backward_size);
    +
    +		// If coder->temp contained the whole Index, see if it has
    +		// enough data to contain also the Stream Header. If so,
    +		// we avoid an external seek.
    +		//
    +		// NOTE: This can happen only with small .xz files and only
    +		// for the non-first Stream as the Stream Flags of the first
    +		// Stream are cached and already handled a few lines above.
    +		// So this isn't as useful as the other seek-avoidance cases.
    +		if (coder->temp_size != 0 && coder->temp_size
    +				- coder->footer_flags.backward_size
    +				>= seek_amount) {
    +			// Make temp_pos and temp_size point to the *end* of
    +			// Stream Header so that SEQ_HEADER_DECODE will find
    +			// the start of Stream Header from coder->temp[
    +			// coder->temp_size - LZMA_STREAM_HEADER_SIZE].
    +			coder->temp_pos = coder->temp_size
    +					- coder->footer_flags.backward_size
    +					- seek_amount
    +					+ LZMA_STREAM_HEADER_SIZE;
    +			coder->temp_size = coder->temp_pos;
    +		} else {
    +			// Seek so that Stream Header will be at the end of
    +			// coder->temp. With typical multi-Stream files we
    +			// will usually also get the Stream Footer and Index
    +			// of the *previous* Stream in coder->temp and thus
    +			// won't need a separate seek for them.
    +			return_if_error(reverse_seek(coder,
    +					in_start, in_pos, in_size));
    +		}
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_HEADER_DECODE:
    +		// Copy the Stream Header field into coder->temp.
    +		// If Stream Header was already available in coder->temp
    +		// in SEQ_INDEX_DECODE, then this does nothing.
    +		if (fill_temp(coder, in, in_pos, in_size))
    +			return LZMA_OK;
    +
    +		// Make all these point to the beginning of Stream Header.
    +		coder->file_target_pos -= LZMA_STREAM_HEADER_SIZE;
    +		coder->temp_size -= LZMA_STREAM_HEADER_SIZE;
    +		coder->temp_pos = coder->temp_size;
    +
    +		// Decode the Stream Header.
    +		return_if_error(hide_format_error(lzma_stream_header_decode(
    +				&coder->header_flags,
    +				coder->temp + coder->temp_size)));
    +
    +		coder->sequence = SEQ_HEADER_COMPARE;
    +
    +	// Fall through
    +
    +	case SEQ_HEADER_COMPARE:
    +		// Compare Stream Header against Stream Footer. They must
    +		// match.
    +		return_if_error(lzma_stream_flags_compare(
    +				&coder->header_flags, &coder->footer_flags));
    +
    +		// Store the decoded Stream Flags into the Index. Use the
    +		// Footer Flags because it contains Backward Size, although
    +		// it shouldn't matter in practice.
    +		if (lzma_index_stream_flags(coder->this_index,
    +				&coder->footer_flags) != LZMA_OK)
    +			return LZMA_PROG_ERROR;
    +
    +		// Store also the size of the Stream Padding field. It is
    +		// needed to calculate the offsets of the Streams correctly.
    +		if (lzma_index_stream_padding(coder->this_index,
    +				coder->stream_padding) != LZMA_OK)
    +			return LZMA_PROG_ERROR;
    +
    +		// Reset it so that it's ready for the next Stream.
    +		coder->stream_padding = 0;
    +
    +		// Append the earlier decoded Indexes after this_index.
    +		if (coder->combined_index != NULL)
    +			return_if_error(lzma_index_cat(coder->this_index,
    +					coder->combined_index, allocator));
    +
    +		coder->combined_index = coder->this_index;
    +		coder->this_index = NULL;
    +
    +		// If the whole file was decoded, tell the caller that we
    +		// are finished.
    +		if (coder->file_target_pos == 0) {
    +			// The combined index must indicate the same file
    +			// size as was told to us at initialization.
    +			assert(lzma_index_file_size(coder->combined_index)
    +					== coder->file_size);
    +
    +			// Make the combined index available to
    +			// the application.
    +			*coder->dest_index = coder->combined_index;
    +			coder->combined_index = NULL;
    +
    +			// Mark the input buffer as used since we may have
    +			// done internal seeking and thus don't know how
    +			// many input bytes were actually used. This way
    +			// lzma_stream.total_in gets a slightly better
    +			// estimate of the amount of input used.
    +			*in_pos = in_size;
    +			return LZMA_STREAM_END;
    +		}
    +
    +		// We didn't hit the beginning of the file yet, so continue
    +		// reading backwards in the file. If we have unprocessed
    +		// data in coder->temp, use it before requesting more data
    +		// from the application.
    +		//
    +		// coder->file_target_pos, coder->temp_size, and
    +		// coder->temp_pos all point to the beginning of Stream Header
    +		// and thus the end of the previous Stream in the file.
    +		coder->sequence = coder->temp_size > 0
    +				? SEQ_PADDING_DECODE : SEQ_PADDING_SEEK;
    +		break;
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +}
    +
    +
    +static lzma_ret
    +file_info_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
    +		uint64_t *old_memlimit, uint64_t new_memlimit)
    +{
    +	lzma_file_info_coder *coder = coder_ptr;
    +
    +	// The memory usage calculation comes from three things:
    +	//
    +	// (1) The Indexes that have already been decoded and processed into
    +	//     coder->combined_index.
    +	//
    +	// (2) The latest Index in coder->this_index that has been decoded but
    +	//     not yet put into coder->combined_index.
    +	//
    +	// (3) The latest Index that we have started decoding but haven't
    +	//     finished and thus isn't available in coder->this_index yet.
    +	//     Memory usage and limit information needs to be communicated
    +	//     from/to coder->index_decoder.
    +	//
    +	// Care has to be taken to not do both (2) and (3) when calculating
    +	// the memory usage.
    +	uint64_t combined_index_memusage = 0;
    +	uint64_t this_index_memusage = 0;
    +
    +	// (1) If we have already successfully decoded one or more Indexes,
    +	// get their memory usage.
    +	if (coder->combined_index != NULL)
    +		combined_index_memusage = lzma_index_memused(
    +				coder->combined_index);
    +
    +	// Choose between (2), (3), or neither.
    +	if (coder->this_index != NULL) {
    +		// (2) The latest Index is available. Use its memory usage.
    +		this_index_memusage = lzma_index_memused(coder->this_index);
    +
    +	} else if (coder->sequence == SEQ_INDEX_DECODE) {
    +		// (3) The Index decoder is activate and hasn't yet stored
    +		// the new index in coder->this_index. Get the memory usage
    +		// information from the Index decoder.
    +		//
    +		// NOTE: If the Index decoder doesn't yet know how much memory
    +		// it will eventually need, it will return a tiny value here.
    +		uint64_t dummy;
    +		if (coder->index_decoder.memconfig(coder->index_decoder.coder,
    +					&this_index_memusage, &dummy, 0)
    +				!= LZMA_OK) {
    +			assert(0);
    +			return LZMA_PROG_ERROR;
    +		}
    +	}
    +
    +	// Now we know the total memory usage/requirement. If we had neither
    +	// old Indexes nor a new Index, this will be zero which isn't
    +	// acceptable as lzma_memusage() has to return non-zero on success
    +	// and even with an empty .xz file we will end up with a lzma_index
    +	// that takes some memory.
    +	*memusage = combined_index_memusage + this_index_memusage;
    +	if (*memusage == 0)
    +		*memusage = lzma_index_memusage(1, 0);
    +
    +	*old_memlimit = coder->memlimit;
    +
    +	// If requested, set a new memory usage limit.
    +	if (new_memlimit != 0) {
    +		if (new_memlimit < *memusage)
    +			return LZMA_MEMLIMIT_ERROR;
    +
    +		// In the condition (3) we need to tell the Index decoder
    +		// its new memory usage limit.
    +		if (coder->this_index == NULL
    +				&& coder->sequence == SEQ_INDEX_DECODE) {
    +			const uint64_t idec_new_memlimit = new_memlimit
    +					- combined_index_memusage;
    +
    +			assert(this_index_memusage > 0);
    +			assert(idec_new_memlimit > 0);
    +
    +			uint64_t dummy1;
    +			uint64_t dummy2;
    +
    +			if (coder->index_decoder.memconfig(
    +					coder->index_decoder.coder,
    +					&dummy1, &dummy2, idec_new_memlimit)
    +					!= LZMA_OK) {
    +				assert(0);
    +				return LZMA_PROG_ERROR;
    +			}
    +		}
    +
    +		coder->memlimit = new_memlimit;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +file_info_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_file_info_coder *coder = coder_ptr;
    +
    +	lzma_next_end(&coder->index_decoder, allocator);
    +	lzma_index_end(coder->this_index, allocator);
    +	lzma_index_end(coder->combined_index, allocator);
    +
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +lzma_file_info_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator, uint64_t *seek_pos,
    +		lzma_index **dest_index,
    +		uint64_t memlimit, uint64_t file_size)
    +{
    +	lzma_next_coder_init(&lzma_file_info_decoder_init, next, allocator);
    +
    +	if (dest_index == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	lzma_file_info_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_file_info_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &file_info_decode;
    +		next->end = &file_info_decoder_end;
    +		next->memconfig = &file_info_decoder_memconfig;
    +
    +		coder->index_decoder = LZMA_NEXT_CODER_INIT;
    +		coder->this_index = NULL;
    +		coder->combined_index = NULL;
    +	}
    +
    +	coder->sequence = SEQ_MAGIC_BYTES;
    +	coder->file_cur_pos = 0;
    +	coder->file_target_pos = 0;
    +	coder->file_size = file_size;
    +
    +	lzma_index_end(coder->this_index, allocator);
    +	coder->this_index = NULL;
    +
    +	lzma_index_end(coder->combined_index, allocator);
    +	coder->combined_index = NULL;
    +
    +	coder->stream_padding = 0;
    +
    +	coder->dest_index = dest_index;
    +	coder->external_seek_pos = seek_pos;
    +
    +	// If memlimit is 0, make it 1 to ensure that lzma_memlimit_get()
    +	// won't return 0 (which would indicate an error).
    +	coder->memlimit = my_max(1, memlimit);
    +
    +	// Prepare these for reading the first Stream Header into coder->temp.
    +	coder->temp_pos = 0;
    +	coder->temp_size = LZMA_STREAM_HEADER_SIZE;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_file_info_decoder(lzma_stream *strm, lzma_index **dest_index,
    +		uint64_t memlimit, uint64_t file_size)
    +{
    +	lzma_next_strm_init(lzma_file_info_decoder_init, strm, &strm->seek_pos,
    +			dest_index, memlimit, file_size);
    +
    +	// We allow LZMA_FINISH in addition to LZMA_RUN for convenience.
    +	// lzma_code() is able to handle the LZMA_FINISH + LZMA_SEEK_NEEDED
    +	// combination in a sane way. Applications still need to be careful
    +	// if they use LZMA_FINISH so that they remember to reset it back
    +	// to LZMA_RUN after seeking if needed.
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_decoder.c
    new file mode 100644
    index 00000000000..cc0d88cc71c
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_decoder.c
    @@ -0,0 +1,87 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_buffer_decoder.c
    +/// \brief      Single-call raw decoding
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "filter_decoder.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_raw_buffer_decode(
    +		const lzma_filter *filters, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	// Validate what isn't validated later in filter_common.c.
    +	if (in == NULL || in_pos == NULL || *in_pos > in_size || out == NULL
    +			|| out_pos == NULL || *out_pos > out_size)
    +		return LZMA_PROG_ERROR;
    +
    +	// Initialize the decoder.
    +	lzma_next_coder next = LZMA_NEXT_CODER_INIT;
    +	return_if_error(lzma_raw_decoder_init(&next, allocator, filters));
    +
    +	// Store the positions so that we can restore them if something
    +	// goes wrong.
    +	const size_t in_start = *in_pos;
    +	const size_t out_start = *out_pos;
    +
    +	// Do the actual decoding and free decoder's memory.
    +	lzma_ret ret = next.code(next.coder, allocator, in, in_pos, in_size,
    +			out, out_pos, out_size, LZMA_FINISH);
    +
    +	if (ret == LZMA_STREAM_END) {
    +		ret = LZMA_OK;
    +	} else {
    +		if (ret == LZMA_OK) {
    +			// Either the input was truncated or the
    +			// output buffer was too small.
    +			assert(*in_pos == in_size || *out_pos == out_size);
    +
    +			if (*in_pos != in_size) {
    +				// Since input wasn't consumed completely,
    +				// the output buffer became full and is
    +				// too small.
    +				ret = LZMA_BUF_ERROR;
    +
    +			} else if (*out_pos != out_size) {
    +				// Since output didn't became full, the input
    +				// has to be truncated.
    +				ret = LZMA_DATA_ERROR;
    +
    +			} else {
    +				// All the input was consumed and output
    +				// buffer is full. Now we don't immediately
    +				// know the reason for the error. Try
    +				// decoding one more byte. If it succeeds,
    +				// then the output buffer was too small. If
    +				// we cannot get a new output byte, the input
    +				// is truncated.
    +				uint8_t tmp[1];
    +				size_t tmp_pos = 0;
    +				(void)next.code(next.coder, allocator,
    +						in, in_pos, in_size,
    +						tmp, &tmp_pos, 1, LZMA_FINISH);
    +
    +				if (tmp_pos == 1)
    +					ret = LZMA_BUF_ERROR;
    +				else
    +					ret = LZMA_DATA_ERROR;
    +			}
    +		}
    +
    +		// Restore the positions.
    +		*in_pos = in_start;
    +		*out_pos = out_start;
    +	}
    +
    +	lzma_next_end(&next, allocator);
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_encoder.c
    new file mode 100644
    index 00000000000..7fb8922ae90
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_encoder.c
    @@ -0,0 +1,54 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_buffer_encoder.c
    +/// \brief      Single-call raw encoding
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "filter_encoder.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_raw_buffer_encode(
    +		const lzma_filter *filters, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	// Validate what isn't validated later in filter_common.c.
    +	if ((in == NULL && in_size != 0) || out == NULL
    +			|| out_pos == NULL || *out_pos > out_size)
    +		return LZMA_PROG_ERROR;
    +
    +	// Initialize the encoder
    +	lzma_next_coder next = LZMA_NEXT_CODER_INIT;
    +	return_if_error(lzma_raw_encoder_init(&next, allocator, filters));
    +
    +	// Store the output position so that we can restore it if
    +	// something goes wrong.
    +	const size_t out_start = *out_pos;
    +
    +	// Do the actual encoding and free coder's memory.
    +	size_t in_pos = 0;
    +	lzma_ret ret = next.code(next.coder, allocator, in, &in_pos, in_size,
    +			out, out_pos, out_size, LZMA_FINISH);
    +	lzma_next_end(&next, allocator);
    +
    +	if (ret == LZMA_STREAM_END) {
    +		ret = LZMA_OK;
    +	} else {
    +		if (ret == LZMA_OK) {
    +			// Output buffer was too small.
    +			assert(*out_pos == out_size);
    +			ret = LZMA_BUF_ERROR;
    +		}
    +
    +		// Restore the output position.
    +		*out_pos = out_start;
    +	}
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.c
    new file mode 100644
    index 00000000000..d15d9cc94f9
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.c
    @@ -0,0 +1,393 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_common.c
    +/// \brief      Filter-specific stuff common for both encoder and decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "filter_common.h"
    +
    +
    +static const struct {
    +	/// Filter ID
    +	lzma_vli id;
    +
    +	/// Size of the filter-specific options structure
    +	size_t options_size;
    +
    +	/// True if it is OK to use this filter as non-last filter in
    +	/// the chain.
    +	bool non_last_ok;
    +
    +	/// True if it is OK to use this filter as the last filter in
    +	/// the chain.
    +	bool last_ok;
    +
    +	/// True if the filter may change the size of the data (that is, the
    +	/// amount of encoded output can be different than the amount of
    +	/// uncompressed input).
    +	bool changes_size;
    +
    +} features[] = {
    +#if defined (HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
    +	{
    +		.id = LZMA_FILTER_LZMA1,
    +		.options_size = sizeof(lzma_options_lzma),
    +		.non_last_ok = false,
    +		.last_ok = true,
    +		.changes_size = true,
    +	},
    +	{
    +		.id = LZMA_FILTER_LZMA1EXT,
    +		.options_size = sizeof(lzma_options_lzma),
    +		.non_last_ok = false,
    +		.last_ok = true,
    +		.changes_size = true,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
    +	{
    +		.id = LZMA_FILTER_LZMA2,
    +		.options_size = sizeof(lzma_options_lzma),
    +		.non_last_ok = false,
    +		.last_ok = true,
    +		.changes_size = true,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
    +	{
    +		.id = LZMA_FILTER_X86,
    +		.options_size = sizeof(lzma_options_bcj),
    +		.non_last_ok = true,
    +		.last_ok = false,
    +		.changes_size = false,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
    +	{
    +		.id = LZMA_FILTER_POWERPC,
    +		.options_size = sizeof(lzma_options_bcj),
    +		.non_last_ok = true,
    +		.last_ok = false,
    +		.changes_size = false,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
    +	{
    +		.id = LZMA_FILTER_IA64,
    +		.options_size = sizeof(lzma_options_bcj),
    +		.non_last_ok = true,
    +		.last_ok = false,
    +		.changes_size = false,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
    +	{
    +		.id = LZMA_FILTER_ARM,
    +		.options_size = sizeof(lzma_options_bcj),
    +		.non_last_ok = true,
    +		.last_ok = false,
    +		.changes_size = false,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
    +	{
    +		.id = LZMA_FILTER_ARMTHUMB,
    +		.options_size = sizeof(lzma_options_bcj),
    +		.non_last_ok = true,
    +		.last_ok = false,
    +		.changes_size = false,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_ARM64) || defined(HAVE_DECODER_ARM64)
    +	{
    +		.id = LZMA_FILTER_ARM64,
    +		.options_size = sizeof(lzma_options_bcj),
    +		.non_last_ok = true,
    +		.last_ok = false,
    +		.changes_size = false,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
    +	{
    +		.id = LZMA_FILTER_SPARC,
    +		.options_size = sizeof(lzma_options_bcj),
    +		.non_last_ok = true,
    +		.last_ok = false,
    +		.changes_size = false,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_RISCV) || defined(HAVE_DECODER_RISCV)
    +	{
    +		.id = LZMA_FILTER_RISCV,
    +		.options_size = sizeof(lzma_options_bcj),
    +		.non_last_ok = true,
    +		.last_ok = false,
    +		.changes_size = false,
    +	},
    +#endif
    +#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
    +	{
    +		.id = LZMA_FILTER_DELTA,
    +		.options_size = sizeof(lzma_options_delta),
    +		.non_last_ok = true,
    +		.last_ok = false,
    +		.changes_size = false,
    +	},
    +#endif
    +	{
    +		.id = LZMA_VLI_UNKNOWN
    +	}
    +};
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_filters_copy(const lzma_filter *src, lzma_filter *real_dest,
    +		const lzma_allocator *allocator)
    +{
    +	if (src == NULL || real_dest == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	// Use a temporary destination so that the real destination
    +	// will never be modified if an error occurs.
    +	lzma_filter dest[LZMA_FILTERS_MAX + 1];
    +
    +	lzma_ret ret;
    +	size_t i;
    +	for (i = 0; src[i].id != LZMA_VLI_UNKNOWN; ++i) {
    +		// There must be a maximum of four filters plus
    +		// the array terminator.
    +		if (i == LZMA_FILTERS_MAX) {
    +			ret = LZMA_OPTIONS_ERROR;
    +			goto error;
    +		}
    +
    +		dest[i].id = src[i].id;
    +
    +		if (src[i].options == NULL) {
    +			dest[i].options = NULL;
    +		} else {
    +			// See if the filter is supported only when the
    +			// options is not NULL. This might be convenient
    +			// sometimes if the app is actually copying only
    +			// a partial filter chain with a place holder ID.
    +			//
    +			// When options is not NULL, the Filter ID must be
    +			// supported by us, because otherwise we don't know
    +			// how big the options are.
    +			size_t j;
    +			for (j = 0; src[i].id != features[j].id; ++j) {
    +				if (features[j].id == LZMA_VLI_UNKNOWN) {
    +					ret = LZMA_OPTIONS_ERROR;
    +					goto error;
    +				}
    +			}
    +
    +			// Allocate and copy the options.
    +			dest[i].options = lzma_alloc(features[j].options_size,
    +					allocator);
    +			if (dest[i].options == NULL) {
    +				ret = LZMA_MEM_ERROR;
    +				goto error;
    +			}
    +
    +			memcpy(dest[i].options, src[i].options,
    +					features[j].options_size);
    +		}
    +	}
    +
    +	// Terminate the filter array.
    +	assert(i < LZMA_FILTERS_MAX + 1);
    +	dest[i].id = LZMA_VLI_UNKNOWN;
    +	dest[i].options = NULL;
    +
    +	// Copy it to the caller-supplied array now that we know that
    +	// no errors occurred.
    +	memcpy(real_dest, dest, (i + 1) * sizeof(lzma_filter));
    +
    +	return LZMA_OK;
    +
    +error:
    +	// Free the options which we have already allocated.
    +	while (i-- > 0)
    +		lzma_free(dest[i].options, allocator);
    +
    +	return ret;
    +}
    +
    +
    +extern LZMA_API(void)
    +lzma_filters_free(lzma_filter *filters, const lzma_allocator *allocator)
    +{
    +	if (filters == NULL)
    +		return;
    +
    +	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
    +		if (i == LZMA_FILTERS_MAX) {
    +			// The API says that LZMA_FILTERS_MAX + 1 is the
    +			// maximum allowed size including the terminating
    +			// element. Thus, we should never get here but in
    +			// case there is a bug and we do anyway, don't go
    +			// past the (probable) end of the array.
    +			assert(0);
    +			break;
    +		}
    +
    +		lzma_free(filters[i].options, allocator);
    +		filters[i].options = NULL;
    +		filters[i].id = LZMA_VLI_UNKNOWN;
    +	}
    +
    +	return;
    +}
    +
    +
    +extern lzma_ret
    +lzma_validate_chain(const lzma_filter *filters, size_t *count)
    +{
    +	// There must be at least one filter.
    +	if (filters == NULL || filters[0].id == LZMA_VLI_UNKNOWN)
    +		return LZMA_PROG_ERROR;
    +
    +	// Number of non-last filters that may change the size of the data
    +	// significantly (that is, more than 1-2 % or so).
    +	size_t changes_size_count = 0;
    +
    +	// True if it is OK to add a new filter after the current filter.
    +	bool non_last_ok = true;
    +
    +	// True if the last filter in the given chain is actually usable as
    +	// the last filter. Only filters that support embedding End of Payload
    +	// Marker can be used as the last filter in the chain.
    +	bool last_ok = false;
    +
    +	size_t i = 0;
    +	do {
    +		size_t j;
    +		for (j = 0; filters[i].id != features[j].id; ++j)
    +			if (features[j].id == LZMA_VLI_UNKNOWN)
    +				return LZMA_OPTIONS_ERROR;
    +
    +		// If the previous filter in the chain cannot be a non-last
    +		// filter, the chain is invalid.
    +		if (!non_last_ok)
    +			return LZMA_OPTIONS_ERROR;
    +
    +		non_last_ok = features[j].non_last_ok;
    +		last_ok = features[j].last_ok;
    +		changes_size_count += features[j].changes_size;
    +
    +	} while (filters[++i].id != LZMA_VLI_UNKNOWN);
    +
    +	// There must be 1-4 filters. The last filter must be usable as
    +	// the last filter in the chain. A maximum of three filters are
    +	// allowed to change the size of the data.
    +	if (i > LZMA_FILTERS_MAX || !last_ok || changes_size_count > 3)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	*count = i;
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_ret
    +lzma_raw_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter *options,
    +		lzma_filter_find coder_find, bool is_encoder)
    +{
    +	// Do some basic validation and get the number of filters.
    +	size_t count;
    +	return_if_error(lzma_validate_chain(options, &count));
    +
    +	// Set the filter functions and copy the options pointer.
    +	lzma_filter_info filters[LZMA_FILTERS_MAX + 1];
    +	if (is_encoder) {
    +		for (size_t i = 0; i < count; ++i) {
    +			// The order of the filters is reversed in the
    +			// encoder. It allows more efficient handling
    +			// of the uncompressed data.
    +			const size_t j = count - i - 1;
    +
    +			const lzma_filter_coder *const fc
    +					= coder_find(options[i].id);
    +			if (fc == NULL || fc->init == NULL)
    +				return LZMA_OPTIONS_ERROR;
    +
    +			filters[j].id = options[i].id;
    +			filters[j].init = fc->init;
    +			filters[j].options = options[i].options;
    +		}
    +	} else {
    +		for (size_t i = 0; i < count; ++i) {
    +			const lzma_filter_coder *const fc
    +					= coder_find(options[i].id);
    +			if (fc == NULL || fc->init == NULL)
    +				return LZMA_OPTIONS_ERROR;
    +
    +			filters[i].id = options[i].id;
    +			filters[i].init = fc->init;
    +			filters[i].options = options[i].options;
    +		}
    +	}
    +
    +	// Terminate the array.
    +	filters[count].id = LZMA_VLI_UNKNOWN;
    +	filters[count].init = NULL;
    +
    +	// Initialize the filters.
    +	const lzma_ret ret = lzma_next_filter_init(next, allocator, filters);
    +	if (ret != LZMA_OK)
    +		lzma_next_end(next, allocator);
    +
    +	return ret;
    +}
    +
    +
    +extern uint64_t
    +lzma_raw_coder_memusage(lzma_filter_find coder_find,
    +		const lzma_filter *filters)
    +{
    +	// The chain has to have at least one filter.
    +	{
    +		size_t tmp;
    +		if (lzma_validate_chain(filters, &tmp) != LZMA_OK)
    +			return UINT64_MAX;
    +	}
    +
    +	uint64_t total = 0;
    +	size_t i = 0;
    +
    +	do {
    +		const lzma_filter_coder *const fc
    +				 = coder_find(filters[i].id);
    +		if (fc == NULL)
    +			return UINT64_MAX; // Unsupported Filter ID
    +
    +		if (fc->memusage == NULL) {
    +			// This filter doesn't have a function to calculate
    +			// the memory usage and validate the options. Such
    +			// filters need only little memory, so we use 1 KiB
    +			// as a good estimate. They also accept all possible
    +			// options, so there's no need to worry about lack
    +			// of validation.
    +			total += 1024;
    +		} else {
    +			// Call the filter-specific memory usage calculation
    +			// function.
    +			const uint64_t usage
    +					= fc->memusage(filters[i].options);
    +			if (usage == UINT64_MAX)
    +				return UINT64_MAX; // Invalid options
    +
    +			total += usage;
    +		}
    +	} while (filters[++i].id != LZMA_VLI_UNKNOWN);
    +
    +	// Add some fixed amount of extra. It's to compensate memory usage
    +	// of Stream, Block etc. coders, malloc() overhead, stack etc.
    +	return total + LZMA_MEMUSAGE_BASE;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.h
    new file mode 100644
    index 00000000000..95f9fe27017
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.h
    @@ -0,0 +1,50 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_common.h
    +/// \brief      Filter-specific stuff common for both encoder and decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_FILTER_COMMON_H
    +#define LZMA_FILTER_COMMON_H
    +
    +#include "common.h"
    +
    +
    +/// Both lzma_filter_encoder and lzma_filter_decoder begin with these members.
    +typedef struct {
    +	/// Filter ID
    +	lzma_vli id;
    +
    +	/// Initializes the filter encoder and calls lzma_next_filter_init()
    +	/// for filters + 1.
    +	lzma_init_function init;
    +
    +	/// Calculates memory usage of the encoder. If the options are
    +	/// invalid, UINT64_MAX is returned.
    +	uint64_t (*memusage)(const void *options);
    +
    +} lzma_filter_coder;
    +
    +
    +typedef const lzma_filter_coder *(*lzma_filter_find)(lzma_vli id);
    +
    +
    +extern lzma_ret lzma_validate_chain(const lzma_filter *filters, size_t *count);
    +
    +
    +extern lzma_ret lzma_raw_coder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter *filters,
    +		lzma_filter_find coder_find, bool is_encoder);
    +
    +
    +extern uint64_t lzma_raw_coder_memusage(lzma_filter_find coder_find,
    +		const lzma_filter *filters);
    +
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.c
    new file mode 100644
    index 00000000000..cbdeb5858f6
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.c
    @@ -0,0 +1,214 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_decoder.c
    +/// \brief      Filter ID mapping to filter-specific functions
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "filter_decoder.h"
    +#include "filter_common.h"
    +#include "lzma_decoder.h"
    +#include "lzma2_decoder.h"
    +#include "simple_decoder.h"
    +#include "delta_decoder.h"
    +
    +
    +typedef struct {
    +	/// Filter ID
    +	lzma_vli id;
    +
    +	/// Initializes the filter encoder and calls lzma_next_filter_init()
    +	/// for filters + 1.
    +	lzma_init_function init;
    +
    +	/// Calculates memory usage of the encoder. If the options are
    +	/// invalid, UINT64_MAX is returned.
    +	uint64_t (*memusage)(const void *options);
    +
    +	/// Decodes Filter Properties.
    +	///
    +	/// \return     - LZMA_OK: Properties decoded successfully.
    +	///             - LZMA_OPTIONS_ERROR: Unsupported properties
    +	///             - LZMA_MEM_ERROR: Memory allocation failed.
    +	lzma_ret (*props_decode)(
    +			void **options, const lzma_allocator *allocator,
    +			const uint8_t *props, size_t props_size);
    +
    +} lzma_filter_decoder;
    +
    +
    +static const lzma_filter_decoder decoders[] = {
    +#ifdef HAVE_DECODER_LZMA1
    +	{
    +		.id = LZMA_FILTER_LZMA1,
    +		.init = &lzma_lzma_decoder_init,
    +		.memusage = &lzma_lzma_decoder_memusage,
    +		.props_decode = &lzma_lzma_props_decode,
    +	},
    +	{
    +		.id = LZMA_FILTER_LZMA1EXT,
    +		.init = &lzma_lzma_decoder_init,
    +		.memusage = &lzma_lzma_decoder_memusage,
    +		.props_decode = &lzma_lzma_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_LZMA2
    +	{
    +		.id = LZMA_FILTER_LZMA2,
    +		.init = &lzma_lzma2_decoder_init,
    +		.memusage = &lzma_lzma2_decoder_memusage,
    +		.props_decode = &lzma_lzma2_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_X86
    +	{
    +		.id = LZMA_FILTER_X86,
    +		.init = &lzma_simple_x86_decoder_init,
    +		.memusage = NULL,
    +		.props_decode = &lzma_simple_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_POWERPC
    +	{
    +		.id = LZMA_FILTER_POWERPC,
    +		.init = &lzma_simple_powerpc_decoder_init,
    +		.memusage = NULL,
    +		.props_decode = &lzma_simple_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_IA64
    +	{
    +		.id = LZMA_FILTER_IA64,
    +		.init = &lzma_simple_ia64_decoder_init,
    +		.memusage = NULL,
    +		.props_decode = &lzma_simple_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_ARM
    +	{
    +		.id = LZMA_FILTER_ARM,
    +		.init = &lzma_simple_arm_decoder_init,
    +		.memusage = NULL,
    +		.props_decode = &lzma_simple_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_ARMTHUMB
    +	{
    +		.id = LZMA_FILTER_ARMTHUMB,
    +		.init = &lzma_simple_armthumb_decoder_init,
    +		.memusage = NULL,
    +		.props_decode = &lzma_simple_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_ARM64
    +	{
    +		.id = LZMA_FILTER_ARM64,
    +		.init = &lzma_simple_arm64_decoder_init,
    +		.memusage = NULL,
    +		.props_decode = &lzma_simple_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_SPARC
    +	{
    +		.id = LZMA_FILTER_SPARC,
    +		.init = &lzma_simple_sparc_decoder_init,
    +		.memusage = NULL,
    +		.props_decode = &lzma_simple_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_RISCV
    +	{
    +		.id = LZMA_FILTER_RISCV,
    +		.init = &lzma_simple_riscv_decoder_init,
    +		.memusage = NULL,
    +		.props_decode = &lzma_simple_props_decode,
    +	},
    +#endif
    +#ifdef HAVE_DECODER_DELTA
    +	{
    +		.id = LZMA_FILTER_DELTA,
    +		.init = &lzma_delta_decoder_init,
    +		.memusage = &lzma_delta_coder_memusage,
    +		.props_decode = &lzma_delta_props_decode,
    +	},
    +#endif
    +};
    +
    +
    +static const lzma_filter_decoder *
    +decoder_find(lzma_vli id)
    +{
    +	for (size_t i = 0; i < ARRAY_SIZE(decoders); ++i)
    +		if (decoders[i].id == id)
    +			return decoders + i;
    +
    +	return NULL;
    +}
    +
    +
    +// lzma_filter_coder begins with the same members as lzma_filter_decoder.
    +// This function is a wrapper with a type that is compatible with the
    +// typedef of lzma_filter_find in filter_common.h.
    +static const lzma_filter_coder *
    +coder_find(lzma_vli id)
    +{
    +	return (const lzma_filter_coder *)decoder_find(id);
    +}
    +
    +
    +extern LZMA_API(lzma_bool)
    +lzma_filter_decoder_is_supported(lzma_vli id)
    +{
    +	return decoder_find(id) != NULL;
    +}
    +
    +
    +extern lzma_ret
    +lzma_raw_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter *options)
    +{
    +	return lzma_raw_coder_init(next, allocator,
    +			options, &coder_find, false);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_raw_decoder(lzma_stream *strm, const lzma_filter *options)
    +{
    +	lzma_next_strm_init(lzma_raw_decoder_init, strm, options);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_raw_decoder_memusage(const lzma_filter *filters)
    +{
    +	return lzma_raw_coder_memusage(&coder_find, filters);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_properties_decode(lzma_filter *filter, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size)
    +{
    +	// Make it always NULL so that the caller can always safely free() it.
    +	filter->options = NULL;
    +
    +	const lzma_filter_decoder *const fd = decoder_find(filter->id);
    +	if (fd == NULL)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	if (fd->props_decode == NULL)
    +		return props_size == 0 ? LZMA_OK : LZMA_OPTIONS_ERROR;
    +
    +	return fd->props_decode(
    +			&filter->options, allocator, props, props_size);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.h
    new file mode 100644
    index 00000000000..e610bc1f44e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.h
    @@ -0,0 +1,22 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_decoder.h
    +/// \brief      Filter ID mapping to filter-specific functions
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_FILTER_DECODER_H
    +#define LZMA_FILTER_DECODER_H
    +
    +#include "common.h"
    +
    +
    +extern lzma_ret lzma_raw_decoder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter *options);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.c
    new file mode 100644
    index 00000000000..bc394448985
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.c
    @@ -0,0 +1,330 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_decoder.c
    +/// \brief      Filter ID mapping to filter-specific functions
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "filter_encoder.h"
    +#include "filter_common.h"
    +#include "lzma_encoder.h"
    +#include "lzma2_encoder.h"
    +#include "simple_encoder.h"
    +#include "delta_encoder.h"
    +
    +
    +typedef struct {
    +	/// Filter ID
    +	lzma_vli id;
    +
    +	/// Initializes the filter encoder and calls lzma_next_filter_init()
    +	/// for filters + 1.
    +	lzma_init_function init;
    +
    +	/// Calculates memory usage of the encoder. If the options are
    +	/// invalid, UINT64_MAX is returned.
    +	uint64_t (*memusage)(const void *options);
    +
    +	/// Calculates the recommended Uncompressed Size for .xz Blocks to
    +	/// which the input data can be split to make multithreaded
    +	/// encoding possible. If this is NULL, it is assumed that
    +	/// the encoder is fast enough with single thread. If the options
    +	/// are invalid, UINT64_MAX is returned.
    +	uint64_t (*block_size)(const void *options);
    +
    +	/// Tells the size of the Filter Properties field. If options are
    +	/// invalid, LZMA_OPTIONS_ERROR is returned and size is set to
    +	/// UINT32_MAX.
    +	lzma_ret (*props_size_get)(uint32_t *size, const void *options);
    +
    +	/// Some filters will always have the same size Filter Properties
    +	/// field. If props_size_get is NULL, this value is used.
    +	uint32_t props_size_fixed;
    +
    +	/// Encodes Filter Properties.
    +	///
    +	/// \return     - LZMA_OK: Properties encoded successfully.
    +	///             - LZMA_OPTIONS_ERROR: Unsupported options
    +	///             - LZMA_PROG_ERROR: Invalid options or not enough
    +	///               output space
    +	lzma_ret (*props_encode)(const void *options, uint8_t *out);
    +
    +} lzma_filter_encoder;
    +
    +
    +static const lzma_filter_encoder encoders[] = {
    +#ifdef HAVE_ENCODER_LZMA1
    +	{
    +		.id = LZMA_FILTER_LZMA1,
    +		.init = &lzma_lzma_encoder_init,
    +		.memusage = &lzma_lzma_encoder_memusage,
    +		.block_size = NULL, // Not needed for LZMA1
    +		.props_size_get = NULL,
    +		.props_size_fixed = 5,
    +		.props_encode = &lzma_lzma_props_encode,
    +	},
    +	{
    +		.id = LZMA_FILTER_LZMA1EXT,
    +		.init = &lzma_lzma_encoder_init,
    +		.memusage = &lzma_lzma_encoder_memusage,
    +		.block_size = NULL, // Not needed for LZMA1
    +		.props_size_get = NULL,
    +		.props_size_fixed = 5,
    +		.props_encode = &lzma_lzma_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_LZMA2
    +	{
    +		.id = LZMA_FILTER_LZMA2,
    +		.init = &lzma_lzma2_encoder_init,
    +		.memusage = &lzma_lzma2_encoder_memusage,
    +		.block_size = &lzma_lzma2_block_size,
    +		.props_size_get = NULL,
    +		.props_size_fixed = 1,
    +		.props_encode = &lzma_lzma2_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_X86
    +	{
    +		.id = LZMA_FILTER_X86,
    +		.init = &lzma_simple_x86_encoder_init,
    +		.memusage = NULL,
    +		.block_size = NULL,
    +		.props_size_get = &lzma_simple_props_size,
    +		.props_encode = &lzma_simple_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_POWERPC
    +	{
    +		.id = LZMA_FILTER_POWERPC,
    +		.init = &lzma_simple_powerpc_encoder_init,
    +		.memusage = NULL,
    +		.block_size = NULL,
    +		.props_size_get = &lzma_simple_props_size,
    +		.props_encode = &lzma_simple_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_IA64
    +	{
    +		.id = LZMA_FILTER_IA64,
    +		.init = &lzma_simple_ia64_encoder_init,
    +		.memusage = NULL,
    +		.block_size = NULL,
    +		.props_size_get = &lzma_simple_props_size,
    +		.props_encode = &lzma_simple_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_ARM
    +	{
    +		.id = LZMA_FILTER_ARM,
    +		.init = &lzma_simple_arm_encoder_init,
    +		.memusage = NULL,
    +		.block_size = NULL,
    +		.props_size_get = &lzma_simple_props_size,
    +		.props_encode = &lzma_simple_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_ARMTHUMB
    +	{
    +		.id = LZMA_FILTER_ARMTHUMB,
    +		.init = &lzma_simple_armthumb_encoder_init,
    +		.memusage = NULL,
    +		.block_size = NULL,
    +		.props_size_get = &lzma_simple_props_size,
    +		.props_encode = &lzma_simple_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_ARM64
    +	{
    +		.id = LZMA_FILTER_ARM64,
    +		.init = &lzma_simple_arm64_encoder_init,
    +		.memusage = NULL,
    +		.block_size = NULL,
    +		.props_size_get = &lzma_simple_props_size,
    +		.props_encode = &lzma_simple_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_SPARC
    +	{
    +		.id = LZMA_FILTER_SPARC,
    +		.init = &lzma_simple_sparc_encoder_init,
    +		.memusage = NULL,
    +		.block_size = NULL,
    +		.props_size_get = &lzma_simple_props_size,
    +		.props_encode = &lzma_simple_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_RISCV
    +	{
    +		.id = LZMA_FILTER_RISCV,
    +		.init = &lzma_simple_riscv_encoder_init,
    +		.memusage = NULL,
    +		.block_size = NULL,
    +		.props_size_get = &lzma_simple_props_size,
    +		.props_encode = &lzma_simple_props_encode,
    +	},
    +#endif
    +#ifdef HAVE_ENCODER_DELTA
    +	{
    +		.id = LZMA_FILTER_DELTA,
    +		.init = &lzma_delta_encoder_init,
    +		.memusage = &lzma_delta_coder_memusage,
    +		.block_size = NULL,
    +		.props_size_get = NULL,
    +		.props_size_fixed = 1,
    +		.props_encode = &lzma_delta_props_encode,
    +	},
    +#endif
    +};
    +
    +
    +static const lzma_filter_encoder *
    +encoder_find(lzma_vli id)
    +{
    +	for (size_t i = 0; i < ARRAY_SIZE(encoders); ++i)
    +		if (encoders[i].id == id)
    +			return encoders + i;
    +
    +	return NULL;
    +}
    +
    +
    +// lzma_filter_coder begins with the same members as lzma_filter_encoder.
    +// This function is a wrapper with a type that is compatible with the
    +// typedef of lzma_filter_find in filter_common.h.
    +static const lzma_filter_coder *
    +coder_find(lzma_vli id)
    +{
    +	return (const lzma_filter_coder *)encoder_find(id);
    +}
    +
    +
    +extern LZMA_API(lzma_bool)
    +lzma_filter_encoder_is_supported(lzma_vli id)
    +{
    +	return encoder_find(id) != NULL;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_filters_update(lzma_stream *strm, const lzma_filter *filters)
    +{
    +	if (strm->internal->next.update == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	// Validate the filter chain.
    +	if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// The actual filter chain in the encoder is reversed. Some things
    +	// still want the normal order chain, so we provide both.
    +	size_t count = 1;
    +	while (filters[count].id != LZMA_VLI_UNKNOWN)
    +		++count;
    +
    +	lzma_filter reversed_filters[LZMA_FILTERS_MAX + 1];
    +	for (size_t i = 0; i < count; ++i)
    +		reversed_filters[count - i - 1] = filters[i];
    +
    +	reversed_filters[count].id = LZMA_VLI_UNKNOWN;
    +
    +	return strm->internal->next.update(strm->internal->next.coder,
    +			strm->allocator, filters, reversed_filters);
    +}
    +
    +
    +extern lzma_ret
    +lzma_raw_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter *filters)
    +{
    +	return lzma_raw_coder_init(next, allocator,
    +			filters, &coder_find, true);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_raw_encoder(lzma_stream *strm, const lzma_filter *filters)
    +{
    +	lzma_next_strm_init(lzma_raw_coder_init, strm, filters,
    +			&coder_find, true);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_raw_encoder_memusage(const lzma_filter *filters)
    +{
    +	return lzma_raw_coder_memusage(&coder_find, filters);
    +}
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_mt_block_size(const lzma_filter *filters)
    +{
    +	if (filters == NULL)
    +		return UINT64_MAX;
    +
    +	uint64_t max = 0;
    +
    +	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
    +		const lzma_filter_encoder *const fe
    +				= encoder_find(filters[i].id);
    +		if (fe == NULL)
    +			return UINT64_MAX;
    +
    +		if (fe->block_size != NULL) {
    +			const uint64_t size
    +					= fe->block_size(filters[i].options);
    +			if (size > max)
    +				max = size;
    +		}
    +	}
    +
    +	return max == 0 ? UINT64_MAX : max;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_properties_size(uint32_t *size, const lzma_filter *filter)
    +{
    +	const lzma_filter_encoder *const fe = encoder_find(filter->id);
    +	if (fe == NULL) {
    +		// Unknown filter - if the Filter ID is a proper VLI,
    +		// return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR,
    +		// because it's possible that we just don't have support
    +		// compiled in for the requested filter.
    +		return filter->id <= LZMA_VLI_MAX
    +				? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR;
    +	}
    +
    +	if (fe->props_size_get == NULL) {
    +		// No props_size_get() function, use props_size_fixed.
    +		*size = fe->props_size_fixed;
    +		return LZMA_OK;
    +	}
    +
    +	return fe->props_size_get(size, filter->options);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_properties_encode(const lzma_filter *filter, uint8_t *props)
    +{
    +	const lzma_filter_encoder *const fe = encoder_find(filter->id);
    +	if (fe == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	if (fe->props_encode == NULL)
    +		return LZMA_OK;
    +
    +	return fe->props_encode(filter->options, props);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.h
    new file mode 100644
    index 00000000000..88f2dafa43b
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.h
    @@ -0,0 +1,22 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_encoder.h
    +/// \brief      Filter ID mapping to filter-specific functions
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_FILTER_ENCODER_H
    +#define LZMA_FILTER_ENCODER_H
    +
    +#include "common.h"
    +
    +
    +extern lzma_ret lzma_raw_encoder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter *filters);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_decoder.c
    new file mode 100644
    index 00000000000..0f5d204d474
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_decoder.c
    @@ -0,0 +1,45 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_flags_decoder.c
    +/// \brief      Decodes a Filter Flags field
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "filter_decoder.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_filter_flags_decode(
    +		lzma_filter *filter, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size)
    +{
    +	// Set the pointer to NULL so the caller can always safely free it.
    +	filter->options = NULL;
    +
    +	// Filter ID
    +	return_if_error(lzma_vli_decode(&filter->id, NULL,
    +			in, in_pos, in_size));
    +
    +	if (filter->id >= LZMA_FILTER_RESERVED_START)
    +		return LZMA_DATA_ERROR;
    +
    +	// Size of Properties
    +	lzma_vli props_size;
    +	return_if_error(lzma_vli_decode(&props_size, NULL,
    +			in, in_pos, in_size));
    +
    +	// Filter Properties
    +	if (in_size - *in_pos < props_size)
    +		return LZMA_DATA_ERROR;
    +
    +	const lzma_ret ret = lzma_properties_decode(
    +			filter, allocator, in + *in_pos, props_size);
    +
    +	*in_pos += props_size;
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_encoder.c
    new file mode 100644
    index 00000000000..e1d65884fb0
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_encoder.c
    @@ -0,0 +1,55 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       filter_flags_encoder.c
    +/// \brief      Encodes a Filter Flags field
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "filter_encoder.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_filter_flags_size(uint32_t *size, const lzma_filter *filter)
    +{
    +	if (filter->id >= LZMA_FILTER_RESERVED_START)
    +		return LZMA_PROG_ERROR;
    +
    +	return_if_error(lzma_properties_size(size, filter));
    +
    +	*size += lzma_vli_size(filter->id) + lzma_vli_size(*size);
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_filter_flags_encode(const lzma_filter *filter,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	// Filter ID
    +	if (filter->id >= LZMA_FILTER_RESERVED_START)
    +		return LZMA_PROG_ERROR;
    +
    +	return_if_error(lzma_vli_encode(filter->id, NULL,
    +			out, out_pos, out_size));
    +
    +	// Size of Properties
    +	uint32_t props_size;
    +	return_if_error(lzma_properties_size(&props_size, filter));
    +	return_if_error(lzma_vli_encode(props_size, NULL,
    +			out, out_pos, out_size));
    +
    +	// Filter Properties
    +	if (out_size - *out_pos < props_size)
    +		return LZMA_PROG_ERROR;
    +
    +	return_if_error(lzma_properties_encode(filter, out + *out_pos));
    +
    +	*out_pos += props_size;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_cputhreads.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_cputhreads.c
    new file mode 100644
    index 00000000000..4ce852b42c3
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_cputhreads.c
    @@ -0,0 +1,33 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       hardware_cputhreads.c
    +/// \brief      Get the number of CPU threads or cores
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +
    +#include "tuklib_cpucores.h"
    +
    +
    +#ifdef HAVE_SYMBOL_VERSIONS_LINUX
    +// This is for compatibility with binaries linked against liblzma that
    +// has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
    +LZMA_SYMVER_API("lzma_cputhreads@XZ_5.2.2",
    +	uint32_t, lzma_cputhreads_522)(void) lzma_nothrow
    +		__attribute__((__alias__("lzma_cputhreads_52")));
    +
    +LZMA_SYMVER_API("lzma_cputhreads@@XZ_5.2",
    +	uint32_t, lzma_cputhreads_52)(void) lzma_nothrow;
    +
    +#define lzma_cputhreads lzma_cputhreads_52
    +#endif
    +extern LZMA_API(uint32_t)
    +lzma_cputhreads(void)
    +{
    +	return tuklib_cpucores();
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_physmem.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_physmem.c
    new file mode 100644
    index 00000000000..1bc34864e84
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_physmem.c
    @@ -0,0 +1,24 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       hardware_physmem.c
    +/// \brief      Get the total amount of physical memory (RAM)
    +//
    +//  Author:     Jonathan Nieder
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +
    +#include "tuklib_physmem.h"
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_physmem(void)
    +{
    +	// It is simpler to make lzma_physmem() a wrapper for
    +	// tuklib_physmem() than to hack appropriate symbol visibility
    +	// support for the tuklib modules.
    +	return tuklib_physmem();
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.c
    new file mode 100644
    index 00000000000..6add6a68350
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.c
    @@ -0,0 +1,1268 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       index.c
    +/// \brief      Handling of .xz Indexes and some other Stream information
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +#include "index.h"
    +#include "stream_flags_common.h"
    +
    +
    +/// \brief      How many Records to allocate at once
    +///
    +/// This should be big enough to avoid making lots of tiny allocations
    +/// but small enough to avoid too much unused memory at once.
    +#define INDEX_GROUP_SIZE 512
    +
    +
    +/// \brief      How many Records can be allocated at once at maximum
    +#define PREALLOC_MAX ((SIZE_MAX - sizeof(index_group)) / sizeof(index_record))
    +
    +
    +/// \brief      Base structure for index_stream and index_group structures
    +typedef struct index_tree_node_s index_tree_node;
    +struct index_tree_node_s {
    +	/// Uncompressed start offset of this Stream (relative to the
    +	/// beginning of the file) or Block (relative to the beginning
    +	/// of the Stream)
    +	lzma_vli uncompressed_base;
    +
    +	/// Compressed start offset of this Stream or Block
    +	lzma_vli compressed_base;
    +
    +	index_tree_node *parent;
    +	index_tree_node *left;
    +	index_tree_node *right;
    +};
    +
    +
    +/// \brief      AVL tree to hold index_stream or index_group structures
    +typedef struct {
    +	/// Root node
    +	index_tree_node *root;
    +
    +	/// Leftmost node. Since the tree will be filled sequentially,
    +	/// this won't change after the first node has been added to
    +	/// the tree.
    +	index_tree_node *leftmost;
    +
    +	/// The rightmost node in the tree. Since the tree is filled
    +	/// sequentially, this is always the node where to add the new data.
    +	index_tree_node *rightmost;
    +
    +	/// Number of nodes in the tree
    +	uint32_t count;
    +
    +} index_tree;
    +
    +
    +typedef struct {
    +	lzma_vli uncompressed_sum;
    +	lzma_vli unpadded_sum;
    +} index_record;
    +
    +
    +typedef struct {
    +	/// Every Record group is part of index_stream.groups tree.
    +	index_tree_node node;
    +
    +	/// Number of Blocks in this Stream before this group.
    +	lzma_vli number_base;
    +
    +	/// Number of Records that can be put in records[].
    +	size_t allocated;
    +
    +	/// Index of the last Record in use.
    +	size_t last;
    +
    +	/// The sizes in this array are stored as cumulative sums relative
    +	/// to the beginning of the Stream. This makes it possible to
    +	/// use binary search in lzma_index_locate().
    +	///
    +	/// Note that the cumulative summing is done specially for
    +	/// unpadded_sum: The previous value is rounded up to the next
    +	/// multiple of four before adding the Unpadded Size of the new
    +	/// Block. The total encoded size of the Blocks in the Stream
    +	/// is records[last].unpadded_sum in the last Record group of
    +	/// the Stream.
    +	///
    +	/// For example, if the Unpadded Sizes are 39, 57, and 81, the
    +	/// stored values are 39, 97 (40 + 57), and 181 (100 + 181).
    +	/// The total encoded size of these Blocks is 184.
    +	///
    +	/// This is a flexible array, because it makes easy to optimize
    +	/// memory usage in case someone concatenates many Streams that
    +	/// have only one or few Blocks.
    +	index_record records[];
    +
    +} index_group;
    +
    +
    +typedef struct {
    +	/// Every index_stream is a node in the tree of Streams.
    +	index_tree_node node;
    +
    +	/// Number of this Stream (first one is 1)
    +	uint32_t number;
    +
    +	/// Total number of Blocks before this Stream
    +	lzma_vli block_number_base;
    +
    +	/// Record groups of this Stream are stored in a tree.
    +	/// It's a T-tree with AVL-tree balancing. There are
    +	/// INDEX_GROUP_SIZE Records per node by default.
    +	/// This keeps the number of memory allocations reasonable
    +	/// and finding a Record is fast.
    +	index_tree groups;
    +
    +	/// Number of Records in this Stream
    +	lzma_vli record_count;
    +
    +	/// Size of the List of Records field in this Stream. This is used
    +	/// together with record_count to calculate the size of the Index
    +	/// field and thus the total size of the Stream.
    +	lzma_vli index_list_size;
    +
    +	/// Stream Flags of this Stream. This is meaningful only if
    +	/// the Stream Flags have been told us with lzma_index_stream_flags().
    +	/// Initially stream_flags.version is set to UINT32_MAX to indicate
    +	/// that the Stream Flags are unknown.
    +	lzma_stream_flags stream_flags;
    +
    +	/// Amount of Stream Padding after this Stream. This defaults to
    +	/// zero and can be set with lzma_index_stream_padding().
    +	lzma_vli stream_padding;
    +
    +} index_stream;
    +
    +
    +struct lzma_index_s {
    +	/// AVL-tree containing the Stream(s). Often there is just one
    +	/// Stream, but using a tree keeps lookups fast even when there
    +	/// are many concatenated Streams.
    +	index_tree streams;
    +
    +	/// Uncompressed size of all the Blocks in the Stream(s)
    +	lzma_vli uncompressed_size;
    +
    +	/// Total size of all the Blocks in the Stream(s)
    +	lzma_vli total_size;
    +
    +	/// Total number of Records in all Streams in this lzma_index
    +	lzma_vli record_count;
    +
    +	/// Size of the List of Records field if all the Streams in this
    +	/// lzma_index were packed into a single Stream (makes it simpler to
    +	/// take many .xz files and combine them into a single Stream).
    +	///
    +	/// This value together with record_count is needed to calculate
    +	/// Backward Size that is stored into Stream Footer.
    +	lzma_vli index_list_size;
    +
    +	/// How many Records to allocate at once in lzma_index_append().
    +	/// This defaults to INDEX_GROUP_SIZE but can be overridden with
    +	/// lzma_index_prealloc().
    +	size_t prealloc;
    +
    +	/// Bitmask indicating what integrity check types have been used
    +	/// as set by lzma_index_stream_flags(). The bit of the last Stream
    +	/// is not included here, since it is possible to change it by
    +	/// calling lzma_index_stream_flags() again.
    +	uint32_t checks;
    +};
    +
    +
    +static void
    +index_tree_init(index_tree *tree)
    +{
    +	tree->root = NULL;
    +	tree->leftmost = NULL;
    +	tree->rightmost = NULL;
    +	tree->count = 0;
    +	return;
    +}
    +
    +
    +/// Helper for index_tree_end()
    +static void
    +index_tree_node_end(index_tree_node *node, const lzma_allocator *allocator,
    +		void (*free_func)(void *node, const lzma_allocator *allocator))
    +{
    +	// The tree won't ever be very huge, so recursion should be fine.
    +	// 20 levels in the tree is likely quite a lot already in practice.
    +	if (node->left != NULL)
    +		index_tree_node_end(node->left, allocator, free_func);
    +
    +	if (node->right != NULL)
    +		index_tree_node_end(node->right, allocator, free_func);
    +
    +	free_func(node, allocator);
    +	return;
    +}
    +
    +
    +/// Free the memory allocated for a tree. Each node is freed using the
    +/// given free_func which is either &lzma_free or &index_stream_end.
    +/// The latter is used to free the Record groups from each index_stream
    +/// before freeing the index_stream itself.
    +static void
    +index_tree_end(index_tree *tree, const lzma_allocator *allocator,
    +		void (*free_func)(void *node, const lzma_allocator *allocator))
    +{
    +	assert(free_func != NULL);
    +
    +	if (tree->root != NULL)
    +		index_tree_node_end(tree->root, allocator, free_func);
    +
    +	return;
    +}
    +
    +
    +/// Add a new node to the tree. node->uncompressed_base and
    +/// node->compressed_base must have been set by the caller already.
    +static void
    +index_tree_append(index_tree *tree, index_tree_node *node)
    +{
    +	node->parent = tree->rightmost;
    +	node->left = NULL;
    +	node->right = NULL;
    +
    +	++tree->count;
    +
    +	// Handle the special case of adding the first node.
    +	if (tree->root == NULL) {
    +		tree->root = node;
    +		tree->leftmost = node;
    +		tree->rightmost = node;
    +		return;
    +	}
    +
    +	// The tree is always filled sequentially.
    +	assert(tree->rightmost->uncompressed_base <= node->uncompressed_base);
    +	assert(tree->rightmost->compressed_base < node->compressed_base);
    +
    +	// Add the new node after the rightmost node. It's the correct
    +	// place due to the reason above.
    +	tree->rightmost->right = node;
    +	tree->rightmost = node;
    +
    +	// Balance the AVL-tree if needed. We don't need to keep the balance
    +	// factors in nodes, because we always fill the tree sequentially,
    +	// and thus know the state of the tree just by looking at the node
    +	// count. From the node count we can calculate how many steps to go
    +	// up in the tree to find the rotation root.
    +	uint32_t up = tree->count ^ (UINT32_C(1) << bsr32(tree->count));
    +	if (up != 0) {
    +		// Locate the root node for the rotation.
    +		up = ctz32(tree->count) + 2;
    +		do {
    +			node = node->parent;
    +		} while (--up > 0);
    +
    +		// Rotate left using node as the rotation root.
    +		index_tree_node *pivot = node->right;
    +
    +		if (node->parent == NULL) {
    +			tree->root = pivot;
    +		} else {
    +			assert(node->parent->right == node);
    +			node->parent->right = pivot;
    +		}
    +
    +		pivot->parent = node->parent;
    +
    +		node->right = pivot->left;
    +		if (node->right != NULL)
    +			node->right->parent = node;
    +
    +		pivot->left = node;
    +		node->parent = pivot;
    +	}
    +
    +	return;
    +}
    +
    +
    +/// Get the next node in the tree. Return NULL if there are no more nodes.
    +static void *
    +index_tree_next(const index_tree_node *node)
    +{
    +	if (node->right != NULL) {
    +		node = node->right;
    +		while (node->left != NULL)
    +			node = node->left;
    +
    +		return (void *)(node);
    +	}
    +
    +	while (node->parent != NULL && node->parent->right == node)
    +		node = node->parent;
    +
    +	return (void *)(node->parent);
    +}
    +
    +
    +/// Locate a node that contains the given uncompressed offset. It is
    +/// caller's job to check that target is not bigger than the uncompressed
    +/// size of the tree (the last node would be returned in that case still).
    +static void *
    +index_tree_locate(const index_tree *tree, lzma_vli target)
    +{
    +	const index_tree_node *result = NULL;
    +	const index_tree_node *node = tree->root;
    +
    +	assert(tree->leftmost == NULL
    +			|| tree->leftmost->uncompressed_base == 0);
    +
    +	// Consecutive nodes may have the same uncompressed_base.
    +	// We must pick the rightmost one.
    +	while (node != NULL) {
    +		if (node->uncompressed_base > target) {
    +			node = node->left;
    +		} else {
    +			result = node;
    +			node = node->right;
    +		}
    +	}
    +
    +	return (void *)(result);
    +}
    +
    +
    +/// Allocate and initialize a new Stream using the given base offsets.
    +static index_stream *
    +index_stream_init(lzma_vli compressed_base, lzma_vli uncompressed_base,
    +		uint32_t stream_number, lzma_vli block_number_base,
    +		const lzma_allocator *allocator)
    +{
    +	index_stream *s = lzma_alloc(sizeof(index_stream), allocator);
    +	if (s == NULL)
    +		return NULL;
    +
    +	s->node.uncompressed_base = uncompressed_base;
    +	s->node.compressed_base = compressed_base;
    +	s->node.parent = NULL;
    +	s->node.left = NULL;
    +	s->node.right = NULL;
    +
    +	s->number = stream_number;
    +	s->block_number_base = block_number_base;
    +
    +	index_tree_init(&s->groups);
    +
    +	s->record_count = 0;
    +	s->index_list_size = 0;
    +	s->stream_flags.version = UINT32_MAX;
    +	s->stream_padding = 0;
    +
    +	return s;
    +}
    +
    +
    +/// Free the memory allocated for a Stream and its Record groups.
    +static void
    +index_stream_end(void *node, const lzma_allocator *allocator)
    +{
    +	index_stream *s = node;
    +	index_tree_end(&s->groups, allocator, &lzma_free);
    +	lzma_free(s, allocator);
    +	return;
    +}
    +
    +
    +static lzma_index *
    +index_init_plain(const lzma_allocator *allocator)
    +{
    +	lzma_index *i = lzma_alloc(sizeof(lzma_index), allocator);
    +	if (i != NULL) {
    +		index_tree_init(&i->streams);
    +		i->uncompressed_size = 0;
    +		i->total_size = 0;
    +		i->record_count = 0;
    +		i->index_list_size = 0;
    +		i->prealloc = INDEX_GROUP_SIZE;
    +		i->checks = 0;
    +	}
    +
    +	return i;
    +}
    +
    +
    +extern LZMA_API(lzma_index *)
    +lzma_index_init(const lzma_allocator *allocator)
    +{
    +	lzma_index *i = index_init_plain(allocator);
    +	if (i == NULL)
    +		return NULL;
    +
    +	index_stream *s = index_stream_init(0, 0, 1, 0, allocator);
    +	if (s == NULL) {
    +		lzma_free(i, allocator);
    +		return NULL;
    +	}
    +
    +	index_tree_append(&i->streams, &s->node);
    +
    +	return i;
    +}
    +
    +
    +extern LZMA_API(void)
    +lzma_index_end(lzma_index *i, const lzma_allocator *allocator)
    +{
    +	// NOTE: If you modify this function, check also the bottom
    +	// of lzma_index_cat().
    +	if (i != NULL) {
    +		index_tree_end(&i->streams, allocator, &index_stream_end);
    +		lzma_free(i, allocator);
    +	}
    +
    +	return;
    +}
    +
    +
    +extern void
    +lzma_index_prealloc(lzma_index *i, lzma_vli records)
    +{
    +	if (records > PREALLOC_MAX)
    +		records = PREALLOC_MAX;
    +
    +	i->prealloc = (size_t)(records);
    +	return;
    +}
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_index_memusage(lzma_vli streams, lzma_vli blocks)
    +{
    +	// This calculates an upper bound that is only a little bit
    +	// bigger than the exact maximum memory usage with the given
    +	// parameters.
    +
    +	// Typical malloc() overhead is 2 * sizeof(void *) but we take
    +	// a little bit extra just in case. Using LZMA_MEMUSAGE_BASE
    +	// instead would give too inaccurate estimate.
    +	const size_t alloc_overhead = 4 * sizeof(void *);
    +
    +	// Amount of memory needed for each Stream base structures.
    +	// We assume that every Stream has at least one Block and
    +	// thus at least one group.
    +	const size_t stream_base = sizeof(index_stream)
    +			+ sizeof(index_group) + 2 * alloc_overhead;
    +
    +	// Amount of memory needed per group.
    +	const size_t group_base = sizeof(index_group)
    +			+ INDEX_GROUP_SIZE * sizeof(index_record)
    +			+ alloc_overhead;
    +
    +	// Number of groups. There may actually be more, but that overhead
    +	// has been taken into account in stream_base already.
    +	const lzma_vli groups
    +			= (blocks + INDEX_GROUP_SIZE - 1) / INDEX_GROUP_SIZE;
    +
    +	// Memory used by index_stream and index_group structures.
    +	const uint64_t streams_mem = streams * stream_base;
    +	const uint64_t groups_mem = groups * group_base;
    +
    +	// Memory used by the base structure.
    +	const uint64_t index_base = sizeof(lzma_index) + alloc_overhead;
    +
    +	// Validate the arguments and catch integer overflows.
    +	// Maximum number of Streams is "only" UINT32_MAX, because
    +	// that limit is used by the tree containing the Streams.
    +	const uint64_t limit = UINT64_MAX - index_base;
    +	if (streams == 0 || streams > UINT32_MAX || blocks > LZMA_VLI_MAX
    +			|| streams > limit / stream_base
    +			|| groups > limit / group_base
    +			|| limit - streams_mem < groups_mem)
    +		return UINT64_MAX;
    +
    +	return index_base + streams_mem + groups_mem;
    +}
    +
    +
    +extern LZMA_API(uint64_t)
    +lzma_index_memused(const lzma_index *i)
    +{
    +	return lzma_index_memusage(i->streams.count, i->record_count);
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_index_block_count(const lzma_index *i)
    +{
    +	return i->record_count;
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_index_stream_count(const lzma_index *i)
    +{
    +	return i->streams.count;
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_index_size(const lzma_index *i)
    +{
    +	return index_size(i->record_count, i->index_list_size);
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_index_total_size(const lzma_index *i)
    +{
    +	return i->total_size;
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_index_stream_size(const lzma_index *i)
    +{
    +	// Stream Header + Blocks + Index + Stream Footer
    +	return LZMA_STREAM_HEADER_SIZE + i->total_size
    +			+ index_size(i->record_count, i->index_list_size)
    +			+ LZMA_STREAM_HEADER_SIZE;
    +}
    +
    +
    +static lzma_vli
    +index_file_size(lzma_vli compressed_base, lzma_vli unpadded_sum,
    +		lzma_vli record_count, lzma_vli index_list_size,
    +		lzma_vli stream_padding)
    +{
    +	// Earlier Streams and Stream Paddings + Stream Header
    +	// + Blocks + Index + Stream Footer + Stream Padding
    +	//
    +	// This might go over LZMA_VLI_MAX due to too big unpadded_sum
    +	// when this function is used in lzma_index_append().
    +	lzma_vli file_size = compressed_base + 2 * LZMA_STREAM_HEADER_SIZE
    +			+ stream_padding + vli_ceil4(unpadded_sum);
    +	if (file_size > LZMA_VLI_MAX)
    +		return LZMA_VLI_UNKNOWN;
    +
    +	// The same applies here.
    +	file_size += index_size(record_count, index_list_size);
    +	if (file_size > LZMA_VLI_MAX)
    +		return LZMA_VLI_UNKNOWN;
    +
    +	return file_size;
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_index_file_size(const lzma_index *i)
    +{
    +	const index_stream *s = (const index_stream *)(i->streams.rightmost);
    +	const index_group *g = (const index_group *)(s->groups.rightmost);
    +	return index_file_size(s->node.compressed_base,
    +			g == NULL ? 0 : g->records[g->last].unpadded_sum,
    +			s->record_count, s->index_list_size,
    +			s->stream_padding);
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_index_uncompressed_size(const lzma_index *i)
    +{
    +	return i->uncompressed_size;
    +}
    +
    +
    +extern LZMA_API(uint32_t)
    +lzma_index_checks(const lzma_index *i)
    +{
    +	uint32_t checks = i->checks;
    +
    +	// Get the type of the Check of the last Stream too.
    +	const index_stream *s = (const index_stream *)(i->streams.rightmost);
    +	if (s->stream_flags.version != UINT32_MAX)
    +		checks |= UINT32_C(1) << s->stream_flags.check;
    +
    +	return checks;
    +}
    +
    +
    +extern uint32_t
    +lzma_index_padding_size(const lzma_index *i)
    +{
    +	return (LZMA_VLI_C(4) - index_size_unpadded(
    +			i->record_count, i->index_list_size)) & 3;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_stream_flags(lzma_index *i, const lzma_stream_flags *stream_flags)
    +{
    +	if (i == NULL || stream_flags == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	// Validate the Stream Flags.
    +	return_if_error(lzma_stream_flags_compare(
    +			stream_flags, stream_flags));
    +
    +	index_stream *s = (index_stream *)(i->streams.rightmost);
    +	s->stream_flags = *stream_flags;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_stream_padding(lzma_index *i, lzma_vli stream_padding)
    +{
    +	if (i == NULL || stream_padding > LZMA_VLI_MAX
    +			|| (stream_padding & 3) != 0)
    +		return LZMA_PROG_ERROR;
    +
    +	index_stream *s = (index_stream *)(i->streams.rightmost);
    +
    +	// Check that the new value won't make the file grow too big.
    +	const lzma_vli old_stream_padding = s->stream_padding;
    +	s->stream_padding = 0;
    +	if (lzma_index_file_size(i) + stream_padding > LZMA_VLI_MAX) {
    +		s->stream_padding = old_stream_padding;
    +		return LZMA_DATA_ERROR;
    +	}
    +
    +	s->stream_padding = stream_padding;
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_append(lzma_index *i, const lzma_allocator *allocator,
    +		lzma_vli unpadded_size, lzma_vli uncompressed_size)
    +{
    +	// Validate.
    +	if (i == NULL || unpadded_size < UNPADDED_SIZE_MIN
    +			|| unpadded_size > UNPADDED_SIZE_MAX
    +			|| uncompressed_size > LZMA_VLI_MAX)
    +		return LZMA_PROG_ERROR;
    +
    +	index_stream *s = (index_stream *)(i->streams.rightmost);
    +	index_group *g = (index_group *)(s->groups.rightmost);
    +
    +	const lzma_vli compressed_base = g == NULL ? 0
    +			: vli_ceil4(g->records[g->last].unpadded_sum);
    +	const lzma_vli uncompressed_base = g == NULL ? 0
    +			: g->records[g->last].uncompressed_sum;
    +	const uint32_t index_list_size_add = lzma_vli_size(unpadded_size)
    +			+ lzma_vli_size(uncompressed_size);
    +
    +	// Check that uncompressed size will not overflow.
    +	if (uncompressed_base + uncompressed_size > LZMA_VLI_MAX)
    +		return LZMA_DATA_ERROR;
    +
    +	// Check that the new unpadded sum will not overflow. This is
    +	// checked again in index_file_size(), but the unpadded sum is
    +	// passed to vli_ceil4() which expects a valid lzma_vli value.
    +	if (compressed_base + unpadded_size > UNPADDED_SIZE_MAX)
    +		return LZMA_DATA_ERROR;
    +
    +	// Check that the file size will stay within limits.
    +	if (index_file_size(s->node.compressed_base,
    +			compressed_base + unpadded_size, s->record_count + 1,
    +			s->index_list_size + index_list_size_add,
    +			s->stream_padding) == LZMA_VLI_UNKNOWN)
    +		return LZMA_DATA_ERROR;
    +
    +	// The size of the Index field must not exceed the maximum value
    +	// that can be stored in the Backward Size field.
    +	if (index_size(i->record_count + 1,
    +			i->index_list_size + index_list_size_add)
    +			> LZMA_BACKWARD_SIZE_MAX)
    +		return LZMA_DATA_ERROR;
    +
    +	if (g != NULL && g->last + 1 < g->allocated) {
    +		// There is space in the last group at least for one Record.
    +		++g->last;
    +	} else {
    +		// We need to allocate a new group.
    +		g = lzma_alloc(sizeof(index_group)
    +				+ i->prealloc * sizeof(index_record),
    +				allocator);
    +		if (g == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		g->last = 0;
    +		g->allocated = i->prealloc;
    +
    +		// Reset prealloc so that if the application happens to
    +		// add new Records, the allocation size will be sane.
    +		i->prealloc = INDEX_GROUP_SIZE;
    +
    +		// Set the start offsets of this group.
    +		g->node.uncompressed_base = uncompressed_base;
    +		g->node.compressed_base = compressed_base;
    +		g->number_base = s->record_count + 1;
    +
    +		// Add the new group to the Stream.
    +		index_tree_append(&s->groups, &g->node);
    +	}
    +
    +	// Add the new Record to the group.
    +	g->records[g->last].uncompressed_sum
    +			= uncompressed_base + uncompressed_size;
    +	g->records[g->last].unpadded_sum
    +			= compressed_base + unpadded_size;
    +
    +	// Update the totals.
    +	++s->record_count;
    +	s->index_list_size += index_list_size_add;
    +
    +	i->total_size += vli_ceil4(unpadded_size);
    +	i->uncompressed_size += uncompressed_size;
    +	++i->record_count;
    +	i->index_list_size += index_list_size_add;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +/// Structure to pass info to index_cat_helper()
    +typedef struct {
    +	/// Uncompressed size of the destination
    +	lzma_vli uncompressed_size;
    +
    +	/// Compressed file size of the destination
    +	lzma_vli file_size;
    +
    +	/// Same as above but for Block numbers
    +	lzma_vli block_number_add;
    +
    +	/// Number of Streams that were in the destination index before we
    +	/// started appending new Streams from the source index. This is
    +	/// used to fix the Stream numbering.
    +	uint32_t stream_number_add;
    +
    +	/// Destination index' Stream tree
    +	index_tree *streams;
    +
    +} index_cat_info;
    +
    +
    +/// Add the Stream nodes from the source index to dest using recursion.
    +/// Simplest iterative traversal of the source tree wouldn't work, because
    +/// we update the pointers in nodes when moving them to the destination tree.
    +static void
    +index_cat_helper(const index_cat_info *info, index_stream *this)
    +{
    +	index_stream *left = (index_stream *)(this->node.left);
    +	index_stream *right = (index_stream *)(this->node.right);
    +
    +	if (left != NULL)
    +		index_cat_helper(info, left);
    +
    +	this->node.uncompressed_base += info->uncompressed_size;
    +	this->node.compressed_base += info->file_size;
    +	this->number += info->stream_number_add;
    +	this->block_number_base += info->block_number_add;
    +	index_tree_append(info->streams, &this->node);
    +
    +	if (right != NULL)
    +		index_cat_helper(info, right);
    +
    +	return;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_cat(lzma_index *restrict dest, lzma_index *restrict src,
    +		const lzma_allocator *allocator)
    +{
    +	if (dest == NULL || src == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	const lzma_vli dest_file_size = lzma_index_file_size(dest);
    +
    +	// Check that we don't exceed the file size limits.
    +	if (dest_file_size + lzma_index_file_size(src) > LZMA_VLI_MAX
    +			|| dest->uncompressed_size + src->uncompressed_size
    +				> LZMA_VLI_MAX)
    +		return LZMA_DATA_ERROR;
    +
    +	// Check that the encoded size of the combined lzma_indexes stays
    +	// within limits. In theory, this should be done only if we know
    +	// that the user plans to actually combine the Streams and thus
    +	// construct a single Index (probably rare). However, exceeding
    +	// this limit is quite theoretical, so we do this check always
    +	// to simplify things elsewhere.
    +	{
    +		const lzma_vli dest_size = index_size_unpadded(
    +				dest->record_count, dest->index_list_size);
    +		const lzma_vli src_size = index_size_unpadded(
    +				src->record_count, src->index_list_size);
    +		if (vli_ceil4(dest_size + src_size) > LZMA_BACKWARD_SIZE_MAX)
    +			return LZMA_DATA_ERROR;
    +	}
    +
    +	// Optimize the last group to minimize memory usage. Allocation has
    +	// to be done before modifying dest or src.
    +	{
    +		index_stream *s = (index_stream *)(dest->streams.rightmost);
    +		index_group *g = (index_group *)(s->groups.rightmost);
    +		if (g != NULL && g->last + 1 < g->allocated) {
    +			assert(g->node.left == NULL);
    +			assert(g->node.right == NULL);
    +
    +			index_group *newg = lzma_alloc(sizeof(index_group)
    +					+ (g->last + 1)
    +					* sizeof(index_record),
    +					allocator);
    +			if (newg == NULL)
    +				return LZMA_MEM_ERROR;
    +
    +			newg->node = g->node;
    +			newg->allocated = g->last + 1;
    +			newg->last = g->last;
    +			newg->number_base = g->number_base;
    +
    +			memcpy(newg->records, g->records, newg->allocated
    +					* sizeof(index_record));
    +
    +			if (g->node.parent != NULL) {
    +				assert(g->node.parent->right == &g->node);
    +				g->node.parent->right = &newg->node;
    +			}
    +
    +			if (s->groups.leftmost == &g->node) {
    +				assert(s->groups.root == &g->node);
    +				s->groups.leftmost = &newg->node;
    +				s->groups.root = &newg->node;
    +			}
    +
    +			assert(s->groups.rightmost == &g->node);
    +			s->groups.rightmost = &newg->node;
    +
    +			lzma_free(g, allocator);
    +
    +			// NOTE: newg isn't leaked here because
    +			// newg == (void *)&newg->node.
    +		}
    +	}
    +
    +	// dest->checks includes the check types of all except the last Stream
    +	// in dest. Set the bit for the check type of the last Stream now so
    +	// that it won't get lost when Stream(s) from src are appended to dest.
    +	dest->checks = lzma_index_checks(dest);
    +
    +	// Add all the Streams from src to dest. Update the base offsets
    +	// of each Stream from src.
    +	const index_cat_info info = {
    +		.uncompressed_size = dest->uncompressed_size,
    +		.file_size = dest_file_size,
    +		.stream_number_add = dest->streams.count,
    +		.block_number_add = dest->record_count,
    +		.streams = &dest->streams,
    +	};
    +	index_cat_helper(&info, (index_stream *)(src->streams.root));
    +
    +	// Update info about all the combined Streams.
    +	dest->uncompressed_size += src->uncompressed_size;
    +	dest->total_size += src->total_size;
    +	dest->record_count += src->record_count;
    +	dest->index_list_size += src->index_list_size;
    +	dest->checks |= src->checks;
    +
    +	// There's nothing else left in src than the base structure.
    +	lzma_free(src, allocator);
    +
    +	return LZMA_OK;
    +}
    +
    +
    +/// Duplicate an index_stream.
    +static index_stream *
    +index_dup_stream(const index_stream *src, const lzma_allocator *allocator)
    +{
    +	// Catch a somewhat theoretical integer overflow.
    +	if (src->record_count > PREALLOC_MAX)
    +		return NULL;
    +
    +	// Allocate and initialize a new Stream.
    +	index_stream *dest = index_stream_init(src->node.compressed_base,
    +			src->node.uncompressed_base, src->number,
    +			src->block_number_base, allocator);
    +	if (dest == NULL)
    +		return NULL;
    +
    +	// Copy the overall information.
    +	dest->record_count = src->record_count;
    +	dest->index_list_size = src->index_list_size;
    +	dest->stream_flags = src->stream_flags;
    +	dest->stream_padding = src->stream_padding;
    +
    +	// Return if there are no groups to duplicate.
    +	if (src->groups.leftmost == NULL)
    +		return dest;
    +
    +	// Allocate memory for the Records. We put all the Records into
    +	// a single group. It's simplest and also tends to make
    +	// lzma_index_locate() a little bit faster with very big Indexes.
    +	index_group *destg = lzma_alloc(sizeof(index_group)
    +			+ src->record_count * sizeof(index_record),
    +			allocator);
    +	if (destg == NULL) {
    +		index_stream_end(dest, allocator);
    +		return NULL;
    +	}
    +
    +	// Initialize destg.
    +	destg->node.uncompressed_base = 0;
    +	destg->node.compressed_base = 0;
    +	destg->number_base = 1;
    +	destg->allocated = src->record_count;
    +	destg->last = src->record_count - 1;
    +
    +	// Go through all the groups in src and copy the Records into destg.
    +	const index_group *srcg = (const index_group *)(src->groups.leftmost);
    +	size_t i = 0;
    +	do {
    +		memcpy(destg->records + i, srcg->records,
    +				(srcg->last + 1) * sizeof(index_record));
    +		i += srcg->last + 1;
    +		srcg = index_tree_next(&srcg->node);
    +	} while (srcg != NULL);
    +
    +	assert(i == destg->allocated);
    +
    +	// Add the group to the new Stream.
    +	index_tree_append(&dest->groups, &destg->node);
    +
    +	return dest;
    +}
    +
    +
    +extern LZMA_API(lzma_index *)
    +lzma_index_dup(const lzma_index *src, const lzma_allocator *allocator)
    +{
    +	// Allocate the base structure (no initial Stream).
    +	lzma_index *dest = index_init_plain(allocator);
    +	if (dest == NULL)
    +		return NULL;
    +
    +	// Copy the totals.
    +	dest->uncompressed_size = src->uncompressed_size;
    +	dest->total_size = src->total_size;
    +	dest->record_count = src->record_count;
    +	dest->index_list_size = src->index_list_size;
    +
    +	// Copy the Streams and the groups in them.
    +	const index_stream *srcstream
    +			= (const index_stream *)(src->streams.leftmost);
    +	do {
    +		index_stream *deststream = index_dup_stream(
    +				srcstream, allocator);
    +		if (deststream == NULL) {
    +			lzma_index_end(dest, allocator);
    +			return NULL;
    +		}
    +
    +		index_tree_append(&dest->streams, &deststream->node);
    +
    +		srcstream = index_tree_next(&srcstream->node);
    +	} while (srcstream != NULL);
    +
    +	return dest;
    +}
    +
    +
    +/// Indexing for lzma_index_iter.internal[]
    +enum {
    +	ITER_INDEX,
    +	ITER_STREAM,
    +	ITER_GROUP,
    +	ITER_RECORD,
    +	ITER_METHOD,
    +};
    +
    +
    +/// Values for lzma_index_iter.internal[ITER_METHOD].s
    +enum {
    +	ITER_METHOD_NORMAL,
    +	ITER_METHOD_NEXT,
    +	ITER_METHOD_LEFTMOST,
    +};
    +
    +
    +static void
    +iter_set_info(lzma_index_iter *iter)
    +{
    +	const lzma_index *i = iter->internal[ITER_INDEX].p;
    +	const index_stream *stream = iter->internal[ITER_STREAM].p;
    +	const index_group *group = iter->internal[ITER_GROUP].p;
    +	const size_t record = iter->internal[ITER_RECORD].s;
    +
    +	// lzma_index_iter.internal must not contain a pointer to the last
    +	// group in the index, because that may be reallocated by
    +	// lzma_index_cat().
    +	if (group == NULL) {
    +		// There are no groups.
    +		assert(stream->groups.root == NULL);
    +		iter->internal[ITER_METHOD].s = ITER_METHOD_LEFTMOST;
    +
    +	} else if (i->streams.rightmost != &stream->node
    +			|| stream->groups.rightmost != &group->node) {
    +		// The group is not not the last group in the index.
    +		iter->internal[ITER_METHOD].s = ITER_METHOD_NORMAL;
    +
    +	} else if (stream->groups.leftmost != &group->node) {
    +		// The group isn't the only group in the Stream, thus we
    +		// know that it must have a parent group i.e. it's not
    +		// the root node.
    +		assert(stream->groups.root != &group->node);
    +		assert(group->node.parent->right == &group->node);
    +		iter->internal[ITER_METHOD].s = ITER_METHOD_NEXT;
    +		iter->internal[ITER_GROUP].p = group->node.parent;
    +
    +	} else {
    +		// The Stream has only one group.
    +		assert(stream->groups.root == &group->node);
    +		assert(group->node.parent == NULL);
    +		iter->internal[ITER_METHOD].s = ITER_METHOD_LEFTMOST;
    +		iter->internal[ITER_GROUP].p = NULL;
    +	}
    +
    +	// NOTE: lzma_index_iter.stream.number is lzma_vli but we use uint32_t
    +	// internally.
    +	iter->stream.number = stream->number;
    +	iter->stream.block_count = stream->record_count;
    +	iter->stream.compressed_offset = stream->node.compressed_base;
    +	iter->stream.uncompressed_offset = stream->node.uncompressed_base;
    +
    +	// iter->stream.flags will be NULL if the Stream Flags haven't been
    +	// set with lzma_index_stream_flags().
    +	iter->stream.flags = stream->stream_flags.version == UINT32_MAX
    +			? NULL : &stream->stream_flags;
    +	iter->stream.padding = stream->stream_padding;
    +
    +	if (stream->groups.rightmost == NULL) {
    +		// Stream has no Blocks.
    +		iter->stream.compressed_size = index_size(0, 0)
    +				+ 2 * LZMA_STREAM_HEADER_SIZE;
    +		iter->stream.uncompressed_size = 0;
    +	} else {
    +		const index_group *g = (const index_group *)(
    +				stream->groups.rightmost);
    +
    +		// Stream Header + Stream Footer + Index + Blocks
    +		iter->stream.compressed_size = 2 * LZMA_STREAM_HEADER_SIZE
    +				+ index_size(stream->record_count,
    +					stream->index_list_size)
    +				+ vli_ceil4(g->records[g->last].unpadded_sum);
    +		iter->stream.uncompressed_size
    +				= g->records[g->last].uncompressed_sum;
    +	}
    +
    +	if (group != NULL) {
    +		iter->block.number_in_stream = group->number_base + record;
    +		iter->block.number_in_file = iter->block.number_in_stream
    +				+ stream->block_number_base;
    +
    +		iter->block.compressed_stream_offset
    +				= record == 0 ? group->node.compressed_base
    +				: vli_ceil4(group->records[
    +					record - 1].unpadded_sum);
    +		iter->block.uncompressed_stream_offset
    +				= record == 0 ? group->node.uncompressed_base
    +				: group->records[record - 1].uncompressed_sum;
    +
    +		iter->block.uncompressed_size
    +				= group->records[record].uncompressed_sum
    +				- iter->block.uncompressed_stream_offset;
    +		iter->block.unpadded_size
    +				= group->records[record].unpadded_sum
    +				- iter->block.compressed_stream_offset;
    +		iter->block.total_size = vli_ceil4(iter->block.unpadded_size);
    +
    +		iter->block.compressed_stream_offset
    +				+= LZMA_STREAM_HEADER_SIZE;
    +
    +		iter->block.compressed_file_offset
    +				= iter->block.compressed_stream_offset
    +				+ iter->stream.compressed_offset;
    +		iter->block.uncompressed_file_offset
    +				= iter->block.uncompressed_stream_offset
    +				+ iter->stream.uncompressed_offset;
    +	}
    +
    +	return;
    +}
    +
    +
    +extern LZMA_API(void)
    +lzma_index_iter_init(lzma_index_iter *iter, const lzma_index *i)
    +{
    +	iter->internal[ITER_INDEX].p = i;
    +	lzma_index_iter_rewind(iter);
    +	return;
    +}
    +
    +
    +extern LZMA_API(void)
    +lzma_index_iter_rewind(lzma_index_iter *iter)
    +{
    +	iter->internal[ITER_STREAM].p = NULL;
    +	iter->internal[ITER_GROUP].p = NULL;
    +	iter->internal[ITER_RECORD].s = 0;
    +	iter->internal[ITER_METHOD].s = ITER_METHOD_NORMAL;
    +	return;
    +}
    +
    +
    +extern LZMA_API(lzma_bool)
    +lzma_index_iter_next(lzma_index_iter *iter, lzma_index_iter_mode mode)
    +{
    +	// Catch unsupported mode values.
    +	if ((unsigned int)(mode) > LZMA_INDEX_ITER_NONEMPTY_BLOCK)
    +		return true;
    +
    +	const lzma_index *i = iter->internal[ITER_INDEX].p;
    +	const index_stream *stream = iter->internal[ITER_STREAM].p;
    +	const index_group *group = NULL;
    +	size_t record = iter->internal[ITER_RECORD].s;
    +
    +	// If we are being asked for the next Stream, leave group to NULL
    +	// so that the rest of the this function thinks that this Stream
    +	// has no groups and will thus go to the next Stream.
    +	if (mode != LZMA_INDEX_ITER_STREAM) {
    +		// Get the pointer to the current group. See iter_set_inf()
    +		// for explanation.
    +		switch (iter->internal[ITER_METHOD].s) {
    +		case ITER_METHOD_NORMAL:
    +			group = iter->internal[ITER_GROUP].p;
    +			break;
    +
    +		case ITER_METHOD_NEXT:
    +			group = index_tree_next(iter->internal[ITER_GROUP].p);
    +			break;
    +
    +		case ITER_METHOD_LEFTMOST:
    +			group = (const index_group *)(
    +					stream->groups.leftmost);
    +			break;
    +		}
    +	}
    +
    +again:
    +	if (stream == NULL) {
    +		// We at the beginning of the lzma_index.
    +		// Locate the first Stream.
    +		stream = (const index_stream *)(i->streams.leftmost);
    +		if (mode >= LZMA_INDEX_ITER_BLOCK) {
    +			// Since we are being asked to return information
    +			// about the first a Block, skip Streams that have
    +			// no Blocks.
    +			while (stream->groups.leftmost == NULL) {
    +				stream = index_tree_next(&stream->node);
    +				if (stream == NULL)
    +					return true;
    +			}
    +		}
    +
    +		// Start from the first Record in the Stream.
    +		group = (const index_group *)(stream->groups.leftmost);
    +		record = 0;
    +
    +	} else if (group != NULL && record < group->last) {
    +		// The next Record is in the same group.
    +		++record;
    +
    +	} else {
    +		// This group has no more Records or this Stream has
    +		// no Blocks at all.
    +		record = 0;
    +
    +		// If group is not NULL, this Stream has at least one Block
    +		// and thus at least one group. Find the next group.
    +		if (group != NULL)
    +			group = index_tree_next(&group->node);
    +
    +		if (group == NULL) {
    +			// This Stream has no more Records. Find the next
    +			// Stream. If we are being asked to return information
    +			// about a Block, we skip empty Streams.
    +			do {
    +				stream = index_tree_next(&stream->node);
    +				if (stream == NULL)
    +					return true;
    +			} while (mode >= LZMA_INDEX_ITER_BLOCK
    +					&& stream->groups.leftmost == NULL);
    +
    +			group = (const index_group *)(
    +					stream->groups.leftmost);
    +		}
    +	}
    +
    +	if (mode == LZMA_INDEX_ITER_NONEMPTY_BLOCK) {
    +		// We need to look for the next Block again if this Block
    +		// is empty.
    +		if (record == 0) {
    +			if (group->node.uncompressed_base
    +					== group->records[0].uncompressed_sum)
    +				goto again;
    +		} else if (group->records[record - 1].uncompressed_sum
    +				== group->records[record].uncompressed_sum) {
    +			goto again;
    +		}
    +	}
    +
    +	iter->internal[ITER_STREAM].p = stream;
    +	iter->internal[ITER_GROUP].p = group;
    +	iter->internal[ITER_RECORD].s = record;
    +
    +	iter_set_info(iter);
    +
    +	return false;
    +}
    +
    +
    +extern LZMA_API(lzma_bool)
    +lzma_index_iter_locate(lzma_index_iter *iter, lzma_vli target)
    +{
    +	const lzma_index *i = iter->internal[ITER_INDEX].p;
    +
    +	// If the target is past the end of the file, return immediately.
    +	if (i->uncompressed_size <= target)
    +		return true;
    +
    +	// Locate the Stream containing the target offset.
    +	const index_stream *stream = index_tree_locate(&i->streams, target);
    +	assert(stream != NULL);
    +	target -= stream->node.uncompressed_base;
    +
    +	// Locate the group containing the target offset.
    +	const index_group *group = index_tree_locate(&stream->groups, target);
    +	assert(group != NULL);
    +
    +	// Use binary search to locate the exact Record. It is the first
    +	// Record whose uncompressed_sum is greater than target.
    +	// This is because we want the rightmost Record that fulfills the
    +	// search criterion. It is possible that there are empty Blocks;
    +	// we don't want to return them.
    +	size_t left = 0;
    +	size_t right = group->last;
    +
    +	while (left < right) {
    +		const size_t pos = left + (right - left) / 2;
    +		if (group->records[pos].uncompressed_sum <= target)
    +			left = pos + 1;
    +		else
    +			right = pos;
    +	}
    +
    +	iter->internal[ITER_STREAM].p = stream;
    +	iter->internal[ITER_GROUP].p = group;
    +	iter->internal[ITER_RECORD].s = left;
    +
    +	iter_set_info(iter);
    +
    +	return false;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.h
    new file mode 100644
    index 00000000000..007e1188f25
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.h
    @@ -0,0 +1,80 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       index.h
    +/// \brief      Handling of Index
    +/// \note       This header file does not include common.h or lzma.h because
    +///             this file is needed by both liblzma internally and by the
    +///             tests. Including common.h will include and define many things
    +///             the tests do not need and prevents issues with header file
    +///             include order. This way, if lzma.h or common.h are not
    +///             included before this file it will break on every OS instead
    +///             of causing more subtle errors.
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_INDEX_H
    +#define LZMA_INDEX_H
    +
    +
    +/// Minimum Unpadded Size
    +#define UNPADDED_SIZE_MIN LZMA_VLI_C(5)
    +
    +/// Maximum Unpadded Size
    +#define UNPADDED_SIZE_MAX (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
    +
    +/// Index Indicator based on xz specification
    +#define INDEX_INDICATOR 0
    +
    +
    +/// Get the size of the Index Padding field. This is needed by Index encoder
    +/// and decoder, but applications should have no use for this.
    +extern uint32_t lzma_index_padding_size(const lzma_index *i);
    +
    +
    +/// Set for how many Records to allocate memory the next time
    +/// lzma_index_append() needs to allocate space for a new Record.
    +/// This is used only by the Index decoder.
    +extern void lzma_index_prealloc(lzma_index *i, lzma_vli records);
    +
    +
    +/// Round the variable-length integer to the next multiple of four.
    +static inline lzma_vli
    +vli_ceil4(lzma_vli vli)
    +{
    +	assert(vli <= UNPADDED_SIZE_MAX);
    +	return (vli + 3) & ~LZMA_VLI_C(3);
    +}
    +
    +
    +/// Calculate the size of the Index field excluding Index Padding
    +static inline lzma_vli
    +index_size_unpadded(lzma_vli count, lzma_vli index_list_size)
    +{
    +	// Index Indicator + Number of Records + List of Records + CRC32
    +	return 1 + lzma_vli_size(count) + index_list_size + 4;
    +}
    +
    +
    +/// Calculate the size of the Index field including Index Padding
    +static inline lzma_vli
    +index_size(lzma_vli count, lzma_vli index_list_size)
    +{
    +	return vli_ceil4(index_size_unpadded(count, index_list_size));
    +}
    +
    +
    +/// Calculate the total size of the Stream
    +static inline lzma_vli
    +index_stream_size(lzma_vli blocks_size,
    +		lzma_vli count, lzma_vli index_list_size)
    +{
    +	return LZMA_STREAM_HEADER_SIZE + blocks_size
    +			+ index_size(count, index_list_size)
    +			+ LZMA_STREAM_HEADER_SIZE;
    +}
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.c
    new file mode 100644
    index 00000000000..4bcb3069211
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.c
    @@ -0,0 +1,372 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       index_decoder.c
    +/// \brief      Decodes the Index field
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "index_decoder.h"
    +#include "check.h"
    +
    +
    +typedef struct {
    +	enum {
    +		SEQ_INDICATOR,
    +		SEQ_COUNT,
    +		SEQ_MEMUSAGE,
    +		SEQ_UNPADDED,
    +		SEQ_UNCOMPRESSED,
    +		SEQ_PADDING_INIT,
    +		SEQ_PADDING,
    +		SEQ_CRC32,
    +	} sequence;
    +
    +	/// Memory usage limit
    +	uint64_t memlimit;
    +
    +	/// Target Index
    +	lzma_index *index;
    +
    +	/// Pointer give by the application, which is set after
    +	/// successful decoding.
    +	lzma_index **index_ptr;
    +
    +	/// Number of Records left to decode.
    +	lzma_vli count;
    +
    +	/// The most recent Unpadded Size field
    +	lzma_vli unpadded_size;
    +
    +	/// The most recent Uncompressed Size field
    +	lzma_vli uncompressed_size;
    +
    +	/// Position in integers
    +	size_t pos;
    +
    +	/// CRC32 of the List of Records field
    +	uint32_t crc32;
    +} lzma_index_coder;
    +
    +
    +static lzma_ret
    +index_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size,
    +		uint8_t *restrict out lzma_attribute((__unused__)),
    +		size_t *restrict out_pos lzma_attribute((__unused__)),
    +		size_t out_size lzma_attribute((__unused__)),
    +		lzma_action action lzma_attribute((__unused__)))
    +{
    +	lzma_index_coder *coder = coder_ptr;
    +
    +	// Similar optimization as in index_encoder.c
    +	const size_t in_start = *in_pos;
    +	lzma_ret ret = LZMA_OK;
    +
    +	while (*in_pos < in_size)
    +	switch (coder->sequence) {
    +	case SEQ_INDICATOR:
    +		// Return LZMA_DATA_ERROR instead of e.g. LZMA_PROG_ERROR or
    +		// LZMA_FORMAT_ERROR, because a typical usage case for Index
    +		// decoder is when parsing the Stream backwards. If seeking
    +		// backward from the Stream Footer gives us something that
    +		// doesn't begin with Index Indicator, the file is considered
    +		// corrupt, not "programming error" or "unrecognized file
    +		// format". One could argue that the application should
    +		// verify the Index Indicator before trying to decode the
    +		// Index, but well, I suppose it is simpler this way.
    +		if (in[(*in_pos)++] != INDEX_INDICATOR)
    +			return LZMA_DATA_ERROR;
    +
    +		coder->sequence = SEQ_COUNT;
    +		break;
    +
    +	case SEQ_COUNT:
    +		ret = lzma_vli_decode(&coder->count, &coder->pos,
    +				in, in_pos, in_size);
    +		if (ret != LZMA_STREAM_END)
    +			goto out;
    +
    +		coder->pos = 0;
    +		coder->sequence = SEQ_MEMUSAGE;
    +
    +	// Fall through
    +
    +	case SEQ_MEMUSAGE:
    +		if (lzma_index_memusage(1, coder->count) > coder->memlimit) {
    +			ret = LZMA_MEMLIMIT_ERROR;
    +			goto out;
    +		}
    +
    +		// Tell the Index handling code how many Records this
    +		// Index has to allow it to allocate memory more efficiently.
    +		lzma_index_prealloc(coder->index, coder->count);
    +
    +		ret = LZMA_OK;
    +		coder->sequence = coder->count == 0
    +				? SEQ_PADDING_INIT : SEQ_UNPADDED;
    +		break;
    +
    +	case SEQ_UNPADDED:
    +	case SEQ_UNCOMPRESSED: {
    +		lzma_vli *size = coder->sequence == SEQ_UNPADDED
    +				? &coder->unpadded_size
    +				: &coder->uncompressed_size;
    +
    +		ret = lzma_vli_decode(size, &coder->pos,
    +				in, in_pos, in_size);
    +		if (ret != LZMA_STREAM_END)
    +			goto out;
    +
    +		ret = LZMA_OK;
    +		coder->pos = 0;
    +
    +		if (coder->sequence == SEQ_UNPADDED) {
    +			// Validate that encoded Unpadded Size isn't too small
    +			// or too big.
    +			if (coder->unpadded_size < UNPADDED_SIZE_MIN
    +					|| coder->unpadded_size
    +						> UNPADDED_SIZE_MAX)
    +				return LZMA_DATA_ERROR;
    +
    +			coder->sequence = SEQ_UNCOMPRESSED;
    +		} else {
    +			// Add the decoded Record to the Index.
    +			return_if_error(lzma_index_append(
    +					coder->index, allocator,
    +					coder->unpadded_size,
    +					coder->uncompressed_size));
    +
    +			// Check if this was the last Record.
    +			coder->sequence = --coder->count == 0
    +					? SEQ_PADDING_INIT
    +					: SEQ_UNPADDED;
    +		}
    +
    +		break;
    +	}
    +
    +	case SEQ_PADDING_INIT:
    +		coder->pos = lzma_index_padding_size(coder->index);
    +		coder->sequence = SEQ_PADDING;
    +
    +	// Fall through
    +
    +	case SEQ_PADDING:
    +		if (coder->pos > 0) {
    +			--coder->pos;
    +			if (in[(*in_pos)++] != 0x00)
    +				return LZMA_DATA_ERROR;
    +
    +			break;
    +		}
    +
    +		// Finish the CRC32 calculation.
    +		coder->crc32 = lzma_crc32(in + in_start,
    +				*in_pos - in_start, coder->crc32);
    +
    +		coder->sequence = SEQ_CRC32;
    +
    +	// Fall through
    +
    +	case SEQ_CRC32:
    +		do {
    +			if (*in_pos == in_size)
    +				return LZMA_OK;
    +
    +			if (((coder->crc32 >> (coder->pos * 8)) & 0xFF)
    +					!= in[(*in_pos)++]) {
    +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    +				return LZMA_DATA_ERROR;
    +#endif
    +			}
    +
    +		} while (++coder->pos < 4);
    +
    +		// Decoding was successful, now we can let the application
    +		// see the decoded Index.
    +		*coder->index_ptr = coder->index;
    +
    +		// Make index NULL so we don't free it unintentionally.
    +		coder->index = NULL;
    +
    +		return LZMA_STREAM_END;
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +out:
    +	// Update the CRC32.
    +	//
    +	// Avoid null pointer + 0 (undefined behavior) in "in + in_start".
    +	// In such a case we had no input and thus in_used == 0.
    +	{
    +		const size_t in_used = *in_pos - in_start;
    +		if (in_used > 0)
    +			coder->crc32 = lzma_crc32(in + in_start,
    +					in_used, coder->crc32);
    +	}
    +
    +	return ret;
    +}
    +
    +
    +static void
    +index_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_index_coder *coder = coder_ptr;
    +	lzma_index_end(coder->index, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +index_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
    +		uint64_t *old_memlimit, uint64_t new_memlimit)
    +{
    +	lzma_index_coder *coder = coder_ptr;
    +
    +	*memusage = lzma_index_memusage(1, coder->count);
    +	*old_memlimit = coder->memlimit;
    +
    +	if (new_memlimit != 0) {
    +		if (new_memlimit < *memusage)
    +			return LZMA_MEMLIMIT_ERROR;
    +
    +		coder->memlimit = new_memlimit;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static lzma_ret
    +index_decoder_reset(lzma_index_coder *coder, const lzma_allocator *allocator,
    +		lzma_index **i, uint64_t memlimit)
    +{
    +	// Remember the pointer given by the application. We will set it
    +	// to point to the decoded Index only if decoding is successful.
    +	// Before that, keep it NULL so that applications can always safely
    +	// pass it to lzma_index_end() no matter did decoding succeed or not.
    +	coder->index_ptr = i;
    +	*i = NULL;
    +
    +	// We always allocate a new lzma_index.
    +	coder->index = lzma_index_init(allocator);
    +	if (coder->index == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	// Initialize the rest.
    +	coder->sequence = SEQ_INDICATOR;
    +	coder->memlimit = my_max(1, memlimit);
    +	coder->count = 0; // Needs to be initialized due to _memconfig().
    +	coder->pos = 0;
    +	coder->crc32 = 0;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_ret
    +lzma_index_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		lzma_index **i, uint64_t memlimit)
    +{
    +	lzma_next_coder_init(&lzma_index_decoder_init, next, allocator);
    +
    +	if (i == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	lzma_index_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &index_decode;
    +		next->end = &index_decoder_end;
    +		next->memconfig = &index_decoder_memconfig;
    +		coder->index = NULL;
    +	} else {
    +		lzma_index_end(coder->index, allocator);
    +	}
    +
    +	return index_decoder_reset(coder, allocator, i, memlimit);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_decoder(lzma_stream *strm, lzma_index **i, uint64_t memlimit)
    +{
    +	// If i isn't NULL, *i must always be initialized due to
    +	// the wording in the API docs. This way it is initialized
    +	// if we return LZMA_PROG_ERROR due to strm == NULL.
    +	if (i != NULL)
    +		*i = NULL;
    +
    +	lzma_next_strm_init(lzma_index_decoder_init, strm, i, memlimit);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_buffer_decode(lzma_index **i, uint64_t *memlimit,
    +		const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size)
    +{
    +	// If i isn't NULL, *i must always be initialized due to
    +	// the wording in the API docs.
    +	if (i != NULL)
    +		*i = NULL;
    +
    +	// Sanity checks
    +	if (i == NULL || memlimit == NULL
    +			|| in == NULL || in_pos == NULL || *in_pos > in_size)
    +		return LZMA_PROG_ERROR;
    +
    +	// Initialize the decoder.
    +	lzma_index_coder coder;
    +	return_if_error(index_decoder_reset(&coder, allocator, i, *memlimit));
    +
    +	// Store the input start position so that we can restore it in case
    +	// of an error.
    +	const size_t in_start = *in_pos;
    +
    +	// Do the actual decoding.
    +	lzma_ret ret = index_decode(&coder, allocator, in, in_pos, in_size,
    +			NULL, NULL, 0, LZMA_RUN);
    +
    +	if (ret == LZMA_STREAM_END) {
    +		ret = LZMA_OK;
    +	} else {
    +		// Something went wrong, free the Index structure and restore
    +		// the input position.
    +		lzma_index_end(coder.index, allocator);
    +		*in_pos = in_start;
    +
    +		if (ret == LZMA_OK) {
    +			// The input is truncated or otherwise corrupt.
    +			// Use LZMA_DATA_ERROR instead of LZMA_BUF_ERROR
    +			// like lzma_vli_decode() does in single-call mode.
    +			ret = LZMA_DATA_ERROR;
    +
    +		} else if (ret == LZMA_MEMLIMIT_ERROR) {
    +			// Tell the caller how much memory would have
    +			// been needed.
    +			*memlimit = lzma_index_memusage(1, coder.count);
    +		}
    +	}
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.h
    new file mode 100644
    index 00000000000..5351d2f0dfa
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.h
    @@ -0,0 +1,24 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       index_decoder.h
    +/// \brief      Decodes the Index field
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_INDEX_DECODER_H
    +#define LZMA_INDEX_DECODER_H
    +
    +#include "common.h"
    +#include "index.h"
    +
    +
    +extern lzma_ret lzma_index_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		lzma_index **i, uint64_t memlimit);
    +
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.c
    new file mode 100644
    index 00000000000..ecc299c0159
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.c
    @@ -0,0 +1,262 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       index_encoder.c
    +/// \brief      Encodes the Index field
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "index_encoder.h"
    +#include "index.h"
    +#include "check.h"
    +
    +
    +typedef struct {
    +	enum {
    +		SEQ_INDICATOR,
    +		SEQ_COUNT,
    +		SEQ_UNPADDED,
    +		SEQ_UNCOMPRESSED,
    +		SEQ_NEXT,
    +		SEQ_PADDING,
    +		SEQ_CRC32,
    +	} sequence;
    +
    +	/// Index being encoded
    +	const lzma_index *index;
    +
    +	/// Iterator for the Index being encoded
    +	lzma_index_iter iter;
    +
    +	/// Position in integers
    +	size_t pos;
    +
    +	/// CRC32 of the List of Records field
    +	uint32_t crc32;
    +} lzma_index_coder;
    +
    +
    +static lzma_ret
    +index_encode(void *coder_ptr,
    +		const lzma_allocator *allocator lzma_attribute((__unused__)),
    +		const uint8_t *restrict in lzma_attribute((__unused__)),
    +		size_t *restrict in_pos lzma_attribute((__unused__)),
    +		size_t in_size lzma_attribute((__unused__)),
    +		uint8_t *restrict out, size_t *restrict out_pos,
    +		size_t out_size,
    +		lzma_action action lzma_attribute((__unused__)))
    +{
    +	lzma_index_coder *coder = coder_ptr;
    +
    +	// Position where to start calculating CRC32. The idea is that we
    +	// need to call lzma_crc32() only once per call to index_encode().
    +	const size_t out_start = *out_pos;
    +
    +	// Return value to use if we return at the end of this function.
    +	// We use "goto out" to jump out of the while-switch construct
    +	// instead of returning directly, because that way we don't need
    +	// to copypaste the lzma_crc32() call to many places.
    +	lzma_ret ret = LZMA_OK;
    +
    +	while (*out_pos < out_size)
    +	switch (coder->sequence) {
    +	case SEQ_INDICATOR:
    +		out[*out_pos] = INDEX_INDICATOR;
    +		++*out_pos;
    +		coder->sequence = SEQ_COUNT;
    +		break;
    +
    +	case SEQ_COUNT: {
    +		const lzma_vli count = lzma_index_block_count(coder->index);
    +		ret = lzma_vli_encode(count, &coder->pos,
    +				out, out_pos, out_size);
    +		if (ret != LZMA_STREAM_END)
    +			goto out;
    +
    +		ret = LZMA_OK;
    +		coder->pos = 0;
    +		coder->sequence = SEQ_NEXT;
    +		break;
    +	}
    +
    +	case SEQ_NEXT:
    +		if (lzma_index_iter_next(
    +				&coder->iter, LZMA_INDEX_ITER_BLOCK)) {
    +			// Get the size of the Index Padding field.
    +			coder->pos = lzma_index_padding_size(coder->index);
    +			assert(coder->pos <= 3);
    +			coder->sequence = SEQ_PADDING;
    +			break;
    +		}
    +
    +		coder->sequence = SEQ_UNPADDED;
    +
    +	// Fall through
    +
    +	case SEQ_UNPADDED:
    +	case SEQ_UNCOMPRESSED: {
    +		const lzma_vli size = coder->sequence == SEQ_UNPADDED
    +				? coder->iter.block.unpadded_size
    +				: coder->iter.block.uncompressed_size;
    +
    +		ret = lzma_vli_encode(size, &coder->pos,
    +				out, out_pos, out_size);
    +		if (ret != LZMA_STREAM_END)
    +			goto out;
    +
    +		ret = LZMA_OK;
    +		coder->pos = 0;
    +
    +		// Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
    +		++coder->sequence;
    +		break;
    +	}
    +
    +	case SEQ_PADDING:
    +		if (coder->pos > 0) {
    +			--coder->pos;
    +			out[(*out_pos)++] = 0x00;
    +			break;
    +		}
    +
    +		// Finish the CRC32 calculation.
    +		coder->crc32 = lzma_crc32(out + out_start,
    +				*out_pos - out_start, coder->crc32);
    +
    +		coder->sequence = SEQ_CRC32;
    +
    +	// Fall through
    +
    +	case SEQ_CRC32:
    +		// We don't use the main loop, because we don't want
    +		// coder->crc32 to be touched anymore.
    +		do {
    +			if (*out_pos == out_size)
    +				return LZMA_OK;
    +
    +			out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
    +					& 0xFF;
    +			++*out_pos;
    +
    +		} while (++coder->pos < 4);
    +
    +		return LZMA_STREAM_END;
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +out:
    +	// Update the CRC32.
    +	//
    +	// Avoid null pointer + 0 (undefined behavior) in "out + out_start".
    +	// In such a case we had no input and thus out_used == 0.
    +	{
    +		const size_t out_used = *out_pos - out_start;
    +		if (out_used > 0)
    +			coder->crc32 = lzma_crc32(out + out_start,
    +					out_used, coder->crc32);
    +	}
    +
    +	return ret;
    +}
    +
    +
    +static void
    +index_encoder_end(void *coder, const lzma_allocator *allocator)
    +{
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static void
    +index_encoder_reset(lzma_index_coder *coder, const lzma_index *i)
    +{
    +	lzma_index_iter_init(&coder->iter, i);
    +
    +	coder->sequence = SEQ_INDICATOR;
    +	coder->index = i;
    +	coder->pos = 0;
    +	coder->crc32 = 0;
    +
    +	return;
    +}
    +
    +
    +extern lzma_ret
    +lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_index *i)
    +{
    +	lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
    +
    +	if (i == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	if (next->coder == NULL) {
    +		next->coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
    +		if (next->coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->code = &index_encode;
    +		next->end = &index_encoder_end;
    +	}
    +
    +	index_encoder_reset(next->coder, i);
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_encoder(lzma_stream *strm, const lzma_index *i)
    +{
    +	lzma_next_strm_init(lzma_index_encoder_init, strm, i);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_buffer_encode(const lzma_index *i,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	// Validate the arguments.
    +	if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
    +		return LZMA_PROG_ERROR;
    +
    +	// Don't try to encode if there's not enough output space.
    +	if (out_size - *out_pos < lzma_index_size(i))
    +		return LZMA_BUF_ERROR;
    +
    +	// The Index encoder needs just one small data structure so we can
    +	// allocate it on stack.
    +	lzma_index_coder coder;
    +	index_encoder_reset(&coder, i);
    +
    +	// Do the actual encoding. This should never fail, but store
    +	// the original *out_pos just in case.
    +	const size_t out_start = *out_pos;
    +	lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0,
    +			out, out_pos, out_size, LZMA_RUN);
    +
    +	if (ret == LZMA_STREAM_END) {
    +		ret = LZMA_OK;
    +	} else {
    +		// We should never get here, but just in case, restore the
    +		// output position and set the error accordingly if something
    +		// goes wrong and debugging isn't enabled.
    +		assert(0);
    +		*out_pos = out_start;
    +		ret = LZMA_PROG_ERROR;
    +	}
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.h
    new file mode 100644
    index 00000000000..29ba1106696
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.h
    @@ -0,0 +1,22 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       index_encoder.h
    +/// \brief      Encodes the Index field
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_INDEX_ENCODER_H
    +#define LZMA_INDEX_ENCODER_H
    +
    +#include "common.h"
    +
    +
    +extern lzma_ret lzma_index_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator, const lzma_index *i);
    +
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_hash.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_hash.c
    new file mode 100644
    index 00000000000..caa5967ca49
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_hash.c
    @@ -0,0 +1,342 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       index_hash.c
    +/// \brief      Validates Index by using a hash function
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +#include "index.h"
    +#include "check.h"
    +
    +
    +typedef struct {
    +	/// Sum of the Block sizes (including Block Padding)
    +	lzma_vli blocks_size;
    +
    +	/// Sum of the Uncompressed Size fields
    +	lzma_vli uncompressed_size;
    +
    +	/// Number of Records
    +	lzma_vli count;
    +
    +	/// Size of the List of Index Records as bytes
    +	lzma_vli index_list_size;
    +
    +	/// Check calculated from Unpadded Sizes and Uncompressed Sizes.
    +	lzma_check_state check;
    +
    +} lzma_index_hash_info;
    +
    +
    +struct lzma_index_hash_s {
    +	enum {
    +		SEQ_BLOCK,
    +		SEQ_COUNT,
    +		SEQ_UNPADDED,
    +		SEQ_UNCOMPRESSED,
    +		SEQ_PADDING_INIT,
    +		SEQ_PADDING,
    +		SEQ_CRC32,
    +	} sequence;
    +
    +	/// Information collected while decoding the actual Blocks.
    +	lzma_index_hash_info blocks;
    +
    +	/// Information collected from the Index field.
    +	lzma_index_hash_info records;
    +
    +	/// Number of Records not fully decoded
    +	lzma_vli remaining;
    +
    +	/// Unpadded Size currently being read from an Index Record.
    +	lzma_vli unpadded_size;
    +
    +	/// Uncompressed Size currently being read from an Index Record.
    +	lzma_vli uncompressed_size;
    +
    +	/// Position in variable-length integers when decoding them from
    +	/// the List of Records.
    +	size_t pos;
    +
    +	/// CRC32 of the Index
    +	uint32_t crc32;
    +};
    +
    +
    +extern LZMA_API(lzma_index_hash *)
    +lzma_index_hash_init(lzma_index_hash *index_hash,
    +		const lzma_allocator *allocator)
    +{
    +	if (index_hash == NULL) {
    +		index_hash = lzma_alloc(sizeof(lzma_index_hash), allocator);
    +		if (index_hash == NULL)
    +			return NULL;
    +	}
    +
    +	index_hash->sequence = SEQ_BLOCK;
    +	index_hash->blocks.blocks_size = 0;
    +	index_hash->blocks.uncompressed_size = 0;
    +	index_hash->blocks.count = 0;
    +	index_hash->blocks.index_list_size = 0;
    +	index_hash->records.blocks_size = 0;
    +	index_hash->records.uncompressed_size = 0;
    +	index_hash->records.count = 0;
    +	index_hash->records.index_list_size = 0;
    +	index_hash->unpadded_size = 0;
    +	index_hash->uncompressed_size = 0;
    +	index_hash->pos = 0;
    +	index_hash->crc32 = 0;
    +
    +	// These cannot fail because LZMA_CHECK_BEST is known to be supported.
    +	(void)lzma_check_init(&index_hash->blocks.check, LZMA_CHECK_BEST);
    +	(void)lzma_check_init(&index_hash->records.check, LZMA_CHECK_BEST);
    +
    +	return index_hash;
    +}
    +
    +
    +extern LZMA_API(void)
    +lzma_index_hash_end(lzma_index_hash *index_hash,
    +		const lzma_allocator *allocator)
    +{
    +	lzma_free(index_hash, allocator);
    +	return;
    +}
    +
    +
    +extern LZMA_API(lzma_vli)
    +lzma_index_hash_size(const lzma_index_hash *index_hash)
    +{
    +	// Get the size of the Index from ->blocks instead of ->records for
    +	// cases where application wants to know the Index Size before
    +	// decoding the Index.
    +	return index_size(index_hash->blocks.count,
    +			index_hash->blocks.index_list_size);
    +}
    +
    +
    +/// Updates the sizes and the hash without any validation.
    +static void
    +hash_append(lzma_index_hash_info *info, lzma_vli unpadded_size,
    +		lzma_vli uncompressed_size)
    +{
    +	info->blocks_size += vli_ceil4(unpadded_size);
    +	info->uncompressed_size += uncompressed_size;
    +	info->index_list_size += lzma_vli_size(unpadded_size)
    +			+ lzma_vli_size(uncompressed_size);
    +	++info->count;
    +
    +	const lzma_vli sizes[2] = { unpadded_size, uncompressed_size };
    +	lzma_check_update(&info->check, LZMA_CHECK_BEST,
    +			(const uint8_t *)(sizes), sizeof(sizes));
    +
    +	return;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_hash_append(lzma_index_hash *index_hash, lzma_vli unpadded_size,
    +		lzma_vli uncompressed_size)
    +{
    +	// Validate the arguments.
    +	if (index_hash == NULL || index_hash->sequence != SEQ_BLOCK
    +			|| unpadded_size < UNPADDED_SIZE_MIN
    +			|| unpadded_size > UNPADDED_SIZE_MAX
    +			|| uncompressed_size > LZMA_VLI_MAX)
    +		return LZMA_PROG_ERROR;
    +
    +	// Update the hash.
    +	hash_append(&index_hash->blocks, unpadded_size, uncompressed_size);
    +
    +	// Validate the properties of *info are still in allowed limits.
    +	if (index_hash->blocks.blocks_size > LZMA_VLI_MAX
    +			|| index_hash->blocks.uncompressed_size > LZMA_VLI_MAX
    +			|| index_size(index_hash->blocks.count,
    +					index_hash->blocks.index_list_size)
    +				> LZMA_BACKWARD_SIZE_MAX
    +			|| index_stream_size(index_hash->blocks.blocks_size,
    +					index_hash->blocks.count,
    +					index_hash->blocks.index_list_size)
    +				> LZMA_VLI_MAX)
    +		return LZMA_DATA_ERROR;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_index_hash_decode(lzma_index_hash *index_hash, const uint8_t *in,
    +		size_t *in_pos, size_t in_size)
    +{
    +	// Catch zero input buffer here, because in contrast to Index encoder
    +	// and decoder functions, applications call this function directly
    +	// instead of via lzma_code(), which does the buffer checking.
    +	if (*in_pos >= in_size)
    +		return LZMA_BUF_ERROR;
    +
    +	// NOTE: This function has many similarities to index_encode() and
    +	// index_decode() functions found from index_encoder.c and
    +	// index_decoder.c. See the comments especially in index_encoder.c.
    +	const size_t in_start = *in_pos;
    +	lzma_ret ret = LZMA_OK;
    +
    +	while (*in_pos < in_size)
    +	switch (index_hash->sequence) {
    +	case SEQ_BLOCK:
    +		// Check the Index Indicator is present.
    +		if (in[(*in_pos)++] != INDEX_INDICATOR)
    +			return LZMA_DATA_ERROR;
    +
    +		index_hash->sequence = SEQ_COUNT;
    +		break;
    +
    +	case SEQ_COUNT: {
    +		ret = lzma_vli_decode(&index_hash->remaining,
    +				&index_hash->pos, in, in_pos, in_size);
    +		if (ret != LZMA_STREAM_END)
    +			goto out;
    +
    +		// The count must match the count of the Blocks decoded.
    +		if (index_hash->remaining != index_hash->blocks.count)
    +			return LZMA_DATA_ERROR;
    +
    +		ret = LZMA_OK;
    +		index_hash->pos = 0;
    +
    +		// Handle the special case when there are no Blocks.
    +		index_hash->sequence = index_hash->remaining == 0
    +				? SEQ_PADDING_INIT : SEQ_UNPADDED;
    +		break;
    +	}
    +
    +	case SEQ_UNPADDED:
    +	case SEQ_UNCOMPRESSED: {
    +		lzma_vli *size = index_hash->sequence == SEQ_UNPADDED
    +				? &index_hash->unpadded_size
    +				: &index_hash->uncompressed_size;
    +
    +		ret = lzma_vli_decode(size, &index_hash->pos,
    +				in, in_pos, in_size);
    +		if (ret != LZMA_STREAM_END)
    +			goto out;
    +
    +		ret = LZMA_OK;
    +		index_hash->pos = 0;
    +
    +		if (index_hash->sequence == SEQ_UNPADDED) {
    +			if (index_hash->unpadded_size < UNPADDED_SIZE_MIN
    +					|| index_hash->unpadded_size
    +						> UNPADDED_SIZE_MAX)
    +				return LZMA_DATA_ERROR;
    +
    +			index_hash->sequence = SEQ_UNCOMPRESSED;
    +		} else {
    +			// Update the hash.
    +			hash_append(&index_hash->records,
    +					index_hash->unpadded_size,
    +					index_hash->uncompressed_size);
    +
    +			// Verify that we don't go over the known sizes. Note
    +			// that this validation is simpler than the one used
    +			// in lzma_index_hash_append(), because here we know
    +			// that values in index_hash->blocks are already
    +			// validated and we are fine as long as we don't
    +			// exceed them in index_hash->records.
    +			if (index_hash->blocks.blocks_size
    +					< index_hash->records.blocks_size
    +					|| index_hash->blocks.uncompressed_size
    +					< index_hash->records.uncompressed_size
    +					|| index_hash->blocks.index_list_size
    +					< index_hash->records.index_list_size)
    +				return LZMA_DATA_ERROR;
    +
    +			// Check if this was the last Record.
    +			index_hash->sequence = --index_hash->remaining == 0
    +					? SEQ_PADDING_INIT : SEQ_UNPADDED;
    +		}
    +
    +		break;
    +	}
    +
    +	case SEQ_PADDING_INIT:
    +		index_hash->pos = (LZMA_VLI_C(4) - index_size_unpadded(
    +				index_hash->records.count,
    +				index_hash->records.index_list_size)) & 3;
    +		index_hash->sequence = SEQ_PADDING;
    +
    +	// Fall through
    +
    +	case SEQ_PADDING:
    +		if (index_hash->pos > 0) {
    +			--index_hash->pos;
    +			if (in[(*in_pos)++] != 0x00)
    +				return LZMA_DATA_ERROR;
    +
    +			break;
    +		}
    +
    +		// Compare the sizes.
    +		if (index_hash->blocks.blocks_size
    +				!= index_hash->records.blocks_size
    +				|| index_hash->blocks.uncompressed_size
    +				!= index_hash->records.uncompressed_size
    +				|| index_hash->blocks.index_list_size
    +				!= index_hash->records.index_list_size)
    +			return LZMA_DATA_ERROR;
    +
    +		// Finish the hashes and compare them.
    +		lzma_check_finish(&index_hash->blocks.check, LZMA_CHECK_BEST);
    +		lzma_check_finish(&index_hash->records.check, LZMA_CHECK_BEST);
    +		if (memcmp(index_hash->blocks.check.buffer.u8,
    +				index_hash->records.check.buffer.u8,
    +				lzma_check_size(LZMA_CHECK_BEST)) != 0)
    +			return LZMA_DATA_ERROR;
    +
    +		// Finish the CRC32 calculation.
    +		index_hash->crc32 = lzma_crc32(in + in_start,
    +				*in_pos - in_start, index_hash->crc32);
    +
    +		index_hash->sequence = SEQ_CRC32;
    +
    +	// Fall through
    +
    +	case SEQ_CRC32:
    +		do {
    +			if (*in_pos == in_size)
    +				return LZMA_OK;
    +
    +			if (((index_hash->crc32 >> (index_hash->pos * 8))
    +					& 0xFF) != in[(*in_pos)++]) {
    +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    +				return LZMA_DATA_ERROR;
    +#endif
    +			}
    +
    +		} while (++index_hash->pos < 4);
    +
    +		return LZMA_STREAM_END;
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +out:
    +	// Update the CRC32.
    +	//
    +	// Avoid null pointer + 0 (undefined behavior) in "in + in_start".
    +	// In such a case we had no input and thus in_used == 0.
    +	{
    +		const size_t in_used = *in_pos - in_start;
    +		if (in_used > 0)
    +			index_hash->crc32 = lzma_crc32(in + in_start,
    +					in_used, index_hash->crc32);
    +	}
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.c
    new file mode 100644
    index 00000000000..651a0ae712c
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.c
    @@ -0,0 +1,417 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzip_decoder.c
    +/// \brief      Decodes .lz (lzip) files
    +//
    +//  Author:     Michał Górny
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lzip_decoder.h"
    +#include "lzma_decoder.h"
    +#include "check.h"
    +
    +
    +// .lz format version 0 lacks the 64-bit Member size field in the footer.
    +#define LZIP_V0_FOOTER_SIZE 12
    +#define LZIP_V1_FOOTER_SIZE 20
    +#define LZIP_FOOTER_SIZE_MAX LZIP_V1_FOOTER_SIZE
    +
    +// lc/lp/pb are hardcoded in the .lz format.
    +#define LZIP_LC 3
    +#define LZIP_LP 0
    +#define LZIP_PB 2
    +
    +
    +typedef struct {
    +	enum {
    +		SEQ_ID_STRING,
    +		SEQ_VERSION,
    +		SEQ_DICT_SIZE,
    +		SEQ_CODER_INIT,
    +		SEQ_LZMA_STREAM,
    +		SEQ_MEMBER_FOOTER,
    +	} sequence;
    +
    +	/// .lz member format version
    +	uint32_t version;
    +
    +	/// CRC32 of the uncompressed data in the .lz member
    +	uint32_t crc32;
    +
    +	/// Uncompressed size of the .lz member
    +	uint64_t uncompressed_size;
    +
    +	/// Compressed size of the .lz member
    +	uint64_t member_size;
    +
    +	/// Memory usage limit
    +	uint64_t memlimit;
    +
    +	/// Amount of memory actually needed
    +	uint64_t memusage;
    +
    +	/// If true, LZMA_GET_CHECK is returned after decoding the header
    +	/// fields. As all files use CRC32 this is redundant but it's
    +	/// implemented anyway since the initialization functions supports
    +	/// all other flags in addition to LZMA_TELL_ANY_CHECK.
    +	bool tell_any_check;
    +
    +	/// If true, we won't calculate or verify the CRC32 of
    +	/// the uncompressed data.
    +	bool ignore_check;
    +
    +	/// If true, we will decode concatenated .lz members and stop if
    +	/// non-.lz data is seen after at least one member has been
    +	/// successfully decoded.
    +	bool concatenated;
    +
    +	/// When decoding concatenated .lz members, this is true as long as
    +	/// we are decoding the first .lz member. This is needed to avoid
    +	/// incorrect LZMA_FORMAT_ERROR in case there is non-.lz data at
    +	/// the end of the file.
    +	bool first_member;
    +
    +	/// Reading position in the header and footer fields
    +	size_t pos;
    +
    +	/// Buffer to hold the .lz footer fields
    +	uint8_t buffer[LZIP_FOOTER_SIZE_MAX];
    +
    +	/// Options decoded from the .lz header that needed to initialize
    +	/// the LZMA1 decoder.
    +	lzma_options_lzma options;
    +
    +	/// LZMA1 decoder
    +	lzma_next_coder lzma_decoder;
    +
    +} lzma_lzip_coder;
    +
    +
    +static lzma_ret
    +lzip_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_lzip_coder *coder = coder_ptr;
    +
    +	while (true)
    +	switch (coder->sequence) {
    +	case SEQ_ID_STRING: {
    +		// The "ID string" or magic bytes are "LZIP" in US-ASCII.
    +		const uint8_t lzip_id_string[4] = { 0x4C, 0x5A, 0x49, 0x50 };
    +
    +		while (coder->pos < sizeof(lzip_id_string)) {
    +			if (*in_pos >= in_size) {
    +				// If we are on the 2nd+ concatenated member
    +				// and the input ends before we can read
    +				// the magic bytes, we discard the bytes that
    +				// were already read (up to 3) and finish.
    +				// See the reasoning below.
    +				return !coder->first_member
    +						&& action == LZMA_FINISH
    +					? LZMA_STREAM_END : LZMA_OK;
    +			}
    +
    +			if (in[*in_pos] != lzip_id_string[coder->pos]) {
    +				// The .lz format allows putting non-.lz data
    +				// at the end of the file. If we have seen
    +				// at least one valid .lz member already,
    +				// then we won't consume the byte at *in_pos
    +				// and will return LZMA_STREAM_END. This way
    +				// apps can easily locate and read the non-.lz
    +				// data after the .lz member(s).
    +				//
    +				// NOTE: If the first 1-3 bytes of the non-.lz
    +				// data match the .lz ID string then the first
    +				// 1-3 bytes of the junk will get ignored by
    +				// us. If apps want to properly locate the
    +				// trailing data they must ensure that the
    +				// first byte of their custom data isn't the
    +				// same as the first byte of .lz ID string.
    +				// With the liblzma API we cannot rewind the
    +				// input position across calls to lzma_code().
    +				return !coder->first_member
    +					? LZMA_STREAM_END : LZMA_FORMAT_ERROR;
    +			}
    +
    +			++*in_pos;
    +			++coder->pos;
    +		}
    +
    +		coder->pos = 0;
    +
    +		coder->crc32 = 0;
    +		coder->uncompressed_size = 0;
    +		coder->member_size = sizeof(lzip_id_string);
    +
    +		coder->sequence = SEQ_VERSION;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_VERSION:
    +		if (*in_pos >= in_size)
    +			return LZMA_OK;
    +
    +		coder->version = in[(*in_pos)++];
    +
    +		// We support version 0 and unextended version 1.
    +		if (coder->version > 1)
    +			return LZMA_OPTIONS_ERROR;
    +
    +		++coder->member_size;
    +		coder->sequence = SEQ_DICT_SIZE;
    +
    +		// .lz versions 0 and 1 use CRC32 as the integrity check
    +		// so if the application wanted to know that
    +		// (LZMA_TELL_ANY_CHECK) we can tell it now.
    +		if (coder->tell_any_check)
    +			return LZMA_GET_CHECK;
    +
    +	// Fall through
    +
    +	case SEQ_DICT_SIZE: {
    +		if (*in_pos >= in_size)
    +			return LZMA_OK;
    +
    +		const uint32_t ds = in[(*in_pos)++];
    +		++coder->member_size;
    +
    +		// The five lowest bits are for the base-2 logarithm of
    +		// the dictionary size and the highest three bits are
    +		// the fractional part (0/16 to 7/16) that will be
    +		// subtracted to get the final value.
    +		//
    +		// For example, with 0xB5:
    +		//     b2log = 21
    +		//     fracnum = 5
    +		//     dict_size = 2^21 - 2^21 * 5 / 16 = 1408 KiB
    +		const uint32_t b2log = ds & 0x1F;
    +		const uint32_t fracnum = ds >> 5;
    +
    +		// The format versions 0 and 1 allow dictionary size in the
    +		// range [4 KiB, 512 MiB].
    +		if (b2log < 12 || b2log > 29 || (b2log == 12 && fracnum > 0))
    +			return LZMA_DATA_ERROR;
    +
    +		//   2^[b2log] - 2^[b2log] * [fracnum] / 16
    +		// = 2^[b2log] - [fracnum] * 2^([b2log] - 4)
    +		coder->options.dict_size = (UINT32_C(1) << b2log)
    +				- (fracnum << (b2log - 4));
    +
    +		assert(coder->options.dict_size >= 4096);
    +		assert(coder->options.dict_size <= (UINT32_C(512) << 20));
    +
    +		coder->options.preset_dict = NULL;
    +		coder->options.lc = LZIP_LC;
    +		coder->options.lp = LZIP_LP;
    +		coder->options.pb = LZIP_PB;
    +
    +		// Calculate the memory usage.
    +		coder->memusage = lzma_lzma_decoder_memusage(&coder->options)
    +				+ LZMA_MEMUSAGE_BASE;
    +
    +		// Initialization is a separate step because if we return
    +		// LZMA_MEMLIMIT_ERROR we need to be able to restart after
    +		// the memlimit has been increased.
    +		coder->sequence = SEQ_CODER_INIT;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_CODER_INIT: {
    +		if (coder->memusage > coder->memlimit)
    +			return LZMA_MEMLIMIT_ERROR;
    +
    +		const lzma_filter_info filters[2] = {
    +			{
    +				.id = LZMA_FILTER_LZMA1,
    +				.init = &lzma_lzma_decoder_init,
    +				.options = &coder->options,
    +			}, {
    +				.init = NULL,
    +			}
    +		};
    +
    +		return_if_error(lzma_next_filter_init(&coder->lzma_decoder,
    +				allocator, filters));
    +
    +		coder->crc32 = 0;
    +		coder->sequence = SEQ_LZMA_STREAM;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_LZMA_STREAM: {
    +		const size_t in_start = *in_pos;
    +		const size_t out_start = *out_pos;
    +
    +		const lzma_ret ret = coder->lzma_decoder.code(
    +				coder->lzma_decoder.coder, allocator,
    +				in, in_pos, in_size, out, out_pos, out_size,
    +				action);
    +
    +		const size_t out_used = *out_pos - out_start;
    +
    +		coder->member_size += *in_pos - in_start;
    +		coder->uncompressed_size += out_used;
    +
    +		// Don't update the CRC32 if the integrity check will be
    +		// ignored or if there was no new output. The latter is
    +		// important in case out == NULL to avoid null pointer + 0
    +		// which is undefined behavior.
    +		if (!coder->ignore_check && out_used > 0)
    +			coder->crc32 = lzma_crc32(out + out_start, out_used,
    +					coder->crc32);
    +
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +
    +		coder->sequence = SEQ_MEMBER_FOOTER;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_MEMBER_FOOTER: {
    +		// The footer of .lz version 0 lacks the Member size field.
    +		// This is the only difference between version 0 and
    +		// unextended version 1 formats.
    +		const size_t footer_size = coder->version == 0
    +				? LZIP_V0_FOOTER_SIZE
    +				: LZIP_V1_FOOTER_SIZE;
    +
    +		// Copy the CRC32, Data size, and Member size fields to
    +		// the internal buffer.
    +		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
    +				footer_size);
    +
    +		// Return if we didn't get the whole footer yet.
    +		if (coder->pos < footer_size)
    +			return LZMA_OK;
    +
    +		coder->pos = 0;
    +		coder->member_size += footer_size;
    +
    +		// Check that the footer fields match the observed data.
    +		if (!coder->ignore_check
    +				&& coder->crc32 != read32le(&coder->buffer[0]))
    +			return LZMA_DATA_ERROR;
    +
    +		if (coder->uncompressed_size != read64le(&coder->buffer[4]))
    +			return LZMA_DATA_ERROR;
    +
    +		if (coder->version > 0) {
    +			// .lz version 0 has no Member size field.
    +			if (coder->member_size != read64le(&coder->buffer[12]))
    +				return LZMA_DATA_ERROR;
    +		}
    +
    +		// Decoding is finished if we weren't requested to decode
    +		// more than one .lz member.
    +		if (!coder->concatenated)
    +			return LZMA_STREAM_END;
    +
    +		coder->first_member = false;
    +		coder->sequence = SEQ_ID_STRING;
    +		break;
    +	}
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	// Never reached
    +}
    +
    +
    +static void
    +lzip_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_lzip_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->lzma_decoder, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_check
    +lzip_decoder_get_check(const void *coder_ptr lzma_attribute((__unused__)))
    +{
    +	return LZMA_CHECK_CRC32;
    +}
    +
    +
    +static lzma_ret
    +lzip_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
    +		uint64_t *old_memlimit, uint64_t new_memlimit)
    +{
    +	lzma_lzip_coder *coder = coder_ptr;
    +
    +	*memusage = coder->memusage;
    +	*old_memlimit = coder->memlimit;
    +
    +	if (new_memlimit != 0) {
    +		if (new_memlimit < coder->memusage)
    +			return LZMA_MEMLIMIT_ERROR;
    +
    +		coder->memlimit = new_memlimit;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzip_decoder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		uint64_t memlimit, uint32_t flags)
    +{
    +	lzma_next_coder_init(&lzma_lzip_decoder_init, next, allocator);
    +
    +	if (flags & ~LZMA_SUPPORTED_FLAGS)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	lzma_lzip_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_lzip_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &lzip_decode;
    +		next->end = &lzip_decoder_end;
    +		next->get_check = &lzip_decoder_get_check;
    +		next->memconfig = &lzip_decoder_memconfig;
    +
    +		coder->lzma_decoder = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	coder->sequence = SEQ_ID_STRING;
    +	coder->memlimit = my_max(1, memlimit);
    +	coder->memusage = LZMA_MEMUSAGE_BASE;
    +	coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0;
    +	coder->ignore_check = (flags & LZMA_IGNORE_CHECK) != 0;
    +	coder->concatenated = (flags & LZMA_CONCATENATED) != 0;
    +	coder->first_member = true;
    +	coder->pos = 0;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_lzip_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
    +{
    +	lzma_next_strm_init(lzma_lzip_decoder_init, strm, memlimit, flags);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.h
    new file mode 100644
    index 00000000000..0e1f7bebd45
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.h
    @@ -0,0 +1,21 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzip_decoder.h
    +/// \brief      Decodes .lz (lzip) files
    +//
    +//  Author:     Michał Górny
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZIP_DECODER_H
    +#define LZMA_LZIP_DECODER_H
    +
    +#include "common.h"
    +
    +extern lzma_ret lzma_lzip_decoder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		uint64_t memlimit, uint32_t flags);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/memcmplen.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/memcmplen.h
    new file mode 100644
    index 00000000000..394a4856dd6
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/memcmplen.h
    @@ -0,0 +1,188 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       memcmplen.h
    +/// \brief      Optimized comparison of two buffers
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_MEMCMPLEN_H
    +#define LZMA_MEMCMPLEN_H
    +
    +#include "common.h"
    +
    +#ifdef HAVE_IMMINTRIN_H
    +#	include 
    +#endif
    +
    +// Only include  if it is needed. The header is only needed
    +// on Windows when using an MSVC compatible compiler. The Intel compiler
    +// can use the intrinsics without the header file.
    +#if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
    +		&& defined(_MSC_VER) \
    +		&& (defined(_M_X64) \
    +			|| defined(_M_ARM64) || defined(_M_ARM64EC)) \
    +		&& !defined(__INTEL_COMPILER)
    +#	include 
    +#endif
    +
    +
    +/// Find out how many equal bytes the two buffers have.
    +///
    +/// \param      buf1    First buffer
    +/// \param      buf2    Second buffer
    +/// \param      len     How many bytes have already been compared and will
    +///                     be assumed to match
    +/// \param      limit   How many bytes to compare at most, including the
    +///                     already-compared bytes. This must be significantly
    +///                     smaller than UINT32_MAX to avoid integer overflows.
    +///                     Up to LZMA_MEMCMPLEN_EXTRA bytes may be read past
    +///                     the specified limit from both buf1 and buf2.
    +///
    +/// \return     Number of equal bytes in the buffers is returned.
    +///             This is always at least len and at most limit.
    +///
    +/// \note       LZMA_MEMCMPLEN_EXTRA defines how many extra bytes may be read.
    +///             It's rounded up to 2^n. This extra amount needs to be
    +///             allocated in the buffers being used. It needs to be
    +///             initialized too to keep Valgrind quiet.
    +static lzma_always_inline uint32_t
    +lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
    +		uint32_t len, uint32_t limit)
    +{
    +	assert(len <= limit);
    +	assert(limit <= UINT32_MAX / 2);
    +
    +#if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
    +		&& (((TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) \
    +				&& (defined(__x86_64__) \
    +					|| defined(__aarch64__))) \
    +			|| (defined(__INTEL_COMPILER) && defined(__x86_64__)) \
    +			|| (defined(__INTEL_COMPILER) && defined(_M_X64)) \
    +			|| (defined(_MSC_VER) && (defined(_M_X64) \
    +				|| defined(_M_ARM64) || defined(_M_ARM64EC))))
    +	// This is only for x86-64 and ARM64 for now. This might be fine on
    +	// other 64-bit processors too. On big endian one should use xor
    +	// instead of subtraction and switch to __builtin_clzll().
    +	//
    +	// Reasons to use subtraction instead of xor:
    +	//
    +	//   - On some x86-64 processors (Intel Sandy Bridge to Tiger Lake),
    +	//     sub+jz and sub+jnz can be fused but xor+jz or xor+jnz cannot.
    +	//     Thus using subtraction has potential to be a tiny amount faster
    +	//     since the code checks if the quotient is non-zero.
    +	//
    +	//   - Some processors (Intel Pentium 4) used to have more ALU
    +	//     resources for add/sub instructions than and/or/xor.
    +	//
    +	// The processor info is based on Agner Fog's microarchitecture.pdf
    +	// version 2023-05-26. https://www.agner.org/optimize/
    +#define LZMA_MEMCMPLEN_EXTRA 8
    +	while (len < limit) {
    +		const uint64_t x = read64ne(buf1 + len) - read64ne(buf2 + len);
    +		if (x != 0) {
    +	// MSVC or Intel C compiler on Windows
    +#	if defined(_MSC_VER) || defined(__INTEL_COMPILER)
    +			unsigned long tmp;
    +			_BitScanForward64(&tmp, x);
    +			len += (uint32_t)tmp >> 3;
    +	// GCC, Clang, or Intel C compiler
    +#	else
    +			len += (uint32_t)__builtin_ctzll(x) >> 3;
    +#	endif
    +			return my_min(len, limit);
    +		}
    +
    +		len += 8;
    +	}
    +
    +	return limit;
    +
    +#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
    +		&& defined(HAVE__MM_MOVEMASK_EPI8) \
    +		&& (defined(__SSE2__) \
    +			|| (defined(_MSC_VER) && defined(_M_IX86_FP) \
    +				&& _M_IX86_FP >= 2))
    +	// NOTE: This will use 128-bit unaligned access which
    +	// TUKLIB_FAST_UNALIGNED_ACCESS wasn't meant to permit,
    +	// but it's convenient here since this is x86-only.
    +	//
    +	// SSE2 version for 32-bit and 64-bit x86. On x86-64 the above
    +	// version is sometimes significantly faster and sometimes
    +	// slightly slower than this SSE2 version, so this SSE2
    +	// version isn't used on x86-64.
    +#	define LZMA_MEMCMPLEN_EXTRA 16
    +	while (len < limit) {
    +		const uint32_t x = 0xFFFF ^ (uint32_t)_mm_movemask_epi8(
    +			_mm_cmpeq_epi8(
    +			_mm_loadu_si128((const __m128i *)(buf1 + len)),
    +			_mm_loadu_si128((const __m128i *)(buf2 + len))));
    +
    +		if (x != 0) {
    +			len += ctz32(x);
    +			return my_min(len, limit);
    +		}
    +
    +		len += 16;
    +	}
    +
    +	return limit;
    +
    +#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && !defined(WORDS_BIGENDIAN)
    +	// Generic 32-bit little endian method
    +#	define LZMA_MEMCMPLEN_EXTRA 4
    +	while (len < limit) {
    +		uint32_t x = read32ne(buf1 + len) - read32ne(buf2 + len);
    +		if (x != 0) {
    +			if ((x & 0xFFFF) == 0) {
    +				len += 2;
    +				x >>= 16;
    +			}
    +
    +			if ((x & 0xFF) == 0)
    +				++len;
    +
    +			return my_min(len, limit);
    +		}
    +
    +		len += 4;
    +	}
    +
    +	return limit;
    +
    +#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && defined(WORDS_BIGENDIAN)
    +	// Generic 32-bit big endian method
    +#	define LZMA_MEMCMPLEN_EXTRA 4
    +	while (len < limit) {
    +		uint32_t x = read32ne(buf1 + len) ^ read32ne(buf2 + len);
    +		if (x != 0) {
    +			if ((x & 0xFFFF0000) == 0) {
    +				len += 2;
    +				x <<= 16;
    +			}
    +
    +			if ((x & 0xFF000000) == 0)
    +				++len;
    +
    +			return my_min(len, limit);
    +		}
    +
    +		len += 4;
    +	}
    +
    +	return limit;
    +
    +#else
    +	// Simple portable version that doesn't use unaligned access.
    +#	define LZMA_MEMCMPLEN_EXTRA 0
    +	while (len < limit && buf1[len] == buf2[len])
    +		++len;
    +
    +	return len;
    +#endif
    +}
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_decoder.c
    new file mode 100644
    index 00000000000..882cb2c808d
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_decoder.c
    @@ -0,0 +1,220 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       microlzma_decoder.c
    +/// \brief      Decode MicroLZMA format
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lzma_decoder.h"
    +#include "lz_decoder.h"
    +
    +
    +typedef struct {
    +	/// LZMA1 decoder
    +	lzma_next_coder lzma;
    +
    +	/// Compressed size of the stream as given by the application.
    +	/// This must be exactly correct.
    +	///
    +	/// This will be decremented when input is read.
    +	uint64_t comp_size;
    +
    +	/// Uncompressed size of the stream as given by the application.
    +	/// This may be less than the actual uncompressed size if
    +	/// uncomp_size_is_exact is false.
    +	///
    +	/// This will be decremented when output is produced.
    +	lzma_vli uncomp_size;
    +
    +	/// LZMA dictionary size as given by the application
    +	uint32_t dict_size;
    +
    +	/// If true, the exact uncompressed size is known. If false,
    +	/// uncomp_size may be smaller than the real uncompressed size;
    +	/// uncomp_size may never be bigger than the real uncompressed size.
    +	bool uncomp_size_is_exact;
    +
    +	/// True once the first byte of the MicroLZMA stream
    +	/// has been processed.
    +	bool props_decoded;
    +} lzma_microlzma_coder;
    +
    +
    +static lzma_ret
    +microlzma_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_microlzma_coder *coder = coder_ptr;
    +
    +	// Remember the in start position so that we can update comp_size.
    +	const size_t in_start = *in_pos;
    +
    +	// Remember the out start position so that we can update uncomp_size.
    +	const size_t out_start = *out_pos;
    +
    +	// Limit the amount of input so that the decoder won't read more than
    +	// comp_size. This is required when uncomp_size isn't exact because
    +	// in that case the LZMA decoder will try to decode more input even
    +	// when it has no output space (it can be looking for EOPM).
    +	if (in_size - *in_pos > coder->comp_size)
    +		in_size = *in_pos + (size_t)(coder->comp_size);
    +
    +	// When the exact uncompressed size isn't known, we must limit
    +	// the available output space to prevent the LZMA decoder from
    +	// trying to decode too much.
    +	if (!coder->uncomp_size_is_exact
    +			&& out_size - *out_pos > coder->uncomp_size)
    +		out_size = *out_pos + (size_t)(coder->uncomp_size);
    +
    +	if (!coder->props_decoded) {
    +		// There must be at least one byte of input to decode
    +		// the properties byte.
    +		if (*in_pos >= in_size)
    +			return LZMA_OK;
    +
    +		lzma_options_lzma options = {
    +			.dict_size = coder->dict_size,
    +			.preset_dict = NULL,
    +			.preset_dict_size = 0,
    +			.ext_flags = 0, // EOPM not allowed when size is known
    +			.ext_size_low = UINT32_MAX, // Unknown size by default
    +			.ext_size_high = UINT32_MAX,
    +		};
    +
    +		if (coder->uncomp_size_is_exact)
    +			lzma_set_ext_size(options, coder->uncomp_size);
    +
    +		// The properties are stored as bitwise-negation
    +		// of the typical encoding.
    +		if (lzma_lzma_lclppb_decode(&options, ~in[*in_pos]))
    +			return LZMA_OPTIONS_ERROR;
    +
    +		++*in_pos;
    +
    +		// Initialize the decoder.
    +		lzma_filter_info filters[2] = {
    +			{
    +				.id = LZMA_FILTER_LZMA1EXT,
    +				.init = &lzma_lzma_decoder_init,
    +				.options = &options,
    +			}, {
    +				.init = NULL,
    +			}
    +		};
    +
    +		return_if_error(lzma_next_filter_init(&coder->lzma,
    +				allocator, filters));
    +
    +		// Pass one dummy 0x00 byte to the LZMA decoder since that
    +		// is what it expects the first byte to be.
    +		const uint8_t dummy_in = 0;
    +		size_t dummy_in_pos = 0;
    +		if (coder->lzma.code(coder->lzma.coder, allocator,
    +				&dummy_in, &dummy_in_pos, 1,
    +				out, out_pos, out_size, LZMA_RUN) != LZMA_OK)
    +			return LZMA_PROG_ERROR;
    +
    +		assert(dummy_in_pos == 1);
    +		coder->props_decoded = true;
    +	}
    +
    +	// The rest is normal LZMA decoding.
    +	lzma_ret ret = coder->lzma.code(coder->lzma.coder, allocator,
    +				in, in_pos, in_size,
    +				out, out_pos, out_size, action);
    +
    +	// Update the remaining compressed size.
    +	assert(coder->comp_size >= *in_pos - in_start);
    +	coder->comp_size -= *in_pos - in_start;
    +
    +	if (coder->uncomp_size_is_exact) {
    +		// After successful decompression of the complete stream
    +		// the compressed size must match.
    +		if (ret == LZMA_STREAM_END && coder->comp_size != 0)
    +			ret = LZMA_DATA_ERROR;
    +	} else {
    +		// Update the amount of output remaining.
    +		assert(coder->uncomp_size >= *out_pos - out_start);
    +		coder->uncomp_size -= *out_pos - out_start;
    +
    +		// - We must not get LZMA_STREAM_END because the stream
    +		//   shouldn't have EOPM.
    +		// - We must use uncomp_size to determine when to
    +		//   return LZMA_STREAM_END.
    +		if (ret == LZMA_STREAM_END)
    +			ret = LZMA_DATA_ERROR;
    +		else if (coder->uncomp_size == 0)
    +			ret = LZMA_STREAM_END;
    +	}
    +
    +	return ret;
    +}
    +
    +
    +static void
    +microlzma_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_microlzma_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->lzma, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +microlzma_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		uint64_t comp_size,
    +		uint64_t uncomp_size, bool uncomp_size_is_exact,
    +		uint32_t dict_size)
    +{
    +	lzma_next_coder_init(µlzma_decoder_init, next, allocator);
    +
    +	lzma_microlzma_coder *coder = next->coder;
    +
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_microlzma_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = µlzma_decode;
    +		next->end = µlzma_decoder_end;
    +
    +		coder->lzma = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	// The public API is uint64_t but the internal LZ decoder API uses
    +	// lzma_vli.
    +	if (uncomp_size > LZMA_VLI_MAX)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	coder->comp_size = comp_size;
    +	coder->uncomp_size = uncomp_size;
    +	coder->uncomp_size_is_exact = uncomp_size_is_exact;
    +	coder->dict_size = dict_size;
    +
    +	coder->props_decoded = false;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_microlzma_decoder(lzma_stream *strm, uint64_t comp_size,
    +		uint64_t uncomp_size, lzma_bool uncomp_size_is_exact,
    +		uint32_t dict_size)
    +{
    +	lzma_next_strm_init(microlzma_decoder_init, strm, comp_size,
    +			uncomp_size, uncomp_size_is_exact, dict_size);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_encoder.c
    new file mode 100644
    index 00000000000..45ec0b12f45
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_encoder.c
    @@ -0,0 +1,140 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       microlzma_encoder.c
    +/// \brief      Encode into MicroLZMA format
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lzma_encoder.h"
    +
    +
    +typedef struct {
    +	/// LZMA1 encoder
    +	lzma_next_coder lzma;
    +
    +	/// LZMA properties byte (lc/lp/pb)
    +	uint8_t props;
    +} lzma_microlzma_coder;
    +
    +
    +static lzma_ret
    +microlzma_encode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_microlzma_coder *coder = coder_ptr;
    +
    +	// Remember *out_pos so that we can overwrite the first byte with
    +	// the LZMA properties byte.
    +	const size_t out_start = *out_pos;
    +
    +	// Remember *in_pos so that we can set it based on how many
    +	// uncompressed bytes were actually encoded.
    +	const size_t in_start = *in_pos;
    +
    +	// Set the output size limit based on the available output space.
    +	// We know that the encoder supports set_out_limit() so
    +	// LZMA_OPTIONS_ERROR isn't possible. LZMA_BUF_ERROR is possible
    +	// but lzma_code() has an assertion to not allow it to be returned
    +	// from here and I don't want to change that for now, so
    +	// LZMA_BUF_ERROR becomes LZMA_PROG_ERROR.
    +	uint64_t uncomp_size;
    +	if (coder->lzma.set_out_limit(coder->lzma.coder,
    +			&uncomp_size, out_size - *out_pos) != LZMA_OK)
    +		return LZMA_PROG_ERROR;
    +
    +	// set_out_limit fails if this isn't true.
    +	assert(out_size - *out_pos >= 6);
    +
    +	// Encode as much as possible.
    +	const lzma_ret ret = coder->lzma.code(coder->lzma.coder, allocator,
    +			in, in_pos, in_size, out, out_pos, out_size, action);
    +
    +	if (ret != LZMA_STREAM_END) {
    +		if (ret == LZMA_OK) {
    +			assert(0);
    +			return LZMA_PROG_ERROR;
    +		}
    +
    +		return ret;
    +	}
    +
    +	// The first output byte is bitwise-negation of the properties byte.
    +	// We know that there is space for this byte because set_out_limit
    +	// and the actual encoding succeeded.
    +	out[out_start] = (uint8_t)(~coder->props);
    +
    +	// The LZMA encoder likely read more input than it was able to encode.
    +	// Set *in_pos based on uncomp_size.
    +	assert(uncomp_size <= in_size - in_start);
    +	*in_pos = in_start + (size_t)(uncomp_size);
    +
    +	return ret;
    +}
    +
    +
    +static void
    +microlzma_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_microlzma_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->lzma, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +microlzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_options_lzma *options)
    +{
    +	lzma_next_coder_init(µlzma_encoder_init, next, allocator);
    +
    +	lzma_microlzma_coder *coder = next->coder;
    +
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_microlzma_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = µlzma_encode;
    +		next->end = µlzma_encoder_end;
    +
    +		coder->lzma = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	// Encode the properties byte. Bitwise-negation of it will be the
    +	// first output byte.
    +	if (lzma_lzma_lclppb_encode(options, &coder->props))
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Initialize the LZMA encoder.
    +	const lzma_filter_info filters[2] = {
    +		{
    +			.id = LZMA_FILTER_LZMA1,
    +			.init = &lzma_lzma_encoder_init,
    +			.options = (void *)(options),
    +		}, {
    +			.init = NULL,
    +		}
    +	};
    +
    +	return lzma_next_filter_init(&coder->lzma, allocator, filters);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_microlzma_encoder(lzma_stream *strm, const lzma_options_lzma *options)
    +{
    +	lzma_next_strm_init(microlzma_encoder_init, strm, options);
    +
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.c
    new file mode 100644
    index 00000000000..eb018eb42b2
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.c
    @@ -0,0 +1,286 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       outqueue.c
    +/// \brief      Output queue handling in multithreaded coding
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "outqueue.h"
    +
    +
    +/// Get the maximum number of buffers that may be allocated based
    +/// on the number of threads. For now this is twice the number of threads.
    +/// It's a compromise between RAM usage and keeping the worker threads busy
    +/// when buffers finish out of order.
    +#define GET_BUFS_LIMIT(threads) (2 * (threads))
    +
    +
    +extern uint64_t
    +lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads)
    +{
    +	// This is to ease integer overflow checking: We may allocate up to
    +	// GET_BUFS_LIMIT(LZMA_THREADS_MAX) buffers and we need some extra
    +	// memory for other data structures too (that's the /2).
    +	//
    +	// lzma_outq_prealloc_buf() will still accept bigger buffers than this.
    +	const uint64_t limit
    +			= UINT64_MAX / GET_BUFS_LIMIT(LZMA_THREADS_MAX) / 2;
    +
    +	if (threads > LZMA_THREADS_MAX || buf_size_max > limit)
    +		return UINT64_MAX;
    +
    +	return GET_BUFS_LIMIT(threads)
    +			* lzma_outq_outbuf_memusage(buf_size_max);
    +}
    +
    +
    +static void
    +move_head_to_cache(lzma_outq *outq, const lzma_allocator *allocator)
    +{
    +	assert(outq->head != NULL);
    +	assert(outq->tail != NULL);
    +	assert(outq->bufs_in_use > 0);
    +
    +	lzma_outbuf *buf = outq->head;
    +	outq->head = buf->next;
    +	if (outq->head == NULL)
    +		outq->tail = NULL;
    +
    +	if (outq->cache != NULL && outq->cache->allocated != buf->allocated)
    +		lzma_outq_clear_cache(outq, allocator);
    +
    +	buf->next = outq->cache;
    +	outq->cache = buf;
    +
    +	--outq->bufs_in_use;
    +	outq->mem_in_use -= lzma_outq_outbuf_memusage(buf->allocated);
    +
    +	return;
    +}
    +
    +
    +static void
    +free_one_cached_buffer(lzma_outq *outq, const lzma_allocator *allocator)
    +{
    +	assert(outq->cache != NULL);
    +
    +	lzma_outbuf *buf = outq->cache;
    +	outq->cache = buf->next;
    +
    +	--outq->bufs_allocated;
    +	outq->mem_allocated -= lzma_outq_outbuf_memusage(buf->allocated);
    +
    +	lzma_free(buf, allocator);
    +	return;
    +}
    +
    +
    +extern void
    +lzma_outq_clear_cache(lzma_outq *outq, const lzma_allocator *allocator)
    +{
    +	while (outq->cache != NULL)
    +		free_one_cached_buffer(outq, allocator);
    +
    +	return;
    +}
    +
    +
    +extern void
    +lzma_outq_clear_cache2(lzma_outq *outq, const lzma_allocator *allocator,
    +		size_t keep_size)
    +{
    +	if (outq->cache == NULL)
    +		return;
    +
    +	// Free all but one.
    +	while (outq->cache->next != NULL)
    +		free_one_cached_buffer(outq, allocator);
    +
    +	// Free the last one only if its size doesn't equal to keep_size.
    +	if (outq->cache->allocated != keep_size)
    +		free_one_cached_buffer(outq, allocator);
    +
    +	return;
    +}
    +
    +
    +extern lzma_ret
    +lzma_outq_init(lzma_outq *outq, const lzma_allocator *allocator,
    +		uint32_t threads)
    +{
    +	if (threads > LZMA_THREADS_MAX)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	const uint32_t bufs_limit = GET_BUFS_LIMIT(threads);
    +
    +	// Clear head/tail.
    +	while (outq->head != NULL)
    +		move_head_to_cache(outq, allocator);
    +
    +	// If new buf_limit is lower than the old one, we may need to free
    +	// a few cached buffers.
    +	while (bufs_limit < outq->bufs_allocated)
    +		free_one_cached_buffer(outq, allocator);
    +
    +	outq->bufs_limit = bufs_limit;
    +	outq->read_pos = 0;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern void
    +lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator)
    +{
    +	while (outq->head != NULL)
    +		move_head_to_cache(outq, allocator);
    +
    +	lzma_outq_clear_cache(outq, allocator);
    +	return;
    +}
    +
    +
    +extern lzma_ret
    +lzma_outq_prealloc_buf(lzma_outq *outq, const lzma_allocator *allocator,
    +		size_t size)
    +{
    +	// Caller must have checked it with lzma_outq_has_buf().
    +	assert(outq->bufs_in_use < outq->bufs_limit);
    +
    +	// If there already is appropriately-sized buffer in the cache,
    +	// we need to do nothing.
    +	if (outq->cache != NULL && outq->cache->allocated == size)
    +		return LZMA_OK;
    +
    +	if (size > SIZE_MAX - sizeof(lzma_outbuf))
    +		return LZMA_MEM_ERROR;
    +
    +	const size_t alloc_size = lzma_outq_outbuf_memusage(size);
    +
    +	// The cache may have buffers but their size is wrong.
    +	lzma_outq_clear_cache(outq, allocator);
    +
    +	outq->cache = lzma_alloc(alloc_size, allocator);
    +	if (outq->cache == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	outq->cache->next = NULL;
    +	outq->cache->allocated = size;
    +
    +	++outq->bufs_allocated;
    +	outq->mem_allocated += alloc_size;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_outbuf *
    +lzma_outq_get_buf(lzma_outq *outq, void *worker)
    +{
    +	// Caller must have used lzma_outq_prealloc_buf() to ensure these.
    +	assert(outq->bufs_in_use < outq->bufs_limit);
    +	assert(outq->bufs_in_use < outq->bufs_allocated);
    +	assert(outq->cache != NULL);
    +
    +	lzma_outbuf *buf = outq->cache;
    +	outq->cache = buf->next;
    +	buf->next = NULL;
    +
    +	if (outq->tail != NULL) {
    +		assert(outq->head != NULL);
    +		outq->tail->next = buf;
    +	} else {
    +		assert(outq->head == NULL);
    +		outq->head = buf;
    +	}
    +
    +	outq->tail = buf;
    +
    +	buf->worker = worker;
    +	buf->finished = false;
    +	buf->finish_ret = LZMA_STREAM_END;
    +	buf->pos = 0;
    +	buf->decoder_in_pos = 0;
    +
    +	buf->unpadded_size = 0;
    +	buf->uncompressed_size = 0;
    +
    +	++outq->bufs_in_use;
    +	outq->mem_in_use += lzma_outq_outbuf_memusage(buf->allocated);
    +
    +	return buf;
    +}
    +
    +
    +extern bool
    +lzma_outq_is_readable(const lzma_outq *outq)
    +{
    +	if (outq->head == NULL)
    +		return false;
    +
    +	return outq->read_pos < outq->head->pos || outq->head->finished;
    +}
    +
    +
    +extern lzma_ret
    +lzma_outq_read(lzma_outq *restrict outq,
    +		const lzma_allocator *restrict allocator,
    +		uint8_t *restrict out, size_t *restrict out_pos,
    +		size_t out_size,
    +		lzma_vli *restrict unpadded_size,
    +		lzma_vli *restrict uncompressed_size)
    +{
    +	// There must be at least one buffer from which to read.
    +	if (outq->bufs_in_use == 0)
    +		return LZMA_OK;
    +
    +	// Get the buffer.
    +	lzma_outbuf *buf = outq->head;
    +
    +	// Copy from the buffer to output.
    +	//
    +	// FIXME? In threaded decoder it may be bad to do this copy while
    +	// the mutex is being held.
    +	lzma_bufcpy(buf->buf, &outq->read_pos, buf->pos,
    +			out, out_pos, out_size);
    +
    +	// Return if we didn't get all the data from the buffer.
    +	if (!buf->finished || outq->read_pos < buf->pos)
    +		return LZMA_OK;
    +
    +	// The buffer was finished. Tell the caller its size information.
    +	if (unpadded_size != NULL)
    +		*unpadded_size = buf->unpadded_size;
    +
    +	if (uncompressed_size != NULL)
    +		*uncompressed_size = buf->uncompressed_size;
    +
    +	// Remember the return value.
    +	const lzma_ret finish_ret = buf->finish_ret;
    +
    +	// Free this buffer for further use.
    +	move_head_to_cache(outq, allocator);
    +	outq->read_pos = 0;
    +
    +	return finish_ret;
    +}
    +
    +
    +extern void
    +lzma_outq_enable_partial_output(lzma_outq *outq,
    +		void (*enable_partial_output)(void *worker))
    +{
    +	if (outq->head != NULL && !outq->head->finished
    +			&& outq->head->worker != NULL) {
    +		enable_partial_output(outq->head->worker);
    +
    +		// Set it to NULL since calling it twice is pointless.
    +		outq->head->worker = NULL;
    +	}
    +
    +	return;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.h
    new file mode 100644
    index 00000000000..25f071977a8
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.h
    @@ -0,0 +1,258 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       outqueue.h
    +/// \brief      Output queue handling in multithreaded coding
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_OUTQUEUE_H
    +#define LZMA_OUTQUEUE_H
    +
    +#include "common.h"
    +
    +
    +/// Output buffer for a single thread
    +typedef struct lzma_outbuf_s lzma_outbuf;
    +struct lzma_outbuf_s {
    +	/// Pointer to the next buffer. This is used for the cached buffers.
    +	/// The worker thread must not modify this.
    +	lzma_outbuf *next;
    +
    +	/// This initialized by lzma_outq_get_buf() and
    +	/// is used by lzma_outq_enable_partial_output().
    +	/// The worker thread must not modify this.
    +	void *worker;
    +
    +	/// Amount of memory allocated for buf[].
    +	/// The worker thread must not modify this.
    +	size_t allocated;
    +
    +	/// Writing position in the worker thread or, in other words, the
    +	/// amount of finished data written to buf[] which can be copied out
    +	///
    +	/// \note       This is read by another thread and thus access
    +	///             to this variable needs a mutex.
    +	size_t pos;
    +
    +	/// Decompression: Position in the input buffer in the worker thread
    +	/// that matches the output "pos" above. This is used to detect if
    +	/// more output might be possible from the worker thread: if it has
    +	/// consumed all its input, then more output isn't possible.
    +	///
    +	/// \note       This is read by another thread and thus access
    +	///             to this variable needs a mutex.
    +	size_t decoder_in_pos;
    +
    +	/// True when no more data will be written into this buffer.
    +	///
    +	/// \note       This is read by another thread and thus access
    +	///             to this variable needs a mutex.
    +	bool finished;
    +
    +	/// Return value for lzma_outq_read() when the last byte from
    +	/// a finished buffer has been read. Defaults to LZMA_STREAM_END.
    +	/// This must *not* be LZMA_OK. The idea is to allow a decoder to
    +	/// pass an error code to the main thread, setting the code here
    +	/// together with finished = true.
    +	lzma_ret finish_ret;
    +
    +	/// Additional size information. lzma_outq_read() may read these
    +	/// when "finished" is true.
    +	lzma_vli unpadded_size;
    +	lzma_vli uncompressed_size;
    +
    +	/// Buffer of "allocated" bytes
    +	uint8_t buf[];
    +};
    +
    +
    +typedef struct {
    +	/// Linked list of buffers in use. The next output byte will be
    +	/// read from the head and buffers for the next thread will be
    +	/// appended to the tail. tail->next is always NULL.
    +	lzma_outbuf *head;
    +	lzma_outbuf *tail;
    +
    +	/// Number of bytes read from head->buf[] in lzma_outq_read()
    +	size_t read_pos;
    +
    +	/// Linked list of allocated buffers that aren't currently used.
    +	/// This way buffers of similar size can be reused and don't
    +	/// need to be reallocated every time. For simplicity, all
    +	/// cached buffers in the list have the same allocated size.
    +	lzma_outbuf *cache;
    +
    +	/// Total amount of memory allocated for buffers
    +	uint64_t mem_allocated;
    +
    +	/// Amount of memory used by the buffers that are in use in
    +	/// the head...tail linked list.
    +	uint64_t mem_in_use;
    +
    +	/// Number of buffers in use in the head...tail list. If and only if
    +	/// this is zero, the pointers head and tail above are NULL.
    +	uint32_t bufs_in_use;
    +
    +	/// Number of buffers allocated (in use + cached)
    +	uint32_t bufs_allocated;
    +
    +	/// Maximum allowed number of allocated buffers
    +	uint32_t bufs_limit;
    +} lzma_outq;
    +
    +
    +/**
    + * \brief       Calculate the memory usage of an output queue
    + *
    + * \return      Approximate memory usage in bytes or UINT64_MAX on error.
    + */
    +extern uint64_t lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads);
    +
    +
    +/// \brief      Initialize an output queue
    +///
    +/// \param      outq            Pointer to an output queue. Before calling
    +///                             this function the first time, *outq should
    +///                             have been zeroed with memzero() so that this
    +///                             function knows that there are no previous
    +///                             allocations to free.
    +/// \param      allocator       Pointer to allocator or NULL
    +/// \param      threads         Number of buffers that may be in use
    +///                             concurrently. Note that more than this number
    +///                             of buffers may actually get allocated to
    +///                             improve performance when buffers finish
    +///                             out of order. The actual maximum number of
    +///                             allocated buffers is derived from the number
    +///                             of threads.
    +///
    +/// \return     - LZMA_OK
    +///             - LZMA_MEM_ERROR
    +///
    +extern lzma_ret lzma_outq_init(lzma_outq *outq,
    +		const lzma_allocator *allocator, uint32_t threads);
    +
    +
    +/// \brief      Free the memory associated with the output queue
    +extern void lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator);
    +
    +
    +/// \brief      Free all cached buffers that consume memory but aren't in use
    +extern void lzma_outq_clear_cache(
    +		lzma_outq *outq, const lzma_allocator *allocator);
    +
    +
    +/// \brief      Like lzma_outq_clear_cache() but might keep one buffer
    +///
    +/// One buffer is not freed if its size is equal to keep_size.
    +/// This is useful if the caller knows that it will soon need a buffer of
    +/// keep_size bytes. This way it won't be freed and immediately reallocated.
    +extern void lzma_outq_clear_cache2(
    +		lzma_outq *outq, const lzma_allocator *allocator,
    +		size_t keep_size);
    +
    +
    +/// \brief      Preallocate a new buffer into cache
    +///
    +/// Splitting the buffer allocation into a separate function makes it
    +/// possible to ensure that way lzma_outq_get_buf() cannot fail.
    +/// If the preallocated buffer isn't actually used (for example, some
    +/// other error occurs), the caller has to do nothing as the buffer will
    +/// be used later or cleared from the cache when not needed.
    +///
    +/// \return     LZMA_OK on success, LZMA_MEM_ERROR if allocation fails
    +///
    +extern lzma_ret lzma_outq_prealloc_buf(
    +		lzma_outq *outq, const lzma_allocator *allocator, size_t size);
    +
    +
    +/// \brief      Get a new buffer
    +///
    +/// lzma_outq_prealloc_buf() must be used to ensure that there is a buffer
    +/// available before calling lzma_outq_get_buf().
    +///
    +extern lzma_outbuf *lzma_outq_get_buf(lzma_outq *outq, void *worker);
    +
    +
    +/// \brief      Test if there is data ready to be read
    +///
    +/// Call to this function must be protected with the same mutex that
    +/// is used to protect lzma_outbuf.finished.
    +///
    +extern bool lzma_outq_is_readable(const lzma_outq *outq);
    +
    +
    +/// \brief      Read finished data
    +///
    +/// \param      outq            Pointer to an output queue
    +/// \param      out             Beginning of the output buffer
    +/// \param      out_pos         The next byte will be written to
    +///                             out[*out_pos].
    +/// \param      out_size        Size of the out buffer; the first byte into
    +///                             which no data is written to is out[out_size].
    +/// \param      unpadded_size   Unpadded Size from the Block encoder
    +/// \param      uncompressed_size Uncompressed Size from the Block encoder
    +///
    +/// \return     - LZMA: All OK. Either no data was available or the buffer
    +///               being read didn't become empty yet.
    +///             - LZMA_STREAM_END: The buffer being read was finished.
    +///               *unpadded_size and *uncompressed_size were set if they
    +///               were not NULL.
    +///
    +/// \note       This reads lzma_outbuf.finished and .pos variables and thus
    +///             calls to this function need to be protected with a mutex.
    +///
    +extern lzma_ret lzma_outq_read(lzma_outq *restrict outq,
    +		const lzma_allocator *restrict allocator,
    +		uint8_t *restrict out, size_t *restrict out_pos,
    +		size_t out_size, lzma_vli *restrict unpadded_size,
    +		lzma_vli *restrict uncompressed_size);
    +
    +
    +/// \brief      Enable partial output from a worker thread
    +///
    +/// If the buffer at the head of the output queue isn't finished,
    +/// this will call enable_partial_output on the worker associated with
    +/// that output buffer.
    +///
    +/// \note       This reads a lzma_outbuf.finished variable and thus
    +///             calls to this function need to be protected with a mutex.
    +///
    +extern void lzma_outq_enable_partial_output(lzma_outq *outq,
    +		void (*enable_partial_output)(void *worker));
    +
    +
    +/// \brief      Test if there is at least one buffer free
    +///
    +/// This must be used before getting a new buffer with lzma_outq_get_buf().
    +///
    +static inline bool
    +lzma_outq_has_buf(const lzma_outq *outq)
    +{
    +	return outq->bufs_in_use < outq->bufs_limit;
    +}
    +
    +
    +/// \brief      Test if the queue is completely empty
    +static inline bool
    +lzma_outq_is_empty(const lzma_outq *outq)
    +{
    +	return outq->bufs_in_use == 0;
    +}
    +
    +
    +/// \brief      Get the amount of memory needed for a single lzma_outbuf
    +///
    +/// \note       Caller must check that the argument is significantly less
    +///             than SIZE_MAX to avoid an integer overflow!
    +static inline uint64_t
    +lzma_outq_outbuf_memusage(size_t buf_size)
    +{
    +	assert(buf_size <= SIZE_MAX - sizeof(lzma_outbuf));
    +	return sizeof(lzma_outbuf) + buf_size;
    +}
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_decoder.c
    new file mode 100644
    index 00000000000..c4f91fb4983
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_decoder.c
    @@ -0,0 +1,90 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_buffer_decoder.c
    +/// \brief      Single-call .xz Stream decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "stream_decoder.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_buffer_decode(uint64_t *memlimit, uint32_t flags,
    +		const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	// Sanity checks
    +	if (in_pos == NULL || (in == NULL && *in_pos != in_size)
    +			|| *in_pos > in_size || out_pos == NULL
    +			|| (out == NULL && *out_pos != out_size)
    +			|| *out_pos > out_size)
    +		return LZMA_PROG_ERROR;
    +
    +	// Catch flags that are not allowed in buffer-to-buffer decoding.
    +	if (flags & LZMA_TELL_ANY_CHECK)
    +		return LZMA_PROG_ERROR;
    +
    +	// Initialize the Stream decoder.
    +	// TODO: We need something to tell the decoder that it can use the
    +	// output buffer as workspace, and thus save significant amount of RAM.
    +	lzma_next_coder stream_decoder = LZMA_NEXT_CODER_INIT;
    +	lzma_ret ret = lzma_stream_decoder_init(
    +			&stream_decoder, allocator, *memlimit, flags);
    +
    +	if (ret == LZMA_OK) {
    +		// Save the positions so that we can restore them in case
    +		// an error occurs.
    +		const size_t in_start = *in_pos;
    +		const size_t out_start = *out_pos;
    +
    +		// Do the actual decoding.
    +		ret = stream_decoder.code(stream_decoder.coder, allocator,
    +				in, in_pos, in_size, out, out_pos, out_size,
    +				LZMA_FINISH);
    +
    +		if (ret == LZMA_STREAM_END) {
    +			ret = LZMA_OK;
    +		} else {
    +			// Something went wrong, restore the positions.
    +			*in_pos = in_start;
    +			*out_pos = out_start;
    +
    +			if (ret == LZMA_OK) {
    +				// Either the input was truncated or the
    +				// output buffer was too small.
    +				assert(*in_pos == in_size
    +						|| *out_pos == out_size);
    +
    +				// If all the input was consumed, then the
    +				// input is truncated, even if the output
    +				// buffer is also full. This is because
    +				// processing the last byte of the Stream
    +				// never produces output.
    +				if (*in_pos == in_size)
    +					ret = LZMA_DATA_ERROR;
    +				else
    +					ret = LZMA_BUF_ERROR;
    +
    +			} else if (ret == LZMA_MEMLIMIT_ERROR) {
    +				// Let the caller know how much memory would
    +				// have been needed.
    +				uint64_t memusage;
    +				(void)stream_decoder.memconfig(
    +						stream_decoder.coder,
    +						memlimit, &memusage, 0);
    +			}
    +		}
    +	}
    +
    +	// Free the decoder memory. This needs to be done even if
    +	// initialization fails, because the internal API doesn't
    +	// require the initialization function to free its memory on error.
    +	lzma_next_end(&stream_decoder, allocator);
    +
    +	return ret;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_encoder.c
    new file mode 100644
    index 00000000000..04d58695946
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_encoder.c
    @@ -0,0 +1,141 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_buffer_encoder.c
    +/// \brief      Single-call .xz Stream encoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +#include "index.h"
    +
    +
    +/// Maximum size of Index that has exactly one Record.
    +/// Index Indicator + Number of Records + Record + CRC32 rounded up to
    +/// the next multiple of four.
    +#define INDEX_BOUND ((1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 4 + 3) & ~3)
    +
    +/// Stream Header, Stream Footer, and Index
    +#define HEADERS_BOUND (2 * LZMA_STREAM_HEADER_SIZE + INDEX_BOUND)
    +
    +
    +extern LZMA_API(size_t)
    +lzma_stream_buffer_bound(size_t uncompressed_size)
    +{
    +	// Get the maximum possible size of a Block.
    +	const size_t block_bound = lzma_block_buffer_bound(uncompressed_size);
    +	if (block_bound == 0)
    +		return 0;
    +
    +	// Catch the possible integer overflow and also prevent the size of
    +	// the Stream exceeding LZMA_VLI_MAX (theoretically possible on
    +	// 64-bit systems).
    +	if (my_min(SIZE_MAX, LZMA_VLI_MAX) - block_bound < HEADERS_BOUND)
    +		return 0;
    +
    +	return block_bound + HEADERS_BOUND;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_buffer_encode(lzma_filter *filters, lzma_check check,
    +		const lzma_allocator *allocator,
    +		const uint8_t *in, size_t in_size,
    +		uint8_t *out, size_t *out_pos_ptr, size_t out_size)
    +{
    +	// Sanity checks
    +	if (filters == NULL || (unsigned int)(check) > LZMA_CHECK_ID_MAX
    +			|| (in == NULL && in_size != 0) || out == NULL
    +			|| out_pos_ptr == NULL || *out_pos_ptr > out_size)
    +		return LZMA_PROG_ERROR;
    +
    +	if (!lzma_check_is_supported(check))
    +		return LZMA_UNSUPPORTED_CHECK;
    +
    +	// Note for the paranoids: Index encoder prevents the Stream from
    +	// getting too big and still being accepted with LZMA_OK, and Block
    +	// encoder catches if the input is too big. So we don't need to
    +	// separately check if the buffers are too big.
    +
    +	// Use a local copy. We update *out_pos_ptr only if everything
    +	// succeeds.
    +	size_t out_pos = *out_pos_ptr;
    +
    +	// Check that there's enough space for both Stream Header and
    +	// Stream Footer.
    +	if (out_size - out_pos <= 2 * LZMA_STREAM_HEADER_SIZE)
    +		return LZMA_BUF_ERROR;
    +
    +	// Reserve space for Stream Footer so we don't need to check for
    +	// available space again before encoding Stream Footer.
    +	out_size -= LZMA_STREAM_HEADER_SIZE;
    +
    +	// Encode the Stream Header.
    +	lzma_stream_flags stream_flags = {
    +		.version = 0,
    +		.check = check,
    +	};
    +
    +	if (lzma_stream_header_encode(&stream_flags, out + out_pos)
    +			!= LZMA_OK)
    +		return LZMA_PROG_ERROR;
    +
    +	out_pos += LZMA_STREAM_HEADER_SIZE;
    +
    +	// Encode a Block but only if there is at least one byte of input.
    +	lzma_block block = {
    +		.version = 0,
    +		.check = check,
    +		.filters = filters,
    +	};
    +
    +	if (in_size > 0)
    +		return_if_error(lzma_block_buffer_encode(&block, allocator,
    +				in, in_size, out, &out_pos, out_size));
    +
    +	// Index
    +	{
    +		// Create an Index. It will have one Record if there was
    +		// at least one byte of input to encode. Otherwise the
    +		// Index will be empty.
    +		lzma_index *i = lzma_index_init(allocator);
    +		if (i == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		lzma_ret ret = LZMA_OK;
    +
    +		if (in_size > 0)
    +			ret = lzma_index_append(i, allocator,
    +					lzma_block_unpadded_size(&block),
    +					block.uncompressed_size);
    +
    +		// If adding the Record was successful, encode the Index
    +		// and get its size which will be stored into Stream Footer.
    +		if (ret == LZMA_OK) {
    +			ret = lzma_index_buffer_encode(
    +					i, out, &out_pos, out_size);
    +
    +			stream_flags.backward_size = lzma_index_size(i);
    +		}
    +
    +		lzma_index_end(i, allocator);
    +
    +		if (ret != LZMA_OK)
    +			return ret;
    +	}
    +
    +	// Stream Footer. We have already reserved space for this.
    +	if (lzma_stream_footer_encode(&stream_flags, out + out_pos)
    +			!= LZMA_OK)
    +		return LZMA_PROG_ERROR;
    +
    +	out_pos += LZMA_STREAM_HEADER_SIZE;
    +
    +	// Everything went fine, make the new output position available
    +	// to the application.
    +	*out_pos_ptr = out_pos;
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.c
    new file mode 100644
    index 00000000000..7f426841366
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.c
    @@ -0,0 +1,473 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_decoder.c
    +/// \brief      Decodes .xz Streams
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "stream_decoder.h"
    +#include "block_decoder.h"
    +#include "index.h"
    +
    +
    +typedef struct {
    +	enum {
    +		SEQ_STREAM_HEADER,
    +		SEQ_BLOCK_HEADER,
    +		SEQ_BLOCK_INIT,
    +		SEQ_BLOCK_RUN,
    +		SEQ_INDEX,
    +		SEQ_STREAM_FOOTER,
    +		SEQ_STREAM_PADDING,
    +	} sequence;
    +
    +	/// Block decoder
    +	lzma_next_coder block_decoder;
    +
    +	/// Block options decoded by the Block Header decoder and used by
    +	/// the Block decoder.
    +	lzma_block block_options;
    +
    +	/// Stream Flags from Stream Header
    +	lzma_stream_flags stream_flags;
    +
    +	/// Index is hashed so that it can be compared to the sizes of Blocks
    +	/// with O(1) memory usage.
    +	lzma_index_hash *index_hash;
    +
    +	/// Memory usage limit
    +	uint64_t memlimit;
    +
    +	/// Amount of memory actually needed (only an estimate)
    +	uint64_t memusage;
    +
    +	/// If true, LZMA_NO_CHECK is returned if the Stream has
    +	/// no integrity check.
    +	bool tell_no_check;
    +
    +	/// If true, LZMA_UNSUPPORTED_CHECK is returned if the Stream has
    +	/// an integrity check that isn't supported by this liblzma build.
    +	bool tell_unsupported_check;
    +
    +	/// If true, LZMA_GET_CHECK is returned after decoding Stream Header.
    +	bool tell_any_check;
    +
    +	/// If true, we will tell the Block decoder to skip calculating
    +	/// and verifying the integrity check.
    +	bool ignore_check;
    +
    +	/// If true, we will decode concatenated Streams that possibly have
    +	/// Stream Padding between or after them. LZMA_STREAM_END is returned
    +	/// once the application isn't giving us any new input (LZMA_FINISH),
    +	/// and we aren't in the middle of a Stream, and possible
    +	/// Stream Padding is a multiple of four bytes.
    +	bool concatenated;
    +
    +	/// When decoding concatenated Streams, this is true as long as we
    +	/// are decoding the first Stream. This is needed to avoid misleading
    +	/// LZMA_FORMAT_ERROR in case the later Streams don't have valid magic
    +	/// bytes.
    +	bool first_stream;
    +
    +	/// Write position in buffer[] and position in Stream Padding
    +	size_t pos;
    +
    +	/// Buffer to hold Stream Header, Block Header, and Stream Footer.
    +	/// Block Header has biggest maximum size.
    +	uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
    +} lzma_stream_coder;
    +
    +
    +static lzma_ret
    +stream_decoder_reset(lzma_stream_coder *coder, const lzma_allocator *allocator)
    +{
    +	// Initialize the Index hash used to verify the Index.
    +	coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator);
    +	if (coder->index_hash == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	// Reset the rest of the variables.
    +	coder->sequence = SEQ_STREAM_HEADER;
    +	coder->pos = 0;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static lzma_ret
    +stream_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +
    +	// When decoding the actual Block, it may be able to produce more
    +	// output even if we don't give it any new input.
    +	while (true)
    +	switch (coder->sequence) {
    +	case SEQ_STREAM_HEADER: {
    +		// Copy the Stream Header to the internal buffer.
    +		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
    +				LZMA_STREAM_HEADER_SIZE);
    +
    +		// Return if we didn't get the whole Stream Header yet.
    +		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
    +			return LZMA_OK;
    +
    +		coder->pos = 0;
    +
    +		// Decode the Stream Header.
    +		const lzma_ret ret = lzma_stream_header_decode(
    +				&coder->stream_flags, coder->buffer);
    +		if (ret != LZMA_OK)
    +			return ret == LZMA_FORMAT_ERROR && !coder->first_stream
    +					? LZMA_DATA_ERROR : ret;
    +
    +		// If we are decoding concatenated Streams, and the later
    +		// Streams have invalid Header Magic Bytes, we give
    +		// LZMA_DATA_ERROR instead of LZMA_FORMAT_ERROR.
    +		coder->first_stream = false;
    +
    +		// Copy the type of the Check so that Block Header and Block
    +		// decoders see it.
    +		coder->block_options.check = coder->stream_flags.check;
    +
    +		// Even if we return LZMA_*_CHECK below, we want
    +		// to continue from Block Header decoding.
    +		coder->sequence = SEQ_BLOCK_HEADER;
    +
    +		// Detect if there's no integrity check or if it is
    +		// unsupported if those were requested by the application.
    +		if (coder->tell_no_check && coder->stream_flags.check
    +				== LZMA_CHECK_NONE)
    +			return LZMA_NO_CHECK;
    +
    +		if (coder->tell_unsupported_check
    +				&& !lzma_check_is_supported(
    +					coder->stream_flags.check))
    +			return LZMA_UNSUPPORTED_CHECK;
    +
    +		if (coder->tell_any_check)
    +			return LZMA_GET_CHECK;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_BLOCK_HEADER: {
    +		if (*in_pos >= in_size)
    +			return LZMA_OK;
    +
    +		if (coder->pos == 0) {
    +			// Detect if it's Index.
    +			if (in[*in_pos] == INDEX_INDICATOR) {
    +				coder->sequence = SEQ_INDEX;
    +				break;
    +			}
    +
    +			// Calculate the size of the Block Header. Note that
    +			// Block Header decoder wants to see this byte too
    +			// so don't advance *in_pos.
    +			coder->block_options.header_size
    +					= lzma_block_header_size_decode(
    +						in[*in_pos]);
    +		}
    +
    +		// Copy the Block Header to the internal buffer.
    +		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
    +				coder->block_options.header_size);
    +
    +		// Return if we didn't get the whole Block Header yet.
    +		if (coder->pos < coder->block_options.header_size)
    +			return LZMA_OK;
    +
    +		coder->pos = 0;
    +		coder->sequence = SEQ_BLOCK_INIT;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_BLOCK_INIT: {
    +		// Checking memusage and doing the initialization needs
    +		// its own sequence point because we need to be able to
    +		// retry if we return LZMA_MEMLIMIT_ERROR.
    +
    +		// Version 1 is needed to support the .ignore_check option.
    +		coder->block_options.version = 1;
    +
    +		// Set up a buffer to hold the filter chain. Block Header
    +		// decoder will initialize all members of this array so
    +		// we don't need to do it here.
    +		lzma_filter filters[LZMA_FILTERS_MAX + 1];
    +		coder->block_options.filters = filters;
    +
    +		// Decode the Block Header.
    +		return_if_error(lzma_block_header_decode(&coder->block_options,
    +				allocator, coder->buffer));
    +
    +		// If LZMA_IGNORE_CHECK was used, this flag needs to be set.
    +		// It has to be set after lzma_block_header_decode() because
    +		// it always resets this to false.
    +		coder->block_options.ignore_check = coder->ignore_check;
    +
    +		// Check the memory usage limit.
    +		const uint64_t memusage = lzma_raw_decoder_memusage(filters);
    +		lzma_ret ret;
    +
    +		if (memusage == UINT64_MAX) {
    +			// One or more unknown Filter IDs.
    +			ret = LZMA_OPTIONS_ERROR;
    +		} else {
    +			// Now we can set coder->memusage since we know that
    +			// the filter chain is valid. We don't want
    +			// lzma_memusage() to return UINT64_MAX in case of
    +			// invalid filter chain.
    +			coder->memusage = memusage;
    +
    +			if (memusage > coder->memlimit) {
    +				// The chain would need too much memory.
    +				ret = LZMA_MEMLIMIT_ERROR;
    +			} else {
    +				// Memory usage is OK.
    +				// Initialize the Block decoder.
    +				ret = lzma_block_decoder_init(
    +						&coder->block_decoder,
    +						allocator,
    +						&coder->block_options);
    +			}
    +		}
    +
    +		// Free the allocated filter options since they are needed
    +		// only to initialize the Block decoder.
    +		lzma_filters_free(filters, allocator);
    +		coder->block_options.filters = NULL;
    +
    +		// Check if memory usage calculation and Block decoder
    +		// initialization succeeded.
    +		if (ret != LZMA_OK)
    +			return ret;
    +
    +		coder->sequence = SEQ_BLOCK_RUN;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_BLOCK_RUN: {
    +		const lzma_ret ret = coder->block_decoder.code(
    +				coder->block_decoder.coder, allocator,
    +				in, in_pos, in_size, out, out_pos, out_size,
    +				action);
    +
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +
    +		// Block decoded successfully. Add the new size pair to
    +		// the Index hash.
    +		return_if_error(lzma_index_hash_append(coder->index_hash,
    +				lzma_block_unpadded_size(
    +					&coder->block_options),
    +				coder->block_options.uncompressed_size));
    +
    +		coder->sequence = SEQ_BLOCK_HEADER;
    +		break;
    +	}
    +
    +	case SEQ_INDEX: {
    +		// If we don't have any input, don't call
    +		// lzma_index_hash_decode() since it would return
    +		// LZMA_BUF_ERROR, which we must not do here.
    +		if (*in_pos >= in_size)
    +			return LZMA_OK;
    +
    +		// Decode the Index and compare it to the hash calculated
    +		// from the sizes of the Blocks (if any).
    +		const lzma_ret ret = lzma_index_hash_decode(coder->index_hash,
    +				in, in_pos, in_size);
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +
    +		coder->sequence = SEQ_STREAM_FOOTER;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_STREAM_FOOTER: {
    +		// Copy the Stream Footer to the internal buffer.
    +		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
    +				LZMA_STREAM_HEADER_SIZE);
    +
    +		// Return if we didn't get the whole Stream Footer yet.
    +		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
    +			return LZMA_OK;
    +
    +		coder->pos = 0;
    +
    +		// Decode the Stream Footer. The decoder gives
    +		// LZMA_FORMAT_ERROR if the magic bytes don't match,
    +		// so convert that return code to LZMA_DATA_ERROR.
    +		lzma_stream_flags footer_flags;
    +		const lzma_ret ret = lzma_stream_footer_decode(
    +				&footer_flags, coder->buffer);
    +		if (ret != LZMA_OK)
    +			return ret == LZMA_FORMAT_ERROR
    +					? LZMA_DATA_ERROR : ret;
    +
    +		// Check that Index Size stored in the Stream Footer matches
    +		// the real size of the Index field.
    +		if (lzma_index_hash_size(coder->index_hash)
    +				!= footer_flags.backward_size)
    +			return LZMA_DATA_ERROR;
    +
    +		// Compare that the Stream Flags fields are identical in
    +		// both Stream Header and Stream Footer.
    +		return_if_error(lzma_stream_flags_compare(
    +				&coder->stream_flags, &footer_flags));
    +
    +		if (!coder->concatenated)
    +			return LZMA_STREAM_END;
    +
    +		coder->sequence = SEQ_STREAM_PADDING;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_STREAM_PADDING:
    +		assert(coder->concatenated);
    +
    +		// Skip over possible Stream Padding.
    +		while (true) {
    +			if (*in_pos >= in_size) {
    +				// Unless LZMA_FINISH was used, we cannot
    +				// know if there's more input coming later.
    +				if (action != LZMA_FINISH)
    +					return LZMA_OK;
    +
    +				// Stream Padding must be a multiple of
    +				// four bytes.
    +				return coder->pos == 0
    +						? LZMA_STREAM_END
    +						: LZMA_DATA_ERROR;
    +			}
    +
    +			// If the byte is not zero, it probably indicates
    +			// beginning of a new Stream (or the file is corrupt).
    +			if (in[*in_pos] != 0x00)
    +				break;
    +
    +			++*in_pos;
    +			coder->pos = (coder->pos + 1) & 3;
    +		}
    +
    +		// Stream Padding must be a multiple of four bytes (empty
    +		// Stream Padding is OK).
    +		if (coder->pos != 0) {
    +			++*in_pos;
    +			return LZMA_DATA_ERROR;
    +		}
    +
    +		// Prepare to decode the next Stream.
    +		return_if_error(stream_decoder_reset(coder, allocator));
    +		break;
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	// Never reached
    +}
    +
    +
    +static void
    +stream_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->block_decoder, allocator);
    +	lzma_index_hash_end(coder->index_hash, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_check
    +stream_decoder_get_check(const void *coder_ptr)
    +{
    +	const lzma_stream_coder *coder = coder_ptr;
    +	return coder->stream_flags.check;
    +}
    +
    +
    +static lzma_ret
    +stream_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
    +		uint64_t *old_memlimit, uint64_t new_memlimit)
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +
    +	*memusage = coder->memusage;
    +	*old_memlimit = coder->memlimit;
    +
    +	if (new_memlimit != 0) {
    +		if (new_memlimit < coder->memusage)
    +			return LZMA_MEMLIMIT_ERROR;
    +
    +		coder->memlimit = new_memlimit;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_ret
    +lzma_stream_decoder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		uint64_t memlimit, uint32_t flags)
    +{
    +	lzma_next_coder_init(&lzma_stream_decoder_init, next, allocator);
    +
    +	if (flags & ~LZMA_SUPPORTED_FLAGS)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	lzma_stream_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &stream_decode;
    +		next->end = &stream_decoder_end;
    +		next->get_check = &stream_decoder_get_check;
    +		next->memconfig = &stream_decoder_memconfig;
    +
    +		coder->block_decoder = LZMA_NEXT_CODER_INIT;
    +		coder->index_hash = NULL;
    +	}
    +
    +	coder->memlimit = my_max(1, memlimit);
    +	coder->memusage = LZMA_MEMUSAGE_BASE;
    +	coder->tell_no_check = (flags & LZMA_TELL_NO_CHECK) != 0;
    +	coder->tell_unsupported_check
    +			= (flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0;
    +	coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0;
    +	coder->ignore_check = (flags & LZMA_IGNORE_CHECK) != 0;
    +	coder->concatenated = (flags & LZMA_CONCATENATED) != 0;
    +	coder->first_stream = true;
    +
    +	return stream_decoder_reset(coder, allocator);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
    +{
    +	lzma_next_strm_init(lzma_stream_decoder_init, strm, memlimit, flags);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.h
    new file mode 100644
    index 00000000000..5803715374d
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.h
    @@ -0,0 +1,21 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_decoder.h
    +/// \brief      Decodes .xz Streams
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_STREAM_DECODER_H
    +#define LZMA_STREAM_DECODER_H
    +
    +#include "common.h"
    +
    +extern lzma_ret lzma_stream_decoder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		uint64_t memlimit, uint32_t flags);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder_mt.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder_mt.c
    new file mode 100644
    index 00000000000..244624a4790
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder_mt.c
    @@ -0,0 +1,2017 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_decoder_mt.c
    +/// \brief      Multithreaded .xz Stream decoder
    +//
    +//  Authors:    Sebastian Andrzej Siewior
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +#include "block_decoder.h"
    +#include "stream_decoder.h"
    +#include "index.h"
    +#include "outqueue.h"
    +
    +
    +typedef enum {
    +	/// Waiting for work.
    +	/// Main thread may change this to THR_RUN or THR_EXIT.
    +	THR_IDLE,
    +
    +	/// Decoding is in progress.
    +	/// Main thread may change this to THR_STOP or THR_EXIT.
    +	/// The worker thread may change this to THR_IDLE.
    +	THR_RUN,
    +
    +	/// The main thread wants the thread to stop whatever it was doing
    +	/// but not exit. Main thread may change this to THR_EXIT.
    +	/// The worker thread may change this to THR_IDLE.
    +	THR_STOP,
    +
    +	/// The main thread wants the thread to exit.
    +	THR_EXIT,
    +
    +} worker_state;
    +
    +
    +typedef enum {
    +	/// Partial updates (storing of worker thread progress
    +	/// to lzma_outbuf) are disabled.
    +	PARTIAL_DISABLED,
    +
    +	/// Main thread requests partial updates to be enabled but
    +	/// no partial update has been done by the worker thread yet.
    +	///
    +	/// Changing from PARTIAL_DISABLED to PARTIAL_START requires
    +	/// use of the worker-thread mutex. Other transitions don't
    +	/// need a mutex.
    +	PARTIAL_START,
    +
    +	/// Partial updates are enabled and the worker thread has done
    +	/// at least one partial update.
    +	PARTIAL_ENABLED,
    +
    +} partial_update_mode;
    +
    +
    +struct worker_thread {
    +	/// Worker state is protected with our mutex.
    +	worker_state state;
    +
    +	/// Input buffer that will contain the whole Block except Block Header.
    +	uint8_t *in;
    +
    +	/// Amount of memory allocated for "in"
    +	size_t in_size;
    +
    +	/// Number of bytes written to "in" by the main thread
    +	size_t in_filled;
    +
    +	/// Number of bytes consumed from "in" by the worker thread.
    +	size_t in_pos;
    +
    +	/// Amount of uncompressed data that has been decoded. This local
    +	/// copy is needed because updating outbuf->pos requires locking
    +	/// the main mutex (coder->mutex).
    +	size_t out_pos;
    +
    +	/// Pointer to the main structure is needed to (1) lock the main
    +	/// mutex (coder->mutex) when updating outbuf->pos and (2) when
    +	/// putting this thread back to the stack of free threads.
    +	struct lzma_stream_coder *coder;
    +
    +	/// The allocator is set by the main thread. Since a copy of the
    +	/// pointer is kept here, the application must not change the
    +	/// allocator before calling lzma_end().
    +	const lzma_allocator *allocator;
    +
    +	/// Output queue buffer to which the uncompressed data is written.
    +	lzma_outbuf *outbuf;
    +
    +	/// Amount of compressed data that has already been decompressed.
    +	/// This is updated from in_pos when our mutex is locked.
    +	/// This is size_t, not uint64_t, because per-thread progress
    +	/// is limited to sizes of allocated buffers.
    +	size_t progress_in;
    +
    +	/// Like progress_in but for uncompressed data.
    +	size_t progress_out;
    +
    +	/// Updating outbuf->pos requires locking the main mutex
    +	/// (coder->mutex). Since the main thread will only read output
    +	/// from the oldest outbuf in the queue, only the worker thread
    +	/// that is associated with the oldest outbuf needs to update its
    +	/// outbuf->pos. This avoids useless mutex contention that would
    +	/// happen if all worker threads were frequently locking the main
    +	/// mutex to update their outbuf->pos.
    +	///
    +	/// Only when partial_update is something else than PARTIAL_DISABLED,
    +	/// this worker thread will update outbuf->pos after each call to
    +	/// the Block decoder.
    +	partial_update_mode partial_update;
    +
    +	/// Block decoder
    +	lzma_next_coder block_decoder;
    +
    +	/// Thread-specific Block options are needed because the Block
    +	/// decoder modifies the struct given to it at initialization.
    +	lzma_block block_options;
    +
    +	/// Filter chain memory usage
    +	uint64_t mem_filters;
    +
    +	/// Next structure in the stack of free worker threads.
    +	struct worker_thread *next;
    +
    +	mythread_mutex mutex;
    +	mythread_cond cond;
    +
    +	/// The ID of this thread is used to join the thread
    +	/// when it's not needed anymore.
    +	mythread thread_id;
    +};
    +
    +
    +struct lzma_stream_coder {
    +	enum {
    +		SEQ_STREAM_HEADER,
    +		SEQ_BLOCK_HEADER,
    +		SEQ_BLOCK_INIT,
    +		SEQ_BLOCK_THR_INIT,
    +		SEQ_BLOCK_THR_RUN,
    +		SEQ_BLOCK_DIRECT_INIT,
    +		SEQ_BLOCK_DIRECT_RUN,
    +		SEQ_INDEX_WAIT_OUTPUT,
    +		SEQ_INDEX_DECODE,
    +		SEQ_STREAM_FOOTER,
    +		SEQ_STREAM_PADDING,
    +		SEQ_ERROR,
    +	} sequence;
    +
    +	/// Block decoder
    +	lzma_next_coder block_decoder;
    +
    +	/// Every Block Header will be decoded into this structure.
    +	/// This is also used to initialize a Block decoder when in
    +	/// direct mode. In threaded mode, a thread-specific copy will
    +	/// be made for decoder initialization because the Block decoder
    +	/// will modify the structure given to it.
    +	lzma_block block_options;
    +
    +	/// Buffer to hold a filter chain for Block Header decoding and
    +	/// initialization. These are freed after successful Block decoder
    +	/// initialization or at stream_decoder_mt_end(). The thread-specific
    +	/// copy of block_options won't hold a pointer to filters[] after
    +	/// initialization.
    +	lzma_filter filters[LZMA_FILTERS_MAX + 1];
    +
    +	/// Stream Flags from Stream Header
    +	lzma_stream_flags stream_flags;
    +
    +	/// Index is hashed so that it can be compared to the sizes of Blocks
    +	/// with O(1) memory usage.
    +	lzma_index_hash *index_hash;
    +
    +
    +	/// Maximum wait time if cannot use all the input and cannot
    +	/// fill the output buffer. This is in milliseconds.
    +	uint32_t timeout;
    +
    +
    +	/// Error code from a worker thread.
    +	///
    +	/// \note       Use mutex.
    +	lzma_ret thread_error;
    +
    +	/// Error code to return after pending output has been copied out. If
    +	/// set in read_output_and_wait(), this is a mirror of thread_error.
    +	/// If set in stream_decode_mt() then it's, for example, error that
    +	/// occurred when decoding Block Header.
    +	lzma_ret pending_error;
    +
    +	/// Number of threads that will be created at maximum.
    +	uint32_t threads_max;
    +
    +	/// Number of thread structures that have been initialized from
    +	/// "threads", and thus the number of worker threads actually
    +	/// created so far.
    +	uint32_t threads_initialized;
    +
    +	/// Array of allocated thread-specific structures. When no threads
    +	/// are in use (direct mode) this is NULL. In threaded mode this
    +	/// points to an array of threads_max number of worker_thread structs.
    +	struct worker_thread *threads;
    +
    +	/// Stack of free threads. When a thread finishes, it puts itself
    +	/// back into this stack. This starts as empty because threads
    +	/// are created only when actually needed.
    +	///
    +	/// \note       Use mutex.
    +	struct worker_thread *threads_free;
    +
    +	/// The most recent worker thread to which the main thread writes
    +	/// the new input from the application.
    +	struct worker_thread *thr;
    +
    +	/// Output buffer queue for decompressed data from the worker threads
    +	///
    +	/// \note       Use mutex with operations that need it.
    +	lzma_outq outq;
    +
    +	mythread_mutex mutex;
    +	mythread_cond cond;
    +
    +
    +	/// Memory usage that will not be exceeded in multi-threaded mode.
    +	/// Single-threaded mode can exceed this even by a large amount.
    +	uint64_t memlimit_threading;
    +
    +	/// Memory usage limit that should never be exceeded.
    +	/// LZMA_MEMLIMIT_ERROR will be returned if decoding isn't possible
    +	/// even in single-threaded mode without exceeding this limit.
    +	uint64_t memlimit_stop;
    +
    +	/// Amount of memory in use by the direct mode decoder
    +	/// (coder->block_decoder). In threaded mode this is 0.
    +	uint64_t mem_direct_mode;
    +
    +	/// Amount of memory needed by the running worker threads.
    +	/// This doesn't include the memory needed by the output buffer.
    +	///
    +	/// \note       Use mutex.
    +	uint64_t mem_in_use;
    +
    +	/// Amount of memory used by the idle (cached) threads.
    +	///
    +	/// \note       Use mutex.
    +	uint64_t mem_cached;
    +
    +
    +	/// Amount of memory needed for the filter chain of the next Block.
    +	uint64_t mem_next_filters;
    +
    +	/// Amount of memory needed for the thread-specific input buffer
    +	/// for the next Block.
    +	uint64_t mem_next_in;
    +
    +	/// Amount of memory actually needed to decode the next Block
    +	/// in threaded mode. This is
    +	/// mem_next_filters + mem_next_in + memory needed for lzma_outbuf.
    +	uint64_t mem_next_block;
    +
    +
    +	/// Amount of compressed data in Stream Header + Blocks that have
    +	/// already been finished.
    +	///
    +	/// \note       Use mutex.
    +	uint64_t progress_in;
    +
    +	/// Amount of uncompressed data in Blocks that have already
    +	/// been finished.
    +	///
    +	/// \note       Use mutex.
    +	uint64_t progress_out;
    +
    +
    +	/// If true, LZMA_NO_CHECK is returned if the Stream has
    +	/// no integrity check.
    +	bool tell_no_check;
    +
    +	/// If true, LZMA_UNSUPPORTED_CHECK is returned if the Stream has
    +	/// an integrity check that isn't supported by this liblzma build.
    +	bool tell_unsupported_check;
    +
    +	/// If true, LZMA_GET_CHECK is returned after decoding Stream Header.
    +	bool tell_any_check;
    +
    +	/// If true, we will tell the Block decoder to skip calculating
    +	/// and verifying the integrity check.
    +	bool ignore_check;
    +
    +	/// If true, we will decode concatenated Streams that possibly have
    +	/// Stream Padding between or after them. LZMA_STREAM_END is returned
    +	/// once the application isn't giving us any new input (LZMA_FINISH),
    +	/// and we aren't in the middle of a Stream, and possible
    +	/// Stream Padding is a multiple of four bytes.
    +	bool concatenated;
    +
    +	/// If true, we will return any errors immediately instead of first
    +	/// producing all output before the location of the error.
    +	bool fail_fast;
    +
    +
    +	/// When decoding concatenated Streams, this is true as long as we
    +	/// are decoding the first Stream. This is needed to avoid misleading
    +	/// LZMA_FORMAT_ERROR in case the later Streams don't have valid magic
    +	/// bytes.
    +	bool first_stream;
    +
    +	/// This is used to track if the previous call to stream_decode_mt()
    +	/// had output space (*out_pos < out_size) and managed to fill the
    +	/// output buffer (*out_pos == out_size). This may be set to true
    +	/// in read_output_and_wait(). This is read and then reset to false
    +	/// at the beginning of stream_decode_mt().
    +	///
    +	/// This is needed to support applications that call lzma_code() in
    +	/// such a way that more input is provided only when lzma_code()
    +	/// didn't fill the output buffer completely. Basically, this makes
    +	/// it easier to convert such applications from single-threaded
    +	/// decoder to multi-threaded decoder.
    +	bool out_was_filled;
    +
    +	/// Write position in buffer[] and position in Stream Padding
    +	size_t pos;
    +
    +	/// Buffer to hold Stream Header, Block Header, and Stream Footer.
    +	/// Block Header has biggest maximum size.
    +	uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
    +};
    +
    +
    +/// Enables updating of outbuf->pos. This is a callback function that is
    +/// used with lzma_outq_enable_partial_output().
    +static void
    +worker_enable_partial_update(void *thr_ptr)
    +{
    +	struct worker_thread *thr = thr_ptr;
    +
    +	mythread_sync(thr->mutex) {
    +		thr->partial_update = PARTIAL_START;
    +		mythread_cond_signal(&thr->cond);
    +	}
    +}
    +
    +
    +/// Things do to at THR_STOP or when finishing a Block.
    +/// This is called with thr->mutex locked.
    +static void
    +worker_stop(struct worker_thread *thr)
    +{
    +	// Update memory usage counters.
    +	thr->coder->mem_in_use -= thr->in_size;
    +	thr->in_size = 0; // thr->in was freed above.
    +
    +	thr->coder->mem_in_use -= thr->mem_filters;
    +	thr->coder->mem_cached += thr->mem_filters;
    +
    +	// Put this thread to the stack of free threads.
    +	thr->next = thr->coder->threads_free;
    +	thr->coder->threads_free = thr;
    +
    +	mythread_cond_signal(&thr->coder->cond);
    +	return;
    +}
    +
    +
    +static MYTHREAD_RET_TYPE
    +worker_decoder(void *thr_ptr)
    +{
    +	struct worker_thread *thr = thr_ptr;
    +	size_t in_filled;
    +	partial_update_mode partial_update;
    +	lzma_ret ret;
    +
    +next_loop_lock:
    +
    +	mythread_mutex_lock(&thr->mutex);
    +next_loop_unlocked:
    +
    +	if (thr->state == THR_IDLE) {
    +		mythread_cond_wait(&thr->cond, &thr->mutex);
    +		goto next_loop_unlocked;
    +	}
    +
    +	if (thr->state == THR_EXIT) {
    +		mythread_mutex_unlock(&thr->mutex);
    +
    +		lzma_free(thr->in, thr->allocator);
    +		lzma_next_end(&thr->block_decoder, thr->allocator);
    +
    +		mythread_mutex_destroy(&thr->mutex);
    +		mythread_cond_destroy(&thr->cond);
    +
    +		return MYTHREAD_RET_VALUE;
    +	}
    +
    +	if (thr->state == THR_STOP) {
    +		thr->state = THR_IDLE;
    +		mythread_mutex_unlock(&thr->mutex);
    +
    +		mythread_sync(thr->coder->mutex) {
    +			worker_stop(thr);
    +		}
    +
    +		goto next_loop_lock;
    +	}
    +
    +	assert(thr->state == THR_RUN);
    +
    +	// Update progress info for get_progress().
    +	thr->progress_in = thr->in_pos;
    +	thr->progress_out = thr->out_pos;
    +
    +	// If we don't have any new input, wait for a signal from the main
    +	// thread except if partial output has just been enabled. In that
    +	// case we will do one normal run so that the partial output info
    +	// gets passed to the main thread. The call to block_decoder.code()
    +	// is useless but harmless as it can occur only once per Block.
    +	in_filled = thr->in_filled;
    +	partial_update = thr->partial_update;
    +
    +	if (in_filled == thr->in_pos && partial_update != PARTIAL_START) {
    +		mythread_cond_wait(&thr->cond, &thr->mutex);
    +		goto next_loop_unlocked;
    +	}
    +
    +	mythread_mutex_unlock(&thr->mutex);
    +
    +	// Pass the input in small chunks to the Block decoder.
    +	// This way we react reasonably fast if we are told to stop/exit,
    +	// and (when partial update is enabled) we tell about our progress
    +	// to the main thread frequently enough.
    +	const size_t chunk_size = 16384;
    +	if ((in_filled - thr->in_pos) > chunk_size)
    +		in_filled = thr->in_pos + chunk_size;
    +
    +	ret = thr->block_decoder.code(
    +			thr->block_decoder.coder, thr->allocator,
    +			thr->in, &thr->in_pos, in_filled,
    +			thr->outbuf->buf, &thr->out_pos,
    +			thr->outbuf->allocated, LZMA_RUN);
    +
    +	if (ret == LZMA_OK) {
    +		if (partial_update != PARTIAL_DISABLED) {
    +			// The main thread uses thr->mutex to change from
    +			// PARTIAL_DISABLED to PARTIAL_START. The main thread
    +			// doesn't care about this variable after that so we
    +			// can safely change it here to PARTIAL_ENABLED
    +			// without a mutex.
    +			thr->partial_update = PARTIAL_ENABLED;
    +
    +			// The main thread is reading decompressed data
    +			// from thr->outbuf. Tell the main thread about
    +			// our progress.
    +			//
    +			// NOTE: It's possible that we consumed input without
    +			// producing any new output so it's possible that
    +			// only in_pos has changed. In case of PARTIAL_START
    +			// it is possible that neither in_pos nor out_pos has
    +			// changed.
    +			mythread_sync(thr->coder->mutex) {
    +				thr->outbuf->pos = thr->out_pos;
    +				thr->outbuf->decoder_in_pos = thr->in_pos;
    +				mythread_cond_signal(&thr->coder->cond);
    +			}
    +		}
    +
    +		goto next_loop_lock;
    +	}
    +
    +	// Either we finished successfully (LZMA_STREAM_END) or an error
    +	// occurred. Both cases are handled almost identically. The error
    +	// case requires updating thr->coder->thread_error.
    +	//
    +	// The sizes are in the Block Header and the Block decoder
    +	// checks that they match, thus we know these:
    +	assert(ret != LZMA_STREAM_END || thr->in_pos == thr->in_size);
    +	assert(ret != LZMA_STREAM_END
    +		|| thr->out_pos == thr->block_options.uncompressed_size);
    +
    +	// Free the input buffer. Don't update in_size as we need
    +	// it later to update thr->coder->mem_in_use.
    +	lzma_free(thr->in, thr->allocator);
    +	thr->in = NULL;
    +
    +	mythread_sync(thr->mutex) {
    +		if (thr->state != THR_EXIT)
    +			thr->state = THR_IDLE;
    +	}
    +
    +	mythread_sync(thr->coder->mutex) {
    +		// Move our progress info to the main thread.
    +		thr->coder->progress_in += thr->in_pos;
    +		thr->coder->progress_out += thr->out_pos;
    +		thr->progress_in = 0;
    +		thr->progress_out = 0;
    +
    +		// Mark the outbuf as finished.
    +		thr->outbuf->pos = thr->out_pos;
    +		thr->outbuf->decoder_in_pos = thr->in_pos;
    +		thr->outbuf->finished = true;
    +		thr->outbuf->finish_ret = ret;
    +		thr->outbuf = NULL;
    +
    +		// If an error occurred, tell it to the main thread.
    +		if (ret != LZMA_STREAM_END
    +				&& thr->coder->thread_error == LZMA_OK)
    +			thr->coder->thread_error = ret;
    +
    +		worker_stop(thr);
    +	}
    +
    +	goto next_loop_lock;
    +}
    +
    +
    +/// Tells the worker threads to exit and waits for them to terminate.
    +static void
    +threads_end(struct lzma_stream_coder *coder, const lzma_allocator *allocator)
    +{
    +	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
    +		mythread_sync(coder->threads[i].mutex) {
    +			coder->threads[i].state = THR_EXIT;
    +			mythread_cond_signal(&coder->threads[i].cond);
    +		}
    +	}
    +
    +	for (uint32_t i = 0; i < coder->threads_initialized; ++i)
    +		mythread_join(coder->threads[i].thread_id);
    +
    +	lzma_free(coder->threads, allocator);
    +	coder->threads_initialized = 0;
    +	coder->threads = NULL;
    +	coder->threads_free = NULL;
    +
    +	// The threads don't update these when they exit. Do it here.
    +	coder->mem_in_use = 0;
    +	coder->mem_cached = 0;
    +
    +	return;
    +}
    +
    +
    +static void
    +threads_stop(struct lzma_stream_coder *coder)
    +{
    +	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
    +		mythread_sync(coder->threads[i].mutex) {
    +			// The state must be changed conditionally because
    +			// THR_IDLE -> THR_STOP is not a valid state change.
    +			if (coder->threads[i].state != THR_IDLE) {
    +				coder->threads[i].state = THR_STOP;
    +				mythread_cond_signal(&coder->threads[i].cond);
    +			}
    +		}
    +	}
    +
    +	return;
    +}
    +
    +
    +/// Initialize a new worker_thread structure and create a new thread.
    +static lzma_ret
    +initialize_new_thread(struct lzma_stream_coder *coder,
    +		const lzma_allocator *allocator)
    +{
    +	// Allocate the coder->threads array if needed. It's done here instead
    +	// of when initializing the decoder because we don't need this if we
    +	// use the direct mode (we may even free coder->threads in the middle
    +	// of the file if we switch from threaded to direct mode).
    +	if (coder->threads == NULL) {
    +		coder->threads = lzma_alloc(
    +			coder->threads_max * sizeof(struct worker_thread),
    +			allocator);
    +
    +		if (coder->threads == NULL)
    +			return LZMA_MEM_ERROR;
    +	}
    +
    +	// Pick a free structure.
    +	assert(coder->threads_initialized < coder->threads_max);
    +	struct worker_thread *thr
    +			= &coder->threads[coder->threads_initialized];
    +
    +	if (mythread_mutex_init(&thr->mutex))
    +		goto error_mutex;
    +
    +	if (mythread_cond_init(&thr->cond))
    +		goto error_cond;
    +
    +	thr->state = THR_IDLE;
    +	thr->in = NULL;
    +	thr->in_size = 0;
    +	thr->allocator = allocator;
    +	thr->coder = coder;
    +	thr->outbuf = NULL;
    +	thr->block_decoder = LZMA_NEXT_CODER_INIT;
    +	thr->mem_filters = 0;
    +
    +	if (mythread_create(&thr->thread_id, worker_decoder, thr))
    +		goto error_thread;
    +
    +	++coder->threads_initialized;
    +	coder->thr = thr;
    +
    +	return LZMA_OK;
    +
    +error_thread:
    +	mythread_cond_destroy(&thr->cond);
    +
    +error_cond:
    +	mythread_mutex_destroy(&thr->mutex);
    +
    +error_mutex:
    +	return LZMA_MEM_ERROR;
    +}
    +
    +
    +static lzma_ret
    +get_thread(struct lzma_stream_coder *coder, const lzma_allocator *allocator)
    +{
    +	// If there is a free structure on the stack, use it.
    +	mythread_sync(coder->mutex) {
    +		if (coder->threads_free != NULL) {
    +			coder->thr = coder->threads_free;
    +			coder->threads_free = coder->threads_free->next;
    +
    +			// The thread is no longer in the cache so subtract
    +			// it from the cached memory usage. Don't add it
    +			// to mem_in_use though; the caller will handle it
    +			// since it knows how much memory it will actually
    +			// use (the filter chain might change).
    +			coder->mem_cached -= coder->thr->mem_filters;
    +		}
    +	}
    +
    +	if (coder->thr == NULL) {
    +		assert(coder->threads_initialized < coder->threads_max);
    +
    +		// Initialize a new thread.
    +		return_if_error(initialize_new_thread(coder, allocator));
    +	}
    +
    +	coder->thr->in_filled = 0;
    +	coder->thr->in_pos = 0;
    +	coder->thr->out_pos = 0;
    +
    +	coder->thr->progress_in = 0;
    +	coder->thr->progress_out = 0;
    +
    +	coder->thr->partial_update = PARTIAL_DISABLED;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static lzma_ret
    +read_output_and_wait(struct lzma_stream_coder *coder,
    +		const lzma_allocator *allocator,
    +		uint8_t *restrict out, size_t *restrict out_pos,
    +		size_t out_size,
    +		bool *input_is_possible,
    +		bool waiting_allowed,
    +		mythread_condtime *wait_abs, bool *has_blocked)
    +{
    +	lzma_ret ret = LZMA_OK;
    +
    +	mythread_sync(coder->mutex) {
    +		do {
    +			// Get as much output from the queue as is possible
    +			// without blocking.
    +			const size_t out_start = *out_pos;
    +			do {
    +				ret = lzma_outq_read(&coder->outq, allocator,
    +						out, out_pos, out_size,
    +						NULL, NULL);
    +
    +				// If a Block was finished, tell the worker
    +				// thread of the next Block (if it is still
    +				// running) to start telling the main thread
    +				// when new output is available.
    +				if (ret == LZMA_STREAM_END)
    +					lzma_outq_enable_partial_output(
    +						&coder->outq,
    +						&worker_enable_partial_update);
    +
    +				// Loop until a Block wasn't finished.
    +				// It's important to loop around even if
    +				// *out_pos == out_size because there could
    +				// be an empty Block that will return
    +				// LZMA_STREAM_END without needing any
    +				// output space.
    +			} while (ret == LZMA_STREAM_END);
    +
    +			// Check if lzma_outq_read reported an error from
    +			// the Block decoder.
    +			if (ret != LZMA_OK)
    +				break;
    +
    +			// If the output buffer is now full but it wasn't full
    +			// when this function was called, set out_was_filled.
    +			// This way the next call to stream_decode_mt() knows
    +			// that some output was produced and no output space
    +			// remained in the previous call to stream_decode_mt().
    +			if (*out_pos == out_size && *out_pos != out_start)
    +				coder->out_was_filled = true;
    +
    +			// Check if any thread has indicated an error.
    +			if (coder->thread_error != LZMA_OK) {
    +				// If LZMA_FAIL_FAST was used, report errors
    +				// from worker threads immediately.
    +				if (coder->fail_fast) {
    +					ret = coder->thread_error;
    +					break;
    +				}
    +
    +				// Otherwise set pending_error. The value we
    +				// set here will not actually get used other
    +				// than working as a flag that an error has
    +				// occurred. This is because in SEQ_ERROR
    +				// all output before the error will be read
    +				// first by calling this function, and once we
    +				// reach the location of the (first) error the
    +				// error code from the above lzma_outq_read()
    +				// will be returned to the application.
    +				//
    +				// Use LZMA_PROG_ERROR since the value should
    +				// never leak to the application. It's
    +				// possible that pending_error has already
    +				// been set but that doesn't matter: if we get
    +				// here, pending_error only works as a flag.
    +				coder->pending_error = LZMA_PROG_ERROR;
    +			}
    +
    +			// Check if decoding of the next Block can be started.
    +			// The memusage of the active threads must be low
    +			// enough, there must be a free buffer slot in the
    +			// output queue, and there must be a free thread
    +			// (that can be either created or an existing one
    +			// reused).
    +			//
    +			// NOTE: This is checked after reading the output
    +			// above because reading the output can free a slot in
    +			// the output queue and also reduce active memusage.
    +			//
    +			// NOTE: If output queue is empty, then input will
    +			// always be possible.
    +			if (input_is_possible != NULL
    +					&& coder->memlimit_threading
    +						- coder->mem_in_use
    +						- coder->outq.mem_in_use
    +						>= coder->mem_next_block
    +					&& lzma_outq_has_buf(&coder->outq)
    +					&& (coder->threads_initialized
    +							< coder->threads_max
    +						|| coder->threads_free
    +							!= NULL)) {
    +				*input_is_possible = true;
    +				break;
    +			}
    +
    +			// If the caller doesn't want us to block, return now.
    +			if (!waiting_allowed)
    +				break;
    +
    +			// This check is needed only when input_is_possible
    +			// is NULL. We must return if we aren't waiting for
    +			// input to become possible and there is no more
    +			// output coming from the queue.
    +			if (lzma_outq_is_empty(&coder->outq)) {
    +				assert(input_is_possible == NULL);
    +				break;
    +			}
    +
    +			// If there is more data available from the queue,
    +			// our out buffer must be full and we need to return
    +			// so that the application can provide more output
    +			// space.
    +			//
    +			// NOTE: In general lzma_outq_is_readable() can return
    +			// true also when there are no more bytes available.
    +			// This can happen when a Block has finished without
    +			// providing any new output. We know that this is not
    +			// the case because in the beginning of this loop we
    +			// tried to read as much as possible even when we had
    +			// no output space left and the mutex has been locked
    +			// all the time (so worker threads cannot have changed
    +			// anything). Thus there must be actual pending output
    +			// in the queue.
    +			if (lzma_outq_is_readable(&coder->outq)) {
    +				assert(*out_pos == out_size);
    +				break;
    +			}
    +
    +			// If the application stops providing more input
    +			// in the middle of a Block, there will eventually
    +			// be one worker thread left that is stuck waiting for
    +			// more input (that might never arrive) and a matching
    +			// outbuf which the worker thread cannot finish due
    +			// to lack of input. We must detect this situation,
    +			// otherwise we would end up waiting indefinitely
    +			// (if no timeout is in use) or keep returning
    +			// LZMA_TIMED_OUT while making no progress. Thus, the
    +			// application would never get LZMA_BUF_ERROR from
    +			// lzma_code() which would tell the application that
    +			// no more progress is possible. No LZMA_BUF_ERROR
    +			// means that, for example, truncated .xz files could
    +			// cause an infinite loop.
    +			//
    +			// A worker thread doing partial updates will
    +			// store not only the output position in outbuf->pos
    +			// but also the matching input position in
    +			// outbuf->decoder_in_pos. Here we check if that
    +			// input position matches the amount of input that
    +			// the worker thread has been given (in_filled).
    +			// If so, we must return and not wait as no more
    +			// output will be coming without first getting more
    +			// input to the worker thread. If the application
    +			// keeps calling lzma_code() without providing more
    +			// input, it will eventually get LZMA_BUF_ERROR.
    +			//
    +			// NOTE: We can read partial_update and in_filled
    +			// without thr->mutex as only the main thread
    +			// modifies these variables. decoder_in_pos requires
    +			// coder->mutex which we are already holding.
    +			if (coder->thr != NULL && coder->thr->partial_update
    +					!= PARTIAL_DISABLED) {
    +				// There is exactly one outbuf in the queue.
    +				assert(coder->thr->outbuf == coder->outq.head);
    +				assert(coder->thr->outbuf == coder->outq.tail);
    +
    +				if (coder->thr->outbuf->decoder_in_pos
    +						== coder->thr->in_filled)
    +					break;
    +			}
    +
    +			// Wait for input or output to become possible.
    +			if (coder->timeout != 0) {
    +				// See the comment in stream_encoder_mt.c
    +				// about why mythread_condtime_set() is used
    +				// like this.
    +				//
    +				// FIXME?
    +				// In contrast to the encoder, this calls
    +				// _condtime_set while the mutex is locked.
    +				if (!*has_blocked) {
    +					*has_blocked = true;
    +					mythread_condtime_set(wait_abs,
    +							&coder->cond,
    +							coder->timeout);
    +				}
    +
    +				if (mythread_cond_timedwait(&coder->cond,
    +						&coder->mutex,
    +						wait_abs) != 0) {
    +					ret = LZMA_TIMED_OUT;
    +					break;
    +				}
    +			} else {
    +				mythread_cond_wait(&coder->cond,
    +						&coder->mutex);
    +			}
    +		} while (ret == LZMA_OK);
    +	}
    +
    +	// If we are returning an error, then the application cannot get
    +	// more output from us and thus keeping the threads running is
    +	// useless and waste of CPU time.
    +	if (ret != LZMA_OK && ret != LZMA_TIMED_OUT)
    +		threads_stop(coder);
    +
    +	return ret;
    +}
    +
    +
    +static lzma_ret
    +decode_block_header(struct lzma_stream_coder *coder,
    +		const lzma_allocator *allocator, const uint8_t *restrict in,
    +		size_t *restrict in_pos, size_t in_size)
    +{
    +	if (*in_pos >= in_size)
    +		return LZMA_OK;
    +
    +	if (coder->pos == 0) {
    +		// Detect if it's Index.
    +		if (in[*in_pos] == INDEX_INDICATOR)
    +			return LZMA_INDEX_DETECTED;
    +
    +		// Calculate the size of the Block Header. Note that
    +		// Block Header decoder wants to see this byte too
    +		// so don't advance *in_pos.
    +		coder->block_options.header_size
    +				= lzma_block_header_size_decode(
    +					in[*in_pos]);
    +	}
    +
    +	// Copy the Block Header to the internal buffer.
    +	lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
    +			coder->block_options.header_size);
    +
    +	// Return if we didn't get the whole Block Header yet.
    +	if (coder->pos < coder->block_options.header_size)
    +		return LZMA_OK;
    +
    +	coder->pos = 0;
    +
    +	// Version 1 is needed to support the .ignore_check option.
    +	coder->block_options.version = 1;
    +
    +	// Block Header decoder will initialize all members of this array
    +	// so we don't need to do it here.
    +	coder->block_options.filters = coder->filters;
    +
    +	// Decode the Block Header.
    +	return_if_error(lzma_block_header_decode(&coder->block_options,
    +			allocator, coder->buffer));
    +
    +	// If LZMA_IGNORE_CHECK was used, this flag needs to be set.
    +	// It has to be set after lzma_block_header_decode() because
    +	// it always resets this to false.
    +	coder->block_options.ignore_check = coder->ignore_check;
    +
    +	// coder->block_options is ready now.
    +	return LZMA_STREAM_END;
    +}
    +
    +
    +/// Get the size of the Compressed Data + Block Padding + Check.
    +static size_t
    +comp_blk_size(const struct lzma_stream_coder *coder)
    +{
    +	return vli_ceil4(coder->block_options.compressed_size)
    +			+ lzma_check_size(coder->stream_flags.check);
    +}
    +
    +
    +/// Returns true if the size (compressed or uncompressed) is such that
    +/// threaded decompression cannot be used. Sizes that are too big compared
    +/// to SIZE_MAX must be rejected to avoid integer overflows and truncations
    +/// when lzma_vli is assigned to a size_t.
    +static bool
    +is_direct_mode_needed(lzma_vli size)
    +{
    +	return size == LZMA_VLI_UNKNOWN || size > SIZE_MAX / 3;
    +}
    +
    +
    +static lzma_ret
    +stream_decoder_reset(struct lzma_stream_coder *coder,
    +		const lzma_allocator *allocator)
    +{
    +	// Initialize the Index hash used to verify the Index.
    +	coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator);
    +	if (coder->index_hash == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	// Reset the rest of the variables.
    +	coder->sequence = SEQ_STREAM_HEADER;
    +	coder->pos = 0;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static lzma_ret
    +stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
    +		 const uint8_t *restrict in, size_t *restrict in_pos,
    +		 size_t in_size,
    +		 uint8_t *restrict out, size_t *restrict out_pos,
    +		 size_t out_size, lzma_action action)
    +{
    +	struct lzma_stream_coder *coder = coder_ptr;
    +
    +	mythread_condtime wait_abs;
    +	bool has_blocked = false;
    +
    +	// Determine if in SEQ_BLOCK_HEADER and SEQ_BLOCK_THR_RUN we should
    +	// tell read_output_and_wait() to wait until it can fill the output
    +	// buffer (or a timeout occurs). Two conditions must be met:
    +	//
    +	// (1) If the caller provided no new input. The reason for this
    +	//     can be, for example, the end of the file or that there is
    +	//     a pause in the input stream and more input is available
    +	//     a little later. In this situation we should wait for output
    +	//     because otherwise we would end up in a busy-waiting loop where
    +	//     we make no progress and the application just calls us again
    +	//     without providing any new input. This would then result in
    +	//     LZMA_BUF_ERROR even though more output would be available
    +	//     once the worker threads decode more data.
    +	//
    +	// (2) Even if (1) is true, we will not wait if the previous call to
    +	//     this function managed to produce some output and the output
    +	//     buffer became full. This is for compatibility with applications
    +	//     that call lzma_code() in such a way that new input is provided
    +	//     only when the output buffer didn't become full. Without this
    +	//     trick such applications would have bad performance (bad
    +	//     parallelization due to decoder not getting input fast enough).
    +	//
    +	//     NOTE: Such loops might require that timeout is disabled (0)
    +	//     if they assume that output-not-full implies that all input has
    +	//     been consumed. If and only if timeout is enabled, we may return
    +	//     when output isn't full *and* not all input has been consumed.
    +	//
    +	// However, if LZMA_FINISH is used, the above is ignored and we always
    +	// wait (timeout can still cause us to return) because we know that
    +	// we won't get any more input. This matters if the input file is
    +	// truncated and we are doing single-shot decoding, that is,
    +	// timeout = 0 and LZMA_FINISH is used on the first call to
    +	// lzma_code() and the output buffer is known to be big enough
    +	// to hold all uncompressed data:
    +	//
    +	//   - If LZMA_FINISH wasn't handled specially, we could return
    +	//     LZMA_OK before providing all output that is possible with the
    +	//     truncated input. The rest would be available if lzma_code() was
    +	//     called again but then it's not single-shot decoding anymore.
    +	//
    +	//   - By handling LZMA_FINISH specially here, the first call will
    +	//     produce all the output, matching the behavior of the
    +	//     single-threaded decoder.
    +	//
    +	// So it's a very specific corner case but also easy to avoid. Note
    +	// that this special handling of LZMA_FINISH has no effect for
    +	// single-shot decoding when the input file is valid (not truncated);
    +	// premature LZMA_OK wouldn't be possible as long as timeout = 0.
    +	const bool waiting_allowed = action == LZMA_FINISH
    +			|| (*in_pos == in_size && !coder->out_was_filled);
    +	coder->out_was_filled = false;
    +
    +	while (true)
    +	switch (coder->sequence) {
    +	case SEQ_STREAM_HEADER: {
    +		// Copy the Stream Header to the internal buffer.
    +		const size_t in_old = *in_pos;
    +		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
    +				LZMA_STREAM_HEADER_SIZE);
    +		coder->progress_in += *in_pos - in_old;
    +
    +		// Return if we didn't get the whole Stream Header yet.
    +		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
    +			return LZMA_OK;
    +
    +		coder->pos = 0;
    +
    +		// Decode the Stream Header.
    +		const lzma_ret ret = lzma_stream_header_decode(
    +				&coder->stream_flags, coder->buffer);
    +		if (ret != LZMA_OK)
    +			return ret == LZMA_FORMAT_ERROR && !coder->first_stream
    +					? LZMA_DATA_ERROR : ret;
    +
    +		// If we are decoding concatenated Streams, and the later
    +		// Streams have invalid Header Magic Bytes, we give
    +		// LZMA_DATA_ERROR instead of LZMA_FORMAT_ERROR.
    +		coder->first_stream = false;
    +
    +		// Copy the type of the Check so that Block Header and Block
    +		// decoders see it.
    +		coder->block_options.check = coder->stream_flags.check;
    +
    +		// Even if we return LZMA_*_CHECK below, we want
    +		// to continue from Block Header decoding.
    +		coder->sequence = SEQ_BLOCK_HEADER;
    +
    +		// Detect if there's no integrity check or if it is
    +		// unsupported if those were requested by the application.
    +		if (coder->tell_no_check && coder->stream_flags.check
    +				== LZMA_CHECK_NONE)
    +			return LZMA_NO_CHECK;
    +
    +		if (coder->tell_unsupported_check
    +				&& !lzma_check_is_supported(
    +					coder->stream_flags.check))
    +			return LZMA_UNSUPPORTED_CHECK;
    +
    +		if (coder->tell_any_check)
    +			return LZMA_GET_CHECK;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_BLOCK_HEADER: {
    +		const size_t in_old = *in_pos;
    +		const lzma_ret ret = decode_block_header(coder, allocator,
    +				in, in_pos, in_size);
    +		coder->progress_in += *in_pos - in_old;
    +
    +		if (ret == LZMA_OK) {
    +			// We didn't decode the whole Block Header yet.
    +			//
    +			// Read output from the queue before returning. This
    +			// is important because it is possible that the
    +			// application doesn't have any new input available
    +			// immediately. If we didn't try to copy output from
    +			// the output queue here, lzma_code() could end up
    +			// returning LZMA_BUF_ERROR even though queued output
    +			// is available.
    +			//
    +			// If the lzma_code() call provided at least one input
    +			// byte, only copy as much data from the output queue
    +			// as is available immediately. This way the
    +			// application will be able to provide more input
    +			// without a delay.
    +			//
    +			// On the other hand, if lzma_code() was called with
    +			// an empty input buffer(*), treat it specially: try
    +			// to fill the output buffer even if it requires
    +			// waiting for the worker threads to provide output
    +			// (timeout, if specified, can still cause us to
    +			// return).
    +			//
    +			//   - This way the application will be able to get all
    +			//     data that can be decoded from the input provided
    +			//     so far.
    +			//
    +			//   - We avoid both premature LZMA_BUF_ERROR and
    +			//     busy-waiting where the application repeatedly
    +			//     calls lzma_code() which immediately returns
    +			//     LZMA_OK without providing new data.
    +			//
    +			//   - If the queue becomes empty, we won't wait
    +			//     anything and will return LZMA_OK immediately
    +			//     (coder->timeout is completely ignored).
    +			//
    +			// (*) See the comment at the beginning of this
    +			//     function how waiting_allowed is determined
    +			//     and why there is an exception to the rule
    +			//     of "called with an empty input buffer".
    +			assert(*in_pos == in_size);
    +
    +			// If LZMA_FINISH was used we know that we won't get
    +			// more input, so the file must be truncated if we
    +			// get here. If worker threads don't detect any
    +			// errors, eventually there will be no more output
    +			// while we keep returning LZMA_OK which gets
    +			// converted to LZMA_BUF_ERROR in lzma_code().
    +			//
    +			// If fail-fast is enabled then we will return
    +			// immediately using LZMA_DATA_ERROR instead of
    +			// LZMA_OK or LZMA_BUF_ERROR. Rationale for the
    +			// error code:
    +			//
    +			//   - Worker threads may have a large amount of
    +			//     not-yet-decoded input data and we don't
    +			//     know for sure if all data is valid. Bad
    +			//     data there would result in LZMA_DATA_ERROR
    +			//     when fail-fast isn't used.
    +			//
    +			//   - Immediate LZMA_BUF_ERROR would be a bit weird
    +			//     considering the older liblzma code. lzma_code()
    +			//     even has an assertion to prevent coders from
    +			//     returning LZMA_BUF_ERROR directly.
    +			//
    +			// The downside of this is that with fail-fast apps
    +			// cannot always distinguish between corrupt and
    +			// truncated files.
    +			if (action == LZMA_FINISH && coder->fail_fast) {
    +				// We won't produce any more output. Stop
    +				// the unfinished worker threads so they
    +				// won't waste CPU time.
    +				threads_stop(coder);
    +				return LZMA_DATA_ERROR;
    +			}
    +
    +			// read_output_and_wait() will call threads_stop()
    +			// if needed so with that we can use return_if_error.
    +			return_if_error(read_output_and_wait(coder, allocator,
    +				out, out_pos, out_size,
    +				NULL, waiting_allowed,
    +				&wait_abs, &has_blocked));
    +
    +			if (coder->pending_error != LZMA_OK) {
    +				coder->sequence = SEQ_ERROR;
    +				break;
    +			}
    +
    +			return LZMA_OK;
    +		}
    +
    +		if (ret == LZMA_INDEX_DETECTED) {
    +			coder->sequence = SEQ_INDEX_WAIT_OUTPUT;
    +			break;
    +		}
    +
    +		// See if an error occurred.
    +		if (ret != LZMA_STREAM_END) {
    +			// NOTE: Here and in all other places where
    +			// pending_error is set, it may overwrite the value
    +			// (LZMA_PROG_ERROR) set by read_output_and_wait().
    +			// That function might overwrite value set here too.
    +			// These are fine because when read_output_and_wait()
    +			// sets pending_error, it actually works as a flag
    +			// variable only ("some error has occurred") and the
    +			// actual value of pending_error is not used in
    +			// SEQ_ERROR. In such cases SEQ_ERROR will eventually
    +			// get the correct error code from the return value of
    +			// a later read_output_and_wait() call.
    +			coder->pending_error = ret;
    +			coder->sequence = SEQ_ERROR;
    +			break;
    +		}
    +
    +		// Calculate the memory usage of the filters / Block decoder.
    +		coder->mem_next_filters = lzma_raw_decoder_memusage(
    +				coder->filters);
    +
    +		if (coder->mem_next_filters == UINT64_MAX) {
    +			// One or more unknown Filter IDs.
    +			coder->pending_error = LZMA_OPTIONS_ERROR;
    +			coder->sequence = SEQ_ERROR;
    +			break;
    +		}
    +
    +		coder->sequence = SEQ_BLOCK_INIT;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_BLOCK_INIT: {
    +		// Check if decoding is possible at all with the current
    +		// memlimit_stop which we must never exceed.
    +		//
    +		// This needs to be the first thing in SEQ_BLOCK_INIT
    +		// to make it possible to restart decoding after increasing
    +		// memlimit_stop with lzma_memlimit_set().
    +		if (coder->mem_next_filters > coder->memlimit_stop) {
    +			// Flush pending output before returning
    +			// LZMA_MEMLIMIT_ERROR. If the application doesn't
    +			// want to increase the limit, at least it will get
    +			// all the output possible so far.
    +			return_if_error(read_output_and_wait(coder, allocator,
    +					out, out_pos, out_size,
    +					NULL, true, &wait_abs, &has_blocked));
    +
    +			if (!lzma_outq_is_empty(&coder->outq))
    +				return LZMA_OK;
    +
    +			return LZMA_MEMLIMIT_ERROR;
    +		}
    +
    +		// Check if the size information is available in Block Header.
    +		// If it is, check if the sizes are small enough that we don't
    +		// need to worry *too* much about integer overflows later in
    +		// the code. If these conditions are not met, we must use the
    +		// single-threaded direct mode.
    +		if (is_direct_mode_needed(coder->block_options.compressed_size)
    +				|| is_direct_mode_needed(
    +				coder->block_options.uncompressed_size)) {
    +			coder->sequence = SEQ_BLOCK_DIRECT_INIT;
    +			break;
    +		}
    +
    +		// Calculate the amount of memory needed for the input and
    +		// output buffers in threaded mode.
    +		//
    +		// These cannot overflow because we already checked that
    +		// the sizes are small enough using is_direct_mode_needed().
    +		coder->mem_next_in = comp_blk_size(coder);
    +		const uint64_t mem_buffers = coder->mem_next_in
    +				+ lzma_outq_outbuf_memusage(
    +				coder->block_options.uncompressed_size);
    +
    +		// Add the amount needed by the filters.
    +		// Avoid integer overflows.
    +		if (UINT64_MAX - mem_buffers < coder->mem_next_filters) {
    +			// Use direct mode if the memusage would overflow.
    +			// This is a theoretical case that shouldn't happen
    +			// in practice unless the input file is weird (broken
    +			// or malicious).
    +			coder->sequence = SEQ_BLOCK_DIRECT_INIT;
    +			break;
    +		}
    +
    +		// Amount of memory needed to decode this Block in
    +		// threaded mode:
    +		coder->mem_next_block = coder->mem_next_filters + mem_buffers;
    +
    +		// If this alone would exceed memlimit_threading, then we must
    +		// use the single-threaded direct mode.
    +		if (coder->mem_next_block > coder->memlimit_threading) {
    +			coder->sequence = SEQ_BLOCK_DIRECT_INIT;
    +			break;
    +		}
    +
    +		// Use the threaded mode. Free the direct mode decoder in
    +		// case it has been initialized.
    +		lzma_next_end(&coder->block_decoder, allocator);
    +		coder->mem_direct_mode = 0;
    +
    +		// Since we already know what the sizes are supposed to be,
    +		// we can already add them to the Index hash. The Block
    +		// decoder will verify the values while decoding.
    +		const lzma_ret ret = lzma_index_hash_append(coder->index_hash,
    +				lzma_block_unpadded_size(
    +					&coder->block_options),
    +				coder->block_options.uncompressed_size);
    +		if (ret != LZMA_OK) {
    +			coder->pending_error = ret;
    +			coder->sequence = SEQ_ERROR;
    +			break;
    +		}
    +
    +		coder->sequence = SEQ_BLOCK_THR_INIT;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_BLOCK_THR_INIT: {
    +		// We need to wait for a multiple conditions to become true
    +		// until we can initialize the Block decoder and let a worker
    +		// thread decode it:
    +		//
    +		//   - Wait for the memory usage of the active threads to drop
    +		//     so that starting the decoding of this Block won't make
    +		//     us go over memlimit_threading.
    +		//
    +		//   - Wait for at least one free output queue slot.
    +		//
    +		//   - Wait for a free worker thread.
    +		//
    +		// While we wait, we must copy decompressed data to the out
    +		// buffer and catch possible decoder errors.
    +		//
    +		// read_output_and_wait() does all the above.
    +		bool block_can_start = false;
    +
    +		return_if_error(read_output_and_wait(coder, allocator,
    +				out, out_pos, out_size,
    +				&block_can_start, true,
    +				&wait_abs, &has_blocked));
    +
    +		if (coder->pending_error != LZMA_OK) {
    +			coder->sequence = SEQ_ERROR;
    +			break;
    +		}
    +
    +		if (!block_can_start) {
    +			// It's not a timeout because return_if_error handles
    +			// it already. Output queue cannot be empty either
    +			// because in that case block_can_start would have
    +			// been true. Thus the output buffer must be full and
    +			// the queue isn't empty.
    +			assert(*out_pos == out_size);
    +			assert(!lzma_outq_is_empty(&coder->outq));
    +			return LZMA_OK;
    +		}
    +
    +		// We know that we can start decoding this Block without
    +		// exceeding memlimit_threading. However, to stay below
    +		// memlimit_threading may require freeing some of the
    +		// cached memory.
    +		//
    +		// Get a local copy of variables that require locking the
    +		// mutex. It is fine if the worker threads modify the real
    +		// values after we read these as those changes can only be
    +		// towards more favorable conditions (less memory in use,
    +		// more in cache).
    +		//
    +		// These are initialized to silence warnings.
    +		uint64_t mem_in_use = 0;
    +		uint64_t mem_cached = 0;
    +		struct worker_thread *thr = NULL;
    +
    +		mythread_sync(coder->mutex) {
    +			mem_in_use = coder->mem_in_use;
    +			mem_cached = coder->mem_cached;
    +			thr = coder->threads_free;
    +		}
    +
    +		// The maximum amount of memory that can be held by other
    +		// threads and cached buffers while allowing us to start
    +		// decoding the next Block.
    +		const uint64_t mem_max = coder->memlimit_threading
    +				- coder->mem_next_block;
    +
    +		// If the existing allocations are so large that starting
    +		// to decode this Block might exceed memlimit_threads,
    +		// try to free memory from the output queue cache first.
    +		//
    +		// NOTE: This math assumes the worst case. It's possible
    +		// that the limit wouldn't be exceeded if the existing cached
    +		// allocations are reused.
    +		if (mem_in_use + mem_cached + coder->outq.mem_allocated
    +				> mem_max) {
    +			// Clear the outq cache except leave one buffer in
    +			// the cache if its size is correct. That way we
    +			// don't free and almost immediately reallocate
    +			// an identical buffer.
    +			lzma_outq_clear_cache2(&coder->outq, allocator,
    +				coder->block_options.uncompressed_size);
    +		}
    +
    +		// If there is at least one worker_thread in the cache and
    +		// the existing allocations are so large that starting to
    +		// decode this Block might exceed memlimit_threads, free
    +		// memory by freeing cached Block decoders.
    +		//
    +		// NOTE: The comparison is different here than above.
    +		// Here we don't care about cached buffers in outq anymore
    +		// and only look at memory actually in use. This is because
    +		// if there is something in outq cache, it's a single buffer
    +		// that can be used as is. We ensured this in the above
    +		// if-block.
    +		uint64_t mem_freed = 0;
    +		if (thr != NULL && mem_in_use + mem_cached
    +				+ coder->outq.mem_in_use > mem_max) {
    +			// Don't free the first Block decoder if its memory
    +			// usage isn't greater than what this Block will need.
    +			// Typically the same filter chain is used for all
    +			// Blocks so this way the allocations can be reused
    +			// when get_thread() picks the first worker_thread
    +			// from the cache.
    +			if (thr->mem_filters <= coder->mem_next_filters)
    +				thr = thr->next;
    +
    +			while (thr != NULL) {
    +				lzma_next_end(&thr->block_decoder, allocator);
    +				mem_freed += thr->mem_filters;
    +				thr->mem_filters = 0;
    +				thr = thr->next;
    +			}
    +		}
    +
    +		// Update the memory usage counters. Note that coder->mem_*
    +		// may have changed since we read them so we must subtract
    +		// or add the changes.
    +		mythread_sync(coder->mutex) {
    +			coder->mem_cached -= mem_freed;
    +
    +			// Memory needed for the filters and the input buffer.
    +			// The output queue takes care of its own counter so
    +			// we don't touch it here.
    +			//
    +			// NOTE: After this, coder->mem_in_use +
    +			// coder->mem_cached might count the same thing twice.
    +			// If so, this will get corrected in get_thread() when
    +			// a worker_thread is picked from coder->free_threads
    +			// and its memory usage is subtracted from mem_cached.
    +			coder->mem_in_use += coder->mem_next_in
    +					+ coder->mem_next_filters;
    +		}
    +
    +		// Allocate memory for the output buffer in the output queue.
    +		lzma_ret ret = lzma_outq_prealloc_buf(
    +				&coder->outq, allocator,
    +				coder->block_options.uncompressed_size);
    +		if (ret != LZMA_OK) {
    +			threads_stop(coder);
    +			return ret;
    +		}
    +
    +		// Set up coder->thr.
    +		ret = get_thread(coder, allocator);
    +		if (ret != LZMA_OK) {
    +			threads_stop(coder);
    +			return ret;
    +		}
    +
    +		// The new Block decoder memory usage is already counted in
    +		// coder->mem_in_use. Store it in the thread too.
    +		coder->thr->mem_filters = coder->mem_next_filters;
    +
    +		// Initialize the Block decoder.
    +		coder->thr->block_options = coder->block_options;
    +		ret = lzma_block_decoder_init(
    +					&coder->thr->block_decoder, allocator,
    +					&coder->thr->block_options);
    +
    +		// Free the allocated filter options since they are needed
    +		// only to initialize the Block decoder.
    +		lzma_filters_free(coder->filters, allocator);
    +		coder->thr->block_options.filters = NULL;
    +
    +		// Check if memory usage calculation and Block encoder
    +		// initialization succeeded.
    +		if (ret != LZMA_OK) {
    +			coder->pending_error = ret;
    +			coder->sequence = SEQ_ERROR;
    +			break;
    +		}
    +
    +		// Allocate the input buffer.
    +		coder->thr->in_size = coder->mem_next_in;
    +		coder->thr->in = lzma_alloc(coder->thr->in_size, allocator);
    +		if (coder->thr->in == NULL) {
    +			threads_stop(coder);
    +			return LZMA_MEM_ERROR;
    +		}
    +
    +		// Get the preallocated output buffer.
    +		coder->thr->outbuf = lzma_outq_get_buf(
    +				&coder->outq, coder->thr);
    +
    +		// Start the decoder.
    +		mythread_sync(coder->thr->mutex) {
    +			assert(coder->thr->state == THR_IDLE);
    +			coder->thr->state = THR_RUN;
    +			mythread_cond_signal(&coder->thr->cond);
    +		}
    +
    +		// Enable output from the thread that holds the oldest output
    +		// buffer in the output queue (if such a thread exists).
    +		mythread_sync(coder->mutex) {
    +			lzma_outq_enable_partial_output(&coder->outq,
    +					&worker_enable_partial_update);
    +		}
    +
    +		coder->sequence = SEQ_BLOCK_THR_RUN;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_BLOCK_THR_RUN: {
    +		if (action == LZMA_FINISH && coder->fail_fast) {
    +			// We know that we won't get more input and that
    +			// the caller wants fail-fast behavior. If we see
    +			// that we don't have enough input to finish this
    +			// Block, return LZMA_DATA_ERROR immediately.
    +			// See SEQ_BLOCK_HEADER for the error code rationale.
    +			const size_t in_avail = in_size - *in_pos;
    +			const size_t in_needed = coder->thr->in_size
    +					- coder->thr->in_filled;
    +			if (in_avail < in_needed) {
    +				threads_stop(coder);
    +				return LZMA_DATA_ERROR;
    +			}
    +		}
    +
    +		// Copy input to the worker thread.
    +		size_t cur_in_filled = coder->thr->in_filled;
    +		lzma_bufcpy(in, in_pos, in_size, coder->thr->in,
    +				&cur_in_filled, coder->thr->in_size);
    +
    +		// Tell the thread how much we copied.
    +		mythread_sync(coder->thr->mutex) {
    +			coder->thr->in_filled = cur_in_filled;
    +
    +			// NOTE: Most of the time we are copying input faster
    +			// than the thread can decode so most of the time
    +			// calling mythread_cond_signal() is useless but
    +			// we cannot make it conditional because thr->in_pos
    +			// is updated without a mutex. And the overhead should
    +			// be very much negligible anyway.
    +			mythread_cond_signal(&coder->thr->cond);
    +		}
    +
    +		// Read output from the output queue. Just like in
    +		// SEQ_BLOCK_HEADER, we wait to fill the output buffer
    +		// only if waiting_allowed was set to true in the beginning
    +		// of this function (see the comment there).
    +		return_if_error(read_output_and_wait(coder, allocator,
    +				out, out_pos, out_size,
    +				NULL, waiting_allowed,
    +				&wait_abs, &has_blocked));
    +
    +		if (coder->pending_error != LZMA_OK) {
    +			coder->sequence = SEQ_ERROR;
    +			break;
    +		}
    +
    +		// Return if the input didn't contain the whole Block.
    +		if (coder->thr->in_filled < coder->thr->in_size) {
    +			assert(*in_pos == in_size);
    +			return LZMA_OK;
    +		}
    +
    +		// The whole Block has been copied to the thread-specific
    +		// buffer. Continue from the next Block Header or Index.
    +		coder->thr = NULL;
    +		coder->sequence = SEQ_BLOCK_HEADER;
    +		break;
    +	}
    +
    +	case SEQ_BLOCK_DIRECT_INIT: {
    +		// Wait for the threads to finish and that all decoded data
    +		// has been copied to the output. That is, wait until the
    +		// output queue becomes empty.
    +		//
    +		// NOTE: No need to check for coder->pending_error as
    +		// we aren't consuming any input until the queue is empty
    +		// and if there is a pending error, read_output_and_wait()
    +		// will eventually return it before the queue is empty.
    +		return_if_error(read_output_and_wait(coder, allocator,
    +				out, out_pos, out_size,
    +				NULL, true, &wait_abs, &has_blocked));
    +		if (!lzma_outq_is_empty(&coder->outq))
    +			return LZMA_OK;
    +
    +		// Free the cached output buffers.
    +		lzma_outq_clear_cache(&coder->outq, allocator);
    +
    +		// Get rid of the worker threads, including the coder->threads
    +		// array.
    +		threads_end(coder, allocator);
    +
    +		// Initialize the Block decoder.
    +		const lzma_ret ret = lzma_block_decoder_init(
    +				&coder->block_decoder, allocator,
    +				&coder->block_options);
    +
    +		// Free the allocated filter options since they are needed
    +		// only to initialize the Block decoder.
    +		lzma_filters_free(coder->filters, allocator);
    +		coder->block_options.filters = NULL;
    +
    +		// Check if Block decoder initialization succeeded.
    +		if (ret != LZMA_OK)
    +			return ret;
    +
    +		// Make the memory usage visible to _memconfig().
    +		coder->mem_direct_mode = coder->mem_next_filters;
    +
    +		coder->sequence = SEQ_BLOCK_DIRECT_RUN;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_BLOCK_DIRECT_RUN: {
    +		const size_t in_old = *in_pos;
    +		const size_t out_old = *out_pos;
    +		const lzma_ret ret = coder->block_decoder.code(
    +				coder->block_decoder.coder, allocator,
    +				in, in_pos, in_size, out, out_pos, out_size,
    +				action);
    +		coder->progress_in += *in_pos - in_old;
    +		coder->progress_out += *out_pos - out_old;
    +
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +
    +		// Block decoded successfully. Add the new size pair to
    +		// the Index hash.
    +		return_if_error(lzma_index_hash_append(coder->index_hash,
    +				lzma_block_unpadded_size(
    +					&coder->block_options),
    +				coder->block_options.uncompressed_size));
    +
    +		coder->sequence = SEQ_BLOCK_HEADER;
    +		break;
    +	}
    +
    +	case SEQ_INDEX_WAIT_OUTPUT:
    +		// Flush the output from all worker threads so that we can
    +		// decode the Index without thinking about threading.
    +		return_if_error(read_output_and_wait(coder, allocator,
    +				out, out_pos, out_size,
    +				NULL, true, &wait_abs, &has_blocked));
    +
    +		if (!lzma_outq_is_empty(&coder->outq))
    +			return LZMA_OK;
    +
    +		coder->sequence = SEQ_INDEX_DECODE;
    +
    +	// Fall through
    +
    +	case SEQ_INDEX_DECODE: {
    +		// If we don't have any input, don't call
    +		// lzma_index_hash_decode() since it would return
    +		// LZMA_BUF_ERROR, which we must not do here.
    +		if (*in_pos >= in_size)
    +			return LZMA_OK;
    +
    +		// Decode the Index and compare it to the hash calculated
    +		// from the sizes of the Blocks (if any).
    +		const size_t in_old = *in_pos;
    +		const lzma_ret ret = lzma_index_hash_decode(coder->index_hash,
    +				in, in_pos, in_size);
    +		coder->progress_in += *in_pos - in_old;
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +
    +		coder->sequence = SEQ_STREAM_FOOTER;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_STREAM_FOOTER: {
    +		// Copy the Stream Footer to the internal buffer.
    +		const size_t in_old = *in_pos;
    +		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
    +				LZMA_STREAM_HEADER_SIZE);
    +		coder->progress_in += *in_pos - in_old;
    +
    +		// Return if we didn't get the whole Stream Footer yet.
    +		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
    +			return LZMA_OK;
    +
    +		coder->pos = 0;
    +
    +		// Decode the Stream Footer. The decoder gives
    +		// LZMA_FORMAT_ERROR if the magic bytes don't match,
    +		// so convert that return code to LZMA_DATA_ERROR.
    +		lzma_stream_flags footer_flags;
    +		const lzma_ret ret = lzma_stream_footer_decode(
    +				&footer_flags, coder->buffer);
    +		if (ret != LZMA_OK)
    +			return ret == LZMA_FORMAT_ERROR
    +					? LZMA_DATA_ERROR : ret;
    +
    +		// Check that Index Size stored in the Stream Footer matches
    +		// the real size of the Index field.
    +		if (lzma_index_hash_size(coder->index_hash)
    +				!= footer_flags.backward_size)
    +			return LZMA_DATA_ERROR;
    +
    +		// Compare that the Stream Flags fields are identical in
    +		// both Stream Header and Stream Footer.
    +		return_if_error(lzma_stream_flags_compare(
    +				&coder->stream_flags, &footer_flags));
    +
    +		if (!coder->concatenated)
    +			return LZMA_STREAM_END;
    +
    +		coder->sequence = SEQ_STREAM_PADDING;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_STREAM_PADDING:
    +		assert(coder->concatenated);
    +
    +		// Skip over possible Stream Padding.
    +		while (true) {
    +			if (*in_pos >= in_size) {
    +				// Unless LZMA_FINISH was used, we cannot
    +				// know if there's more input coming later.
    +				if (action != LZMA_FINISH)
    +					return LZMA_OK;
    +
    +				// Stream Padding must be a multiple of
    +				// four bytes.
    +				return coder->pos == 0
    +						? LZMA_STREAM_END
    +						: LZMA_DATA_ERROR;
    +			}
    +
    +			// If the byte is not zero, it probably indicates
    +			// beginning of a new Stream (or the file is corrupt).
    +			if (in[*in_pos] != 0x00)
    +				break;
    +
    +			++*in_pos;
    +			++coder->progress_in;
    +			coder->pos = (coder->pos + 1) & 3;
    +		}
    +
    +		// Stream Padding must be a multiple of four bytes (empty
    +		// Stream Padding is OK).
    +		if (coder->pos != 0) {
    +			++*in_pos;
    +			++coder->progress_in;
    +			return LZMA_DATA_ERROR;
    +		}
    +
    +		// Prepare to decode the next Stream.
    +		return_if_error(stream_decoder_reset(coder, allocator));
    +		break;
    +
    +	case SEQ_ERROR:
    +		if (!coder->fail_fast) {
    +			// Let the application get all data before the point
    +			// where the error was detected. This matches the
    +			// behavior of single-threaded use.
    +			//
    +			// FIXME? Some errors (LZMA_MEM_ERROR) don't get here,
    +			// they are returned immediately. Thus in rare cases
    +			// the output will be less than in the single-threaded
    +			// mode. Maybe this doesn't matter much in practice.
    +			return_if_error(read_output_and_wait(coder, allocator,
    +					out, out_pos, out_size,
    +					NULL, true, &wait_abs, &has_blocked));
    +
    +			// We get here only if the error happened in the main
    +			// thread, for example, unsupported Block Header.
    +			if (!lzma_outq_is_empty(&coder->outq))
    +				return LZMA_OK;
    +		}
    +
    +		// We only get here if no errors were detected by the worker
    +		// threads. Errors from worker threads would have already been
    +		// returned by the call to read_output_and_wait() above.
    +		return coder->pending_error;
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	// Never reached
    +}
    +
    +
    +static void
    +stream_decoder_mt_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	struct lzma_stream_coder *coder = coder_ptr;
    +
    +	threads_end(coder, allocator);
    +	lzma_outq_end(&coder->outq, allocator);
    +
    +	lzma_next_end(&coder->block_decoder, allocator);
    +	lzma_filters_free(coder->filters, allocator);
    +	lzma_index_hash_end(coder->index_hash, allocator);
    +
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_check
    +stream_decoder_mt_get_check(const void *coder_ptr)
    +{
    +	const struct lzma_stream_coder *coder = coder_ptr;
    +	return coder->stream_flags.check;
    +}
    +
    +
    +static lzma_ret
    +stream_decoder_mt_memconfig(void *coder_ptr, uint64_t *memusage,
    +		uint64_t *old_memlimit, uint64_t new_memlimit)
    +{
    +	// NOTE: This function gets/sets memlimit_stop. For now,
    +	// memlimit_threading cannot be modified after initialization.
    +	//
    +	// *memusage will include cached memory too. Excluding cached memory
    +	// would be misleading and it wouldn't help the applications to
    +	// know how much memory is actually needed to decompress the file
    +	// because the higher the number of threads and the memlimits are
    +	// the more memory the decoder may use.
    +	//
    +	// Setting a new limit includes the cached memory too and too low
    +	// limits will be rejected. Alternative could be to free the cached
    +	// memory immediately if that helps to bring the limit down but
    +	// the current way is the simplest. It's unlikely that limit needs
    +	// to be lowered in the middle of a file anyway; the typical reason
    +	// to want a new limit is to increase after LZMA_MEMLIMIT_ERROR
    +	// and even such use isn't common.
    +	struct lzma_stream_coder *coder = coder_ptr;
    +
    +	mythread_sync(coder->mutex) {
    +		*memusage = coder->mem_direct_mode
    +				+ coder->mem_in_use
    +				+ coder->mem_cached
    +				+ coder->outq.mem_allocated;
    +	}
    +
    +	// If no filter chains are allocated, *memusage may be zero.
    +	// Always return at least LZMA_MEMUSAGE_BASE.
    +	if (*memusage < LZMA_MEMUSAGE_BASE)
    +		*memusage = LZMA_MEMUSAGE_BASE;
    +
    +	*old_memlimit = coder->memlimit_stop;
    +
    +	if (new_memlimit != 0) {
    +		if (new_memlimit < *memusage)
    +			return LZMA_MEMLIMIT_ERROR;
    +
    +		coder->memlimit_stop = new_memlimit;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +stream_decoder_mt_get_progress(void *coder_ptr,
    +		uint64_t *progress_in, uint64_t *progress_out)
    +{
    +	struct lzma_stream_coder *coder = coder_ptr;
    +
    +	// Lock coder->mutex to prevent finishing threads from moving their
    +	// progress info from the worker_thread structure to lzma_stream_coder.
    +	mythread_sync(coder->mutex) {
    +		*progress_in = coder->progress_in;
    +		*progress_out = coder->progress_out;
    +
    +		for (size_t i = 0; i < coder->threads_initialized; ++i) {
    +			mythread_sync(coder->threads[i].mutex) {
    +				*progress_in += coder->threads[i].progress_in;
    +				*progress_out += coder->threads[i]
    +						.progress_out;
    +			}
    +		}
    +	}
    +
    +	return;
    +}
    +
    +
    +static lzma_ret
    +stream_decoder_mt_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		       const lzma_mt *options)
    +{
    +	struct lzma_stream_coder *coder;
    +
    +	if (options->threads == 0 || options->threads > LZMA_THREADS_MAX)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	if (options->flags & ~LZMA_SUPPORTED_FLAGS)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	lzma_next_coder_init(&stream_decoder_mt_init, next, allocator);
    +
    +	coder = next->coder;
    +	if (!coder) {
    +		coder = lzma_alloc(sizeof(struct lzma_stream_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +
    +		if (mythread_mutex_init(&coder->mutex)) {
    +			lzma_free(coder, allocator);
    +			return LZMA_MEM_ERROR;
    +		}
    +
    +		if (mythread_cond_init(&coder->cond)) {
    +			mythread_mutex_destroy(&coder->mutex);
    +			lzma_free(coder, allocator);
    +			return LZMA_MEM_ERROR;
    +		}
    +
    +		next->code = &stream_decode_mt;
    +		next->end = &stream_decoder_mt_end;
    +		next->get_check = &stream_decoder_mt_get_check;
    +		next->memconfig = &stream_decoder_mt_memconfig;
    +		next->get_progress = &stream_decoder_mt_get_progress;
    +
    +		coder->filters[0].id = LZMA_VLI_UNKNOWN;
    +		memzero(&coder->outq, sizeof(coder->outq));
    +
    +		coder->block_decoder = LZMA_NEXT_CODER_INIT;
    +		coder->mem_direct_mode = 0;
    +
    +		coder->index_hash = NULL;
    +		coder->threads = NULL;
    +		coder->threads_free = NULL;
    +		coder->threads_initialized = 0;
    +	}
    +
    +	// Cleanup old filter chain if one remains after unfinished decoding
    +	// of a previous Stream.
    +	lzma_filters_free(coder->filters, allocator);
    +
    +	// By allocating threads from scratch we can start memory-usage
    +	// accounting from scratch, too. Changes in filter and block sizes may
    +	// affect number of threads.
    +	//
    +	// FIXME? Reusing should be easy but unlike the single-threaded
    +	// decoder, with some types of input file combinations reusing
    +	// could leave quite a lot of memory allocated but unused (first
    +	// file could allocate a lot, the next files could use fewer
    +	// threads and some of the allocations from the first file would not
    +	// get freed unless memlimit_threading forces us to clear caches).
    +	//
    +	// NOTE: The direct mode decoder isn't freed here if one exists.
    +	// It will be reused or freed as needed in the main loop.
    +	threads_end(coder, allocator);
    +
    +	// All memusage counters start at 0 (including mem_direct_mode).
    +	// The little extra that is needed for the structs in this file
    +	// get accounted well enough by the filter chain memory usage
    +	// which adds LZMA_MEMUSAGE_BASE for each chain. However,
    +	// stream_decoder_mt_memconfig() has to handle this specially so that
    +	// it will never return less than LZMA_MEMUSAGE_BASE as memory usage.
    +	coder->mem_in_use = 0;
    +	coder->mem_cached = 0;
    +	coder->mem_next_block = 0;
    +
    +	coder->progress_in = 0;
    +	coder->progress_out = 0;
    +
    +	coder->sequence = SEQ_STREAM_HEADER;
    +	coder->thread_error = LZMA_OK;
    +	coder->pending_error = LZMA_OK;
    +	coder->thr = NULL;
    +
    +	coder->timeout = options->timeout;
    +
    +	coder->memlimit_threading = my_max(1, options->memlimit_threading);
    +	coder->memlimit_stop = my_max(1, options->memlimit_stop);
    +	if (coder->memlimit_threading > coder->memlimit_stop)
    +		coder->memlimit_threading = coder->memlimit_stop;
    +
    +	coder->tell_no_check = (options->flags & LZMA_TELL_NO_CHECK) != 0;
    +	coder->tell_unsupported_check
    +			= (options->flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0;
    +	coder->tell_any_check = (options->flags & LZMA_TELL_ANY_CHECK) != 0;
    +	coder->ignore_check = (options->flags & LZMA_IGNORE_CHECK) != 0;
    +	coder->concatenated = (options->flags & LZMA_CONCATENATED) != 0;
    +	coder->fail_fast = (options->flags & LZMA_FAIL_FAST) != 0;
    +
    +	coder->first_stream = true;
    +	coder->out_was_filled = false;
    +	coder->pos = 0;
    +
    +	coder->threads_max = options->threads;
    +
    +	return_if_error(lzma_outq_init(&coder->outq, allocator,
    +				       coder->threads_max));
    +
    +	return stream_decoder_reset(coder, allocator);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_decoder_mt(lzma_stream *strm, const lzma_mt *options)
    +{
    +	lzma_next_strm_init(stream_decoder_mt_init, strm, options);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder.c
    new file mode 100644
    index 00000000000..e7e5b3fce7e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder.c
    @@ -0,0 +1,354 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_encoder.c
    +/// \brief      Encodes .xz Streams
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "block_encoder.h"
    +#include "index_encoder.h"
    +
    +
    +typedef struct {
    +	enum {
    +		SEQ_STREAM_HEADER,
    +		SEQ_BLOCK_INIT,
    +		SEQ_BLOCK_HEADER,
    +		SEQ_BLOCK_ENCODE,
    +		SEQ_INDEX_ENCODE,
    +		SEQ_STREAM_FOOTER,
    +	} sequence;
    +
    +	/// True if Block encoder has been initialized by
    +	/// stream_encoder_init() or stream_encoder_update()
    +	/// and thus doesn't need to be initialized in stream_encode().
    +	bool block_encoder_is_initialized;
    +
    +	/// Block
    +	lzma_next_coder block_encoder;
    +
    +	/// Options for the Block encoder
    +	lzma_block block_options;
    +
    +	/// The filter chain currently in use
    +	lzma_filter filters[LZMA_FILTERS_MAX + 1];
    +
    +	/// Index encoder. This is separate from Block encoder, because this
    +	/// doesn't take much memory, and when encoding multiple Streams
    +	/// with the same encoding options we avoid reallocating memory.
    +	lzma_next_coder index_encoder;
    +
    +	/// Index to hold sizes of the Blocks
    +	lzma_index *index;
    +
    +	/// Read position in buffer[]
    +	size_t buffer_pos;
    +
    +	/// Total number of bytes in buffer[]
    +	size_t buffer_size;
    +
    +	/// Buffer to hold Stream Header, Block Header, and Stream Footer.
    +	/// Block Header has biggest maximum size.
    +	uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
    +} lzma_stream_coder;
    +
    +
    +static lzma_ret
    +block_encoder_init(lzma_stream_coder *coder, const lzma_allocator *allocator)
    +{
    +	// Prepare the Block options. Even though Block encoder doesn't need
    +	// compressed_size, uncompressed_size, and header_size to be
    +	// initialized, it is a good idea to do it here, because this way
    +	// we catch if someone gave us Filter ID that cannot be used in
    +	// Blocks/Streams.
    +	coder->block_options.compressed_size = LZMA_VLI_UNKNOWN;
    +	coder->block_options.uncompressed_size = LZMA_VLI_UNKNOWN;
    +
    +	return_if_error(lzma_block_header_size(&coder->block_options));
    +
    +	// Initialize the actual Block encoder.
    +	return lzma_block_encoder_init(&coder->block_encoder, allocator,
    +			&coder->block_options);
    +}
    +
    +
    +static lzma_ret
    +stream_encode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +
    +	// Main loop
    +	while (*out_pos < out_size)
    +	switch (coder->sequence) {
    +	case SEQ_STREAM_HEADER:
    +	case SEQ_BLOCK_HEADER:
    +	case SEQ_STREAM_FOOTER:
    +		lzma_bufcpy(coder->buffer, &coder->buffer_pos,
    +				coder->buffer_size, out, out_pos, out_size);
    +		if (coder->buffer_pos < coder->buffer_size)
    +			return LZMA_OK;
    +
    +		if (coder->sequence == SEQ_STREAM_FOOTER)
    +			return LZMA_STREAM_END;
    +
    +		coder->buffer_pos = 0;
    +		++coder->sequence;
    +		break;
    +
    +	case SEQ_BLOCK_INIT: {
    +		if (*in_pos == in_size) {
    +			// If we are requested to flush or finish the current
    +			// Block, return LZMA_STREAM_END immediately since
    +			// there's nothing to do.
    +			if (action != LZMA_FINISH)
    +				return action == LZMA_RUN
    +						? LZMA_OK : LZMA_STREAM_END;
    +
    +			// The application had used LZMA_FULL_FLUSH to finish
    +			// the previous Block, but now wants to finish without
    +			// encoding new data, or it is simply creating an
    +			// empty Stream with no Blocks.
    +			//
    +			// Initialize the Index encoder, and continue to
    +			// actually encoding the Index.
    +			return_if_error(lzma_index_encoder_init(
    +					&coder->index_encoder, allocator,
    +					coder->index));
    +			coder->sequence = SEQ_INDEX_ENCODE;
    +			break;
    +		}
    +
    +		// Initialize the Block encoder unless it was already
    +		// initialized by stream_encoder_init() or
    +		// stream_encoder_update().
    +		if (!coder->block_encoder_is_initialized)
    +			return_if_error(block_encoder_init(coder, allocator));
    +
    +		// Make it false so that we don't skip the initialization
    +		// with the next Block.
    +		coder->block_encoder_is_initialized = false;
    +
    +		// Encode the Block Header. This shouldn't fail since we have
    +		// already initialized the Block encoder.
    +		if (lzma_block_header_encode(&coder->block_options,
    +				coder->buffer) != LZMA_OK)
    +			return LZMA_PROG_ERROR;
    +
    +		coder->buffer_size = coder->block_options.header_size;
    +		coder->sequence = SEQ_BLOCK_HEADER;
    +		break;
    +	}
    +
    +	case SEQ_BLOCK_ENCODE: {
    +		static const lzma_action convert[LZMA_ACTION_MAX + 1] = {
    +			LZMA_RUN,
    +			LZMA_SYNC_FLUSH,
    +			LZMA_FINISH,
    +			LZMA_FINISH,
    +			LZMA_FINISH,
    +		};
    +
    +		const lzma_ret ret = coder->block_encoder.code(
    +				coder->block_encoder.coder, allocator,
    +				in, in_pos, in_size,
    +				out, out_pos, out_size, convert[action]);
    +		if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
    +			return ret;
    +
    +		// Add a new Index Record.
    +		const lzma_vli unpadded_size = lzma_block_unpadded_size(
    +				&coder->block_options);
    +		assert(unpadded_size != 0);
    +		return_if_error(lzma_index_append(coder->index, allocator,
    +				unpadded_size,
    +				coder->block_options.uncompressed_size));
    +
    +		coder->sequence = SEQ_BLOCK_INIT;
    +		break;
    +	}
    +
    +	case SEQ_INDEX_ENCODE: {
    +		// Call the Index encoder. It doesn't take any input, so
    +		// those pointers can be NULL.
    +		const lzma_ret ret = coder->index_encoder.code(
    +				coder->index_encoder.coder, allocator,
    +				NULL, NULL, 0,
    +				out, out_pos, out_size, LZMA_RUN);
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +
    +		// Encode the Stream Footer into coder->buffer.
    +		const lzma_stream_flags stream_flags = {
    +			.version = 0,
    +			.backward_size = lzma_index_size(coder->index),
    +			.check = coder->block_options.check,
    +		};
    +
    +		if (lzma_stream_footer_encode(&stream_flags, coder->buffer)
    +				!= LZMA_OK)
    +			return LZMA_PROG_ERROR;
    +
    +		coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
    +		coder->sequence = SEQ_STREAM_FOOTER;
    +		break;
    +	}
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +stream_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +
    +	lzma_next_end(&coder->block_encoder, allocator);
    +	lzma_next_end(&coder->index_encoder, allocator);
    +	lzma_index_end(coder->index, allocator);
    +
    +	lzma_filters_free(coder->filters, allocator);
    +
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +stream_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
    +		const lzma_filter *filters,
    +		const lzma_filter *reversed_filters)
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +	lzma_ret ret;
    +
    +	// Make a copy to a temporary buffer first. This way it is easier
    +	// to keep the encoder state unchanged if an error occurs with
    +	// lzma_filters_copy().
    +	lzma_filter temp[LZMA_FILTERS_MAX + 1];
    +	return_if_error(lzma_filters_copy(filters, temp, allocator));
    +
    +	if (coder->sequence <= SEQ_BLOCK_INIT) {
    +		// There is no incomplete Block waiting to be finished,
    +		// thus we can change the whole filter chain. Start by
    +		// trying to initialize the Block encoder with the new
    +		// chain. This way we detect if the chain is valid.
    +		coder->block_encoder_is_initialized = false;
    +		coder->block_options.filters = temp;
    +		ret = block_encoder_init(coder, allocator);
    +		coder->block_options.filters = coder->filters;
    +		if (ret != LZMA_OK)
    +			goto error;
    +
    +		coder->block_encoder_is_initialized = true;
    +
    +	} else if (coder->sequence <= SEQ_BLOCK_ENCODE) {
    +		// We are in the middle of a Block. Try to update only
    +		// the filter-specific options.
    +		ret = coder->block_encoder.update(
    +				coder->block_encoder.coder, allocator,
    +				filters, reversed_filters);
    +		if (ret != LZMA_OK)
    +			goto error;
    +	} else {
    +		// Trying to update the filter chain when we are already
    +		// encoding Index or Stream Footer.
    +		ret = LZMA_PROG_ERROR;
    +		goto error;
    +	}
    +
    +	// Free the options of the old chain.
    +	lzma_filters_free(coder->filters, allocator);
    +
    +	// Copy the new filter chain in place.
    +	memcpy(coder->filters, temp, sizeof(temp));
    +
    +	return LZMA_OK;
    +
    +error:
    +	lzma_filters_free(temp, allocator);
    +	return ret;
    +}
    +
    +
    +static lzma_ret
    +stream_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter *filters, lzma_check check)
    +{
    +	lzma_next_coder_init(&stream_encoder_init, next, allocator);
    +
    +	if (filters == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	lzma_stream_coder *coder = next->coder;
    +
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &stream_encode;
    +		next->end = &stream_encoder_end;
    +		next->update = &stream_encoder_update;
    +
    +		coder->filters[0].id = LZMA_VLI_UNKNOWN;
    +		coder->block_encoder = LZMA_NEXT_CODER_INIT;
    +		coder->index_encoder = LZMA_NEXT_CODER_INIT;
    +		coder->index = NULL;
    +	}
    +
    +	// Basic initializations
    +	coder->sequence = SEQ_STREAM_HEADER;
    +	coder->block_options.version = 0;
    +	coder->block_options.check = check;
    +
    +	// Initialize the Index
    +	lzma_index_end(coder->index, allocator);
    +	coder->index = lzma_index_init(allocator);
    +	if (coder->index == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	// Encode the Stream Header
    +	lzma_stream_flags stream_flags = {
    +		.version = 0,
    +		.check = check,
    +	};
    +	return_if_error(lzma_stream_header_encode(
    +			&stream_flags, coder->buffer));
    +
    +	coder->buffer_pos = 0;
    +	coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
    +
    +	// Initialize the Block encoder. This way we detect unsupported
    +	// filter chains when initializing the Stream encoder instead of
    +	// giving an error after Stream Header has already been written out.
    +	return stream_encoder_update(coder, allocator, filters, NULL);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_encoder(lzma_stream *strm,
    +		const lzma_filter *filters, lzma_check check)
    +{
    +	lzma_next_strm_init(stream_encoder_init, strm, filters, check);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
    +	strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
    +	strm->internal->supported_actions[LZMA_FULL_BARRIER] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder_mt.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder_mt.c
    new file mode 100644
    index 00000000000..f0fef152331
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder_mt.c
    @@ -0,0 +1,1280 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_encoder_mt.c
    +/// \brief      Multithreaded .xz Stream encoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "filter_encoder.h"
    +#include "easy_preset.h"
    +#include "block_encoder.h"
    +#include "block_buffer_encoder.h"
    +#include "index_encoder.h"
    +#include "outqueue.h"
    +
    +
    +/// Maximum supported block size. This makes it simpler to prevent integer
    +/// overflows if we are given unusually large block size.
    +#define BLOCK_SIZE_MAX (UINT64_MAX / LZMA_THREADS_MAX)
    +
    +
    +typedef enum {
    +	/// Waiting for work.
    +	THR_IDLE,
    +
    +	/// Encoding is in progress.
    +	THR_RUN,
    +
    +	/// Encoding is in progress but no more input data will
    +	/// be read.
    +	THR_FINISH,
    +
    +	/// The main thread wants the thread to stop whatever it was doing
    +	/// but not exit.
    +	THR_STOP,
    +
    +	/// The main thread wants the thread to exit. We could use
    +	/// cancellation but since there's stopped anyway, this is lazier.
    +	THR_EXIT,
    +
    +} worker_state;
    +
    +typedef struct lzma_stream_coder_s lzma_stream_coder;
    +
    +typedef struct worker_thread_s worker_thread;
    +struct worker_thread_s {
    +	worker_state state;
    +
    +	/// Input buffer of coder->block_size bytes. The main thread will
    +	/// put new input into this and update in_size accordingly. Once
    +	/// no more input is coming, state will be set to THR_FINISH.
    +	uint8_t *in;
    +
    +	/// Amount of data available in the input buffer. This is modified
    +	/// only by the main thread.
    +	size_t in_size;
    +
    +	/// Output buffer for this thread. This is set by the main
    +	/// thread every time a new Block is started with this thread
    +	/// structure.
    +	lzma_outbuf *outbuf;
    +
    +	/// Pointer to the main structure is needed when putting this
    +	/// thread back to the stack of free threads.
    +	lzma_stream_coder *coder;
    +
    +	/// The allocator is set by the main thread. Since a copy of the
    +	/// pointer is kept here, the application must not change the
    +	/// allocator before calling lzma_end().
    +	const lzma_allocator *allocator;
    +
    +	/// Amount of uncompressed data that has already been compressed.
    +	uint64_t progress_in;
    +
    +	/// Amount of compressed data that is ready.
    +	uint64_t progress_out;
    +
    +	/// Block encoder
    +	lzma_next_coder block_encoder;
    +
    +	/// Compression options for this Block
    +	lzma_block block_options;
    +
    +	/// Filter chain for this thread. By copying the filters array
    +	/// to each thread it is possible to change the filter chain
    +	/// between Blocks using lzma_filters_update().
    +	lzma_filter filters[LZMA_FILTERS_MAX + 1];
    +
    +	/// Next structure in the stack of free worker threads.
    +	worker_thread *next;
    +
    +	mythread_mutex mutex;
    +	mythread_cond cond;
    +
    +	/// The ID of this thread is used to join the thread
    +	/// when it's not needed anymore.
    +	mythread thread_id;
    +};
    +
    +
    +struct lzma_stream_coder_s {
    +	enum {
    +		SEQ_STREAM_HEADER,
    +		SEQ_BLOCK,
    +		SEQ_INDEX,
    +		SEQ_STREAM_FOOTER,
    +	} sequence;
    +
    +	/// Start a new Block every block_size bytes of input unless
    +	/// LZMA_FULL_FLUSH or LZMA_FULL_BARRIER is used earlier.
    +	size_t block_size;
    +
    +	/// The filter chain to use for the next Block.
    +	/// This can be updated using lzma_filters_update()
    +	/// after LZMA_FULL_BARRIER or LZMA_FULL_FLUSH.
    +	lzma_filter filters[LZMA_FILTERS_MAX + 1];
    +
    +	/// A copy of filters[] will be put here when attempting to get
    +	/// a new worker thread. This will be copied to a worker thread
    +	/// when a thread becomes free and then this cache is marked as
    +	/// empty by setting [0].id = LZMA_VLI_UNKNOWN. Without this cache
    +	/// the filter options from filters[] would get uselessly copied
    +	/// multiple times (allocated and freed) when waiting for a new free
    +	/// worker thread.
    +	///
    +	/// This is freed if filters[] is updated via lzma_filters_update().
    +	lzma_filter filters_cache[LZMA_FILTERS_MAX + 1];
    +
    +
    +	/// Index to hold sizes of the Blocks
    +	lzma_index *index;
    +
    +	/// Index encoder
    +	lzma_next_coder index_encoder;
    +
    +
    +	/// Stream Flags for encoding the Stream Header and Stream Footer.
    +	lzma_stream_flags stream_flags;
    +
    +	/// Buffer to hold Stream Header and Stream Footer.
    +	uint8_t header[LZMA_STREAM_HEADER_SIZE];
    +
    +	/// Read position in header[]
    +	size_t header_pos;
    +
    +
    +	/// Output buffer queue for compressed data
    +	lzma_outq outq;
    +
    +	/// How much memory to allocate for each lzma_outbuf.buf
    +	size_t outbuf_alloc_size;
    +
    +
    +	/// Maximum wait time if cannot use all the input and cannot
    +	/// fill the output buffer. This is in milliseconds.
    +	uint32_t timeout;
    +
    +
    +	/// Error code from a worker thread
    +	lzma_ret thread_error;
    +
    +	/// Array of allocated thread-specific structures
    +	worker_thread *threads;
    +
    +	/// Number of structures in "threads" above. This is also the
    +	/// number of threads that will be created at maximum.
    +	uint32_t threads_max;
    +
    +	/// Number of thread structures that have been initialized, and
    +	/// thus the number of worker threads actually created so far.
    +	uint32_t threads_initialized;
    +
    +	/// Stack of free threads. When a thread finishes, it puts itself
    +	/// back into this stack. This starts as empty because threads
    +	/// are created only when actually needed.
    +	worker_thread *threads_free;
    +
    +	/// The most recent worker thread to which the main thread writes
    +	/// the new input from the application.
    +	worker_thread *thr;
    +
    +
    +	/// Amount of uncompressed data in Blocks that have already
    +	/// been finished.
    +	uint64_t progress_in;
    +
    +	/// Amount of compressed data in Stream Header + Blocks that
    +	/// have already been finished.
    +	uint64_t progress_out;
    +
    +
    +	mythread_mutex mutex;
    +	mythread_cond cond;
    +};
    +
    +
    +/// Tell the main thread that something has gone wrong.
    +static void
    +worker_error(worker_thread *thr, lzma_ret ret)
    +{
    +	assert(ret != LZMA_OK);
    +	assert(ret != LZMA_STREAM_END);
    +
    +	mythread_sync(thr->coder->mutex) {
    +		if (thr->coder->thread_error == LZMA_OK)
    +			thr->coder->thread_error = ret;
    +
    +		mythread_cond_signal(&thr->coder->cond);
    +	}
    +
    +	return;
    +}
    +
    +
    +static worker_state
    +worker_encode(worker_thread *thr, size_t *out_pos, worker_state state)
    +{
    +	assert(thr->progress_in == 0);
    +	assert(thr->progress_out == 0);
    +
    +	// Set the Block options.
    +	thr->block_options = (lzma_block){
    +		.version = 0,
    +		.check = thr->coder->stream_flags.check,
    +		.compressed_size = thr->outbuf->allocated,
    +		.uncompressed_size = thr->coder->block_size,
    +		.filters = thr->filters,
    +	};
    +
    +	// Calculate maximum size of the Block Header. This amount is
    +	// reserved in the beginning of the buffer so that Block Header
    +	// along with Compressed Size and Uncompressed Size can be
    +	// written there.
    +	lzma_ret ret = lzma_block_header_size(&thr->block_options);
    +	if (ret != LZMA_OK) {
    +		worker_error(thr, ret);
    +		return THR_STOP;
    +	}
    +
    +	// Initialize the Block encoder.
    +	ret = lzma_block_encoder_init(&thr->block_encoder,
    +			thr->allocator, &thr->block_options);
    +	if (ret != LZMA_OK) {
    +		worker_error(thr, ret);
    +		return THR_STOP;
    +	}
    +
    +	size_t in_pos = 0;
    +	size_t in_size = 0;
    +
    +	*out_pos = thr->block_options.header_size;
    +	const size_t out_size = thr->outbuf->allocated;
    +
    +	do {
    +		mythread_sync(thr->mutex) {
    +			// Store in_pos and *out_pos into *thr so that
    +			// an application may read them via
    +			// lzma_get_progress() to get progress information.
    +			//
    +			// NOTE: These aren't updated when the encoding
    +			// finishes. Instead, the final values are taken
    +			// later from thr->outbuf.
    +			thr->progress_in = in_pos;
    +			thr->progress_out = *out_pos;
    +
    +			while (in_size == thr->in_size
    +					&& thr->state == THR_RUN)
    +				mythread_cond_wait(&thr->cond, &thr->mutex);
    +
    +			state = thr->state;
    +			in_size = thr->in_size;
    +		}
    +
    +		// Return if we were asked to stop or exit.
    +		if (state >= THR_STOP)
    +			return state;
    +
    +		lzma_action action = state == THR_FINISH
    +				? LZMA_FINISH : LZMA_RUN;
    +
    +		// Limit the amount of input given to the Block encoder
    +		// at once. This way this thread can react fairly quickly
    +		// if the main thread wants us to stop or exit.
    +		static const size_t in_chunk_max = 16384;
    +		size_t in_limit = in_size;
    +		if (in_size - in_pos > in_chunk_max) {
    +			in_limit = in_pos + in_chunk_max;
    +			action = LZMA_RUN;
    +		}
    +
    +		ret = thr->block_encoder.code(
    +				thr->block_encoder.coder, thr->allocator,
    +				thr->in, &in_pos, in_limit, thr->outbuf->buf,
    +				out_pos, out_size, action);
    +	} while (ret == LZMA_OK && *out_pos < out_size);
    +
    +	switch (ret) {
    +	case LZMA_STREAM_END:
    +		assert(state == THR_FINISH);
    +
    +		// Encode the Block Header. By doing it after
    +		// the compression, we can store the Compressed Size
    +		// and Uncompressed Size fields.
    +		ret = lzma_block_header_encode(&thr->block_options,
    +				thr->outbuf->buf);
    +		if (ret != LZMA_OK) {
    +			worker_error(thr, ret);
    +			return THR_STOP;
    +		}
    +
    +		break;
    +
    +	case LZMA_OK:
    +		// The data was incompressible. Encode it using uncompressed
    +		// LZMA2 chunks.
    +		//
    +		// First wait that we have gotten all the input.
    +		mythread_sync(thr->mutex) {
    +			while (thr->state == THR_RUN)
    +				mythread_cond_wait(&thr->cond, &thr->mutex);
    +
    +			state = thr->state;
    +			in_size = thr->in_size;
    +		}
    +
    +		if (state >= THR_STOP)
    +			return state;
    +
    +		// Do the encoding. This takes care of the Block Header too.
    +		*out_pos = 0;
    +		ret = lzma_block_uncomp_encode(&thr->block_options,
    +				thr->in, in_size, thr->outbuf->buf,
    +				out_pos, out_size);
    +
    +		// It shouldn't fail.
    +		if (ret != LZMA_OK) {
    +			worker_error(thr, LZMA_PROG_ERROR);
    +			return THR_STOP;
    +		}
    +
    +		break;
    +
    +	default:
    +		worker_error(thr, ret);
    +		return THR_STOP;
    +	}
    +
    +	// Set the size information that will be read by the main thread
    +	// to write the Index field.
    +	thr->outbuf->unpadded_size
    +			= lzma_block_unpadded_size(&thr->block_options);
    +	assert(thr->outbuf->unpadded_size != 0);
    +	thr->outbuf->uncompressed_size = thr->block_options.uncompressed_size;
    +
    +	return THR_FINISH;
    +}
    +
    +
    +static MYTHREAD_RET_TYPE
    +worker_start(void *thr_ptr)
    +{
    +	worker_thread *thr = thr_ptr;
    +	worker_state state = THR_IDLE; // Init to silence a warning
    +
    +	while (true) {
    +		// Wait for work.
    +		mythread_sync(thr->mutex) {
    +			while (true) {
    +				// The thread is already idle so if we are
    +				// requested to stop, just set the state.
    +				if (thr->state == THR_STOP) {
    +					thr->state = THR_IDLE;
    +					mythread_cond_signal(&thr->cond);
    +				}
    +
    +				state = thr->state;
    +				if (state != THR_IDLE)
    +					break;
    +
    +				mythread_cond_wait(&thr->cond, &thr->mutex);
    +			}
    +		}
    +
    +		size_t out_pos = 0;
    +
    +		assert(state != THR_IDLE);
    +		assert(state != THR_STOP);
    +
    +		if (state <= THR_FINISH)
    +			state = worker_encode(thr, &out_pos, state);
    +
    +		if (state == THR_EXIT)
    +			break;
    +
    +		// Mark the thread as idle unless the main thread has
    +		// told us to exit. Signal is needed for the case
    +		// where the main thread is waiting for the threads to stop.
    +		mythread_sync(thr->mutex) {
    +			if (thr->state != THR_EXIT) {
    +				thr->state = THR_IDLE;
    +				mythread_cond_signal(&thr->cond);
    +			}
    +		}
    +
    +		mythread_sync(thr->coder->mutex) {
    +			// If no errors occurred, make the encoded data
    +			// available to be copied out.
    +			if (state == THR_FINISH) {
    +				thr->outbuf->pos = out_pos;
    +				thr->outbuf->finished = true;
    +			}
    +
    +			// Update the main progress info.
    +			thr->coder->progress_in
    +					+= thr->outbuf->uncompressed_size;
    +			thr->coder->progress_out += out_pos;
    +			thr->progress_in = 0;
    +			thr->progress_out = 0;
    +
    +			// Return this thread to the stack of free threads.
    +			thr->next = thr->coder->threads_free;
    +			thr->coder->threads_free = thr;
    +
    +			mythread_cond_signal(&thr->coder->cond);
    +		}
    +	}
    +
    +	// Exiting, free the resources.
    +	lzma_filters_free(thr->filters, thr->allocator);
    +
    +	mythread_mutex_destroy(&thr->mutex);
    +	mythread_cond_destroy(&thr->cond);
    +
    +	lzma_next_end(&thr->block_encoder, thr->allocator);
    +	lzma_free(thr->in, thr->allocator);
    +	return MYTHREAD_RET_VALUE;
    +}
    +
    +
    +/// Make the threads stop but not exit. Optionally wait for them to stop.
    +static void
    +threads_stop(lzma_stream_coder *coder, bool wait_for_threads)
    +{
    +	// Tell the threads to stop.
    +	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
    +		mythread_sync(coder->threads[i].mutex) {
    +			coder->threads[i].state = THR_STOP;
    +			mythread_cond_signal(&coder->threads[i].cond);
    +		}
    +	}
    +
    +	if (!wait_for_threads)
    +		return;
    +
    +	// Wait for the threads to settle in the idle state.
    +	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
    +		mythread_sync(coder->threads[i].mutex) {
    +			while (coder->threads[i].state != THR_IDLE)
    +				mythread_cond_wait(&coder->threads[i].cond,
    +						&coder->threads[i].mutex);
    +		}
    +	}
    +
    +	return;
    +}
    +
    +
    +/// Stop the threads and free the resources associated with them.
    +/// Wait until the threads have exited.
    +static void
    +threads_end(lzma_stream_coder *coder, const lzma_allocator *allocator)
    +{
    +	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
    +		mythread_sync(coder->threads[i].mutex) {
    +			coder->threads[i].state = THR_EXIT;
    +			mythread_cond_signal(&coder->threads[i].cond);
    +		}
    +	}
    +
    +	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
    +		int ret = mythread_join(coder->threads[i].thread_id);
    +		assert(ret == 0);
    +		(void)ret;
    +	}
    +
    +	lzma_free(coder->threads, allocator);
    +	return;
    +}
    +
    +
    +/// Initialize a new worker_thread structure and create a new thread.
    +static lzma_ret
    +initialize_new_thread(lzma_stream_coder *coder,
    +		const lzma_allocator *allocator)
    +{
    +	worker_thread *thr = &coder->threads[coder->threads_initialized];
    +
    +	thr->in = lzma_alloc(coder->block_size, allocator);
    +	if (thr->in == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	if (mythread_mutex_init(&thr->mutex))
    +		goto error_mutex;
    +
    +	if (mythread_cond_init(&thr->cond))
    +		goto error_cond;
    +
    +	thr->state = THR_IDLE;
    +	thr->allocator = allocator;
    +	thr->coder = coder;
    +	thr->progress_in = 0;
    +	thr->progress_out = 0;
    +	thr->block_encoder = LZMA_NEXT_CODER_INIT;
    +	thr->filters[0].id = LZMA_VLI_UNKNOWN;
    +
    +	if (mythread_create(&thr->thread_id, &worker_start, thr))
    +		goto error_thread;
    +
    +	++coder->threads_initialized;
    +	coder->thr = thr;
    +
    +	return LZMA_OK;
    +
    +error_thread:
    +	mythread_cond_destroy(&thr->cond);
    +
    +error_cond:
    +	mythread_mutex_destroy(&thr->mutex);
    +
    +error_mutex:
    +	lzma_free(thr->in, allocator);
    +	return LZMA_MEM_ERROR;
    +}
    +
    +
    +static lzma_ret
    +get_thread(lzma_stream_coder *coder, const lzma_allocator *allocator)
    +{
    +	// If there are no free output subqueues, there is no
    +	// point to try getting a thread.
    +	if (!lzma_outq_has_buf(&coder->outq))
    +		return LZMA_OK;
    +
    +	// That's also true if we cannot allocate memory for the output
    +	// buffer in the output queue.
    +	return_if_error(lzma_outq_prealloc_buf(&coder->outq, allocator,
    +			coder->outbuf_alloc_size));
    +
    +	// Make a thread-specific copy of the filter chain. Put it in
    +	// the cache array first so that if we cannot get a new thread yet,
    +	// the allocation is ready when we try again.
    +	if (coder->filters_cache[0].id == LZMA_VLI_UNKNOWN)
    +		return_if_error(lzma_filters_copy(
    +			coder->filters, coder->filters_cache, allocator));
    +
    +	// If there is a free structure on the stack, use it.
    +	mythread_sync(coder->mutex) {
    +		if (coder->threads_free != NULL) {
    +			coder->thr = coder->threads_free;
    +			coder->threads_free = coder->threads_free->next;
    +		}
    +	}
    +
    +	if (coder->thr == NULL) {
    +		// If there are no uninitialized structures left, return.
    +		if (coder->threads_initialized == coder->threads_max)
    +			return LZMA_OK;
    +
    +		// Initialize a new thread.
    +		return_if_error(initialize_new_thread(coder, allocator));
    +	}
    +
    +	// Reset the parts of the thread state that have to be done
    +	// in the main thread.
    +	mythread_sync(coder->thr->mutex) {
    +		coder->thr->state = THR_RUN;
    +		coder->thr->in_size = 0;
    +		coder->thr->outbuf = lzma_outq_get_buf(&coder->outq, NULL);
    +
    +		// Free the old thread-specific filter options and replace
    +		// them with the already-allocated new options from
    +		// coder->filters_cache[]. Then mark the cache as empty.
    +		lzma_filters_free(coder->thr->filters, allocator);
    +		memcpy(coder->thr->filters, coder->filters_cache,
    +				sizeof(coder->filters_cache));
    +		coder->filters_cache[0].id = LZMA_VLI_UNKNOWN;
    +
    +		mythread_cond_signal(&coder->thr->cond);
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static lzma_ret
    +stream_encode_in(lzma_stream_coder *coder, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, lzma_action action)
    +{
    +	while (*in_pos < in_size
    +			|| (coder->thr != NULL && action != LZMA_RUN)) {
    +		if (coder->thr == NULL) {
    +			// Get a new thread.
    +			const lzma_ret ret = get_thread(coder, allocator);
    +			if (coder->thr == NULL)
    +				return ret;
    +		}
    +
    +		// Copy the input data to thread's buffer.
    +		size_t thr_in_size = coder->thr->in_size;
    +		lzma_bufcpy(in, in_pos, in_size, coder->thr->in,
    +				&thr_in_size, coder->block_size);
    +
    +		// Tell the Block encoder to finish if
    +		//  - it has got block_size bytes of input; or
    +		//  - all input was used and LZMA_FINISH, LZMA_FULL_FLUSH,
    +		//    or LZMA_FULL_BARRIER was used.
    +		//
    +		// TODO: LZMA_SYNC_FLUSH and LZMA_SYNC_BARRIER.
    +		const bool finish = thr_in_size == coder->block_size
    +				|| (*in_pos == in_size && action != LZMA_RUN);
    +
    +		bool block_error = false;
    +
    +		mythread_sync(coder->thr->mutex) {
    +			if (coder->thr->state == THR_IDLE) {
    +				// Something has gone wrong with the Block
    +				// encoder. It has set coder->thread_error
    +				// which we will read a few lines later.
    +				block_error = true;
    +			} else {
    +				// Tell the Block encoder its new amount
    +				// of input and update the state if needed.
    +				coder->thr->in_size = thr_in_size;
    +
    +				if (finish)
    +					coder->thr->state = THR_FINISH;
    +
    +				mythread_cond_signal(&coder->thr->cond);
    +			}
    +		}
    +
    +		if (block_error) {
    +			lzma_ret ret = LZMA_OK; // Init to silence a warning.
    +
    +			mythread_sync(coder->mutex) {
    +				ret = coder->thread_error;
    +			}
    +
    +			return ret;
    +		}
    +
    +		if (finish)
    +			coder->thr = NULL;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +/// Wait until more input can be consumed, more output can be read, or
    +/// an optional timeout is reached.
    +static bool
    +wait_for_work(lzma_stream_coder *coder, mythread_condtime *wait_abs,
    +		bool *has_blocked, bool has_input)
    +{
    +	if (coder->timeout != 0 && !*has_blocked) {
    +		// Every time when stream_encode_mt() is called via
    +		// lzma_code(), *has_blocked starts as false. We set it
    +		// to true here and calculate the absolute time when
    +		// we must return if there's nothing to do.
    +		//
    +		// This way if we block multiple times for short moments
    +		// less than "timeout" milliseconds, we will return once
    +		// "timeout" amount of time has passed since the *first*
    +		// blocking occurred. If the absolute time was calculated
    +		// again every time we block, "timeout" would effectively
    +		// be meaningless if we never consecutively block longer
    +		// than "timeout" ms.
    +		*has_blocked = true;
    +		mythread_condtime_set(wait_abs, &coder->cond, coder->timeout);
    +	}
    +
    +	bool timed_out = false;
    +
    +	mythread_sync(coder->mutex) {
    +		// There are four things that we wait. If one of them
    +		// becomes possible, we return.
    +		//  - If there is input left, we need to get a free
    +		//    worker thread and an output buffer for it.
    +		//  - Data ready to be read from the output queue.
    +		//  - A worker thread indicates an error.
    +		//  - Time out occurs.
    +		while ((!has_input || coder->threads_free == NULL
    +					|| !lzma_outq_has_buf(&coder->outq))
    +				&& !lzma_outq_is_readable(&coder->outq)
    +				&& coder->thread_error == LZMA_OK
    +				&& !timed_out) {
    +			if (coder->timeout != 0)
    +				timed_out = mythread_cond_timedwait(
    +						&coder->cond, &coder->mutex,
    +						wait_abs) != 0;
    +			else
    +				mythread_cond_wait(&coder->cond,
    +						&coder->mutex);
    +		}
    +	}
    +
    +	return timed_out;
    +}
    +
    +
    +static lzma_ret
    +stream_encode_mt(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +
    +	switch (coder->sequence) {
    +	case SEQ_STREAM_HEADER:
    +		lzma_bufcpy(coder->header, &coder->header_pos,
    +				sizeof(coder->header),
    +				out, out_pos, out_size);
    +		if (coder->header_pos < sizeof(coder->header))
    +			return LZMA_OK;
    +
    +		coder->header_pos = 0;
    +		coder->sequence = SEQ_BLOCK;
    +
    +	// Fall through
    +
    +	case SEQ_BLOCK: {
    +		// Initialized to silence warnings.
    +		lzma_vli unpadded_size = 0;
    +		lzma_vli uncompressed_size = 0;
    +		lzma_ret ret = LZMA_OK;
    +
    +		// These are for wait_for_work().
    +		bool has_blocked = false;
    +		mythread_condtime wait_abs = { 0 };
    +
    +		while (true) {
    +			mythread_sync(coder->mutex) {
    +				// Check for Block encoder errors.
    +				ret = coder->thread_error;
    +				if (ret != LZMA_OK) {
    +					assert(ret != LZMA_STREAM_END);
    +					break; // Break out of mythread_sync.
    +				}
    +
    +				// Try to read compressed data to out[].
    +				ret = lzma_outq_read(&coder->outq, allocator,
    +						out, out_pos, out_size,
    +						&unpadded_size,
    +						&uncompressed_size);
    +			}
    +
    +			if (ret == LZMA_STREAM_END) {
    +				// End of Block. Add it to the Index.
    +				ret = lzma_index_append(coder->index,
    +						allocator, unpadded_size,
    +						uncompressed_size);
    +				if (ret != LZMA_OK) {
    +					threads_stop(coder, false);
    +					return ret;
    +				}
    +
    +				// If we didn't fill the output buffer yet,
    +				// try to read more data. Maybe the next
    +				// outbuf has been finished already too.
    +				if (*out_pos < out_size)
    +					continue;
    +			}
    +
    +			if (ret != LZMA_OK) {
    +				// coder->thread_error was set.
    +				threads_stop(coder, false);
    +				return ret;
    +			}
    +
    +			// Try to give uncompressed data to a worker thread.
    +			ret = stream_encode_in(coder, allocator,
    +					in, in_pos, in_size, action);
    +			if (ret != LZMA_OK) {
    +				threads_stop(coder, false);
    +				return ret;
    +			}
    +
    +			// See if we should wait or return.
    +			//
    +			// TODO: LZMA_SYNC_FLUSH and LZMA_SYNC_BARRIER.
    +			if (*in_pos == in_size) {
    +				// LZMA_RUN: More data is probably coming
    +				// so return to let the caller fill the
    +				// input buffer.
    +				if (action == LZMA_RUN)
    +					return LZMA_OK;
    +
    +				// LZMA_FULL_BARRIER: The same as with
    +				// LZMA_RUN but tell the caller that the
    +				// barrier was completed.
    +				if (action == LZMA_FULL_BARRIER)
    +					return LZMA_STREAM_END;
    +
    +				// Finishing or flushing isn't completed until
    +				// all input data has been encoded and copied
    +				// to the output buffer.
    +				if (lzma_outq_is_empty(&coder->outq)) {
    +					// LZMA_FINISH: Continue to encode
    +					// the Index field.
    +					if (action == LZMA_FINISH)
    +						break;
    +
    +					// LZMA_FULL_FLUSH: Return to tell
    +					// the caller that flushing was
    +					// completed.
    +					if (action == LZMA_FULL_FLUSH)
    +						return LZMA_STREAM_END;
    +				}
    +			}
    +
    +			// Return if there is no output space left.
    +			// This check must be done after testing the input
    +			// buffer, because we might want to use a different
    +			// return code.
    +			if (*out_pos == out_size)
    +				return LZMA_OK;
    +
    +			// Neither in nor out has been used completely.
    +			// Wait until there's something we can do.
    +			if (wait_for_work(coder, &wait_abs, &has_blocked,
    +					*in_pos < in_size))
    +				return LZMA_TIMED_OUT;
    +		}
    +
    +		// All Blocks have been encoded and the threads have stopped.
    +		// Prepare to encode the Index field.
    +		return_if_error(lzma_index_encoder_init(
    +				&coder->index_encoder, allocator,
    +				coder->index));
    +		coder->sequence = SEQ_INDEX;
    +
    +		// Update the progress info to take the Index and
    +		// Stream Footer into account. Those are very fast to encode
    +		// so in terms of progress information they can be thought
    +		// to be ready to be copied out.
    +		coder->progress_out += lzma_index_size(coder->index)
    +				+ LZMA_STREAM_HEADER_SIZE;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_INDEX: {
    +		// Call the Index encoder. It doesn't take any input, so
    +		// those pointers can be NULL.
    +		const lzma_ret ret = coder->index_encoder.code(
    +				coder->index_encoder.coder, allocator,
    +				NULL, NULL, 0,
    +				out, out_pos, out_size, LZMA_RUN);
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +
    +		// Encode the Stream Footer into coder->buffer.
    +		coder->stream_flags.backward_size
    +				= lzma_index_size(coder->index);
    +		if (lzma_stream_footer_encode(&coder->stream_flags,
    +				coder->header) != LZMA_OK)
    +			return LZMA_PROG_ERROR;
    +
    +		coder->sequence = SEQ_STREAM_FOOTER;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_STREAM_FOOTER:
    +		lzma_bufcpy(coder->header, &coder->header_pos,
    +				sizeof(coder->header),
    +				out, out_pos, out_size);
    +		return coder->header_pos < sizeof(coder->header)
    +				? LZMA_OK : LZMA_STREAM_END;
    +	}
    +
    +	assert(0);
    +	return LZMA_PROG_ERROR;
    +}
    +
    +
    +static void
    +stream_encoder_mt_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +
    +	// Threads must be killed before the output queue can be freed.
    +	threads_end(coder, allocator);
    +	lzma_outq_end(&coder->outq, allocator);
    +
    +	lzma_filters_free(coder->filters, allocator);
    +	lzma_filters_free(coder->filters_cache, allocator);
    +
    +	lzma_next_end(&coder->index_encoder, allocator);
    +	lzma_index_end(coder->index, allocator);
    +
    +	mythread_cond_destroy(&coder->cond);
    +	mythread_mutex_destroy(&coder->mutex);
    +
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +stream_encoder_mt_update(void *coder_ptr, const lzma_allocator *allocator,
    +		const lzma_filter *filters,
    +		const lzma_filter *reversed_filters
    +			lzma_attribute((__unused__)))
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +
    +	// Applications shouldn't attempt to change the options when
    +	// we are already encoding the Index or Stream Footer.
    +	if (coder->sequence > SEQ_BLOCK)
    +		return LZMA_PROG_ERROR;
    +
    +	// For now the threaded encoder doesn't support changing
    +	// the options in the middle of a Block.
    +	if (coder->thr != NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	// Check if the filter chain seems mostly valid. See the comment
    +	// in stream_encoder_mt_init().
    +	if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Make a copy to a temporary buffer first. This way the encoder
    +	// state stays unchanged if an error occurs in lzma_filters_copy().
    +	lzma_filter temp[LZMA_FILTERS_MAX + 1];
    +	return_if_error(lzma_filters_copy(filters, temp, allocator));
    +
    +	// Free the options of the old chain as well as the cache.
    +	lzma_filters_free(coder->filters, allocator);
    +	lzma_filters_free(coder->filters_cache, allocator);
    +
    +	// Copy the new filter chain in place.
    +	memcpy(coder->filters, temp, sizeof(temp));
    +
    +	return LZMA_OK;
    +}
    +
    +
    +/// Options handling for lzma_stream_encoder_mt_init() and
    +/// lzma_stream_encoder_mt_memusage()
    +static lzma_ret
    +get_options(const lzma_mt *options, lzma_options_easy *opt_easy,
    +		const lzma_filter **filters, uint64_t *block_size,
    +		uint64_t *outbuf_size_max)
    +{
    +	// Validate some of the options.
    +	if (options == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	if (options->flags != 0 || options->threads == 0
    +			|| options->threads > LZMA_THREADS_MAX)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	if (options->filters != NULL) {
    +		// Filter chain was given, use it as is.
    +		*filters = options->filters;
    +	} else {
    +		// Use a preset.
    +		if (lzma_easy_preset(opt_easy, options->preset))
    +			return LZMA_OPTIONS_ERROR;
    +
    +		*filters = opt_easy->filters;
    +	}
    +
    +	// If the Block size is not set, determine it from the filter chain.
    +	if (options->block_size > 0)
    +		*block_size = options->block_size;
    +	else
    +		*block_size = lzma_mt_block_size(*filters);
    +
    +	// UINT64_MAX > BLOCK_SIZE_MAX, so the second condition
    +	// should be optimized out by any reasonable compiler.
    +	// The second condition should be there in the unlikely event that
    +	// the macros change and UINT64_MAX < BLOCK_SIZE_MAX.
    +	if (*block_size > BLOCK_SIZE_MAX || *block_size == UINT64_MAX)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Calculate the maximum amount output that a single output buffer
    +	// may need to hold. This is the same as the maximum total size of
    +	// a Block.
    +	*outbuf_size_max = lzma_block_buffer_bound64(*block_size);
    +	if (*outbuf_size_max == 0)
    +		return LZMA_MEM_ERROR;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +get_progress(void *coder_ptr, uint64_t *progress_in, uint64_t *progress_out)
    +{
    +	lzma_stream_coder *coder = coder_ptr;
    +
    +	// Lock coder->mutex to prevent finishing threads from moving their
    +	// progress info from the worker_thread structure to lzma_stream_coder.
    +	mythread_sync(coder->mutex) {
    +		*progress_in = coder->progress_in;
    +		*progress_out = coder->progress_out;
    +
    +		for (size_t i = 0; i < coder->threads_initialized; ++i) {
    +			mythread_sync(coder->threads[i].mutex) {
    +				*progress_in += coder->threads[i].progress_in;
    +				*progress_out += coder->threads[i]
    +						.progress_out;
    +			}
    +		}
    +	}
    +
    +	return;
    +}
    +
    +
    +static lzma_ret
    +stream_encoder_mt_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_mt *options)
    +{
    +	lzma_next_coder_init(&stream_encoder_mt_init, next, allocator);
    +
    +	// Get the filter chain.
    +	lzma_options_easy easy;
    +	const lzma_filter *filters;
    +	uint64_t block_size;
    +	uint64_t outbuf_size_max;
    +	return_if_error(get_options(options, &easy, &filters,
    +			&block_size, &outbuf_size_max));
    +
    +#if SIZE_MAX < UINT64_MAX
    +	if (block_size > SIZE_MAX || outbuf_size_max > SIZE_MAX)
    +		return LZMA_MEM_ERROR;
    +#endif
    +
    +	// Validate the filter chain so that we can give an error in this
    +	// function instead of delaying it to the first call to lzma_code().
    +	// The memory usage calculation verifies the filter chain as
    +	// a side effect so we take advantage of that. It's not a perfect
    +	// check though as raw encoder allows LZMA1 too but such problems
    +	// will be caught eventually with Block Header encoder.
    +	if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Validate the Check ID.
    +	if ((unsigned int)(options->check) > LZMA_CHECK_ID_MAX)
    +		return LZMA_PROG_ERROR;
    +
    +	if (!lzma_check_is_supported(options->check))
    +		return LZMA_UNSUPPORTED_CHECK;
    +
    +	// Allocate and initialize the base structure if needed.
    +	lzma_stream_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +
    +		// For the mutex and condition variable initializations
    +		// the error handling has to be done here because
    +		// stream_encoder_mt_end() doesn't know if they have
    +		// already been initialized or not.
    +		if (mythread_mutex_init(&coder->mutex)) {
    +			lzma_free(coder, allocator);
    +			next->coder = NULL;
    +			return LZMA_MEM_ERROR;
    +		}
    +
    +		if (mythread_cond_init(&coder->cond)) {
    +			mythread_mutex_destroy(&coder->mutex);
    +			lzma_free(coder, allocator);
    +			next->coder = NULL;
    +			return LZMA_MEM_ERROR;
    +		}
    +
    +		next->code = &stream_encode_mt;
    +		next->end = &stream_encoder_mt_end;
    +		next->get_progress = &get_progress;
    +		next->update = &stream_encoder_mt_update;
    +
    +		coder->filters[0].id = LZMA_VLI_UNKNOWN;
    +		coder->filters_cache[0].id = LZMA_VLI_UNKNOWN;
    +		coder->index_encoder = LZMA_NEXT_CODER_INIT;
    +		coder->index = NULL;
    +		memzero(&coder->outq, sizeof(coder->outq));
    +		coder->threads = NULL;
    +		coder->threads_max = 0;
    +		coder->threads_initialized = 0;
    +	}
    +
    +	// Basic initializations
    +	coder->sequence = SEQ_STREAM_HEADER;
    +	coder->block_size = (size_t)(block_size);
    +	coder->outbuf_alloc_size = (size_t)(outbuf_size_max);
    +	coder->thread_error = LZMA_OK;
    +	coder->thr = NULL;
    +
    +	// Allocate the thread-specific base structures.
    +	assert(options->threads > 0);
    +	if (coder->threads_max != options->threads) {
    +		threads_end(coder, allocator);
    +
    +		coder->threads = NULL;
    +		coder->threads_max = 0;
    +
    +		coder->threads_initialized = 0;
    +		coder->threads_free = NULL;
    +
    +		coder->threads = lzma_alloc(
    +				options->threads * sizeof(worker_thread),
    +				allocator);
    +		if (coder->threads == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		coder->threads_max = options->threads;
    +	} else {
    +		// Reuse the old structures and threads. Tell the running
    +		// threads to stop and wait until they have stopped.
    +		threads_stop(coder, true);
    +	}
    +
    +	// Output queue
    +	return_if_error(lzma_outq_init(&coder->outq, allocator,
    +			options->threads));
    +
    +	// Timeout
    +	coder->timeout = options->timeout;
    +
    +	// Free the old filter chain and the cache.
    +	lzma_filters_free(coder->filters, allocator);
    +	lzma_filters_free(coder->filters_cache, allocator);
    +
    +	// Copy the new filter chain.
    +	return_if_error(lzma_filters_copy(
    +			filters, coder->filters, allocator));
    +
    +	// Index
    +	lzma_index_end(coder->index, allocator);
    +	coder->index = lzma_index_init(allocator);
    +	if (coder->index == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	// Stream Header
    +	coder->stream_flags.version = 0;
    +	coder->stream_flags.check = options->check;
    +	return_if_error(lzma_stream_header_encode(
    +			&coder->stream_flags, coder->header));
    +
    +	coder->header_pos = 0;
    +
    +	// Progress info
    +	coder->progress_in = 0;
    +	coder->progress_out = LZMA_STREAM_HEADER_SIZE;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +#ifdef HAVE_SYMBOL_VERSIONS_LINUX
    +// These are for compatibility with binaries linked against liblzma that
    +// has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
    +// Actually that patch didn't create lzma_stream_encoder_mt@XZ_5.2.2
    +// but it has been added here anyway since someone might misread the
    +// RHEL patch and think both @XZ_5.1.2alpha and @XZ_5.2.2 exist.
    +LZMA_SYMVER_API("lzma_stream_encoder_mt@XZ_5.1.2alpha",
    +	lzma_ret, lzma_stream_encoder_mt_512a)(
    +		lzma_stream *strm, const lzma_mt *options)
    +		lzma_nothrow lzma_attr_warn_unused_result
    +		__attribute__((__alias__("lzma_stream_encoder_mt_52")));
    +
    +LZMA_SYMVER_API("lzma_stream_encoder_mt@XZ_5.2.2",
    +	lzma_ret, lzma_stream_encoder_mt_522)(
    +		lzma_stream *strm, const lzma_mt *options)
    +		lzma_nothrow lzma_attr_warn_unused_result
    +		__attribute__((__alias__("lzma_stream_encoder_mt_52")));
    +
    +LZMA_SYMVER_API("lzma_stream_encoder_mt@@XZ_5.2",
    +	lzma_ret, lzma_stream_encoder_mt_52)(
    +		lzma_stream *strm, const lzma_mt *options)
    +		lzma_nothrow lzma_attr_warn_unused_result;
    +
    +#define lzma_stream_encoder_mt lzma_stream_encoder_mt_52
    +#endif
    +extern LZMA_API(lzma_ret)
    +lzma_stream_encoder_mt(lzma_stream *strm, const lzma_mt *options)
    +{
    +	lzma_next_strm_init(stream_encoder_mt_init, strm, options);
    +
    +	strm->internal->supported_actions[LZMA_RUN] = true;
    +// 	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
    +	strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
    +	strm->internal->supported_actions[LZMA_FULL_BARRIER] = true;
    +	strm->internal->supported_actions[LZMA_FINISH] = true;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +#ifdef HAVE_SYMBOL_VERSIONS_LINUX
    +LZMA_SYMVER_API("lzma_stream_encoder_mt_memusage@XZ_5.1.2alpha",
    +	uint64_t, lzma_stream_encoder_mt_memusage_512a)(
    +	const lzma_mt *options) lzma_nothrow lzma_attr_pure
    +	__attribute__((__alias__("lzma_stream_encoder_mt_memusage_52")));
    +
    +LZMA_SYMVER_API("lzma_stream_encoder_mt_memusage@XZ_5.2.2",
    +	uint64_t, lzma_stream_encoder_mt_memusage_522)(
    +	const lzma_mt *options) lzma_nothrow lzma_attr_pure
    +	__attribute__((__alias__("lzma_stream_encoder_mt_memusage_52")));
    +
    +LZMA_SYMVER_API("lzma_stream_encoder_mt_memusage@@XZ_5.2",
    +	uint64_t, lzma_stream_encoder_mt_memusage_52)(
    +	const lzma_mt *options) lzma_nothrow lzma_attr_pure;
    +
    +#define lzma_stream_encoder_mt_memusage lzma_stream_encoder_mt_memusage_52
    +#endif
    +// This function name is a monster but it's consistent with the older
    +// monster names. :-( 31 chars is the max that C99 requires so in that
    +// sense it's not too long. ;-)
    +extern LZMA_API(uint64_t)
    +lzma_stream_encoder_mt_memusage(const lzma_mt *options)
    +{
    +	lzma_options_easy easy;
    +	const lzma_filter *filters;
    +	uint64_t block_size;
    +	uint64_t outbuf_size_max;
    +
    +	if (get_options(options, &easy, &filters, &block_size,
    +			&outbuf_size_max) != LZMA_OK)
    +		return UINT64_MAX;
    +
    +	// Memory usage of the input buffers
    +	const uint64_t inbuf_memusage = options->threads * block_size;
    +
    +	// Memory usage of the filter encoders
    +	uint64_t filters_memusage = lzma_raw_encoder_memusage(filters);
    +	if (filters_memusage == UINT64_MAX)
    +		return UINT64_MAX;
    +
    +	filters_memusage *= options->threads;
    +
    +	// Memory usage of the output queue
    +	const uint64_t outq_memusage = lzma_outq_memusage(
    +			outbuf_size_max, options->threads);
    +	if (outq_memusage == UINT64_MAX)
    +		return UINT64_MAX;
    +
    +	// Sum them with overflow checking.
    +	uint64_t total_memusage = LZMA_MEMUSAGE_BASE
    +			+ sizeof(lzma_stream_coder)
    +			+ options->threads * sizeof(worker_thread);
    +
    +	if (UINT64_MAX - total_memusage < inbuf_memusage)
    +		return UINT64_MAX;
    +
    +	total_memusage += inbuf_memusage;
    +
    +	if (UINT64_MAX - total_memusage < filters_memusage)
    +		return UINT64_MAX;
    +
    +	total_memusage += filters_memusage;
    +
    +	if (UINT64_MAX - total_memusage < outq_memusage)
    +		return UINT64_MAX;
    +
    +	return total_memusage + outq_memusage;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.c
    new file mode 100644
    index 00000000000..41b8dcb70d7
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.c
    @@ -0,0 +1,46 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_flags_common.c
    +/// \brief      Common stuff for Stream flags coders
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "stream_flags_common.h"
    +
    +
    +const uint8_t lzma_header_magic[6] = { 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00 };
    +const uint8_t lzma_footer_magic[2] = { 0x59, 0x5A };
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_flags_compare(
    +		const lzma_stream_flags *a, const lzma_stream_flags *b)
    +{
    +	// We can compare only version 0 structures.
    +	if (a->version != 0 || b->version != 0)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Check type
    +	if ((unsigned int)(a->check) > LZMA_CHECK_ID_MAX
    +			|| (unsigned int)(b->check) > LZMA_CHECK_ID_MAX)
    +		return LZMA_PROG_ERROR;
    +
    +	if (a->check != b->check)
    +		return LZMA_DATA_ERROR;
    +
    +	// Backward Sizes are compared only if they are known in both.
    +	if (a->backward_size != LZMA_VLI_UNKNOWN
    +			&& b->backward_size != LZMA_VLI_UNKNOWN) {
    +		if (!is_backward_size_valid(a) || !is_backward_size_valid(b))
    +			return LZMA_PROG_ERROR;
    +
    +		if (a->backward_size != b->backward_size)
    +			return LZMA_DATA_ERROR;
    +	}
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.h
    new file mode 100644
    index 00000000000..28729dbcb6f
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.h
    @@ -0,0 +1,35 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_flags_common.h
    +/// \brief      Common stuff for Stream flags coders
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_STREAM_FLAGS_COMMON_H
    +#define LZMA_STREAM_FLAGS_COMMON_H
    +
    +#include "common.h"
    +
    +/// Size of the Stream Flags field
    +#define LZMA_STREAM_FLAGS_SIZE 2
    +
    +lzma_attr_visibility_hidden
    +extern const uint8_t lzma_header_magic[6];
    +
    +lzma_attr_visibility_hidden
    +extern const uint8_t lzma_footer_magic[2];
    +
    +
    +static inline bool
    +is_backward_size_valid(const lzma_stream_flags *options)
    +{
    +	return options->backward_size >= LZMA_BACKWARD_SIZE_MIN
    +			&& options->backward_size <= LZMA_BACKWARD_SIZE_MAX
    +			&& (options->backward_size & 3) == 0;
    +}
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_decoder.c
    new file mode 100644
    index 00000000000..522c98b6fd5
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_decoder.c
    @@ -0,0 +1,87 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_flags_decoder.c
    +/// \brief      Decodes Stream Header and Stream Footer from .xz files
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "stream_flags_common.h"
    +
    +
    +static bool
    +stream_flags_decode(lzma_stream_flags *options, const uint8_t *in)
    +{
    +	// Reserved bits must be unset.
    +	if (in[0] != 0x00 || (in[1] & 0xF0))
    +		return true;
    +
    +	options->version = 0;
    +	options->check = in[1] & 0x0F;
    +
    +	return false;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_header_decode(lzma_stream_flags *options, const uint8_t *in)
    +{
    +	// Magic
    +	if (memcmp(in, lzma_header_magic, sizeof(lzma_header_magic)) != 0)
    +		return LZMA_FORMAT_ERROR;
    +
    +	// Verify the CRC32 so we can distinguish between corrupt
    +	// and unsupported files.
    +	const uint32_t crc = lzma_crc32(in + sizeof(lzma_header_magic),
    +			LZMA_STREAM_FLAGS_SIZE, 0);
    +	if (crc != read32le(in + sizeof(lzma_header_magic)
    +			+ LZMA_STREAM_FLAGS_SIZE)) {
    +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    +		return LZMA_DATA_ERROR;
    +#endif
    +	}
    +
    +	// Stream Flags
    +	if (stream_flags_decode(options, in + sizeof(lzma_header_magic)))
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Set Backward Size to indicate unknown value. That way
    +	// lzma_stream_flags_compare() can be used to compare Stream Header
    +	// and Stream Footer while keeping it useful also for comparing
    +	// two Stream Footers.
    +	options->backward_size = LZMA_VLI_UNKNOWN;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_footer_decode(lzma_stream_flags *options, const uint8_t *in)
    +{
    +	// Magic
    +	if (memcmp(in + sizeof(uint32_t) * 2 + LZMA_STREAM_FLAGS_SIZE,
    +			lzma_footer_magic, sizeof(lzma_footer_magic)) != 0)
    +		return LZMA_FORMAT_ERROR;
    +
    +	// CRC32
    +	const uint32_t crc = lzma_crc32(in + sizeof(uint32_t),
    +			sizeof(uint32_t) + LZMA_STREAM_FLAGS_SIZE, 0);
    +	if (crc != read32le(in)) {
    +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    +		return LZMA_DATA_ERROR;
    +#endif
    +	}
    +
    +	// Stream Flags
    +	if (stream_flags_decode(options, in + sizeof(uint32_t) * 2))
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Backward Size
    +	options->backward_size = read32le(in + sizeof(uint32_t));
    +	options->backward_size = (options->backward_size + 1) * 4;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_encoder.c
    new file mode 100644
    index 00000000000..f94b5cd0a23
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_encoder.c
    @@ -0,0 +1,85 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       stream_flags_encoder.c
    +/// \brief      Encodes Stream Header and Stream Footer for .xz files
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "stream_flags_common.h"
    +
    +
    +static bool
    +stream_flags_encode(const lzma_stream_flags *options, uint8_t *out)
    +{
    +	if ((unsigned int)(options->check) > LZMA_CHECK_ID_MAX)
    +		return true;
    +
    +	out[0] = 0x00;
    +	out[1] = options->check;
    +
    +	return false;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_header_encode(const lzma_stream_flags *options, uint8_t *out)
    +{
    +	assert(sizeof(lzma_header_magic) + LZMA_STREAM_FLAGS_SIZE
    +			+ 4 == LZMA_STREAM_HEADER_SIZE);
    +
    +	if (options->version != 0)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Magic
    +	memcpy(out, lzma_header_magic, sizeof(lzma_header_magic));
    +
    +	// Stream Flags
    +	if (stream_flags_encode(options, out + sizeof(lzma_header_magic)))
    +		return LZMA_PROG_ERROR;
    +
    +	// CRC32 of the Stream Header
    +	const uint32_t crc = lzma_crc32(out + sizeof(lzma_header_magic),
    +			LZMA_STREAM_FLAGS_SIZE, 0);
    +
    +	write32le(out + sizeof(lzma_header_magic) + LZMA_STREAM_FLAGS_SIZE,
    +			crc);
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_stream_footer_encode(const lzma_stream_flags *options, uint8_t *out)
    +{
    +	assert(2 * 4 + LZMA_STREAM_FLAGS_SIZE + sizeof(lzma_footer_magic)
    +			== LZMA_STREAM_HEADER_SIZE);
    +
    +	if (options->version != 0)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Backward Size
    +	if (!is_backward_size_valid(options))
    +		return LZMA_PROG_ERROR;
    +
    +	write32le(out + 4, options->backward_size / 4 - 1);
    +
    +	// Stream Flags
    +	if (stream_flags_encode(options, out + 2 * 4))
    +		return LZMA_PROG_ERROR;
    +
    +	// CRC32
    +	const uint32_t crc = lzma_crc32(
    +			out + 4, 4 + LZMA_STREAM_FLAGS_SIZE, 0);
    +
    +	write32le(out, crc);
    +
    +	// Magic
    +	memcpy(out + 2 * 4 + LZMA_STREAM_FLAGS_SIZE,
    +			lzma_footer_magic, sizeof(lzma_footer_magic));
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/string_conversion.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/string_conversion.c
    new file mode 100644
    index 00000000000..c899783c642
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/string_conversion.c
    @@ -0,0 +1,1338 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       string_conversion.c
    +/// \brief      Conversion of strings to filter chain and vice versa
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "filter_common.h"
    +
    +
    +/////////////////////
    +// String building //
    +/////////////////////
    +
    +/// How much memory to allocate for strings. For now, no realloc is used
    +/// so this needs to be big enough even though there of course is
    +/// an overflow check still.
    +///
    +/// FIXME? Using a fixed size is wasteful if the application doesn't free
    +/// the string fairly quickly but this can be improved later if needed.
    +#define STR_ALLOC_SIZE 800
    +
    +
    +typedef struct {
    +	char *buf;
    +	size_t pos;
    +} lzma_str;
    +
    +
    +static lzma_ret
    +str_init(lzma_str *str, const lzma_allocator *allocator)
    +{
    +	str->buf = lzma_alloc(STR_ALLOC_SIZE, allocator);
    +	if (str->buf == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	str->pos = 0;
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +str_free(lzma_str *str, const lzma_allocator *allocator)
    +{
    +	lzma_free(str->buf, allocator);
    +	return;
    +}
    +
    +
    +static bool
    +str_is_full(const lzma_str *str)
    +{
    +	return str->pos == STR_ALLOC_SIZE - 1;
    +}
    +
    +
    +static lzma_ret
    +str_finish(char **dest, lzma_str *str, const lzma_allocator *allocator)
    +{
    +	if (str_is_full(str)) {
    +		// The preallocated buffer was too small.
    +		// This shouldn't happen as STR_ALLOC_SIZE should
    +		// be adjusted if new filters are added.
    +		lzma_free(str->buf, allocator);
    +		*dest = NULL;
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	str->buf[str->pos] = '\0';
    +	*dest = str->buf;
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +str_append_str(lzma_str *str, const char *s)
    +{
    +	const size_t len = strlen(s);
    +	const size_t limit = STR_ALLOC_SIZE - 1 - str->pos;
    +	const size_t copy_size = my_min(len, limit);
    +
    +	memcpy(str->buf + str->pos, s, copy_size);
    +	str->pos += copy_size;
    +	return;
    +}
    +
    +
    +static void
    +str_append_u32(lzma_str *str, uint32_t v, bool use_byte_suffix)
    +{
    +	if (v == 0) {
    +		str_append_str(str, "0");
    +	} else {
    +		// NOTE: Don't use plain "B" because xz and the parser in this
    +		// file don't support it and at glance it may look like 8
    +		// (there cannot be a space before the suffix).
    +		static const char suffixes[4][4] = { "", "KiB", "MiB", "GiB" };
    +
    +		size_t suf = 0;
    +		if (use_byte_suffix) {
    +			while ((v & 1023) == 0
    +					&& suf < ARRAY_SIZE(suffixes) - 1) {
    +				v >>= 10;
    +				++suf;
    +			}
    +		}
    +
    +		// UINT32_MAX in base 10 would need 10 + 1 bytes. Remember
    +		// that initializing to "" initializes all elements to
    +		// zero so '\0'-termination gets handled by this.
    +		char buf[16] = "";
    +		size_t pos = sizeof(buf) - 1;
    +
    +		do {
    +			buf[--pos] = '0' + (v % 10);
    +			v /= 10;
    +		} while (v != 0);
    +
    +		str_append_str(str, buf + pos);
    +		str_append_str(str, suffixes[suf]);
    +	}
    +
    +	return;
    +}
    +
    +
    +//////////////////////////////////////////////
    +// Parsing and stringification declarations //
    +//////////////////////////////////////////////
    +
    +/// Maximum length for filter and option names.
    +/// 11 chars + terminating '\0' + sizeof(uint32_t) = 16 bytes
    +#define NAME_LEN_MAX 11
    +
    +
    +/// For option_map.flags: Use .u.map to do convert the input value
    +/// to an integer. Without this flag, .u.range.{min,max} are used
    +/// as the allowed range for the integer.
    +#define OPTMAP_USE_NAME_VALUE_MAP 0x01
    +
    +/// For option_map.flags: Allow KiB/MiB/GiB in input string and use them in
    +/// the stringified output if the value is an exact multiple of these.
    +/// This is used e.g. for LZMA1/2 dictionary size.
    +#define OPTMAP_USE_BYTE_SUFFIX 0x02
    +
    +/// For option_map.flags: If the integer value is zero then this option
    +/// won't be included in the stringified output. It's used e.g. for
    +/// BCJ filter start offset which usually is zero.
    +#define OPTMAP_NO_STRFY_ZERO 0x04
    +
    +/// Possible values for option_map.type. Since OPTMAP_TYPE_UINT32 is 0,
    +/// it doesn't need to be specified in the initializers as it is
    +/// the implicit value.
    +enum {
    +	OPTMAP_TYPE_UINT32,
    +	OPTMAP_TYPE_LZMA_MODE,
    +	OPTMAP_TYPE_LZMA_MATCH_FINDER,
    +	OPTMAP_TYPE_LZMA_PRESET,
    +};
    +
    +
    +/// This is for mapping string values in options to integers.
    +/// The last element of an array must have "" as the name.
    +/// It's used e.g. for match finder names in LZMA1/2.
    +typedef struct {
    +	const char name[NAME_LEN_MAX + 1];
    +	const uint32_t value;
    +} name_value_map;
    +
    +
    +/// Each filter that has options needs an array of option_map structures.
    +/// The array doesn't need to be terminated as the functions take the
    +/// length of the array as an argument.
    +///
    +/// When converting a string to filter options structure, option values
    +/// will be handled in a few different ways:
    +///
    +/// (1) If .type equals OPTMAP_TYPE_LZMA_PRESET then LZMA1/2 preset string
    +///     is handled specially.
    +///
    +/// (2) If .flags has OPTMAP_USE_NAME_VALUE_MAP set then the string is
    +///     converted to an integer using the name_value_map pointed by .u.map.
    +///     The last element in .u.map must have .name = "" as the terminator.
    +///
    +/// (3) Otherwise the string is treated as a non-negative unsigned decimal
    +///     integer which must be in the range set in .u.range. If .flags has
    +///     OPTMAP_USE_BYTE_SUFFIX then KiB, MiB, and GiB suffixes are allowed.
    +///
    +/// The integer value from (2) or (3) is then stored to filter_options
    +/// at the offset specified in .offset using the type specified in .type
    +/// (default is uint32_t).
    +///
    +/// Stringifying a filter is done by processing a given number of options
    +/// in order from the beginning of an option_map array. The integer is
    +/// read from filter_options at .offset using the type from .type.
    +///
    +/// If the integer is zero and .flags has OPTMAP_NO_STRFY_ZERO then the
    +/// option is skipped.
    +///
    +/// If .flags has OPTMAP_USE_NAME_VALUE_MAP set then .u.map will be used
    +/// to convert the option to a string. If the map doesn't contain a string
    +/// for the integer value then "UNKNOWN" is used.
    +///
    +/// If .flags doesn't have OPTMAP_USE_NAME_VALUE_MAP set then the integer is
    +/// converted to a decimal value. If OPTMAP_USE_BYTE_SUFFIX is used then KiB,
    +/// MiB, or GiB suffix is used if the value is an exact multiple of these.
    +/// Plain "B" suffix is never used.
    +typedef struct {
    +	char name[NAME_LEN_MAX + 1];
    +	uint8_t type;
    +	uint8_t flags;
    +	uint16_t offset;
    +
    +	union {
    +		// NVHPC has problems with unions that contain pointers that
    +		// are not the first members, so keep "map" at the top.
    +		const name_value_map *map;
    +
    +		struct {
    +			uint32_t min;
    +			uint32_t max;
    +		} range;
    +	} u;
    +} option_map;
    +
    +
    +static const char *parse_options(const char **const str, const char *str_end,
    +		void *filter_options,
    +		const option_map *const optmap, const size_t optmap_size);
    +
    +
    +/////////
    +// BCJ //
    +/////////
    +
    +#if defined(HAVE_ENCODER_X86) \
    +		|| defined(HAVE_DECODER_X86) \
    +		|| defined(HAVE_ENCODER_ARM) \
    +		|| defined(HAVE_DECODER_ARM) \
    +		|| defined(HAVE_ENCODER_ARMTHUMB) \
    +		|| defined(HAVE_DECODER_ARMTHUMB) \
    +		|| defined(HAVE_ENCODER_ARM64) \
    +		|| defined(HAVE_DECODER_ARM64) \
    +		|| defined(HAVE_ENCODER_POWERPC) \
    +		|| defined(HAVE_DECODER_POWERPC) \
    +		|| defined(HAVE_ENCODER_IA64) \
    +		|| defined(HAVE_DECODER_IA64) \
    +		|| defined(HAVE_ENCODER_SPARC) \
    +		|| defined(HAVE_DECODER_SPARC) \
    +		|| defined(HAVE_ENCODER_RISCV) \
    +		|| defined(HAVE_DECODER_RISCV)
    +static const option_map bcj_optmap[] = {
    +	{
    +		.name = "start",
    +		.flags = OPTMAP_NO_STRFY_ZERO | OPTMAP_USE_BYTE_SUFFIX,
    +		.offset = offsetof(lzma_options_bcj, start_offset),
    +		.u.range.min = 0,
    +		.u.range.max = UINT32_MAX,
    +	}
    +};
    +
    +
    +static const char *
    +parse_bcj(const char **const str, const char *str_end, void *filter_options)
    +{
    +	// filter_options was zeroed on allocation and that is enough
    +	// for the default value.
    +	return parse_options(str, str_end, filter_options,
    +			bcj_optmap, ARRAY_SIZE(bcj_optmap));
    +}
    +#endif
    +
    +
    +///////////
    +// Delta //
    +///////////
    +
    +#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
    +static const option_map delta_optmap[] = {
    +	{
    +		.name = "dist",
    +		.offset = offsetof(lzma_options_delta, dist),
    +		.u.range.min = LZMA_DELTA_DIST_MIN,
    +		.u.range.max = LZMA_DELTA_DIST_MAX,
    +	}
    +};
    +
    +
    +static const char *
    +parse_delta(const char **const str, const char *str_end, void *filter_options)
    +{
    +	lzma_options_delta *opts = filter_options;
    +	opts->type = LZMA_DELTA_TYPE_BYTE;
    +	opts->dist = LZMA_DELTA_DIST_MIN;
    +
    +	return parse_options(str, str_end, filter_options,
    +			delta_optmap, ARRAY_SIZE(delta_optmap));
    +}
    +#endif
    +
    +
    +///////////////////
    +// LZMA1 & LZMA2 //
    +///////////////////
    +
    +/// Help string for presets
    +#define LZMA12_PRESET_STR "0-9[e]"
    +
    +
    +static const char *
    +parse_lzma12_preset(const char **const str, const char *str_end,
    +		uint32_t *preset)
    +{
    +	assert(*str < str_end);
    +	*preset = (uint32_t)(**str - '0');
    +
    +	// NOTE: Remember to update LZMA12_PRESET_STR if this is modified!
    +	while (++*str < str_end) {
    +		switch (**str) {
    +		case 'e':
    +			*preset |= LZMA_PRESET_EXTREME;
    +			break;
    +
    +		default:
    +			return "Unsupported preset flag";
    +		}
    +	}
    +
    +	return NULL;
    +}
    +
    +
    +static const char *
    +set_lzma12_preset(const char **const str, const char *str_end,
    +		void *filter_options)
    +{
    +	uint32_t preset;
    +	const char *errmsg = parse_lzma12_preset(str, str_end, &preset);
    +	if (errmsg != NULL)
    +		return errmsg;
    +
    +	lzma_options_lzma *opts = filter_options;
    +	if (lzma_lzma_preset(opts, preset))
    +		return "Unsupported preset";
    +
    +	return NULL;
    +}
    +
    +
    +static const name_value_map lzma12_mode_map[] = {
    +	{ "fast",   LZMA_MODE_FAST },
    +	{ "normal", LZMA_MODE_NORMAL },
    +	{ "",       0 }
    +};
    +
    +
    +static const name_value_map lzma12_mf_map[] = {
    +	{ "hc3", LZMA_MF_HC3 },
    +	{ "hc4", LZMA_MF_HC4 },
    +	{ "bt2", LZMA_MF_BT2 },
    +	{ "bt3", LZMA_MF_BT3 },
    +	{ "bt4", LZMA_MF_BT4 },
    +	{ "",    0 }
    +};
    +
    +
    +static const option_map lzma12_optmap[] = {
    +	{
    +		.name = "preset",
    +		.type = OPTMAP_TYPE_LZMA_PRESET,
    +	}, {
    +		.name = "dict",
    +		.flags = OPTMAP_USE_BYTE_SUFFIX,
    +		.offset = offsetof(lzma_options_lzma, dict_size),
    +		.u.range.min = LZMA_DICT_SIZE_MIN,
    +		// FIXME? The max is really max for encoding but decoding
    +		// would allow 4 GiB - 1 B.
    +		.u.range.max = (UINT32_C(1) << 30) + (UINT32_C(1) << 29),
    +	}, {
    +		.name = "lc",
    +		.offset = offsetof(lzma_options_lzma, lc),
    +		.u.range.min = LZMA_LCLP_MIN,
    +		.u.range.max = LZMA_LCLP_MAX,
    +	}, {
    +		.name = "lp",
    +		.offset = offsetof(lzma_options_lzma, lp),
    +		.u.range.min = LZMA_LCLP_MIN,
    +		.u.range.max = LZMA_LCLP_MAX,
    +	}, {
    +		.name = "pb",
    +		.offset = offsetof(lzma_options_lzma, pb),
    +		.u.range.min = LZMA_PB_MIN,
    +		.u.range.max = LZMA_PB_MAX,
    +	}, {
    +		.name = "mode",
    +		.type = OPTMAP_TYPE_LZMA_MODE,
    +		.flags = OPTMAP_USE_NAME_VALUE_MAP,
    +		.offset = offsetof(lzma_options_lzma, mode),
    +		.u.map = lzma12_mode_map,
    +	}, {
    +		.name = "nice",
    +		.offset = offsetof(lzma_options_lzma, nice_len),
    +		.u.range.min = 2,
    +		.u.range.max = 273,
    +	}, {
    +		.name = "mf",
    +		.type = OPTMAP_TYPE_LZMA_MATCH_FINDER,
    +		.flags = OPTMAP_USE_NAME_VALUE_MAP,
    +		.offset = offsetof(lzma_options_lzma, mf),
    +		.u.map = lzma12_mf_map,
    +	}, {
    +		.name = "depth",
    +		.offset = offsetof(lzma_options_lzma, depth),
    +		.u.range.min = 0,
    +		.u.range.max = UINT32_MAX,
    +	}
    +};
    +
    +
    +static const char *
    +parse_lzma12(const char **const str, const char *str_end, void *filter_options)
    +{
    +	lzma_options_lzma *opts = filter_options;
    +
    +	// It cannot fail.
    +	const bool preset_ret = lzma_lzma_preset(opts, LZMA_PRESET_DEFAULT);
    +	assert(!preset_ret);
    +	(void)preset_ret;
    +
    +	const char *errmsg = parse_options(str, str_end, filter_options,
    +			lzma12_optmap, ARRAY_SIZE(lzma12_optmap));
    +	if (errmsg != NULL)
    +		return errmsg;
    +
    +	if (opts->lc + opts->lp > LZMA_LCLP_MAX)
    +		return "The sum of lc and lp must not exceed 4";
    +
    +	return NULL;
    +}
    +
    +
    +/////////////////////////////////////////
    +// Generic parsing and stringification //
    +/////////////////////////////////////////
    +
    +static const struct {
    +	/// Name of the filter
    +	char name[NAME_LEN_MAX + 1];
    +
    +	/// For lzma_str_to_filters:
    +	/// Size of the filter-specific options structure.
    +	uint32_t opts_size;
    +
    +	/// Filter ID
    +	lzma_vli id;
    +
    +	/// For lzma_str_to_filters:
    +	/// Function to parse the filter-specific options. The filter_options
    +	/// will already have been allocated using lzma_alloc_zero().
    +	const char *(*parse)(const char **str, const char *str_end,
    +			void *filter_options);
    +
    +	/// For lzma_str_from_filters:
    +	/// If the flag LZMA_STR_ENCODER is used then the first
    +	/// strfy_encoder elements of optmap are stringified.
    +	/// With LZMA_STR_DECODER strfy_decoder is used.
    +	/// Currently encoders use all options that decoders do but if
    +	/// that changes then this needs to be changed too, for example,
    +	/// add a new OPTMAP flag to skip printing some decoder-only options.
    +	const option_map *optmap;
    +	uint8_t strfy_encoder;
    +	uint8_t strfy_decoder;
    +
    +	/// For lzma_str_from_filters:
    +	/// If true, lzma_filter.options is allowed to be NULL. In that case,
    +	/// only the filter name is printed without any options.
    +	bool allow_null;
    +
    +} filter_name_map[] = {
    +#if defined (HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
    +	{ "lzma1",        sizeof(lzma_options_lzma),  LZMA_FILTER_LZMA1,
    +	  &parse_lzma12,  lzma12_optmap, 9, 5, false },
    +#endif
    +
    +#if defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
    +	{ "lzma2",        sizeof(lzma_options_lzma),  LZMA_FILTER_LZMA2,
    +	  &parse_lzma12,  lzma12_optmap, 9, 2, false },
    +#endif
    +
    +#if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
    +	{ "x86",          sizeof(lzma_options_bcj),   LZMA_FILTER_X86,
    +	  &parse_bcj,     bcj_optmap, 1, 1, true },
    +#endif
    +
    +#if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
    +	{ "arm",          sizeof(lzma_options_bcj),   LZMA_FILTER_ARM,
    +	  &parse_bcj,     bcj_optmap, 1, 1, true },
    +#endif
    +
    +#if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
    +	{ "armthumb",     sizeof(lzma_options_bcj),   LZMA_FILTER_ARMTHUMB,
    +	  &parse_bcj,     bcj_optmap, 1, 1, true },
    +#endif
    +
    +#if defined(HAVE_ENCODER_ARM64) || defined(HAVE_DECODER_ARM64)
    +	{ "arm64",        sizeof(lzma_options_bcj),   LZMA_FILTER_ARM64,
    +	  &parse_bcj,     bcj_optmap, 1, 1, true },
    +#endif
    +
    +#if defined(HAVE_ENCODER_RISCV) || defined(HAVE_DECODER_RISCV)
    +	{ "riscv",        sizeof(lzma_options_bcj),   LZMA_FILTER_RISCV,
    +	  &parse_bcj,     bcj_optmap, 1, 1, true },
    +#endif
    +
    +#if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
    +	{ "powerpc",      sizeof(lzma_options_bcj),   LZMA_FILTER_POWERPC,
    +	  &parse_bcj,     bcj_optmap, 1, 1, true },
    +#endif
    +
    +#if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
    +	{ "ia64",         sizeof(lzma_options_bcj),   LZMA_FILTER_IA64,
    +	  &parse_bcj,     bcj_optmap, 1, 1, true },
    +#endif
    +
    +#if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
    +	{ "sparc",        sizeof(lzma_options_bcj),   LZMA_FILTER_SPARC,
    +	  &parse_bcj,     bcj_optmap, 1, 1, true },
    +#endif
    +
    +#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
    +	{ "delta",        sizeof(lzma_options_delta), LZMA_FILTER_DELTA,
    +	  &parse_delta,   delta_optmap, 1, 1, false },
    +#endif
    +};
    +
    +
    +/// Decodes options from a string for one filter (name1=value1,name2=value2).
    +/// Caller must have allocated memory for filter_options already and set
    +/// the initial default values. This is called from the filter-specific
    +/// parse_* functions.
    +///
    +/// The input string starts at *str and the address in str_end is the first
    +/// char that is not part of the string anymore. So no '\0' terminator is
    +/// used. *str is advanced every time something has been decoded successfully.
    +static const char *
    +parse_options(const char **const str, const char *str_end,
    +		void *filter_options,
    +		const option_map *const optmap, const size_t optmap_size)
    +{
    +	while (*str < str_end && **str != '\0') {
    +		// Each option is of the form name=value.
    +		// Commas (',') separate options. Extra commas are ignored.
    +		// Ignoring extra commas makes it simpler if an optional
    +		// option stored in a shell variable which can be empty.
    +		if (**str == ',') {
    +			++*str;
    +			continue;
    +		}
    +
    +		// Find where the next name=value ends.
    +		const size_t str_len = (size_t)(str_end - *str);
    +		const char *name_eq_value_end = memchr(*str, ',', str_len);
    +		if (name_eq_value_end == NULL)
    +			name_eq_value_end = str_end;
    +
    +		const char *equals_sign = memchr(*str, '=',
    +				(size_t)(name_eq_value_end - *str));
    +
    +		// Fail if the '=' wasn't found or the option name is missing
    +		// (the first char is '=').
    +		if (equals_sign == NULL || **str == '=')
    +			return "Options must be 'name=value' pairs separated "
    +					"with commas";
    +
    +		// Reject a too long option name so that the memcmp()
    +		// in the loop below won't read past the end of the
    +		// string in optmap[i].name.
    +		const size_t name_len = (size_t)(equals_sign - *str);
    +		if (name_len > NAME_LEN_MAX)
    +			return "Unknown option name";
    +
    +		// Find the option name from optmap[].
    +		size_t i = 0;
    +		while (true) {
    +			if (i == optmap_size)
    +				return "Unknown option name";
    +
    +			if (memcmp(*str, optmap[i].name, name_len) == 0
    +					&& optmap[i].name[name_len] == '\0')
    +				break;
    +
    +			++i;
    +		}
    +
    +		// The input string is good at least until the start of
    +		// the option value.
    +		*str = equals_sign + 1;
    +
    +		// The code assumes that the option value isn't an empty
    +		// string so check it here.
    +		const size_t value_len = (size_t)(name_eq_value_end - *str);
    +		if (value_len == 0)
    +			return "Option value cannot be empty";
    +
    +		// LZMA1/2 preset has its own parsing function.
    +		if (optmap[i].type == OPTMAP_TYPE_LZMA_PRESET) {
    +			const char *errmsg = set_lzma12_preset(str,
    +					name_eq_value_end, filter_options);
    +			if (errmsg != NULL)
    +				return errmsg;
    +
    +			continue;
    +		}
    +
    +		// It's an integer value.
    +		uint32_t v;
    +		if (optmap[i].flags & OPTMAP_USE_NAME_VALUE_MAP) {
    +			// The integer is picked from a string-to-integer map.
    +			//
    +			// Reject a too long value string so that the memcmp()
    +			// in the loop below won't read past the end of the
    +			// string in optmap[i].u.map[j].name.
    +			if (value_len > NAME_LEN_MAX)
    +				return "Invalid option value";
    +
    +			const name_value_map *map = optmap[i].u.map;
    +			size_t j = 0;
    +			while (true) {
    +				// The array is terminated with an empty name.
    +				if (map[j].name[0] == '\0')
    +					return "Invalid option value";
    +
    +				if (memcmp(*str, map[j].name, value_len) == 0
    +						&& map[j].name[value_len]
    +							== '\0') {
    +					v = map[j].value;
    +					break;
    +				}
    +
    +				++j;
    +			}
    +		} else if (**str < '0' || **str > '9') {
    +			// Note that "max" isn't supported while it is
    +			// supported in xz. It's not useful here.
    +			return "Value is not a non-negative decimal integer";
    +		} else {
    +			// strtoul() has locale-specific behavior so it cannot
    +			// be relied on to get reproducible results since we
    +			// cannot change the locate in a thread-safe library.
    +			// It also needs '\0'-termination.
    +			//
    +			// Use a temporary pointer so that *str will point
    +			// to the beginning of the value string in case
    +			// an error occurs.
    +			const char *p = *str;
    +			v = 0;
    +			do {
    +				if (v > UINT32_MAX / 10)
    +					return "Value out of range";
    +
    +				v *= 10;
    +
    +				const uint32_t add = (uint32_t)(*p - '0');
    +				if (UINT32_MAX - add < v)
    +					return "Value out of range";
    +
    +				v += add;
    +				++p;
    +			} while (p < name_eq_value_end
    +					&& *p >= '0' && *p <= '9');
    +
    +			if (p < name_eq_value_end) {
    +				// Remember this position so that it can be
    +				// used for error messages that are
    +				// specifically about the suffix. (Out of
    +				// range values are about the whole value
    +				// and those error messages point to the
    +				// beginning of the number part,
    +				// not to the suffix.)
    +				const char *multiplier_start = p;
    +
    +				// If multiplier suffix shouldn't be used
    +				// then don't allow them even if the value
    +				// would stay within limits. This is a somewhat
    +				// unnecessary check but it rejects silly
    +				// things like lzma2:pb=0MiB which xz allows.
    +				if ((optmap[i].flags & OPTMAP_USE_BYTE_SUFFIX)
    +						== 0) {
    +					*str = multiplier_start;
    +					return "This option does not support "
    +						"any integer suffixes";
    +				}
    +
    +				uint32_t shift;
    +
    +				switch (*p) {
    +				case 'k':
    +				case 'K':
    +					shift = 10;
    +					break;
    +
    +				case 'm':
    +				case 'M':
    +					shift = 20;
    +					break;
    +
    +				case 'g':
    +				case 'G':
    +					shift = 30;
    +					break;
    +
    +				default:
    +					*str = multiplier_start;
    +					return "Invalid multiplier suffix "
    +							"(KiB, MiB, or GiB)";
    +				}
    +
    +				++p;
    +
    +				// Allow "M", "Mi", "MB", "MiB" and the same
    +				// for the other five characters from the
    +				// switch-statement above. All are handled
    +				// as base-2 (perhaps a mistake, perhaps not).
    +				// Note that 'i' and 'B' are case sensitive.
    +				if (p < name_eq_value_end && *p == 'i')
    +					++p;
    +
    +				if (p < name_eq_value_end && *p == 'B')
    +					++p;
    +
    +				// Now we must have no chars remaining.
    +				if (p < name_eq_value_end) {
    +					*str = multiplier_start;
    +					return "Invalid multiplier suffix "
    +							"(KiB, MiB, or GiB)";
    +				}
    +
    +				if (v > (UINT32_MAX >> shift))
    +					return "Value out of range";
    +
    +				v <<= shift;
    +			}
    +
    +			if (v < optmap[i].u.range.min
    +					|| v > optmap[i].u.range.max)
    +				return "Value out of range";
    +		}
    +
    +		// Set the value in filter_options. Enums are handled
    +		// specially since the underlying type isn't the same
    +		// as uint32_t on all systems.
    +		void *ptr = (char *)filter_options + optmap[i].offset;
    +		switch (optmap[i].type) {
    +		case OPTMAP_TYPE_LZMA_MODE:
    +			*(lzma_mode *)ptr = (lzma_mode)v;
    +			break;
    +
    +		case OPTMAP_TYPE_LZMA_MATCH_FINDER:
    +			*(lzma_match_finder *)ptr = (lzma_match_finder)v;
    +			break;
    +
    +		default:
    +			*(uint32_t *)ptr = v;
    +			break;
    +		}
    +
    +		// This option has been successfully handled.
    +		*str = name_eq_value_end;
    +	}
    +
    +	// No errors.
    +	return NULL;
    +}
    +
    +
    +/// Finds the name of the filter at the beginning of the string and
    +/// calls filter_name_map[i].parse() to decode the filter-specific options.
    +/// The caller must have set str_end so that exactly one filter and its
    +/// options are present without any trailing characters.
    +static const char *
    +parse_filter(const char **const str, const char *str_end, lzma_filter *filter,
    +		const lzma_allocator *allocator, bool only_xz)
    +{
    +	// Search for a colon or equals sign that would separate the filter
    +	// name from filter options. If neither is found, then the input
    +	// string only contains a filter name and there are no options.
    +	//
    +	// First assume that a colon or equals sign won't be found:
    +	const char *name_end = str_end;
    +	const char *opts_start = str_end;
    +
    +	for (const char *p = *str; p < str_end; ++p) {
    +		if (*p == ':' || *p == '=') {
    +			name_end = p;
    +
    +			// Filter options (name1=value1,name2=value2,...)
    +			// begin after the colon or equals sign.
    +			opts_start = p + 1;
    +			break;
    +		}
    +	}
    +
    +	// Reject a too long filter name so that the memcmp()
    +	// in the loop below won't read past the end of the
    +	// string in filter_name_map[i].name.
    +	const size_t name_len = (size_t)(name_end - *str);
    +	if (name_len > NAME_LEN_MAX)
    +		return "Unknown filter name";
    +
    +	for (size_t i = 0; i < ARRAY_SIZE(filter_name_map); ++i) {
    +		if (memcmp(*str, filter_name_map[i].name, name_len) == 0
    +				&& filter_name_map[i].name[name_len] == '\0') {
    +			if (only_xz && filter_name_map[i].id
    +					>= LZMA_FILTER_RESERVED_START)
    +				return "This filter cannot be used in "
    +						"the .xz format";
    +
    +			// Allocate the filter-specific options and
    +			// initialize the memory with zeros.
    +			void *options = lzma_alloc_zero(
    +					filter_name_map[i].opts_size,
    +					allocator);
    +			if (options == NULL)
    +				return "Memory allocation failed";
    +
    +			// Filter name was found so the input string is good
    +			// at least this far.
    +			*str = opts_start;
    +
    +			const char *errmsg = filter_name_map[i].parse(
    +					str, str_end, options);
    +			if (errmsg != NULL) {
    +				lzma_free(options, allocator);
    +				return errmsg;
    +			}
    +
    +			// *filter is modified only when parsing is successful.
    +			filter->id = filter_name_map[i].id;
    +			filter->options = options;
    +			return NULL;
    +		}
    +	}
    +
    +	return "Unknown filter name";
    +}
    +
    +
    +/// Converts the string to a filter chain (array of lzma_filter structures).
    +///
    +/// *str is advanced every time something has been decoded successfully.
    +/// This way the caller knows where in the string a possible error occurred.
    +static const char *
    +str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags,
    +		const lzma_allocator *allocator)
    +{
    +	const char *errmsg;
    +
    +	// Skip leading spaces.
    +	while (**str == ' ')
    +		++*str;
    +
    +	if (**str == '\0')
    +		return "Empty string is not allowed, "
    +				"try \"6\" if a default value is needed";
    +
    +	// Detect the type of the string.
    +	//
    +	// A string beginning with a digit or a string beginning with
    +	// one dash and a digit are treated as presets. Trailing spaces
    +	// will be ignored too (leading spaces were already ignored above).
    +	//
    +	// For example, "6", "7  ", "-9e", or "  -3  " are treated as presets.
    +	// Strings like "-" or "- " aren't preset.
    +#define MY_IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
    +	if (MY_IS_DIGIT(**str) || (**str == '-' && MY_IS_DIGIT((*str)[1]))) {
    +		if (**str == '-')
    +			++*str;
    +
    +		// Ignore trailing spaces.
    +		const size_t str_len = strlen(*str);
    +		const char *str_end = memchr(*str, ' ', str_len);
    +		if (str_end != NULL) {
    +			// There is at least one trailing space. Check that
    +			// there are no chars other than spaces.
    +			for (size_t i = 1; str_end[i] != '\0'; ++i)
    +				if (str_end[i] != ' ')
    +					return "Unsupported preset";
    +		} else {
    +			// There are no trailing spaces. Use the whole string.
    +			str_end = *str + str_len;
    +		}
    +
    +		uint32_t preset;
    +		errmsg = parse_lzma12_preset(str, str_end, &preset);
    +		if (errmsg != NULL)
    +			return errmsg;
    +
    +		lzma_options_lzma *opts = lzma_alloc(sizeof(*opts), allocator);
    +		if (opts == NULL)
    +			return "Memory allocation failed";
    +
    +		if (lzma_lzma_preset(opts, preset)) {
    +			lzma_free(opts, allocator);
    +			return "Unsupported preset";
    +		}
    +
    +		filters[0].id = LZMA_FILTER_LZMA2;
    +		filters[0].options = opts;
    +		filters[1].id = LZMA_VLI_UNKNOWN;
    +		filters[1].options = NULL;
    +
    +		return NULL;
    +	}
    +
    +	// Not a preset so it must be a filter chain.
    +	//
    +	// If LZMA_STR_ALL_FILTERS isn't used we allow only filters that
    +	// can be used in .xz.
    +	const bool only_xz = (flags & LZMA_STR_ALL_FILTERS) == 0;
    +
    +	// Use a temporary array so that we don't modify the caller-supplied
    +	// one until we know that no errors occurred.
    +	lzma_filter temp_filters[LZMA_FILTERS_MAX + 1];
    +
    +	size_t i = 0;
    +	do {
    +		if (i == LZMA_FILTERS_MAX) {
    +			errmsg = "The maximum number of filters is four";
    +			goto error;
    +		}
    +
    +		// Skip "--" if present.
    +		if ((*str)[0] == '-' && (*str)[1] == '-')
    +			*str += 2;
    +
    +		// Locate the end of "filter:name1=value1,name2=value2",
    +		// stopping at the first "--" or a single space.
    +		const char *filter_end = *str;
    +		while (filter_end[0] != '\0') {
    +			if ((filter_end[0] == '-' && filter_end[1] == '-')
    +					|| filter_end[0] == ' ')
    +				break;
    +
    +			++filter_end;
    +		}
    +
    +		// Inputs that have "--" at the end or "-- " in the middle
    +		// will result in an empty filter name.
    +		if (filter_end == *str) {
    +			errmsg = "Filter name is missing";
    +			goto error;
    +		}
    +
    +		errmsg = parse_filter(str, filter_end, &temp_filters[i],
    +				allocator, only_xz);
    +		if (errmsg != NULL)
    +			goto error;
    +
    +		// Skip trailing spaces.
    +		while (**str == ' ')
    +			++*str;
    +
    +		++i;
    +	} while (**str != '\0');
    +
    +	// Seems to be good, terminate the array so that
    +	// basic validation can be done.
    +	temp_filters[i].id = LZMA_VLI_UNKNOWN;
    +	temp_filters[i].options = NULL;
    +
    +	// Do basic validation if the application didn't prohibit it.
    +	if ((flags & LZMA_STR_NO_VALIDATION) == 0) {
    +		size_t dummy;
    +		const lzma_ret ret = lzma_validate_chain(temp_filters, &dummy);
    +		assert(ret == LZMA_OK || ret == LZMA_OPTIONS_ERROR);
    +		if (ret != LZMA_OK) {
    +			errmsg = "Invalid filter chain "
    +					"('lzma2' missing at the end?)";
    +			goto error;
    +		}
    +	}
    +
    +	// All good. Copy the filters to the application supplied array.
    +	memcpy(filters, temp_filters, (i + 1) * sizeof(lzma_filter));
    +	return NULL;
    +
    +error:
    +	// Free the filter options that were successfully decoded.
    +	while (i-- > 0)
    +		lzma_free(temp_filters[i].options, allocator);
    +
    +	return errmsg;
    +}
    +
    +
    +extern LZMA_API(const char *)
    +lzma_str_to_filters(const char *str, int *error_pos, lzma_filter *filters,
    +		uint32_t flags, const lzma_allocator *allocator)
    +{
    +	// If error_pos isn't NULL, *error_pos must always be set.
    +	// liblzma <= 5.4.6 and <= 5.6.1 have a bug and don't do this
    +	// when str == NULL or filters == NULL or flags are unsupported.
    +	if (error_pos != NULL)
    +		*error_pos = 0;
    +
    +	if (str == NULL || filters == NULL)
    +		return "Unexpected NULL pointer argument(s) "
    +				"to lzma_str_to_filters()";
    +
    +	// Validate the flags.
    +	const uint32_t supported_flags
    +			= LZMA_STR_ALL_FILTERS
    +			| LZMA_STR_NO_VALIDATION;
    +
    +	if (flags & ~supported_flags)
    +		return "Unsupported flags to lzma_str_to_filters()";
    +
    +	const char *used = str;
    +	const char *errmsg = str_to_filters(&used, filters, flags, allocator);
    +
    +	if (error_pos != NULL) {
    +		const size_t n = (size_t)(used - str);
    +		*error_pos = n > INT_MAX ? INT_MAX : (int)n;
    +	}
    +
    +	return errmsg;
    +}
    +
    +
    +/// Converts options of one filter to a string.
    +///
    +/// The caller must have already put the filter name in the destination
    +/// string. Since it is possible that no options will be needed, the caller
    +/// won't have put a delimiter character (':' or '=') in the string yet.
    +/// We will add it if at least one option will be added to the string.
    +static void
    +strfy_filter(lzma_str *dest, const char *delimiter,
    +		const option_map *optmap, size_t optmap_count,
    +		const void *filter_options)
    +{
    +	for (size_t i = 0; i < optmap_count; ++i) {
    +		// No attempt is made to reverse LZMA1/2 preset.
    +		if (optmap[i].type == OPTMAP_TYPE_LZMA_PRESET)
    +			continue;
    +
    +		// All options have integer values, some just are mapped
    +		// to a string with a name_value_map. LZMA1/2 preset
    +		// isn't reversed back to preset=PRESET form.
    +		uint32_t v;
    +		const void *ptr
    +			= (const char *)filter_options + optmap[i].offset;
    +		switch (optmap[i].type) {
    +			case OPTMAP_TYPE_LZMA_MODE:
    +				v = *(const lzma_mode *)ptr;
    +				break;
    +
    +			case OPTMAP_TYPE_LZMA_MATCH_FINDER:
    +				v = *(const lzma_match_finder *)ptr;
    +				break;
    +
    +			default:
    +				v = *(const uint32_t *)ptr;
    +				break;
    +		}
    +
    +		// Skip this if this option should be omitted from
    +		// the string when the value is zero.
    +		if (v == 0 && (optmap[i].flags & OPTMAP_NO_STRFY_ZERO))
    +			continue;
    +
    +		// Before the first option we add whatever delimiter
    +		// the caller gave us. For later options a comma is used.
    +		str_append_str(dest, delimiter);
    +		delimiter = ",";
    +
    +		// Add the option name and equals sign.
    +		str_append_str(dest, optmap[i].name);
    +		str_append_str(dest, "=");
    +
    +		if (optmap[i].flags & OPTMAP_USE_NAME_VALUE_MAP) {
    +			const name_value_map *map = optmap[i].u.map;
    +			size_t j = 0;
    +			while (true) {
    +				if (map[j].name[0] == '\0') {
    +					str_append_str(dest, "UNKNOWN");
    +					break;
    +				}
    +
    +				if (map[j].value == v) {
    +					str_append_str(dest, map[j].name);
    +					break;
    +				}
    +
    +				++j;
    +			}
    +		} else {
    +			str_append_u32(dest, v,
    +				optmap[i].flags & OPTMAP_USE_BYTE_SUFFIX);
    +		}
    +	}
    +
    +	return;
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_str_from_filters(char **output_str, const lzma_filter *filters,
    +		uint32_t flags, const lzma_allocator *allocator)
    +{
    +	// On error *output_str is always set to NULL.
    +	// Do it as the very first step.
    +	if (output_str == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	*output_str = NULL;
    +
    +	if (filters == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	// Validate the flags.
    +	const uint32_t supported_flags
    +			= LZMA_STR_ENCODER
    +			| LZMA_STR_DECODER
    +			| LZMA_STR_GETOPT_LONG
    +			| LZMA_STR_NO_SPACES;
    +
    +	if (flags & ~supported_flags)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// There must be at least one filter.
    +	if (filters[0].id == LZMA_VLI_UNKNOWN)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Allocate memory for the output string.
    +	lzma_str dest;
    +	return_if_error(str_init(&dest, allocator));
    +
    +	const bool show_opts = (flags & (LZMA_STR_ENCODER | LZMA_STR_DECODER));
    +
    +	const char *opt_delim = (flags & LZMA_STR_GETOPT_LONG) ? "=" : ":";
    +
    +	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
    +		// If we reach LZMA_FILTERS_MAX, then the filters array
    +		// is too large since the ID cannot be LZMA_VLI_UNKNOWN here.
    +		if (i == LZMA_FILTERS_MAX) {
    +			str_free(&dest, allocator);
    +			return LZMA_OPTIONS_ERROR;
    +		}
    +
    +		// Don't add a space between filters if the caller
    +		// doesn't want them.
    +		if (i > 0 && !(flags & LZMA_STR_NO_SPACES))
    +			str_append_str(&dest, " ");
    +
    +		// Use dashes for xz getopt_long() compatible syntax but also
    +		// use dashes to separate filters when spaces weren't wanted.
    +		if ((flags & LZMA_STR_GETOPT_LONG)
    +				|| (i > 0 && (flags & LZMA_STR_NO_SPACES)))
    +			str_append_str(&dest, "--");
    +
    +		size_t j = 0;
    +		while (true) {
    +			if (j == ARRAY_SIZE(filter_name_map)) {
    +				// Filter ID in filters[i].id isn't supported.
    +				str_free(&dest, allocator);
    +				return LZMA_OPTIONS_ERROR;
    +			}
    +
    +			if (filter_name_map[j].id == filters[i].id) {
    +				// Add the filter name.
    +				str_append_str(&dest, filter_name_map[j].name);
    +
    +				// If only the filter names were wanted then
    +				// skip to the next filter. In this case
    +				// .options is ignored and may be NULL even
    +				// when the filter doesn't allow NULL options.
    +				if (!show_opts)
    +					break;
    +
    +				if (filters[i].options == NULL) {
    +					if (!filter_name_map[j].allow_null) {
    +						// Filter-specific options
    +						// are missing but with
    +						// this filter the options
    +						// structure is mandatory.
    +						str_free(&dest, allocator);
    +						return LZMA_OPTIONS_ERROR;
    +					}
    +
    +					// .options is allowed to be NULL.
    +					// There is no need to add any
    +					// options to the string.
    +					break;
    +				}
    +
    +				// Options structure is available. Add
    +				// the filter options to the string.
    +				const size_t optmap_count
    +					= (flags & LZMA_STR_ENCODER)
    +					? filter_name_map[j].strfy_encoder
    +					: filter_name_map[j].strfy_decoder;
    +				strfy_filter(&dest, opt_delim,
    +						filter_name_map[j].optmap,
    +						optmap_count,
    +						filters[i].options);
    +				break;
    +			}
    +
    +			++j;
    +		}
    +	}
    +
    +	return str_finish(output_str, &dest, allocator);
    +}
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_str_list_filters(char **output_str, lzma_vli filter_id, uint32_t flags,
    +		const lzma_allocator *allocator)
    +{
    +	// On error *output_str is always set to NULL.
    +	// Do it as the very first step.
    +	if (output_str == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	*output_str = NULL;
    +
    +	// Validate the flags.
    +	const uint32_t supported_flags
    +			= LZMA_STR_ALL_FILTERS
    +			| LZMA_STR_ENCODER
    +			| LZMA_STR_DECODER
    +			| LZMA_STR_GETOPT_LONG;
    +
    +	if (flags & ~supported_flags)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Allocate memory for the output string.
    +	lzma_str dest;
    +	return_if_error(str_init(&dest, allocator));
    +
    +	// If only listing the filter names then separate them with spaces.
    +	// Otherwise use newlines.
    +	const bool show_opts = (flags & (LZMA_STR_ENCODER | LZMA_STR_DECODER));
    +	const char *filter_delim = show_opts ? "\n" : " ";
    +
    +	const char *opt_delim = (flags & LZMA_STR_GETOPT_LONG) ? "=" : ":";
    +	bool first_filter_printed = false;
    +
    +	for (size_t i = 0; i < ARRAY_SIZE(filter_name_map); ++i) {
    +		// If we are printing only one filter then skip others.
    +		if (filter_id != LZMA_VLI_UNKNOWN
    +				&& filter_id != filter_name_map[i].id)
    +			continue;
    +
    +		// If we are printing only .xz filters then skip the others.
    +		if (filter_name_map[i].id >= LZMA_FILTER_RESERVED_START
    +				&& (flags & LZMA_STR_ALL_FILTERS) == 0
    +				&& filter_id == LZMA_VLI_UNKNOWN)
    +			continue;
    +
    +		// Add a new line if this isn't the first filter being
    +		// written to the string.
    +		if (first_filter_printed)
    +			str_append_str(&dest, filter_delim);
    +
    +		first_filter_printed = true;
    +
    +		if (flags & LZMA_STR_GETOPT_LONG)
    +			str_append_str(&dest, "--");
    +
    +		str_append_str(&dest, filter_name_map[i].name);
    +
    +		// If only the filter names were wanted then continue
    +		// to the next filter.
    +		if (!show_opts)
    +			continue;
    +
    +		const option_map *optmap = filter_name_map[i].optmap;
    +		const char *d = opt_delim;
    +
    +		const size_t end = (flags & LZMA_STR_ENCODER)
    +				? filter_name_map[i].strfy_encoder
    +				: filter_name_map[i].strfy_decoder;
    +
    +		for (size_t j = 0; j < end; ++j) {
    +			// The first option is delimited from the filter
    +			// name using "=" or ":" and the rest of the options
    +			// are separated with ",".
    +			str_append_str(&dest, d);
    +			d = ",";
    +
    +			// optname=
    +			str_append_str(&dest, optmap[j].name);
    +			str_append_str(&dest, "=<");
    +
    +			if (optmap[j].type == OPTMAP_TYPE_LZMA_PRESET) {
    +				// LZMA1/2 preset has its custom help string.
    +				str_append_str(&dest, LZMA12_PRESET_STR);
    +			} else if (optmap[j].flags
    +					& OPTMAP_USE_NAME_VALUE_MAP) {
    +				// Separate the possible option values by "|".
    +				const name_value_map *m = optmap[j].u.map;
    +				for (size_t k = 0; m[k].name[0] != '\0'; ++k) {
    +					if (k > 0)
    +						str_append_str(&dest, "|");
    +
    +					str_append_str(&dest, m[k].name);
    +				}
    +			} else {
    +				// Integer range is shown as min-max.
    +				const bool use_byte_suffix = optmap[j].flags
    +						& OPTMAP_USE_BYTE_SUFFIX;
    +				str_append_u32(&dest, optmap[j].u.range.min,
    +						use_byte_suffix);
    +				str_append_str(&dest, "-");
    +				str_append_u32(&dest, optmap[j].u.range.max,
    +						use_byte_suffix);
    +			}
    +
    +			str_append_str(&dest, ">");
    +		}
    +	}
    +
    +	// If no filters were added to the string then it must be because
    +	// the caller provided an unsupported Filter ID.
    +	if (!first_filter_printed) {
    +		str_free(&dest, allocator);
    +		return LZMA_OPTIONS_ERROR;
    +	}
    +
    +	return str_finish(output_str, &dest, allocator);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_decoder.c
    new file mode 100644
    index 00000000000..3254ccc35bd
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_decoder.c
    @@ -0,0 +1,85 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       vli_decoder.c
    +/// \brief      Decodes variable-length integers
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_vli_decode(lzma_vli *restrict vli, size_t *vli_pos,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size)
    +{
    +	// If we haven't been given vli_pos, work in single-call mode.
    +	size_t vli_pos_internal = 0;
    +	if (vli_pos == NULL) {
    +		vli_pos = &vli_pos_internal;
    +		*vli = 0;
    +
    +		// If there's no input, use LZMA_DATA_ERROR. This way it is
    +		// easy to decode VLIs from buffers that have known size,
    +		// and get the correct error code in case the buffer is
    +		// too short.
    +		if (*in_pos >= in_size)
    +			return LZMA_DATA_ERROR;
    +
    +	} else {
    +		// Initialize *vli when starting to decode a new integer.
    +		if (*vli_pos == 0)
    +			*vli = 0;
    +
    +		// Validate the arguments.
    +		if (*vli_pos >= LZMA_VLI_BYTES_MAX
    +				|| (*vli >> (*vli_pos * 7)) != 0)
    +			return LZMA_PROG_ERROR;;
    +
    +		if (*in_pos >= in_size)
    +			return LZMA_BUF_ERROR;
    +	}
    +
    +	do {
    +		// Read the next byte. Use a temporary variable so that we
    +		// can update *in_pos immediately.
    +		const uint8_t byte = in[*in_pos];
    +		++*in_pos;
    +
    +		// Add the newly read byte to *vli.
    +		*vli += (lzma_vli)(byte & 0x7F) << (*vli_pos * 7);
    +		++*vli_pos;
    +
    +		// Check if this is the last byte of a multibyte integer.
    +		if ((byte & 0x80) == 0) {
    +			// We don't allow using variable-length integers as
    +			// padding i.e. the encoding must use the most the
    +			// compact form.
    +			if (byte == 0x00 && *vli_pos > 1)
    +				return LZMA_DATA_ERROR;
    +
    +			return vli_pos == &vli_pos_internal
    +					? LZMA_OK : LZMA_STREAM_END;
    +		}
    +
    +		// There is at least one more byte coming. If we have already
    +		// read maximum number of bytes, the integer is considered
    +		// corrupt.
    +		//
    +		// If we need bigger integers in future, old versions liblzma
    +		// will confusingly indicate the file being corrupt instead of
    +		// unsupported. I suppose it's still better this way, because
    +		// in the foreseeable future (writing this in 2008) the only
    +		// reason why files would appear having over 63-bit integers
    +		// is that the files are simply corrupt.
    +		if (*vli_pos == LZMA_VLI_BYTES_MAX)
    +			return LZMA_DATA_ERROR;
    +
    +	} while (*in_pos < in_size);
    +
    +	return vli_pos == &vli_pos_internal ? LZMA_DATA_ERROR : LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_encoder.c
    new file mode 100644
    index 00000000000..3859006a94f
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_encoder.c
    @@ -0,0 +1,68 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       vli_encoder.c
    +/// \brief      Encodes variable-length integers
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +
    +
    +extern LZMA_API(lzma_ret)
    +lzma_vli_encode(lzma_vli vli, size_t *vli_pos,
    +		uint8_t *restrict out, size_t *restrict out_pos,
    +		size_t out_size)
    +{
    +	// If we haven't been given vli_pos, work in single-call mode.
    +	size_t vli_pos_internal = 0;
    +	if (vli_pos == NULL) {
    +		vli_pos = &vli_pos_internal;
    +
    +		// In single-call mode, we expect that the caller has
    +		// reserved enough output space.
    +		if (*out_pos >= out_size)
    +			return LZMA_PROG_ERROR;
    +	} else {
    +		// This never happens when we are called by liblzma, but
    +		// may happen if called directly from an application.
    +		if (*out_pos >= out_size)
    +			return LZMA_BUF_ERROR;
    +	}
    +
    +	// Validate the arguments.
    +	if (*vli_pos >= LZMA_VLI_BYTES_MAX || vli > LZMA_VLI_MAX)
    +		return LZMA_PROG_ERROR;
    +
    +	// Shift vli so that the next bits to encode are the lowest. In
    +	// single-call mode this never changes vli since *vli_pos is zero.
    +	vli >>= *vli_pos * 7;
    +
    +	// Write the non-last bytes in a loop.
    +	while (vli >= 0x80) {
    +		// We don't need *vli_pos during this function call anymore,
    +		// but update it here so that it is ready if we need to
    +		// return before the whole integer has been decoded.
    +		++*vli_pos;
    +		assert(*vli_pos < LZMA_VLI_BYTES_MAX);
    +
    +		// Write the next byte.
    +		out[*out_pos] = (uint8_t)(vli) | 0x80;
    +		vli >>= 7;
    +
    +		if (++*out_pos == out_size)
    +			return vli_pos == &vli_pos_internal
    +					? LZMA_PROG_ERROR : LZMA_OK;
    +	}
    +
    +	// Write the last byte.
    +	out[*out_pos] = (uint8_t)(vli);
    +	++*out_pos;
    +	++*vli_pos;
    +
    +	return vli_pos == &vli_pos_internal ? LZMA_OK : LZMA_STREAM_END;
    +
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_size.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_size.c
    new file mode 100644
    index 00000000000..c8cb2ec10ad
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_size.c
    @@ -0,0 +1,29 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       vli_size.c
    +/// \brief      Calculates the encoded size of a variable-length integer
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +
    +
    +extern LZMA_API(uint32_t)
    +lzma_vli_size(lzma_vli vli)
    +{
    +	if (vli > LZMA_VLI_MAX)
    +		return 0;
    +
    +	uint32_t i = 0;
    +	do {
    +		vli >>= 7;
    +		++i;
    +	} while (vli != 0);
    +
    +	assert(i <= LZMA_VLI_BYTES_MAX);
    +	return i;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.c
    new file mode 100644
    index 00000000000..5dbe253b4b3
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.c
    @@ -0,0 +1,72 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       delta_common.c
    +/// \brief      Common stuff for Delta encoder and decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "delta_common.h"
    +#include "delta_private.h"
    +
    +
    +static void
    +delta_coder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_delta_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->next, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +extern lzma_ret
    +lzma_delta_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	// Allocate memory for the decoder if needed.
    +	lzma_delta_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_delta_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +
    +		// End function is the same for encoder and decoder.
    +		next->end = &delta_coder_end;
    +		coder->next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	// Validate the options.
    +	if (lzma_delta_coder_memusage(filters[0].options) == UINT64_MAX)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Set the delta distance.
    +	const lzma_options_delta *opt = filters[0].options;
    +	coder->distance = opt->dist;
    +
    +	// Initialize the rest of the variables.
    +	coder->pos = 0;
    +	memzero(coder->history, LZMA_DELTA_DIST_MAX);
    +
    +	// Initialize the next decoder in the chain, if any.
    +	return lzma_next_filter_init(&coder->next, allocator, filters + 1);
    +}
    +
    +
    +extern uint64_t
    +lzma_delta_coder_memusage(const void *options)
    +{
    +	const lzma_options_delta *opt = options;
    +
    +	if (opt == NULL || opt->type != LZMA_DELTA_TYPE_BYTE
    +			|| opt->dist < LZMA_DELTA_DIST_MIN
    +			|| opt->dist > LZMA_DELTA_DIST_MAX)
    +		return UINT64_MAX;
    +
    +	return sizeof(lzma_delta_coder);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.h
    new file mode 100644
    index 00000000000..bd091276972
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.h
    @@ -0,0 +1,19 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       delta_common.h
    +/// \brief      Common stuff for Delta encoder and decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_DELTA_COMMON_H
    +#define LZMA_DELTA_COMMON_H
    +
    +#include "common.h"
    +
    +extern uint64_t lzma_delta_coder_memusage(const void *options);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.c
    new file mode 100644
    index 00000000000..9f0d49ca415
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.c
    @@ -0,0 +1,87 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       delta_decoder.c
    +/// \brief      Delta filter decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "delta_decoder.h"
    +#include "delta_private.h"
    +
    +
    +static void
    +decode_buffer(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
    +{
    +	const size_t distance = coder->distance;
    +
    +	for (size_t i = 0; i < size; ++i) {
    +		buffer[i] += coder->history[(distance + coder->pos) & 0xFF];
    +		coder->history[coder->pos-- & 0xFF] = buffer[i];
    +	}
    +}
    +
    +
    +// For an unknown reason NVIDIA HPC Compiler needs this pragma
    +// to produce working code.
    +#ifdef __NVCOMPILER
    +#	pragma routine novector
    +#endif
    +static lzma_ret
    +delta_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_delta_coder *coder = coder_ptr;
    +
    +	assert(coder->next.code != NULL);
    +
    +	const size_t out_start = *out_pos;
    +
    +	const lzma_ret ret = coder->next.code(coder->next.coder, allocator,
    +			in, in_pos, in_size, out, out_pos, out_size,
    +			action);
    +
    +	// out might be NULL. In that case size == 0. Null pointer + 0 is
    +	// undefined behavior so skip the call in that case as it would
    +	// do nothing anyway.
    +	const size_t size = *out_pos - out_start;
    +	if (size > 0)
    +		decode_buffer(coder, out + out_start, size);
    +
    +	return ret;
    +}
    +
    +
    +extern lzma_ret
    +lzma_delta_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	next->code = &delta_decode;
    +	return lzma_delta_coder_init(next, allocator, filters);
    +}
    +
    +
    +extern lzma_ret
    +lzma_delta_props_decode(void **options, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size)
    +{
    +	if (props_size != 1)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	lzma_options_delta *opt
    +			= lzma_alloc(sizeof(lzma_options_delta), allocator);
    +	if (opt == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	opt->type = LZMA_DELTA_TYPE_BYTE;
    +	opt->dist = props[0] + 1U;
    +
    +	*options = opt;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.h
    new file mode 100644
    index 00000000000..e2268ed44e7
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.h
    @@ -0,0 +1,25 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       delta_decoder.h
    +/// \brief      Delta filter decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_DELTA_DECODER_H
    +#define LZMA_DELTA_DECODER_H
    +
    +#include "delta_common.h"
    +
    +extern lzma_ret lzma_delta_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_delta_props_decode(
    +		void **options, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.c
    new file mode 100644
    index 00000000000..ba4a50b1f42
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.c
    @@ -0,0 +1,132 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       delta_encoder.c
    +/// \brief      Delta filter encoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "delta_encoder.h"
    +#include "delta_private.h"
    +
    +
    +/// Copies and encodes the data at the same time. This is used when Delta
    +/// is the first filter in the chain (and thus the last filter in the
    +/// encoder's filter stack).
    +static void
    +copy_and_encode(lzma_delta_coder *coder,
    +		const uint8_t *restrict in, uint8_t *restrict out, size_t size)
    +{
    +	const size_t distance = coder->distance;
    +
    +	for (size_t i = 0; i < size; ++i) {
    +		const uint8_t tmp = coder->history[
    +				(distance + coder->pos) & 0xFF];
    +		coder->history[coder->pos-- & 0xFF] = in[i];
    +		out[i] = in[i] - tmp;
    +	}
    +}
    +
    +
    +/// Encodes the data in place. This is used when we are the last filter
    +/// in the chain (and thus non-last filter in the encoder's filter stack).
    +static void
    +encode_in_place(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
    +{
    +	const size_t distance = coder->distance;
    +
    +	for (size_t i = 0; i < size; ++i) {
    +		const uint8_t tmp = coder->history[
    +				(distance + coder->pos) & 0xFF];
    +		coder->history[coder->pos-- & 0xFF] = buffer[i];
    +		buffer[i] -= tmp;
    +	}
    +}
    +
    +
    +static lzma_ret
    +delta_encode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_delta_coder *coder = coder_ptr;
    +
    +	lzma_ret ret;
    +
    +	if (coder->next.code == NULL) {
    +		const size_t in_avail = in_size - *in_pos;
    +		const size_t out_avail = out_size - *out_pos;
    +		const size_t size = my_min(in_avail, out_avail);
    +
    +		// in and out might be NULL. In such cases size == 0.
    +		// Null pointer + 0 is undefined behavior so skip
    +		// the call in that case as it would do nothing anyway.
    +		if (size > 0)
    +			copy_and_encode(coder, in + *in_pos, out + *out_pos,
    +					size);
    +
    +		*in_pos += size;
    +		*out_pos += size;
    +
    +		ret = action != LZMA_RUN && *in_pos == in_size
    +				? LZMA_STREAM_END : LZMA_OK;
    +
    +	} else {
    +		const size_t out_start = *out_pos;
    +
    +		ret = coder->next.code(coder->next.coder, allocator,
    +				in, in_pos, in_size, out, out_pos, out_size,
    +				action);
    +
    +		// Like above, avoid null pointer + 0.
    +		const size_t size = *out_pos - out_start;
    +		if (size > 0)
    +			encode_in_place(coder, out + out_start, size);
    +	}
    +
    +	return ret;
    +}
    +
    +
    +static lzma_ret
    +delta_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
    +		const lzma_filter *filters_null lzma_attribute((__unused__)),
    +		const lzma_filter *reversed_filters)
    +{
    +	lzma_delta_coder *coder = coder_ptr;
    +
    +	// Delta doesn't and will never support changing the options in
    +	// the middle of encoding. If the app tries to change them, we
    +	// simply ignore them.
    +	return lzma_next_filter_update(
    +			&coder->next, allocator, reversed_filters + 1);
    +}
    +
    +
    +extern lzma_ret
    +lzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	next->code = &delta_encode;
    +	next->update = &delta_encoder_update;
    +	return lzma_delta_coder_init(next, allocator, filters);
    +}
    +
    +
    +extern lzma_ret
    +lzma_delta_props_encode(const void *options, uint8_t *out)
    +{
    +	// The caller must have already validated the options, so it's
    +	// LZMA_PROG_ERROR if they are invalid.
    +	if (lzma_delta_coder_memusage(options) == UINT64_MAX)
    +		return LZMA_PROG_ERROR;
    +
    +	const lzma_options_delta *opt = options;
    +	out[0] = opt->dist - LZMA_DELTA_DIST_MIN;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.h
    new file mode 100644
    index 00000000000..735f0ed0091
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.h
    @@ -0,0 +1,23 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       delta_encoder.h
    +/// \brief      Delta filter encoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_DELTA_ENCODER_H
    +#define LZMA_DELTA_ENCODER_H
    +
    +#include "delta_common.h"
    +
    +extern lzma_ret lzma_delta_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_delta_props_encode(const void *options, uint8_t *out);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_private.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_private.h
    new file mode 100644
    index 00000000000..e54721a8466
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_private.h
    @@ -0,0 +1,36 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       delta_private.h
    +/// \brief      Private common stuff for Delta encoder and decoder
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_DELTA_PRIVATE_H
    +#define LZMA_DELTA_PRIVATE_H
    +
    +#include "delta_common.h"
    +
    +typedef struct {
    +	/// Next coder in the chain
    +	lzma_next_coder next;
    +
    +	/// Delta distance
    +	size_t distance;
    +
    +	/// Position in history[]
    +	uint8_t pos;
    +
    +	/// Buffer to hold history of the original data
    +	uint8_t history[LZMA_DELTA_DIST_MAX];
    +} lzma_delta_coder;
    +
    +
    +extern lzma_ret lzma_delta_coder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma.pc.in b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma.pc.in
    new file mode 100644
    index 00000000000..a432992b707
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma.pc.in
    @@ -0,0 +1,16 @@
    +# SPDX-License-Identifier: 0BSD
    +# Author: Lasse Collin
    +
    +prefix=@prefix@
    +exec_prefix=@exec_prefix@
    +libdir=@libdir@
    +includedir=@includedir@
    +
    +Name: liblzma
    +Description: General purpose data compression library
    +URL: @PACKAGE_URL@
    +Version: @PACKAGE_VERSION@
    +Cflags: -I${includedir}
    +Cflags.private: -DLZMA_API_STATIC
    +Libs: -L${libdir} -llzma
    +Libs.private: @PTHREAD_CFLAGS@ @LIBS@
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_generic.map b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_generic.map
    new file mode 100644
    index 00000000000..f74c1548455
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_generic.map
    @@ -0,0 +1,128 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +XZ_5.0 {
    +global:
    +	lzma_alone_decoder;
    +	lzma_alone_encoder;
    +	lzma_auto_decoder;
    +	lzma_block_buffer_bound;
    +	lzma_block_buffer_decode;
    +	lzma_block_buffer_encode;
    +	lzma_block_compressed_size;
    +	lzma_block_decoder;
    +	lzma_block_encoder;
    +	lzma_block_header_decode;
    +	lzma_block_header_encode;
    +	lzma_block_header_size;
    +	lzma_block_total_size;
    +	lzma_block_unpadded_size;
    +	lzma_check_is_supported;
    +	lzma_check_size;
    +	lzma_code;
    +	lzma_crc32;
    +	lzma_crc64;
    +	lzma_easy_buffer_encode;
    +	lzma_easy_decoder_memusage;
    +	lzma_easy_encoder;
    +	lzma_easy_encoder_memusage;
    +	lzma_end;
    +	lzma_filter_decoder_is_supported;
    +	lzma_filter_encoder_is_supported;
    +	lzma_filter_flags_decode;
    +	lzma_filter_flags_encode;
    +	lzma_filter_flags_size;
    +	lzma_filters_copy;
    +	lzma_filters_update;
    +	lzma_get_check;
    +	lzma_index_append;
    +	lzma_index_block_count;
    +	lzma_index_buffer_decode;
    +	lzma_index_buffer_encode;
    +	lzma_index_cat;
    +	lzma_index_checks;
    +	lzma_index_decoder;
    +	lzma_index_dup;
    +	lzma_index_encoder;
    +	lzma_index_end;
    +	lzma_index_file_size;
    +	lzma_index_hash_append;
    +	lzma_index_hash_decode;
    +	lzma_index_hash_end;
    +	lzma_index_hash_init;
    +	lzma_index_hash_size;
    +	lzma_index_init;
    +	lzma_index_iter_init;
    +	lzma_index_iter_locate;
    +	lzma_index_iter_next;
    +	lzma_index_iter_rewind;
    +	lzma_index_memusage;
    +	lzma_index_memused;
    +	lzma_index_size;
    +	lzma_index_stream_count;
    +	lzma_index_stream_flags;
    +	lzma_index_stream_padding;
    +	lzma_index_stream_size;
    +	lzma_index_total_size;
    +	lzma_index_uncompressed_size;
    +	lzma_lzma_preset;
    +	lzma_memlimit_get;
    +	lzma_memlimit_set;
    +	lzma_memusage;
    +	lzma_mf_is_supported;
    +	lzma_mode_is_supported;
    +	lzma_physmem;
    +	lzma_properties_decode;
    +	lzma_properties_encode;
    +	lzma_properties_size;
    +	lzma_raw_buffer_decode;
    +	lzma_raw_buffer_encode;
    +	lzma_raw_decoder;
    +	lzma_raw_decoder_memusage;
    +	lzma_raw_encoder;
    +	lzma_raw_encoder_memusage;
    +	lzma_stream_buffer_bound;
    +	lzma_stream_buffer_decode;
    +	lzma_stream_buffer_encode;
    +	lzma_stream_decoder;
    +	lzma_stream_encoder;
    +	lzma_stream_flags_compare;
    +	lzma_stream_footer_decode;
    +	lzma_stream_footer_encode;
    +	lzma_stream_header_decode;
    +	lzma_stream_header_encode;
    +	lzma_version_number;
    +	lzma_version_string;
    +	lzma_vli_decode;
    +	lzma_vli_encode;
    +	lzma_vli_size;
    +
    +local:
    +	*;
    +};
    +
    +XZ_5.2 {
    +global:
    +	lzma_block_uncomp_encode;
    +	lzma_cputhreads;
    +	lzma_get_progress;
    +	lzma_stream_encoder_mt;
    +	lzma_stream_encoder_mt_memusage;
    +} XZ_5.0;
    +
    +XZ_5.4 {
    +global:
    +	lzma_file_info_decoder;
    +	lzma_filters_free;
    +	lzma_lzip_decoder;
    +	lzma_microlzma_decoder;
    +	lzma_microlzma_encoder;
    +	lzma_stream_decoder_mt;
    +	lzma_str_from_filters;
    +	lzma_str_list_filters;
    +	lzma_str_to_filters;
    +} XZ_5.2;
    +
    +XZ_5.6.0 {
    +global:
    +	lzma_mt_block_size;
    +} XZ_5.4;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_linux.map b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_linux.map
    new file mode 100644
    index 00000000000..7e4b25e1762
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_linux.map
    @@ -0,0 +1,143 @@
    +/* SPDX-License-Identifier: 0BSD */
    +
    +XZ_5.0 {
    +global:
    +	lzma_alone_decoder;
    +	lzma_alone_encoder;
    +	lzma_auto_decoder;
    +	lzma_block_buffer_bound;
    +	lzma_block_buffer_decode;
    +	lzma_block_buffer_encode;
    +	lzma_block_compressed_size;
    +	lzma_block_decoder;
    +	lzma_block_encoder;
    +	lzma_block_header_decode;
    +	lzma_block_header_encode;
    +	lzma_block_header_size;
    +	lzma_block_total_size;
    +	lzma_block_unpadded_size;
    +	lzma_check_is_supported;
    +	lzma_check_size;
    +	lzma_code;
    +	lzma_crc32;
    +	lzma_crc64;
    +	lzma_easy_buffer_encode;
    +	lzma_easy_decoder_memusage;
    +	lzma_easy_encoder;
    +	lzma_easy_encoder_memusage;
    +	lzma_end;
    +	lzma_filter_decoder_is_supported;
    +	lzma_filter_encoder_is_supported;
    +	lzma_filter_flags_decode;
    +	lzma_filter_flags_encode;
    +	lzma_filter_flags_size;
    +	lzma_filters_copy;
    +	lzma_filters_update;
    +	lzma_get_check;
    +	lzma_index_append;
    +	lzma_index_block_count;
    +	lzma_index_buffer_decode;
    +	lzma_index_buffer_encode;
    +	lzma_index_cat;
    +	lzma_index_checks;
    +	lzma_index_decoder;
    +	lzma_index_dup;
    +	lzma_index_encoder;
    +	lzma_index_end;
    +	lzma_index_file_size;
    +	lzma_index_hash_append;
    +	lzma_index_hash_decode;
    +	lzma_index_hash_end;
    +	lzma_index_hash_init;
    +	lzma_index_hash_size;
    +	lzma_index_init;
    +	lzma_index_iter_init;
    +	lzma_index_iter_locate;
    +	lzma_index_iter_next;
    +	lzma_index_iter_rewind;
    +	lzma_index_memusage;
    +	lzma_index_memused;
    +	lzma_index_size;
    +	lzma_index_stream_count;
    +	lzma_index_stream_flags;
    +	lzma_index_stream_padding;
    +	lzma_index_stream_size;
    +	lzma_index_total_size;
    +	lzma_index_uncompressed_size;
    +	lzma_lzma_preset;
    +	lzma_memlimit_get;
    +	lzma_memlimit_set;
    +	lzma_memusage;
    +	lzma_mf_is_supported;
    +	lzma_mode_is_supported;
    +	lzma_physmem;
    +	lzma_properties_decode;
    +	lzma_properties_encode;
    +	lzma_properties_size;
    +	lzma_raw_buffer_decode;
    +	lzma_raw_buffer_encode;
    +	lzma_raw_decoder;
    +	lzma_raw_decoder_memusage;
    +	lzma_raw_encoder;
    +	lzma_raw_encoder_memusage;
    +	lzma_stream_buffer_bound;
    +	lzma_stream_buffer_decode;
    +	lzma_stream_buffer_encode;
    +	lzma_stream_decoder;
    +	lzma_stream_encoder;
    +	lzma_stream_flags_compare;
    +	lzma_stream_footer_decode;
    +	lzma_stream_footer_encode;
    +	lzma_stream_header_decode;
    +	lzma_stream_header_encode;
    +	lzma_version_number;
    +	lzma_version_string;
    +	lzma_vli_decode;
    +	lzma_vli_encode;
    +	lzma_vli_size;
    +
    +local:
    +	*;
    +};
    +
    +XZ_5.2 {
    +global:
    +	lzma_block_uncomp_encode;
    +	lzma_cputhreads;
    +	lzma_get_progress;
    +	lzma_stream_encoder_mt;
    +	lzma_stream_encoder_mt_memusage;
    +} XZ_5.0;
    +
    +XZ_5.1.2alpha {
    +global:
    +	lzma_stream_encoder_mt;
    +	lzma_stream_encoder_mt_memusage;
    +} XZ_5.0;
    +
    +XZ_5.2.2 {
    +global:
    +	lzma_block_uncomp_encode;
    +	lzma_cputhreads;
    +	lzma_get_progress;
    +	lzma_stream_encoder_mt;
    +	lzma_stream_encoder_mt_memusage;
    +} XZ_5.1.2alpha;
    +
    +XZ_5.4 {
    +global:
    +	lzma_file_info_decoder;
    +	lzma_filters_free;
    +	lzma_lzip_decoder;
    +	lzma_microlzma_decoder;
    +	lzma_microlzma_encoder;
    +	lzma_stream_decoder_mt;
    +	lzma_str_from_filters;
    +	lzma_str_list_filters;
    +	lzma_str_to_filters;
    +} XZ_5.2;
    +
    +XZ_5.6.0 {
    +global:
    +	lzma_mt_block_size;
    +} XZ_5.4;
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.c
    new file mode 100644
    index 00000000000..92913f225a0
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.c
    @@ -0,0 +1,324 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lz_decoder.c
    +/// \brief      LZ out window
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +// liblzma supports multiple LZ77-based filters. The LZ part is shared
    +// between these filters. The LZ code takes care of dictionary handling
    +// and passing the data between filters in the chain. The filter-specific
    +// part decodes from the input buffer to the dictionary.
    +
    +
    +#include "lz_decoder.h"
    +
    +
    +typedef struct {
    +	/// Dictionary (history buffer)
    +	lzma_dict dict;
    +
    +	/// The actual LZ-based decoder e.g. LZMA
    +	lzma_lz_decoder lz;
    +
    +	/// Next filter in the chain, if any. Note that LZMA and LZMA2 are
    +	/// only allowed as the last filter, but the long-range filter in
    +	/// future can be in the middle of the chain.
    +	lzma_next_coder next;
    +
    +	/// True if the next filter in the chain has returned LZMA_STREAM_END.
    +	bool next_finished;
    +
    +	/// True if the LZ decoder (e.g. LZMA) has detected end of payload
    +	/// marker. This may become true before next_finished becomes true.
    +	bool this_finished;
    +
    +	/// Temporary buffer needed when the LZ-based filter is not the last
    +	/// filter in the chain. The output of the next filter is first
    +	/// decoded into buffer[], which is then used as input for the actual
    +	/// LZ-based decoder.
    +	struct {
    +		size_t pos;
    +		size_t size;
    +		uint8_t buffer[LZMA_BUFFER_SIZE];
    +	} temp;
    +} lzma_coder;
    +
    +
    +static void
    +lz_decoder_reset(lzma_coder *coder)
    +{
    +	coder->dict.pos = 2 * LZ_DICT_REPEAT_MAX;
    +	coder->dict.full = 0;
    +	coder->dict.buf[2 * LZ_DICT_REPEAT_MAX - 1] = '\0';
    +	coder->dict.has_wrapped = false;
    +	coder->dict.need_reset = false;
    +	return;
    +}
    +
    +
    +static lzma_ret
    +decode_buffer(lzma_coder *coder,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size)
    +{
    +	while (true) {
    +		// Wrap the dictionary if needed.
    +		if (coder->dict.pos == coder->dict.size) {
    +			// See the comment of #define LZ_DICT_REPEAT_MAX.
    +			coder->dict.pos = LZ_DICT_REPEAT_MAX;
    +			coder->dict.has_wrapped = true;
    +			memcpy(coder->dict.buf, coder->dict.buf
    +						+ coder->dict.size
    +						- LZ_DICT_REPEAT_MAX,
    +					LZ_DICT_REPEAT_MAX);
    +		}
    +
    +		// Store the current dictionary position. It is needed to know
    +		// where to start copying to the out[] buffer.
    +		const size_t dict_start = coder->dict.pos;
    +
    +		// Calculate how much we allow coder->lz.code() to decode.
    +		// It must not decode past the end of the dictionary
    +		// buffer, and we don't want it to decode more than is
    +		// actually needed to fill the out[] buffer.
    +		coder->dict.limit = coder->dict.pos
    +				+ my_min(out_size - *out_pos,
    +					coder->dict.size - coder->dict.pos);
    +
    +		// Call the coder->lz.code() to do the actual decoding.
    +		const lzma_ret ret = coder->lz.code(
    +				coder->lz.coder, &coder->dict,
    +				in, in_pos, in_size);
    +
    +		// Copy the decoded data from the dictionary to the out[]
    +		// buffer. Do it conditionally because out can be NULL
    +		// (in which case copy_size is always 0). Calling memcpy()
    +		// with a null-pointer is undefined even if the third
    +		// argument is 0.
    +		const size_t copy_size = coder->dict.pos - dict_start;
    +		assert(copy_size <= out_size - *out_pos);
    +
    +		if (copy_size > 0)
    +			memcpy(out + *out_pos, coder->dict.buf + dict_start,
    +					copy_size);
    +
    +		*out_pos += copy_size;
    +
    +		// Reset the dictionary if so requested by coder->lz.code().
    +		if (coder->dict.need_reset) {
    +			lz_decoder_reset(coder);
    +
    +			// Since we reset dictionary, we don't check if
    +			// dictionary became full.
    +			if (ret != LZMA_OK || *out_pos == out_size)
    +				return ret;
    +		} else {
    +			// Return if everything got decoded or an error
    +			// occurred, or if there's no more data to decode.
    +			//
    +			// Note that detecting if there's something to decode
    +			// is done by looking if dictionary become full
    +			// instead of looking if *in_pos == in_size. This
    +			// is because it is possible that all the input was
    +			// consumed already but some data is pending to be
    +			// written to the dictionary.
    +			if (ret != LZMA_OK || *out_pos == out_size
    +					|| coder->dict.pos < coder->dict.size)
    +				return ret;
    +		}
    +	}
    +}
    +
    +
    +static lzma_ret
    +lz_decode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size,
    +		lzma_action action)
    +{
    +	lzma_coder *coder = coder_ptr;
    +
    +	if (coder->next.code == NULL)
    +		return decode_buffer(coder, in, in_pos, in_size,
    +				out, out_pos, out_size);
    +
    +	// We aren't the last coder in the chain, we need to decode
    +	// our input to a temporary buffer.
    +	while (*out_pos < out_size) {
    +		// Fill the temporary buffer if it is empty.
    +		if (!coder->next_finished
    +				&& coder->temp.pos == coder->temp.size) {
    +			coder->temp.pos = 0;
    +			coder->temp.size = 0;
    +
    +			const lzma_ret ret = coder->next.code(
    +					coder->next.coder,
    +					allocator, in, in_pos, in_size,
    +					coder->temp.buffer, &coder->temp.size,
    +					LZMA_BUFFER_SIZE, action);
    +
    +			if (ret == LZMA_STREAM_END)
    +				coder->next_finished = true;
    +			else if (ret != LZMA_OK || coder->temp.size == 0)
    +				return ret;
    +		}
    +
    +		if (coder->this_finished) {
    +			if (coder->temp.size != 0)
    +				return LZMA_DATA_ERROR;
    +
    +			if (coder->next_finished)
    +				return LZMA_STREAM_END;
    +
    +			return LZMA_OK;
    +		}
    +
    +		const lzma_ret ret = decode_buffer(coder, coder->temp.buffer,
    +				&coder->temp.pos, coder->temp.size,
    +				out, out_pos, out_size);
    +
    +		if (ret == LZMA_STREAM_END)
    +			coder->this_finished = true;
    +		else if (ret != LZMA_OK)
    +			return ret;
    +		else if (coder->next_finished && *out_pos < out_size)
    +			return LZMA_DATA_ERROR;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +lz_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_coder *coder = coder_ptr;
    +
    +	lzma_next_end(&coder->next, allocator);
    +	lzma_free(coder->dict.buf, allocator);
    +
    +	if (coder->lz.end != NULL)
    +		coder->lz.end(coder->lz.coder, allocator);
    +	else
    +		lzma_free(coder->lz.coder, allocator);
    +
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +extern lzma_ret
    +lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters,
    +		lzma_ret (*lz_init)(lzma_lz_decoder *lz,
    +			const lzma_allocator *allocator,
    +			lzma_vli id, const void *options,
    +			lzma_lz_options *lz_options))
    +{
    +	// Allocate the base structure if it isn't already allocated.
    +	lzma_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &lz_decode;
    +		next->end = &lz_decoder_end;
    +
    +		coder->dict.buf = NULL;
    +		coder->dict.size = 0;
    +		coder->lz = LZMA_LZ_DECODER_INIT;
    +		coder->next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	// Allocate and initialize the LZ-based decoder. It will also give
    +	// us the dictionary size.
    +	lzma_lz_options lz_options;
    +	return_if_error(lz_init(&coder->lz, allocator,
    +			filters[0].id, filters[0].options, &lz_options));
    +
    +	// If the dictionary size is very small, increase it to 4096 bytes.
    +	// This is to prevent constant wrapping of the dictionary, which
    +	// would slow things down. The downside is that since we don't check
    +	// separately for the real dictionary size, we may happily accept
    +	// corrupt files.
    +	if (lz_options.dict_size < 4096)
    +		lz_options.dict_size = 4096;
    +
    +	// Make dictionary size a multiple of 16. Some LZ-based decoders like
    +	// LZMA use the lowest bits lzma_dict.pos to know the alignment of the
    +	// data. Aligned buffer is also good when memcpying from the
    +	// dictionary to the output buffer, since applications are
    +	// recommended to give aligned buffers to liblzma.
    +	//
    +	// Reserve 2 * LZ_DICT_REPEAT_MAX bytes of extra space which is
    +	// needed for alloc_size.
    +	//
    +	// Avoid integer overflow.
    +	if (lz_options.dict_size > SIZE_MAX - 15 - 2 * LZ_DICT_REPEAT_MAX)
    +		return LZMA_MEM_ERROR;
    +
    +	lz_options.dict_size = (lz_options.dict_size + 15) & ~((size_t)(15));
    +
    +	// Reserve extra space as explained in the comment
    +	// of #define LZ_DICT_REPEAT_MAX.
    +	const size_t alloc_size
    +			= lz_options.dict_size + 2 * LZ_DICT_REPEAT_MAX;
    +
    +	// Allocate and initialize the dictionary.
    +	if (coder->dict.size != alloc_size) {
    +		lzma_free(coder->dict.buf, allocator);
    +		coder->dict.buf = lzma_alloc(alloc_size, allocator);
    +		if (coder->dict.buf == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		// NOTE: Yes, alloc_size, not lz_options.dict_size. The way
    +		// coder->dict.full is updated will take care that we will
    +		// still reject distances larger than lz_options.dict_size.
    +		coder->dict.size = alloc_size;
    +	}
    +
    +	lz_decoder_reset(next->coder);
    +
    +	// Use the preset dictionary if it was given to us.
    +	if (lz_options.preset_dict != NULL
    +			&& lz_options.preset_dict_size > 0) {
    +		// If the preset dictionary is bigger than the actual
    +		// dictionary, copy only the tail.
    +		const size_t copy_size = my_min(lz_options.preset_dict_size,
    +				lz_options.dict_size);
    +		const size_t offset = lz_options.preset_dict_size - copy_size;
    +		memcpy(coder->dict.buf + coder->dict.pos,
    +				lz_options.preset_dict + offset,
    +				copy_size);
    +
    +		// dict.pos isn't zero after lz_decoder_reset().
    +		coder->dict.pos += copy_size;
    +		coder->dict.full = copy_size;
    +	}
    +
    +	// Miscellaneous initializations
    +	coder->next_finished = false;
    +	coder->this_finished = false;
    +	coder->temp.pos = 0;
    +	coder->temp.size = 0;
    +
    +	// Initialize the next filter in the chain, if any.
    +	return lzma_next_filter_init(&coder->next, allocator, filters + 1);
    +}
    +
    +
    +extern uint64_t
    +lzma_lz_decoder_memusage(size_t dictionary_size)
    +{
    +	return sizeof(lzma_coder) + (uint64_t)(dictionary_size);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.h
    new file mode 100644
    index 00000000000..cb61b6e24c7
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.h
    @@ -0,0 +1,250 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lz_decoder.h
    +/// \brief      LZ out window
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZ_DECODER_H
    +#define LZMA_LZ_DECODER_H
    +
    +#include "common.h"
    +
    +
    +/// Maximum length of a match rounded up to a nice power of 2 which is
    +/// a good size for aligned memcpy(). The allocated dictionary buffer will
    +/// be 2 * LZ_DICT_REPEAT_MAX bytes larger than the actual dictionary size:
    +///
    +/// (1) Every time the decoder reaches the end of the dictionary buffer,
    +///     the last LZ_DICT_REPEAT_MAX bytes will be copied to the beginning.
    +///     This way dict_repeat() will only need to copy from one place,
    +///     never from both the end and beginning of the buffer.
    +///
    +/// (2) The other LZ_DICT_REPEAT_MAX bytes is kept as a buffer between
    +///     the oldest byte still in the dictionary and the current write
    +///     position. This way dict_repeat(dict, dict->size - 1, &len)
    +///     won't need memmove() as the copying cannot overlap.
    +///
    +/// Note that memcpy() still cannot be used if distance < len.
    +///
    +/// LZMA's longest match length is 273 so pick a multiple of 16 above that.
    +#define LZ_DICT_REPEAT_MAX 288
    +
    +
    +typedef struct {
    +	/// Pointer to the dictionary buffer.
    +	uint8_t *buf;
    +
    +	/// Write position in dictionary. The next byte will be written to
    +	/// buf[pos].
    +	size_t pos;
    +
    +	/// Indicates how full the dictionary is. This is used by
    +	/// dict_is_distance_valid() to detect corrupt files that would
    +	/// read beyond the beginning of the dictionary.
    +	size_t full;
    +
    +	/// Write limit
    +	size_t limit;
    +
    +	/// Allocated size of buf. This is 2 * LZ_DICT_REPEAT_MAX bytes
    +	/// larger than the actual dictionary size. This is enforced by
    +	/// how the value for "full" is set; it can be at most
    +	/// "size - 2 * LZ_DICT_REPEAT_MAX".
    +	size_t size;
    +
    +	/// True once the dictionary has become full and the writing position
    +	/// has been wrapped in decode_buffer() in lz_decoder.c.
    +	bool has_wrapped;
    +
    +	/// True when dictionary should be reset before decoding more data.
    +	bool need_reset;
    +
    +} lzma_dict;
    +
    +
    +typedef struct {
    +	size_t dict_size;
    +	const uint8_t *preset_dict;
    +	size_t preset_dict_size;
    +} lzma_lz_options;
    +
    +
    +typedef struct {
    +	/// Data specific to the LZ-based decoder
    +	void *coder;
    +
    +	/// Function to decode from in[] to *dict
    +	lzma_ret (*code)(void *coder,
    +			lzma_dict *restrict dict, const uint8_t *restrict in,
    +			size_t *restrict in_pos, size_t in_size);
    +
    +	void (*reset)(void *coder, const void *options);
    +
    +	/// Set the uncompressed size. If uncompressed_size == LZMA_VLI_UNKNOWN
    +	/// then allow_eopm will always be true.
    +	void (*set_uncompressed)(void *coder, lzma_vli uncompressed_size,
    +			bool allow_eopm);
    +
    +	/// Free allocated resources
    +	void (*end)(void *coder, const lzma_allocator *allocator);
    +
    +} lzma_lz_decoder;
    +
    +
    +#define LZMA_LZ_DECODER_INIT \
    +	(lzma_lz_decoder){ \
    +		.coder = NULL, \
    +		.code = NULL, \
    +		.reset = NULL, \
    +		.set_uncompressed = NULL, \
    +		.end = NULL, \
    +	}
    +
    +
    +extern lzma_ret lzma_lz_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters,
    +		lzma_ret (*lz_init)(lzma_lz_decoder *lz,
    +			const lzma_allocator *allocator,
    +			lzma_vli id, const void *options,
    +			lzma_lz_options *lz_options));
    +
    +extern uint64_t lzma_lz_decoder_memusage(size_t dictionary_size);
    +
    +
    +//////////////////////
    +// Inline functions //
    +//////////////////////
    +
    +/// Get a byte from the history buffer.
    +static inline uint8_t
    +dict_get(const lzma_dict *const dict, const uint32_t distance)
    +{
    +	return dict->buf[dict->pos - distance - 1
    +			+ (distance < dict->pos
    +				? 0 : dict->size - LZ_DICT_REPEAT_MAX)];
    +}
    +
    +
    +/// Optimized version of dict_get(dict, 0)
    +static inline uint8_t
    +dict_get0(const lzma_dict *const dict)
    +{
    +	return dict->buf[dict->pos - 1];
    +}
    +
    +
    +/// Test if dictionary is empty.
    +static inline bool
    +dict_is_empty(const lzma_dict *const dict)
    +{
    +	return dict->full == 0;
    +}
    +
    +
    +/// Validate the match distance
    +static inline bool
    +dict_is_distance_valid(const lzma_dict *const dict, const size_t distance)
    +{
    +	return dict->full > distance;
    +}
    +
    +
    +/// Repeat *len bytes at distance.
    +static inline bool
    +dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len)
    +{
    +	// Don't write past the end of the dictionary.
    +	const size_t dict_avail = dict->limit - dict->pos;
    +	uint32_t left = my_min(dict_avail, *len);
    +	*len -= left;
    +
    +	size_t back = dict->pos - distance - 1;
    +	if (distance >= dict->pos)
    +		back += dict->size - LZ_DICT_REPEAT_MAX;
    +
    +	// Repeat a block of data from the history. Because memcpy() is faster
    +	// than copying byte by byte in a loop, the copying process gets split
    +	// into two cases.
    +	if (distance < left) {
    +		// Source and target areas overlap, thus we can't use
    +		// memcpy() nor even memmove() safely.
    +		do {
    +			dict->buf[dict->pos++] = dict->buf[back++];
    +		} while (--left > 0);
    +	} else {
    +		memcpy(dict->buf + dict->pos, dict->buf + back, left);
    +		dict->pos += left;
    +	}
    +
    +	// Update how full the dictionary is.
    +	if (!dict->has_wrapped)
    +		dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;
    +
    +	return *len != 0;
    +}
    +
    +
    +static inline void
    +dict_put(lzma_dict *dict, uint8_t byte)
    +{
    +	dict->buf[dict->pos++] = byte;
    +
    +	if (!dict->has_wrapped)
    +		dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;
    +}
    +
    +
    +/// Puts one byte into the dictionary. Returns true if the dictionary was
    +/// already full and the byte couldn't be added.
    +static inline bool
    +dict_put_safe(lzma_dict *dict, uint8_t byte)
    +{
    +	if (unlikely(dict->pos == dict->limit))
    +		return true;
    +
    +	dict_put(dict, byte);
    +	return false;
    +}
    +
    +
    +/// Copies arbitrary amount of data into the dictionary.
    +static inline void
    +dict_write(lzma_dict *restrict dict, const uint8_t *restrict in,
    +		size_t *restrict in_pos, size_t in_size,
    +		size_t *restrict left)
    +{
    +	// NOTE: If we are being given more data than the size of the
    +	// dictionary, it could be possible to optimize the LZ decoder
    +	// so that not everything needs to go through the dictionary.
    +	// This shouldn't be very common thing in practice though, and
    +	// the slowdown of one extra memcpy() isn't bad compared to how
    +	// much time it would have taken if the data were compressed.
    +
    +	if (in_size - *in_pos > *left)
    +		in_size = *in_pos + *left;
    +
    +	*left -= lzma_bufcpy(in, in_pos, in_size,
    +			dict->buf, &dict->pos, dict->limit);
    +
    +	if (!dict->has_wrapped)
    +		dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;
    +
    +	return;
    +}
    +
    +
    +static inline void
    +dict_reset(lzma_dict *dict)
    +{
    +	dict->need_reset = true;
    +	return;
    +}
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.c
    new file mode 100644
    index 00000000000..4af23e14c42
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.c
    @@ -0,0 +1,632 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lz_encoder.c
    +/// \brief      LZ in window
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lz_encoder.h"
    +#include "lz_encoder_hash.h"
    +
    +// See lz_encoder_hash.h. This is a bit hackish but avoids making
    +// endianness a conditional in makefiles.
    +#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL)
    +#	include "lz_encoder_hash_table.h"
    +#endif
    +
    +#include "memcmplen.h"
    +
    +
    +typedef struct {
    +	/// LZ-based encoder e.g. LZMA
    +	lzma_lz_encoder lz;
    +
    +	/// History buffer and match finder
    +	lzma_mf mf;
    +
    +	/// Next coder in the chain
    +	lzma_next_coder next;
    +} lzma_coder;
    +
    +
    +/// \brief      Moves the data in the input window to free space for new data
    +///
    +/// mf->buffer is a sliding input window, which keeps mf->keep_size_before
    +/// bytes of input history available all the time. Now and then we need to
    +/// "slide" the buffer to make space for the new data to the end of the
    +/// buffer. At the same time, data older than keep_size_before is dropped.
    +///
    +static void
    +move_window(lzma_mf *mf)
    +{
    +	// Align the move to a multiple of 16 bytes. Some LZ-based encoders
    +	// like LZMA use the lowest bits of mf->read_pos to know the
    +	// alignment of the uncompressed data. We also get better speed
    +	// for memmove() with aligned buffers.
    +	assert(mf->read_pos > mf->keep_size_before);
    +	const uint32_t move_offset
    +		= (mf->read_pos - mf->keep_size_before) & ~UINT32_C(15);
    +
    +	assert(mf->write_pos > move_offset);
    +	const size_t move_size = mf->write_pos - move_offset;
    +
    +	assert(move_offset + move_size <= mf->size);
    +
    +	memmove(mf->buffer, mf->buffer + move_offset, move_size);
    +
    +	mf->offset += move_offset;
    +	mf->read_pos -= move_offset;
    +	mf->read_limit -= move_offset;
    +	mf->write_pos -= move_offset;
    +
    +	return;
    +}
    +
    +
    +/// \brief      Tries to fill the input window (mf->buffer)
    +///
    +/// If we are the last encoder in the chain, our input data is in in[].
    +/// Otherwise we call the next filter in the chain to process in[] and
    +/// write its output to mf->buffer.
    +///
    +/// This function must not be called once it has returned LZMA_STREAM_END.
    +///
    +static lzma_ret
    +fill_window(lzma_coder *coder, const lzma_allocator *allocator,
    +		const uint8_t *in, size_t *in_pos, size_t in_size,
    +		lzma_action action)
    +{
    +	assert(coder->mf.read_pos <= coder->mf.write_pos);
    +
    +	// Move the sliding window if needed.
    +	if (coder->mf.read_pos >= coder->mf.size - coder->mf.keep_size_after)
    +		move_window(&coder->mf);
    +
    +	// Maybe this is ugly, but lzma_mf uses uint32_t for most things
    +	// (which I find cleanest), but we need size_t here when filling
    +	// the history window.
    +	size_t write_pos = coder->mf.write_pos;
    +	lzma_ret ret;
    +	if (coder->next.code == NULL) {
    +		// Not using a filter, simply memcpy() as much as possible.
    +		lzma_bufcpy(in, in_pos, in_size, coder->mf.buffer,
    +				&write_pos, coder->mf.size);
    +
    +		ret = action != LZMA_RUN && *in_pos == in_size
    +				? LZMA_STREAM_END : LZMA_OK;
    +
    +	} else {
    +		ret = coder->next.code(coder->next.coder, allocator,
    +				in, in_pos, in_size,
    +				coder->mf.buffer, &write_pos,
    +				coder->mf.size, action);
    +	}
    +
    +	coder->mf.write_pos = write_pos;
    +
    +	// Silence Valgrind. lzma_memcmplen() can read extra bytes
    +	// and Valgrind will give warnings if those bytes are uninitialized
    +	// because Valgrind cannot see that the values of the uninitialized
    +	// bytes are eventually ignored.
    +	memzero(coder->mf.buffer + write_pos, LZMA_MEMCMPLEN_EXTRA);
    +
    +	// If end of stream has been reached or flushing completed, we allow
    +	// the encoder to process all the input (that is, read_pos is allowed
    +	// to reach write_pos). Otherwise we keep keep_size_after bytes
    +	// available as prebuffer.
    +	if (ret == LZMA_STREAM_END) {
    +		assert(*in_pos == in_size);
    +		ret = LZMA_OK;
    +		coder->mf.action = action;
    +		coder->mf.read_limit = coder->mf.write_pos;
    +
    +	} else if (coder->mf.write_pos > coder->mf.keep_size_after) {
    +		// This needs to be done conditionally, because if we got
    +		// only little new input, there may be too little input
    +		// to do any encoding yet.
    +		coder->mf.read_limit = coder->mf.write_pos
    +				- coder->mf.keep_size_after;
    +	}
    +
    +	// Restart the match finder after finished LZMA_SYNC_FLUSH.
    +	if (coder->mf.pending > 0
    +			&& coder->mf.read_pos < coder->mf.read_limit) {
    +		// Match finder may update coder->pending and expects it to
    +		// start from zero, so use a temporary variable.
    +		const uint32_t pending = coder->mf.pending;
    +		coder->mf.pending = 0;
    +
    +		// Rewind read_pos so that the match finder can hash
    +		// the pending bytes.
    +		assert(coder->mf.read_pos >= pending);
    +		coder->mf.read_pos -= pending;
    +
    +		// Call the skip function directly instead of using
    +		// mf_skip(), since we don't want to touch mf->read_ahead.
    +		coder->mf.skip(&coder->mf, pending);
    +	}
    +
    +	return ret;
    +}
    +
    +
    +static lzma_ret
    +lz_encode(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size,
    +		uint8_t *restrict out, size_t *restrict out_pos,
    +		size_t out_size, lzma_action action)
    +{
    +	lzma_coder *coder = coder_ptr;
    +
    +	while (*out_pos < out_size
    +			&& (*in_pos < in_size || action != LZMA_RUN)) {
    +		// Read more data to coder->mf.buffer if needed.
    +		if (coder->mf.action == LZMA_RUN && coder->mf.read_pos
    +				>= coder->mf.read_limit)
    +			return_if_error(fill_window(coder, allocator,
    +					in, in_pos, in_size, action));
    +
    +		// Encode
    +		const lzma_ret ret = coder->lz.code(coder->lz.coder,
    +				&coder->mf, out, out_pos, out_size);
    +		if (ret != LZMA_OK) {
    +			// Setting this to LZMA_RUN for cases when we are
    +			// flushing. It doesn't matter when finishing or if
    +			// an error occurred.
    +			coder->mf.action = LZMA_RUN;
    +			return ret;
    +		}
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static bool
    +lz_encoder_prepare(lzma_mf *mf, const lzma_allocator *allocator,
    +		const lzma_lz_options *lz_options)
    +{
    +	// For now, the dictionary size is limited to 1.5 GiB. This may grow
    +	// in the future if needed, but it needs a little more work than just
    +	// changing this check.
    +	if (!IS_ENC_DICT_SIZE_VALID(lz_options->dict_size)
    +			|| lz_options->nice_len > lz_options->match_len_max)
    +		return true;
    +
    +	mf->keep_size_before = lz_options->before_size + lz_options->dict_size;
    +
    +	mf->keep_size_after = lz_options->after_size
    +			+ lz_options->match_len_max;
    +
    +	// To avoid constant memmove()s, allocate some extra space. Since
    +	// memmove()s become more expensive when the size of the buffer
    +	// increases, we reserve more space when a large dictionary is
    +	// used to make the memmove() calls rarer.
    +	//
    +	// This works with dictionaries up to about 3 GiB. If bigger
    +	// dictionary is wanted, some extra work is needed:
    +	//   - Several variables in lzma_mf have to be changed from uint32_t
    +	//     to size_t.
    +	//   - Memory usage calculation needs something too, e.g. use uint64_t
    +	//     for mf->size.
    +	uint32_t reserve = lz_options->dict_size / 2;
    +	if (reserve > (UINT32_C(1) << 30))
    +		reserve /= 2;
    +
    +	reserve += (lz_options->before_size + lz_options->match_len_max
    +			+ lz_options->after_size) / 2 + (UINT32_C(1) << 19);
    +
    +	const uint32_t old_size = mf->size;
    +	mf->size = mf->keep_size_before + reserve + mf->keep_size_after;
    +
    +	// Deallocate the old history buffer if it exists but has different
    +	// size than what is needed now.
    +	if (mf->buffer != NULL && old_size != mf->size) {
    +		lzma_free(mf->buffer, allocator);
    +		mf->buffer = NULL;
    +	}
    +
    +	// Match finder options
    +	mf->match_len_max = lz_options->match_len_max;
    +	mf->nice_len = lz_options->nice_len;
    +
    +	// cyclic_size has to stay smaller than 2 Gi. Note that this doesn't
    +	// mean limiting dictionary size to less than 2 GiB. With a match
    +	// finder that uses multibyte resolution (hashes start at e.g. every
    +	// fourth byte), cyclic_size would stay below 2 Gi even when
    +	// dictionary size is greater than 2 GiB.
    +	//
    +	// It would be possible to allow cyclic_size >= 2 Gi, but then we
    +	// would need to be careful to use 64-bit types in various places
    +	// (size_t could do since we would need bigger than 32-bit address
    +	// space anyway). It would also require either zeroing a multigigabyte
    +	// buffer at initialization (waste of time and RAM) or allow
    +	// normalization in lz_encoder_mf.c to access uninitialized
    +	// memory to keep the code simpler. The current way is simple and
    +	// still allows pretty big dictionaries, so I don't expect these
    +	// limits to change.
    +	mf->cyclic_size = lz_options->dict_size + 1;
    +
    +	// Validate the match finder ID and setup the function pointers.
    +	switch (lz_options->match_finder) {
    +#ifdef HAVE_MF_HC3
    +	case LZMA_MF_HC3:
    +		mf->find = &lzma_mf_hc3_find;
    +		mf->skip = &lzma_mf_hc3_skip;
    +		break;
    +#endif
    +#ifdef HAVE_MF_HC4
    +	case LZMA_MF_HC4:
    +		mf->find = &lzma_mf_hc4_find;
    +		mf->skip = &lzma_mf_hc4_skip;
    +		break;
    +#endif
    +#ifdef HAVE_MF_BT2
    +	case LZMA_MF_BT2:
    +		mf->find = &lzma_mf_bt2_find;
    +		mf->skip = &lzma_mf_bt2_skip;
    +		break;
    +#endif
    +#ifdef HAVE_MF_BT3
    +	case LZMA_MF_BT3:
    +		mf->find = &lzma_mf_bt3_find;
    +		mf->skip = &lzma_mf_bt3_skip;
    +		break;
    +#endif
    +#ifdef HAVE_MF_BT4
    +	case LZMA_MF_BT4:
    +		mf->find = &lzma_mf_bt4_find;
    +		mf->skip = &lzma_mf_bt4_skip;
    +		break;
    +#endif
    +
    +	default:
    +		return true;
    +	}
    +
    +	// Calculate the sizes of mf->hash and mf->son.
    +	//
    +	// NOTE: Since 5.3.5beta the LZMA encoder ensures that nice_len
    +	// is big enough for the selected match finder. This makes it
    +	// easier for applications as nice_len = 2 will always be accepted
    +	// even though the effective value can be slightly bigger.
    +	const uint32_t hash_bytes
    +			= mf_get_hash_bytes(lz_options->match_finder);
    +	assert(hash_bytes <= mf->nice_len);
    +
    +	const bool is_bt = (lz_options->match_finder & 0x10) != 0;
    +	uint32_t hs;
    +
    +	if (hash_bytes == 2) {
    +		hs = 0xFFFF;
    +	} else {
    +		// Round dictionary size up to the next 2^n - 1 so it can
    +		// be used as a hash mask.
    +		hs = lz_options->dict_size - 1;
    +		hs |= hs >> 1;
    +		hs |= hs >> 2;
    +		hs |= hs >> 4;
    +		hs |= hs >> 8;
    +		hs >>= 1;
    +		hs |= 0xFFFF;
    +
    +		if (hs > (UINT32_C(1) << 24)) {
    +			if (hash_bytes == 3)
    +				hs = (UINT32_C(1) << 24) - 1;
    +			else
    +				hs >>= 1;
    +		}
    +	}
    +
    +	mf->hash_mask = hs;
    +
    +	++hs;
    +	if (hash_bytes > 2)
    +		hs += HASH_2_SIZE;
    +	if (hash_bytes > 3)
    +		hs += HASH_3_SIZE;
    +/*
    +	No match finder uses this at the moment.
    +	if (mf->hash_bytes > 4)
    +		hs += HASH_4_SIZE;
    +*/
    +
    +	const uint32_t old_hash_count = mf->hash_count;
    +	const uint32_t old_sons_count = mf->sons_count;
    +	mf->hash_count = hs;
    +	mf->sons_count = mf->cyclic_size;
    +	if (is_bt)
    +		mf->sons_count *= 2;
    +
    +	// Deallocate the old hash array if it exists and has different size
    +	// than what is needed now.
    +	if (old_hash_count != mf->hash_count
    +			|| old_sons_count != mf->sons_count) {
    +		lzma_free(mf->hash, allocator);
    +		mf->hash = NULL;
    +
    +		lzma_free(mf->son, allocator);
    +		mf->son = NULL;
    +	}
    +
    +	// Maximum number of match finder cycles
    +	mf->depth = lz_options->depth;
    +	if (mf->depth == 0) {
    +		if (is_bt)
    +			mf->depth = 16 + mf->nice_len / 2;
    +		else
    +			mf->depth = 4 + mf->nice_len / 4;
    +	}
    +
    +	return false;
    +}
    +
    +
    +static bool
    +lz_encoder_init(lzma_mf *mf, const lzma_allocator *allocator,
    +		const lzma_lz_options *lz_options)
    +{
    +	// Allocate the history buffer.
    +	if (mf->buffer == NULL) {
    +		// lzma_memcmplen() is used for the dictionary buffer
    +		// so we need to allocate a few extra bytes to prevent
    +		// it from reading past the end of the buffer.
    +		mf->buffer = lzma_alloc(mf->size + LZMA_MEMCMPLEN_EXTRA,
    +				allocator);
    +		if (mf->buffer == NULL)
    +			return true;
    +
    +		// Keep Valgrind happy with lzma_memcmplen() and initialize
    +		// the extra bytes whose value may get read but which will
    +		// effectively get ignored.
    +		memzero(mf->buffer + mf->size, LZMA_MEMCMPLEN_EXTRA);
    +	}
    +
    +	// Use cyclic_size as initial mf->offset. This allows
    +	// avoiding a few branches in the match finders. The downside is
    +	// that match finder needs to be normalized more often, which may
    +	// hurt performance with huge dictionaries.
    +	mf->offset = mf->cyclic_size;
    +	mf->read_pos = 0;
    +	mf->read_ahead = 0;
    +	mf->read_limit = 0;
    +	mf->write_pos = 0;
    +	mf->pending = 0;
    +
    +#if UINT32_MAX >= SIZE_MAX / 4
    +	// Check for integer overflow. (Huge dictionaries are not
    +	// possible on 32-bit CPU.)
    +	if (mf->hash_count > SIZE_MAX / sizeof(uint32_t)
    +			|| mf->sons_count > SIZE_MAX / sizeof(uint32_t))
    +		return true;
    +#endif
    +
    +	// Allocate and initialize the hash table. Since EMPTY_HASH_VALUE
    +	// is zero, we can use lzma_alloc_zero() or memzero() for mf->hash.
    +	//
    +	// We don't need to initialize mf->son, but not doing that may
    +	// make Valgrind complain in normalization (see normalize() in
    +	// lz_encoder_mf.c). Skipping the initialization is *very* good
    +	// when big dictionary is used but only small amount of data gets
    +	// actually compressed: most of the mf->son won't get actually
    +	// allocated by the kernel, so we avoid wasting RAM and improve
    +	// initialization speed a lot.
    +	if (mf->hash == NULL) {
    +		mf->hash = lzma_alloc_zero(mf->hash_count * sizeof(uint32_t),
    +				allocator);
    +		mf->son = lzma_alloc(mf->sons_count * sizeof(uint32_t),
    +				allocator);
    +
    +		if (mf->hash == NULL || mf->son == NULL) {
    +			lzma_free(mf->hash, allocator);
    +			mf->hash = NULL;
    +
    +			lzma_free(mf->son, allocator);
    +			mf->son = NULL;
    +
    +			return true;
    +		}
    +	} else {
    +/*
    +		for (uint32_t i = 0; i < mf->hash_count; ++i)
    +			mf->hash[i] = EMPTY_HASH_VALUE;
    +*/
    +		memzero(mf->hash, mf->hash_count * sizeof(uint32_t));
    +	}
    +
    +	mf->cyclic_pos = 0;
    +
    +	// Handle preset dictionary.
    +	if (lz_options->preset_dict != NULL
    +			&& lz_options->preset_dict_size > 0) {
    +		// If the preset dictionary is bigger than the actual
    +		// dictionary, use only the tail.
    +		mf->write_pos = my_min(lz_options->preset_dict_size, mf->size);
    +		memcpy(mf->buffer, lz_options->preset_dict
    +				+ lz_options->preset_dict_size - mf->write_pos,
    +				mf->write_pos);
    +		mf->action = LZMA_SYNC_FLUSH;
    +		mf->skip(mf, mf->write_pos);
    +	}
    +
    +	mf->action = LZMA_RUN;
    +
    +	return false;
    +}
    +
    +
    +extern uint64_t
    +lzma_lz_encoder_memusage(const lzma_lz_options *lz_options)
    +{
    +	// Old buffers must not exist when calling lz_encoder_prepare().
    +	lzma_mf mf = {
    +		.buffer = NULL,
    +		.hash = NULL,
    +		.son = NULL,
    +		.hash_count = 0,
    +		.sons_count = 0,
    +	};
    +
    +	// Setup the size information into mf.
    +	if (lz_encoder_prepare(&mf, NULL, lz_options))
    +		return UINT64_MAX;
    +
    +	// Calculate the memory usage.
    +	return ((uint64_t)(mf.hash_count) + mf.sons_count) * sizeof(uint32_t)
    +			+ mf.size + sizeof(lzma_coder);
    +}
    +
    +
    +static void
    +lz_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_coder *coder = coder_ptr;
    +
    +	lzma_next_end(&coder->next, allocator);
    +
    +	lzma_free(coder->mf.son, allocator);
    +	lzma_free(coder->mf.hash, allocator);
    +	lzma_free(coder->mf.buffer, allocator);
    +
    +	if (coder->lz.end != NULL)
    +		coder->lz.end(coder->lz.coder, allocator);
    +	else
    +		lzma_free(coder->lz.coder, allocator);
    +
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +lz_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
    +		const lzma_filter *filters_null lzma_attribute((__unused__)),
    +		const lzma_filter *reversed_filters)
    +{
    +	lzma_coder *coder = coder_ptr;
    +
    +	if (coder->lz.options_update == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	return_if_error(coder->lz.options_update(
    +			coder->lz.coder, reversed_filters));
    +
    +	return lzma_next_filter_update(
    +			&coder->next, allocator, reversed_filters + 1);
    +}
    +
    +
    +static lzma_ret
    +lz_encoder_set_out_limit(void *coder_ptr, uint64_t *uncomp_size,
    +		uint64_t out_limit)
    +{
    +	lzma_coder *coder = coder_ptr;
    +
    +	// This is supported only if there are no other filters chained.
    +	if (coder->next.code == NULL && coder->lz.set_out_limit != NULL)
    +		return coder->lz.set_out_limit(
    +				coder->lz.coder, uncomp_size, out_limit);
    +
    +	return LZMA_OPTIONS_ERROR;
    +}
    +
    +
    +extern lzma_ret
    +lzma_lz_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters,
    +		lzma_ret (*lz_init)(lzma_lz_encoder *lz,
    +			const lzma_allocator *allocator,
    +			lzma_vli id, const void *options,
    +			lzma_lz_options *lz_options))
    +{
    +#if defined(HAVE_SMALL) && !defined(HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR)
    +	// The CRC32 table must be initialized.
    +	lzma_crc32_init();
    +#endif
    +
    +	// Allocate and initialize the base data structure.
    +	lzma_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &lz_encode;
    +		next->end = &lz_encoder_end;
    +		next->update = &lz_encoder_update;
    +		next->set_out_limit = &lz_encoder_set_out_limit;
    +
    +		coder->lz.coder = NULL;
    +		coder->lz.code = NULL;
    +		coder->lz.end = NULL;
    +		coder->lz.options_update = NULL;
    +		coder->lz.set_out_limit = NULL;
    +
    +		// mf.size is initialized to silence Valgrind
    +		// when used on optimized binaries (GCC may reorder
    +		// code in a way that Valgrind gets unhappy).
    +		coder->mf.buffer = NULL;
    +		coder->mf.size = 0;
    +		coder->mf.hash = NULL;
    +		coder->mf.son = NULL;
    +		coder->mf.hash_count = 0;
    +		coder->mf.sons_count = 0;
    +
    +		coder->next = LZMA_NEXT_CODER_INIT;
    +	}
    +
    +	// Initialize the LZ-based encoder.
    +	lzma_lz_options lz_options;
    +	return_if_error(lz_init(&coder->lz, allocator,
    +			filters[0].id, filters[0].options, &lz_options));
    +
    +	// Setup the size information into coder->mf and deallocate
    +	// old buffers if they have wrong size.
    +	if (lz_encoder_prepare(&coder->mf, allocator, &lz_options))
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Allocate new buffers if needed, and do the rest of
    +	// the initialization.
    +	if (lz_encoder_init(&coder->mf, allocator, &lz_options))
    +		return LZMA_MEM_ERROR;
    +
    +	// Initialize the next filter in the chain, if any.
    +	return lzma_next_filter_init(&coder->next, allocator, filters + 1);
    +}
    +
    +
    +extern LZMA_API(lzma_bool)
    +lzma_mf_is_supported(lzma_match_finder mf)
    +{
    +	switch (mf) {
    +#ifdef HAVE_MF_HC3
    +	case LZMA_MF_HC3:
    +		return true;
    +#endif
    +#ifdef HAVE_MF_HC4
    +	case LZMA_MF_HC4:
    +		return true;
    +#endif
    +#ifdef HAVE_MF_BT2
    +	case LZMA_MF_BT2:
    +		return true;
    +#endif
    +#ifdef HAVE_MF_BT3
    +	case LZMA_MF_BT3:
    +		return true;
    +#endif
    +#ifdef HAVE_MF_BT4
    +	case LZMA_MF_BT4:
    +		return true;
    +#endif
    +	default:
    +		return false;
    +	}
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.h
    new file mode 100644
    index 00000000000..eb197c6b6cd
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.h
    @@ -0,0 +1,352 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lz_encoder.h
    +/// \brief      LZ in window and match finder API
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZ_ENCODER_H
    +#define LZMA_LZ_ENCODER_H
    +
    +#include "common.h"
    +
    +
    +// For now, the dictionary size is limited to 1.5 GiB. This may grow
    +// in the future if needed, but it needs a little more work than just
    +// changing this check.
    +#define IS_ENC_DICT_SIZE_VALID(size) \
    +	((size) >= LZMA_DICT_SIZE_MIN \
    +		&& (size) <= (UINT32_C(1) << 30) + (UINT32_C(1) << 29))
    +
    +
    +/// A table of these is used by the LZ-based encoder to hold
    +/// the length-distance pairs found by the match finder.
    +typedef struct {
    +	uint32_t len;
    +	uint32_t dist;
    +} lzma_match;
    +
    +
    +typedef struct lzma_mf_s lzma_mf;
    +struct lzma_mf_s {
    +	///////////////
    +	// In Window //
    +	///////////////
    +
    +	/// Pointer to buffer with data to be compressed
    +	uint8_t *buffer;
    +
    +	/// Total size of the allocated buffer (that is, including all
    +	/// the extra space)
    +	uint32_t size;
    +
    +	/// Number of bytes that must be kept available in our input history.
    +	/// That is, once keep_size_before bytes have been processed,
    +	/// buffer[read_pos - keep_size_before] is the oldest byte that
    +	/// must be available for reading.
    +	uint32_t keep_size_before;
    +
    +	/// Number of bytes that must be kept in buffer after read_pos.
    +	/// That is, read_pos <= write_pos - keep_size_after as long as
    +	/// action is LZMA_RUN; when action != LZMA_RUN, read_pos is allowed
    +	/// to reach write_pos so that the last bytes get encoded too.
    +	uint32_t keep_size_after;
    +
    +	/// Match finders store locations of matches using 32-bit integers.
    +	/// To avoid adjusting several megabytes of integers every time the
    +	/// input window is moved with move_window, we only adjust the
    +	/// offset of the buffer. Thus, buffer[value_in_hash_table - offset]
    +	/// is the byte pointed by value_in_hash_table.
    +	uint32_t offset;
    +
    +	/// buffer[read_pos] is the next byte to run through the match
    +	/// finder. This is incremented in the match finder once the byte
    +	/// has been processed.
    +	uint32_t read_pos;
    +
    +	/// Number of bytes that have been ran through the match finder, but
    +	/// which haven't been encoded by the LZ-based encoder yet.
    +	uint32_t read_ahead;
    +
    +	/// As long as read_pos is less than read_limit, there is enough
    +	/// input available in buffer for at least one encoding loop.
    +	///
    +	/// Because of the stateful API, read_limit may and will get greater
    +	/// than read_pos quite often. This is taken into account when
    +	/// calculating the value for keep_size_after.
    +	uint32_t read_limit;
    +
    +	/// buffer[write_pos] is the first byte that doesn't contain valid
    +	/// uncompressed data; that is, the next input byte will be copied
    +	/// to buffer[write_pos].
    +	uint32_t write_pos;
    +
    +	/// Number of bytes not hashed before read_pos. This is needed to
    +	/// restart the match finder after LZMA_SYNC_FLUSH.
    +	uint32_t pending;
    +
    +	//////////////////
    +	// Match Finder //
    +	//////////////////
    +
    +	/// Find matches. Returns the number of distance-length pairs written
    +	/// to the matches array. This is called only via lzma_mf_find().
    +	uint32_t (*find)(lzma_mf *mf, lzma_match *matches);
    +
    +	/// Skips num bytes. This is like find() but doesn't make the
    +	/// distance-length pairs available, thus being a little faster.
    +	/// This is called only via mf_skip().
    +	void (*skip)(lzma_mf *mf, uint32_t num);
    +
    +	uint32_t *hash;
    +	uint32_t *son;
    +	uint32_t cyclic_pos;
    +	uint32_t cyclic_size; // Must be dictionary size + 1.
    +	uint32_t hash_mask;
    +
    +	/// Maximum number of loops in the match finder
    +	uint32_t depth;
    +
    +	/// Maximum length of a match that the match finder will try to find.
    +	uint32_t nice_len;
    +
    +	/// Maximum length of a match supported by the LZ-based encoder.
    +	/// If the longest match found by the match finder is nice_len,
    +	/// mf_find() tries to expand it up to match_len_max bytes.
    +	uint32_t match_len_max;
    +
    +	/// When running out of input, binary tree match finders need to know
    +	/// if it is due to flushing or finishing. The action is used also
    +	/// by the LZ-based encoders themselves.
    +	lzma_action action;
    +
    +	/// Number of elements in hash[]
    +	uint32_t hash_count;
    +
    +	/// Number of elements in son[]
    +	uint32_t sons_count;
    +};
    +
    +
    +typedef struct {
    +	/// Extra amount of data to keep available before the "actual"
    +	/// dictionary.
    +	size_t before_size;
    +
    +	/// Size of the history buffer
    +	size_t dict_size;
    +
    +	/// Extra amount of data to keep available after the "actual"
    +	/// dictionary.
    +	size_t after_size;
    +
    +	/// Maximum length of a match that the LZ-based encoder can accept.
    +	/// This is used to extend matches of length nice_len to the
    +	/// maximum possible length.
    +	size_t match_len_max;
    +
    +	/// Match finder will search matches up to this length.
    +	/// This must be less than or equal to match_len_max.
    +	size_t nice_len;
    +
    +	/// Type of the match finder to use
    +	lzma_match_finder match_finder;
    +
    +	/// Maximum search depth
    +	uint32_t depth;
    +
    +	/// Initial dictionary for the match finder to search.
    +	const uint8_t *preset_dict;
    +
    +	/// If the preset dictionary is NULL, this value is ignored.
    +	/// Otherwise this member must indicate the preset dictionary's
    +	/// buffer size. If this size is larger than dict_size, then only
    +	/// the dict_size sized tail of the preset_dict will be used.
    +	uint32_t preset_dict_size;
    +
    +} lzma_lz_options;
    +
    +
    +// The total usable buffer space at any moment outside the match finder:
    +// before_size + dict_size + after_size + match_len_max
    +//
    +// In reality, there's some extra space allocated to prevent the number of
    +// memmove() calls reasonable. The bigger the dict_size is, the bigger
    +// this extra buffer will be since with bigger dictionaries memmove() would
    +// also take longer.
    +//
    +// A single encoder loop in the LZ-based encoder may call the match finder
    +// (mf_find() or mf_skip()) at most after_size times. In other words,
    +// a single encoder loop may increment lzma_mf.read_pos at most after_size
    +// times. Since matches are looked up to
    +// lzma_mf.buffer[lzma_mf.read_pos + match_len_max - 1], the total
    +// amount of extra buffer needed after dict_size becomes
    +// after_size + match_len_max.
    +//
    +// before_size has two uses. The first one is to keep literals available
    +// in cases when the LZ-based encoder has made some read ahead.
    +// TODO: Maybe this could be changed by making the LZ-based encoders to
    +// store the actual literals as they do with length-distance pairs.
    +//
    +// Algorithms such as LZMA2 first try to compress a chunk, and then check
    +// if the encoded result is smaller than the uncompressed one. If the chunk
    +// was incompressible, it is better to store it in uncompressed form in
    +// the output stream. To do this, the whole uncompressed chunk has to be
    +// still available in the history buffer. before_size achieves that.
    +
    +
    +typedef struct {
    +	/// Data specific to the LZ-based encoder
    +	void *coder;
    +
    +	/// Function to encode from *dict to out[]
    +	lzma_ret (*code)(void *coder,
    +			lzma_mf *restrict mf, uint8_t *restrict out,
    +			size_t *restrict out_pos, size_t out_size);
    +
    +	/// Free allocated resources
    +	void (*end)(void *coder, const lzma_allocator *allocator);
    +
    +	/// Update the options in the middle of the encoding.
    +	lzma_ret (*options_update)(void *coder, const lzma_filter *filter);
    +
    +	/// Set maximum allowed output size
    +	lzma_ret (*set_out_limit)(void *coder, uint64_t *uncomp_size,
    +			uint64_t out_limit);
    +
    +} lzma_lz_encoder;
    +
    +
    +// Basic steps:
    +//  1. Input gets copied into the dictionary.
    +//  2. Data in dictionary gets run through the match finder byte by byte.
    +//  3. The literals and matches are encoded using e.g. LZMA.
    +//
    +// The bytes that have been ran through the match finder, but not encoded yet,
    +// are called 'read ahead'.
    +
    +
    +/// Get how many bytes the match finder hashes in its initial step.
    +/// This is also the minimum nice_len value with the match finder.
    +static inline uint32_t
    +mf_get_hash_bytes(lzma_match_finder match_finder)
    +{
    +	return (uint32_t)match_finder & 0x0F;
    +}
    +
    +
    +/// Get pointer to the first byte not ran through the match finder
    +static inline const uint8_t *
    +mf_ptr(const lzma_mf *mf)
    +{
    +	return mf->buffer + mf->read_pos;
    +}
    +
    +
    +/// Get the number of bytes that haven't been ran through the match finder yet.
    +static inline uint32_t
    +mf_avail(const lzma_mf *mf)
    +{
    +	return mf->write_pos - mf->read_pos;
    +}
    +
    +
    +/// Get the number of bytes that haven't been encoded yet (some of these
    +/// bytes may have been ran through the match finder though).
    +static inline uint32_t
    +mf_unencoded(const lzma_mf *mf)
    +{
    +	return mf->write_pos - mf->read_pos + mf->read_ahead;
    +}
    +
    +
    +/// Calculate the absolute offset from the beginning of the most recent
    +/// dictionary reset. Only the lowest four bits are important, so there's no
    +/// problem that we don't know the 64-bit size of the data encoded so far.
    +///
    +/// NOTE: When moving the input window, we need to do it so that the lowest
    +/// bits of dict->read_pos are not modified to keep this macro working
    +/// as intended.
    +static inline uint32_t
    +mf_position(const lzma_mf *mf)
    +{
    +	return mf->read_pos - mf->read_ahead;
    +}
    +
    +
    +/// Since everything else begins with mf_, use it also for lzma_mf_find().
    +#define mf_find lzma_mf_find
    +
    +
    +/// Skip the given number of bytes. This is used when a good match was found.
    +/// For example, if mf_find() finds a match of 200 bytes long, the first byte
    +/// of that match was already consumed by mf_find(), and the rest 199 bytes
    +/// have to be skipped with mf_skip(mf, 199).
    +static inline void
    +mf_skip(lzma_mf *mf, uint32_t amount)
    +{
    +	if (amount != 0) {
    +		mf->skip(mf, amount);
    +		mf->read_ahead += amount;
    +	}
    +}
    +
    +
    +/// Copies at most *left number of bytes from the history buffer
    +/// to out[]. This is needed by LZMA2 to encode uncompressed chunks.
    +static inline void
    +mf_read(lzma_mf *mf, uint8_t *out, size_t *out_pos, size_t out_size,
    +		size_t *left)
    +{
    +	const size_t out_avail = out_size - *out_pos;
    +	const size_t copy_size = my_min(out_avail, *left);
    +
    +	assert(mf->read_ahead == 0);
    +	assert(mf->read_pos >= *left);
    +
    +	memcpy(out + *out_pos, mf->buffer + mf->read_pos - *left,
    +			copy_size);
    +
    +	*out_pos += copy_size;
    +	*left -= copy_size;
    +	return;
    +}
    +
    +
    +extern lzma_ret lzma_lz_encoder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters,
    +		lzma_ret (*lz_init)(lzma_lz_encoder *lz,
    +			const lzma_allocator *allocator,
    +			lzma_vli id, const void *options,
    +			lzma_lz_options *lz_options));
    +
    +
    +extern uint64_t lzma_lz_encoder_memusage(const lzma_lz_options *lz_options);
    +
    +
    +// These are only for LZ encoder's internal use.
    +extern uint32_t lzma_mf_find(
    +		lzma_mf *mf, uint32_t *count, lzma_match *matches);
    +
    +extern uint32_t lzma_mf_hc3_find(lzma_mf *dict, lzma_match *matches);
    +extern void lzma_mf_hc3_skip(lzma_mf *dict, uint32_t amount);
    +
    +extern uint32_t lzma_mf_hc4_find(lzma_mf *dict, lzma_match *matches);
    +extern void lzma_mf_hc4_skip(lzma_mf *dict, uint32_t amount);
    +
    +extern uint32_t lzma_mf_bt2_find(lzma_mf *dict, lzma_match *matches);
    +extern void lzma_mf_bt2_skip(lzma_mf *dict, uint32_t amount);
    +
    +extern uint32_t lzma_mf_bt3_find(lzma_mf *dict, lzma_match *matches);
    +extern void lzma_mf_bt3_skip(lzma_mf *dict, uint32_t amount);
    +
    +extern uint32_t lzma_mf_bt4_find(lzma_mf *dict, lzma_match *matches);
    +extern void lzma_mf_bt4_skip(lzma_mf *dict, uint32_t amount);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash.h
    new file mode 100644
    index 00000000000..8ace82b04c5
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash.h
    @@ -0,0 +1,108 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lz_encoder_hash.h
    +/// \brief      Hash macros for match finders
    +//
    +//  Author:     Igor Pavlov
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZ_ENCODER_HASH_H
    +#define LZMA_LZ_ENCODER_HASH_H
    +
    +#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL)
    +	// This is to make liblzma produce the same output on big endian
    +	// systems that it does on little endian systems. lz_encoder.c
    +	// takes care of including the actual table.
    +	lzma_attr_visibility_hidden
    +	extern const uint32_t lzma_lz_hash_table[256];
    +#	define hash_table lzma_lz_hash_table
    +#else
    +#	include "check.h"
    +#	define hash_table lzma_crc32_table[0]
    +#endif
    +
    +#define HASH_2_SIZE (UINT32_C(1) << 10)
    +#define HASH_3_SIZE (UINT32_C(1) << 16)
    +#define HASH_4_SIZE (UINT32_C(1) << 20)
    +
    +#define HASH_2_MASK (HASH_2_SIZE - 1)
    +#define HASH_3_MASK (HASH_3_SIZE - 1)
    +#define HASH_4_MASK (HASH_4_SIZE - 1)
    +
    +#define FIX_3_HASH_SIZE (HASH_2_SIZE)
    +#define FIX_4_HASH_SIZE (HASH_2_SIZE + HASH_3_SIZE)
    +#define FIX_5_HASH_SIZE (HASH_2_SIZE + HASH_3_SIZE + HASH_4_SIZE)
    +
    +// Endianness doesn't matter in hash_2_calc() (no effect on the output).
    +#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
    +#	define hash_2_calc() \
    +		const uint32_t hash_value = read16ne(cur)
    +#else
    +#	define hash_2_calc() \
    +		const uint32_t hash_value \
    +			= (uint32_t)(cur[0]) | ((uint32_t)(cur[1]) << 8)
    +#endif
    +
    +#define hash_3_calc() \
    +	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
    +	const uint32_t hash_2_value = temp & HASH_2_MASK; \
    +	const uint32_t hash_value \
    +			= (temp ^ ((uint32_t)(cur[2]) << 8)) & mf->hash_mask
    +
    +#define hash_4_calc() \
    +	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
    +	const uint32_t hash_2_value = temp & HASH_2_MASK; \
    +	const uint32_t hash_3_value \
    +			= (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
    +	const uint32_t hash_value = (temp ^ ((uint32_t)(cur[2]) << 8) \
    +			^ (hash_table[cur[3]] << 5)) & mf->hash_mask
    +
    +
    +// The following are not currently used.
    +
    +#define hash_5_calc() \
    +	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
    +	const uint32_t hash_2_value = temp & HASH_2_MASK; \
    +	const uint32_t hash_3_value \
    +			= (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
    +	uint32_t hash_4_value = (temp ^ ((uint32_t)(cur[2]) << 8) ^ \
    +			^ hash_table[cur[3]] << 5); \
    +	const uint32_t hash_value \
    +			= (hash_4_value ^ (hash_table[cur[4]] << 3)) \
    +				& mf->hash_mask; \
    +	hash_4_value &= HASH_4_MASK
    +
    +/*
    +#define hash_zip_calc() \
    +	const uint32_t hash_value \
    +			= (((uint32_t)(cur[0]) | ((uint32_t)(cur[1]) << 8)) \
    +				^ hash_table[cur[2]]) & 0xFFFF
    +*/
    +
    +#define hash_zip_calc() \
    +	const uint32_t hash_value \
    +			= (((uint32_t)(cur[2]) | ((uint32_t)(cur[0]) << 8)) \
    +				^ hash_table[cur[1]]) & 0xFFFF
    +
    +#define mt_hash_2_calc() \
    +	const uint32_t hash_2_value \
    +			= (hash_table[cur[0]] ^ cur[1]) & HASH_2_MASK
    +
    +#define mt_hash_3_calc() \
    +	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
    +	const uint32_t hash_2_value = temp & HASH_2_MASK; \
    +	const uint32_t hash_3_value \
    +			= (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK
    +
    +#define mt_hash_4_calc() \
    +	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
    +	const uint32_t hash_2_value = temp & HASH_2_MASK; \
    +	const uint32_t hash_3_value \
    +			= (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
    +	const uint32_t hash_4_value = (temp ^ ((uint32_t)(cur[2]) << 8) ^ \
    +			(hash_table[cur[3]] << 5)) & HASH_4_MASK
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash_table.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash_table.h
    new file mode 100644
    index 00000000000..2b3a60e43e8
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash_table.h
    @@ -0,0 +1,70 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +// This file has been generated by crc32_tablegen.c.
    +
    +const uint32_t lzma_lz_hash_table[256] = {
    +	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
    +	0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
    +	0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
    +	0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
    +	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
    +	0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
    +	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
    +	0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
    +	0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
    +	0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
    +	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
    +	0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
    +	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
    +	0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
    +	0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
    +	0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
    +	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
    +	0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
    +	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
    +	0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
    +	0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
    +	0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
    +	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
    +	0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
    +	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
    +	0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
    +	0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
    +	0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
    +	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
    +	0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
    +	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
    +	0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
    +	0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
    +	0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
    +	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
    +	0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
    +	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
    +	0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
    +	0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
    +	0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
    +	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
    +	0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
    +	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
    +	0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
    +	0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
    +	0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
    +	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
    +	0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
    +	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
    +	0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
    +	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
    +	0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
    +	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
    +	0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
    +	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
    +	0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
    +	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
    +	0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
    +	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
    +	0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
    +	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
    +	0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
    +	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
    +	0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
    +};
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_mf.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_mf.c
    new file mode 100644
    index 00000000000..557c2612f2a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_mf.c
    @@ -0,0 +1,744 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lz_encoder_mf.c
    +/// \brief      Match finders
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lz_encoder.h"
    +#include "lz_encoder_hash.h"
    +#include "memcmplen.h"
    +
    +
    +/// \brief      Find matches starting from the current byte
    +///
    +/// \return     The length of the longest match found
    +extern uint32_t
    +lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches)
    +{
    +	// Call the match finder. It returns the number of length-distance
    +	// pairs found.
    +	// FIXME: Minimum count is zero, what _exactly_ is the maximum?
    +	const uint32_t count = mf->find(mf, matches);
    +
    +	// Length of the longest match; assume that no matches were found
    +	// and thus the maximum length is zero.
    +	uint32_t len_best = 0;
    +
    +	if (count > 0) {
    +#ifndef NDEBUG
    +		// Validate the matches.
    +		for (uint32_t i = 0; i < count; ++i) {
    +			assert(matches[i].len <= mf->nice_len);
    +			assert(matches[i].dist < mf->read_pos);
    +			assert(memcmp(mf_ptr(mf) - 1,
    +				mf_ptr(mf) - matches[i].dist - 2,
    +				matches[i].len) == 0);
    +		}
    +#endif
    +
    +		// The last used element in the array contains
    +		// the longest match.
    +		len_best = matches[count - 1].len;
    +
    +		// If a match of maximum search length was found, try to
    +		// extend the match to maximum possible length.
    +		if (len_best == mf->nice_len) {
    +			// The limit for the match length is either the
    +			// maximum match length supported by the LZ-based
    +			// encoder or the number of bytes left in the
    +			// dictionary, whichever is smaller.
    +			uint32_t limit = mf_avail(mf) + 1;
    +			if (limit > mf->match_len_max)
    +				limit = mf->match_len_max;
    +
    +			// Pointer to the byte we just ran through
    +			// the match finder.
    +			const uint8_t *p1 = mf_ptr(mf) - 1;
    +
    +			// Pointer to the beginning of the match. We need -1
    +			// here because the match distances are zero based.
    +			const uint8_t *p2 = p1 - matches[count - 1].dist - 1;
    +
    +			len_best = lzma_memcmplen(p1, p2, len_best, limit);
    +		}
    +	}
    +
    +	*count_ptr = count;
    +
    +	// Finally update the read position to indicate that match finder was
    +	// run for this dictionary offset.
    +	++mf->read_ahead;
    +
    +	return len_best;
    +}
    +
    +
    +/// Hash value to indicate unused element in the hash. Since we start the
    +/// positions from dict_size + 1, zero is always too far to qualify
    +/// as usable match position.
    +#define EMPTY_HASH_VALUE 0
    +
    +
    +/// Normalization must be done when lzma_mf.offset + lzma_mf.read_pos
    +/// reaches MUST_NORMALIZE_POS.
    +#define MUST_NORMALIZE_POS UINT32_MAX
    +
    +
    +/// \brief      Normalizes hash values
    +///
    +/// The hash arrays store positions of match candidates. The positions are
    +/// relative to an arbitrary offset that is not the same as the absolute
    +/// offset in the input stream. The relative position of the current byte
    +/// is lzma_mf.offset + lzma_mf.read_pos. The distances of the matches are
    +/// the differences of the current read position and the position found from
    +/// the hash.
    +///
    +/// To prevent integer overflows of the offsets stored in the hash arrays,
    +/// we need to "normalize" the stored values now and then. During the
    +/// normalization, we drop values that indicate distance greater than the
    +/// dictionary size, thus making space for new values.
    +static void
    +normalize(lzma_mf *mf)
    +{
    +	assert(mf->read_pos + mf->offset == MUST_NORMALIZE_POS);
    +
    +	// In future we may not want to touch the lowest bits, because there
    +	// may be match finders that use larger resolution than one byte.
    +	const uint32_t subvalue
    +			= (MUST_NORMALIZE_POS - mf->cyclic_size);
    +				// & ~((UINT32_C(1) << 10) - 1);
    +
    +	for (uint32_t i = 0; i < mf->hash_count; ++i) {
    +		// If the distance is greater than the dictionary size,
    +		// we can simply mark the hash element as empty.
    +		if (mf->hash[i] <= subvalue)
    +			mf->hash[i] = EMPTY_HASH_VALUE;
    +		else
    +			mf->hash[i] -= subvalue;
    +	}
    +
    +	for (uint32_t i = 0; i < mf->sons_count; ++i) {
    +		// Do the same for mf->son.
    +		//
    +		// NOTE: There may be uninitialized elements in mf->son.
    +		// Valgrind may complain that the "if" below depends on
    +		// an uninitialized value. In this case it is safe to ignore
    +		// the warning. See also the comments in lz_encoder_init()
    +		// in lz_encoder.c.
    +		if (mf->son[i] <= subvalue)
    +			mf->son[i] = EMPTY_HASH_VALUE;
    +		else
    +			mf->son[i] -= subvalue;
    +	}
    +
    +	// Update offset to match the new locations.
    +	mf->offset -= subvalue;
    +
    +	return;
    +}
    +
    +
    +/// Mark the current byte as processed from point of view of the match finder.
    +static void
    +move_pos(lzma_mf *mf)
    +{
    +	if (++mf->cyclic_pos == mf->cyclic_size)
    +		mf->cyclic_pos = 0;
    +
    +	++mf->read_pos;
    +	assert(mf->read_pos <= mf->write_pos);
    +
    +	if (unlikely(mf->read_pos + mf->offset == UINT32_MAX))
    +		normalize(mf);
    +}
    +
    +
    +/// When flushing, we cannot run the match finder unless there is nice_len
    +/// bytes available in the dictionary. Instead, we skip running the match
    +/// finder (indicating that no match was found), and count how many bytes we
    +/// have ignored this way.
    +///
    +/// When new data is given after the flushing was completed, the match finder
    +/// is restarted by rewinding mf->read_pos backwards by mf->pending. Then
    +/// the missed bytes are added to the hash using the match finder's skip
    +/// function (with small amount of input, it may start using mf->pending
    +/// again if flushing).
    +///
    +/// Due to this rewinding, we don't touch cyclic_pos or test for
    +/// normalization. It will be done when the match finder's skip function
    +/// catches up after a flush.
    +static void
    +move_pending(lzma_mf *mf)
    +{
    +	++mf->read_pos;
    +	assert(mf->read_pos <= mf->write_pos);
    +	++mf->pending;
    +}
    +
    +
    +/// Calculate len_limit and determine if there is enough input to run
    +/// the actual match finder code. Sets up "cur" and "pos". This macro
    +/// is used by all find functions and binary tree skip functions. Hash
    +/// chain skip function doesn't need len_limit so a simpler code is used
    +/// in them.
    +#define header(is_bt, len_min, ret_op) \
    +	uint32_t len_limit = mf_avail(mf); \
    +	if (mf->nice_len <= len_limit) { \
    +		len_limit = mf->nice_len; \
    +	} else if (len_limit < (len_min) \
    +			|| (is_bt && mf->action == LZMA_SYNC_FLUSH)) { \
    +		assert(mf->action != LZMA_RUN); \
    +		move_pending(mf); \
    +		ret_op; \
    +	} \
    +	const uint8_t *cur = mf_ptr(mf); \
    +	const uint32_t pos = mf->read_pos + mf->offset
    +
    +
    +/// Header for find functions. "return 0" indicates that zero matches
    +/// were found.
    +#define header_find(is_bt, len_min) \
    +	header(is_bt, len_min, return 0); \
    +	uint32_t matches_count = 0
    +
    +
    +/// Header for a loop in a skip function. "continue" tells to skip the rest
    +/// of the code in the loop.
    +#define header_skip(is_bt, len_min) \
    +	header(is_bt, len_min, continue)
    +
    +
    +/// Calls hc_find_func() or bt_find_func() and calculates the total number
    +/// of matches found. Updates the dictionary position and returns the number
    +/// of matches found.
    +#define call_find(func, len_best) \
    +do { \
    +	matches_count = (uint32_t)(func(len_limit, pos, cur, cur_match, \
    +				mf->depth, mf->son, \
    +				mf->cyclic_pos, mf->cyclic_size, \
    +				matches + matches_count, len_best) \
    +			- matches); \
    +	move_pos(mf); \
    +	return matches_count; \
    +} while (0)
    +
    +
    +////////////////
    +// Hash Chain //
    +////////////////
    +
    +#if defined(HAVE_MF_HC3) || defined(HAVE_MF_HC4)
    +///
    +///
    +/// \param      len_limit       Don't look for matches longer than len_limit.
    +/// \param      pos             lzma_mf.read_pos + lzma_mf.offset
    +/// \param      cur             Pointer to current byte (mf_ptr(mf))
    +/// \param      cur_match       Start position of the current match candidate
    +/// \param      depth           Maximum length of the hash chain
    +/// \param      son             lzma_mf.son (contains the hash chain)
    +/// \param      cyclic_pos      lzma_mf.cyclic_pos
    +/// \param      cyclic_size     lzma_mf_cyclic_size
    +/// \param      matches         Array to hold the matches.
    +/// \param      len_best        The length of the longest match found so far.
    +static lzma_match *
    +hc_find_func(
    +		const uint32_t len_limit,
    +		const uint32_t pos,
    +		const uint8_t *const cur,
    +		uint32_t cur_match,
    +		uint32_t depth,
    +		uint32_t *const son,
    +		const uint32_t cyclic_pos,
    +		const uint32_t cyclic_size,
    +		lzma_match *matches,
    +		uint32_t len_best)
    +{
    +	son[cyclic_pos] = cur_match;
    +
    +	while (true) {
    +		const uint32_t delta = pos - cur_match;
    +		if (depth-- == 0 || delta >= cyclic_size)
    +			return matches;
    +
    +		const uint8_t *const pb = cur - delta;
    +		cur_match = son[cyclic_pos - delta
    +				+ (delta > cyclic_pos ? cyclic_size : 0)];
    +
    +		if (pb[len_best] == cur[len_best] && pb[0] == cur[0]) {
    +			uint32_t len = lzma_memcmplen(pb, cur, 1, len_limit);
    +
    +			if (len_best < len) {
    +				len_best = len;
    +				matches->len = len;
    +				matches->dist = delta - 1;
    +				++matches;
    +
    +				if (len == len_limit)
    +					return matches;
    +			}
    +		}
    +	}
    +}
    +
    +
    +#define hc_find(len_best) \
    +	call_find(hc_find_func, len_best)
    +
    +
    +#define hc_skip() \
    +do { \
    +	mf->son[mf->cyclic_pos] = cur_match; \
    +	move_pos(mf); \
    +} while (0)
    +
    +#endif
    +
    +
    +#ifdef HAVE_MF_HC3
    +extern uint32_t
    +lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches)
    +{
    +	header_find(false, 3);
    +
    +	hash_3_calc();
    +
    +	const uint32_t delta2 = pos - mf->hash[hash_2_value];
    +	const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
    +
    +	mf->hash[hash_2_value] = pos;
    +	mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
    +
    +	uint32_t len_best = 2;
    +
    +	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
    +		len_best = lzma_memcmplen(cur - delta2, cur,
    +				len_best, len_limit);
    +
    +		matches[0].len = len_best;
    +		matches[0].dist = delta2 - 1;
    +		matches_count = 1;
    +
    +		if (len_best == len_limit) {
    +			hc_skip();
    +			return 1; // matches_count
    +		}
    +	}
    +
    +	hc_find(len_best);
    +}
    +
    +
    +extern void
    +lzma_mf_hc3_skip(lzma_mf *mf, uint32_t amount)
    +{
    +	do {
    +		if (mf_avail(mf) < 3) {
    +			move_pending(mf);
    +			continue;
    +		}
    +
    +		const uint8_t *cur = mf_ptr(mf);
    +		const uint32_t pos = mf->read_pos + mf->offset;
    +
    +		hash_3_calc();
    +
    +		const uint32_t cur_match
    +				= mf->hash[FIX_3_HASH_SIZE + hash_value];
    +
    +		mf->hash[hash_2_value] = pos;
    +		mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
    +
    +		hc_skip();
    +
    +	} while (--amount != 0);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_MF_HC4
    +extern uint32_t
    +lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches)
    +{
    +	header_find(false, 4);
    +
    +	hash_4_calc();
    +
    +	uint32_t delta2 = pos - mf->hash[hash_2_value];
    +	const uint32_t delta3
    +			= pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
    +	const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
    +
    +	mf->hash[hash_2_value ] = pos;
    +	mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
    +	mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
    +
    +	uint32_t len_best = 1;
    +
    +	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
    +		len_best = 2;
    +		matches[0].len = 2;
    +		matches[0].dist = delta2 - 1;
    +		matches_count = 1;
    +	}
    +
    +	if (delta2 != delta3 && delta3 < mf->cyclic_size
    +			&& *(cur - delta3) == *cur) {
    +		len_best = 3;
    +		matches[matches_count++].dist = delta3 - 1;
    +		delta2 = delta3;
    +	}
    +
    +	if (matches_count != 0) {
    +		len_best = lzma_memcmplen(cur - delta2, cur,
    +				len_best, len_limit);
    +
    +		matches[matches_count - 1].len = len_best;
    +
    +		if (len_best == len_limit) {
    +			hc_skip();
    +			return matches_count;
    +		}
    +	}
    +
    +	if (len_best < 3)
    +		len_best = 3;
    +
    +	hc_find(len_best);
    +}
    +
    +
    +extern void
    +lzma_mf_hc4_skip(lzma_mf *mf, uint32_t amount)
    +{
    +	do {
    +		if (mf_avail(mf) < 4) {
    +			move_pending(mf);
    +			continue;
    +		}
    +
    +		const uint8_t *cur = mf_ptr(mf);
    +		const uint32_t pos = mf->read_pos + mf->offset;
    +
    +		hash_4_calc();
    +
    +		const uint32_t cur_match
    +				= mf->hash[FIX_4_HASH_SIZE + hash_value];
    +
    +		mf->hash[hash_2_value] = pos;
    +		mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
    +		mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
    +
    +		hc_skip();
    +
    +	} while (--amount != 0);
    +}
    +#endif
    +
    +
    +/////////////////
    +// Binary Tree //
    +/////////////////
    +
    +#if defined(HAVE_MF_BT2) || defined(HAVE_MF_BT3) || defined(HAVE_MF_BT4)
    +static lzma_match *
    +bt_find_func(
    +		const uint32_t len_limit,
    +		const uint32_t pos,
    +		const uint8_t *const cur,
    +		uint32_t cur_match,
    +		uint32_t depth,
    +		uint32_t *const son,
    +		const uint32_t cyclic_pos,
    +		const uint32_t cyclic_size,
    +		lzma_match *matches,
    +		uint32_t len_best)
    +{
    +	uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
    +	uint32_t *ptr1 = son + (cyclic_pos << 1);
    +
    +	uint32_t len0 = 0;
    +	uint32_t len1 = 0;
    +
    +	while (true) {
    +		const uint32_t delta = pos - cur_match;
    +		if (depth-- == 0 || delta >= cyclic_size) {
    +			*ptr0 = EMPTY_HASH_VALUE;
    +			*ptr1 = EMPTY_HASH_VALUE;
    +			return matches;
    +		}
    +
    +		uint32_t *const pair = son + ((cyclic_pos - delta
    +				+ (delta > cyclic_pos ? cyclic_size : 0))
    +				<< 1);
    +
    +		const uint8_t *const pb = cur - delta;
    +		uint32_t len = my_min(len0, len1);
    +
    +		if (pb[len] == cur[len]) {
    +			len = lzma_memcmplen(pb, cur, len + 1, len_limit);
    +
    +			if (len_best < len) {
    +				len_best = len;
    +				matches->len = len;
    +				matches->dist = delta - 1;
    +				++matches;
    +
    +				if (len == len_limit) {
    +					*ptr1 = pair[0];
    +					*ptr0 = pair[1];
    +					return matches;
    +				}
    +			}
    +		}
    +
    +		if (pb[len] < cur[len]) {
    +			*ptr1 = cur_match;
    +			ptr1 = pair + 1;
    +			cur_match = *ptr1;
    +			len1 = len;
    +		} else {
    +			*ptr0 = cur_match;
    +			ptr0 = pair;
    +			cur_match = *ptr0;
    +			len0 = len;
    +		}
    +	}
    +}
    +
    +
    +static void
    +bt_skip_func(
    +		const uint32_t len_limit,
    +		const uint32_t pos,
    +		const uint8_t *const cur,
    +		uint32_t cur_match,
    +		uint32_t depth,
    +		uint32_t *const son,
    +		const uint32_t cyclic_pos,
    +		const uint32_t cyclic_size)
    +{
    +	uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
    +	uint32_t *ptr1 = son + (cyclic_pos << 1);
    +
    +	uint32_t len0 = 0;
    +	uint32_t len1 = 0;
    +
    +	while (true) {
    +		const uint32_t delta = pos - cur_match;
    +		if (depth-- == 0 || delta >= cyclic_size) {
    +			*ptr0 = EMPTY_HASH_VALUE;
    +			*ptr1 = EMPTY_HASH_VALUE;
    +			return;
    +		}
    +
    +		uint32_t *pair = son + ((cyclic_pos - delta
    +				+ (delta > cyclic_pos ? cyclic_size : 0))
    +				<< 1);
    +		const uint8_t *pb = cur - delta;
    +		uint32_t len = my_min(len0, len1);
    +
    +		if (pb[len] == cur[len]) {
    +			len = lzma_memcmplen(pb, cur, len + 1, len_limit);
    +
    +			if (len == len_limit) {
    +				*ptr1 = pair[0];
    +				*ptr0 = pair[1];
    +				return;
    +			}
    +		}
    +
    +		if (pb[len] < cur[len]) {
    +			*ptr1 = cur_match;
    +			ptr1 = pair + 1;
    +			cur_match = *ptr1;
    +			len1 = len;
    +		} else {
    +			*ptr0 = cur_match;
    +			ptr0 = pair;
    +			cur_match = *ptr0;
    +			len0 = len;
    +		}
    +	}
    +}
    +
    +
    +#define bt_find(len_best) \
    +	call_find(bt_find_func, len_best)
    +
    +#define bt_skip() \
    +do { \
    +	bt_skip_func(len_limit, pos, cur, cur_match, mf->depth, \
    +			mf->son, mf->cyclic_pos, \
    +			mf->cyclic_size); \
    +	move_pos(mf); \
    +} while (0)
    +
    +#endif
    +
    +
    +#ifdef HAVE_MF_BT2
    +extern uint32_t
    +lzma_mf_bt2_find(lzma_mf *mf, lzma_match *matches)
    +{
    +	header_find(true, 2);
    +
    +	hash_2_calc();
    +
    +	const uint32_t cur_match = mf->hash[hash_value];
    +	mf->hash[hash_value] = pos;
    +
    +	bt_find(1);
    +}
    +
    +
    +extern void
    +lzma_mf_bt2_skip(lzma_mf *mf, uint32_t amount)
    +{
    +	do {
    +		header_skip(true, 2);
    +
    +		hash_2_calc();
    +
    +		const uint32_t cur_match = mf->hash[hash_value];
    +		mf->hash[hash_value] = pos;
    +
    +		bt_skip();
    +
    +	} while (--amount != 0);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_MF_BT3
    +extern uint32_t
    +lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches)
    +{
    +	header_find(true, 3);
    +
    +	hash_3_calc();
    +
    +	const uint32_t delta2 = pos - mf->hash[hash_2_value];
    +	const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
    +
    +	mf->hash[hash_2_value] = pos;
    +	mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
    +
    +	uint32_t len_best = 2;
    +
    +	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
    +		len_best = lzma_memcmplen(
    +				cur, cur - delta2, len_best, len_limit);
    +
    +		matches[0].len = len_best;
    +		matches[0].dist = delta2 - 1;
    +		matches_count = 1;
    +
    +		if (len_best == len_limit) {
    +			bt_skip();
    +			return 1; // matches_count
    +		}
    +	}
    +
    +	bt_find(len_best);
    +}
    +
    +
    +extern void
    +lzma_mf_bt3_skip(lzma_mf *mf, uint32_t amount)
    +{
    +	do {
    +		header_skip(true, 3);
    +
    +		hash_3_calc();
    +
    +		const uint32_t cur_match
    +				= mf->hash[FIX_3_HASH_SIZE + hash_value];
    +
    +		mf->hash[hash_2_value] = pos;
    +		mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
    +
    +		bt_skip();
    +
    +	} while (--amount != 0);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_MF_BT4
    +extern uint32_t
    +lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches)
    +{
    +	header_find(true, 4);
    +
    +	hash_4_calc();
    +
    +	uint32_t delta2 = pos - mf->hash[hash_2_value];
    +	const uint32_t delta3
    +			= pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
    +	const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
    +
    +	mf->hash[hash_2_value] = pos;
    +	mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
    +	mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
    +
    +	uint32_t len_best = 1;
    +
    +	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
    +		len_best = 2;
    +		matches[0].len = 2;
    +		matches[0].dist = delta2 - 1;
    +		matches_count = 1;
    +	}
    +
    +	if (delta2 != delta3 && delta3 < mf->cyclic_size
    +			&& *(cur - delta3) == *cur) {
    +		len_best = 3;
    +		matches[matches_count++].dist = delta3 - 1;
    +		delta2 = delta3;
    +	}
    +
    +	if (matches_count != 0) {
    +		len_best = lzma_memcmplen(
    +				cur, cur - delta2, len_best, len_limit);
    +
    +		matches[matches_count - 1].len = len_best;
    +
    +		if (len_best == len_limit) {
    +			bt_skip();
    +			return matches_count;
    +		}
    +	}
    +
    +	if (len_best < 3)
    +		len_best = 3;
    +
    +	bt_find(len_best);
    +}
    +
    +
    +extern void
    +lzma_mf_bt4_skip(lzma_mf *mf, uint32_t amount)
    +{
    +	do {
    +		header_skip(true, 4);
    +
    +		hash_4_calc();
    +
    +		const uint32_t cur_match
    +				= mf->hash[FIX_4_HASH_SIZE + hash_value];
    +
    +		mf->hash[hash_2_value] = pos;
    +		mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
    +		mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
    +
    +		bt_skip();
    +
    +	} while (--amount != 0);
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos.h
    new file mode 100644
    index 00000000000..d3969a753fa
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos.h
    @@ -0,0 +1,141 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       fastpos.h
    +/// \brief      Kind of two-bit version of bit scan reverse
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_FASTPOS_H
    +#define LZMA_FASTPOS_H
    +
    +// LZMA encodes match distances by storing the highest two bits using
    +// a six-bit value [0, 63], and then the missing lower bits.
    +// Dictionary size is also stored using this encoding in the .xz
    +// file format header.
    +//
    +// fastpos.h provides a way to quickly find out the correct six-bit
    +// values. The following table gives some examples of this encoding:
    +//
    +//     dist   return
    +//       0       0
    +//       1       1
    +//       2       2
    +//       3       3
    +//       4       4
    +//       5       4
    +//       6       5
    +//       7       5
    +//       8       6
    +//      11       6
    +//      12       7
    +//     ...      ...
    +//      15       7
    +//      16       8
    +//      17       8
    +//     ...      ...
    +//      23       8
    +//      24       9
    +//      25       9
    +//     ...      ...
    +//
    +//
    +// Provided functions or macros
    +// ----------------------------
    +//
    +// get_dist_slot(dist) is the basic version. get_dist_slot_2(dist)
    +// assumes that dist >= FULL_DISTANCES, thus the result is at least
    +// FULL_DISTANCES_BITS * 2. Using get_dist_slot(dist) instead of
    +// get_dist_slot_2(dist) would give the same result, but get_dist_slot_2(dist)
    +// should be tiny bit faster due to the assumption being made.
    +//
    +//
    +// Size vs. speed
    +// --------------
    +//
    +// With some CPUs that have fast BSR (bit scan reverse) instruction, the
    +// size optimized version is slightly faster than the bigger table based
    +// approach. Such CPUs include Intel Pentium Pro, Pentium II, Pentium III
    +// and Core 2 (possibly others). AMD K7 seems to have slower BSR, but that
    +// would still have speed roughly comparable to the table version. Older
    +// x86 CPUs like the original Pentium have very slow BSR; on those systems
    +// the table version is a lot faster.
    +//
    +// On some CPUs, the table version is a lot faster when using position
    +// dependent code, but with position independent code the size optimized
    +// version is slightly faster. This occurs at least on 32-bit SPARC (no
    +// ASM optimizations).
    +//
    +// I'm making the table version the default, because that has good speed
    +// on all systems I have tried. The size optimized version is sometimes
    +// slightly faster, but sometimes it is a lot slower.
    +
    +#ifdef HAVE_SMALL
    +#	define get_dist_slot(dist) \
    +		((dist) <= 4 ? (dist) : get_dist_slot_2(dist))
    +
    +static inline uint32_t
    +get_dist_slot_2(uint32_t dist)
    +{
    +	const uint32_t i = bsr32(dist);
    +	return (i + i) + ((dist >> (i - 1)) & 1);
    +}
    +
    +
    +#else
    +
    +#define FASTPOS_BITS 13
    +
    +lzma_attr_visibility_hidden
    +extern const uint8_t lzma_fastpos[1 << FASTPOS_BITS];
    +
    +
    +#define fastpos_shift(extra, n) \
    +	((extra) + (n) * (FASTPOS_BITS - 1))
    +
    +#define fastpos_limit(extra, n) \
    +	(UINT32_C(1) << (FASTPOS_BITS + fastpos_shift(extra, n)))
    +
    +#define fastpos_result(dist, extra, n) \
    +	(uint32_t)(lzma_fastpos[(dist) >> fastpos_shift(extra, n)]) \
    +			+ 2 * fastpos_shift(extra, n)
    +
    +
    +static inline uint32_t
    +get_dist_slot(uint32_t dist)
    +{
    +	// If it is small enough, we can pick the result directly from
    +	// the precalculated table.
    +	if (dist < fastpos_limit(0, 0))
    +		return lzma_fastpos[dist];
    +
    +	if (dist < fastpos_limit(0, 1))
    +		return fastpos_result(dist, 0, 1);
    +
    +	return fastpos_result(dist, 0, 2);
    +}
    +
    +
    +#ifdef FULL_DISTANCES_BITS
    +static inline uint32_t
    +get_dist_slot_2(uint32_t dist)
    +{
    +	assert(dist >= FULL_DISTANCES);
    +
    +	if (dist < fastpos_limit(FULL_DISTANCES_BITS - 1, 0))
    +		return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 0);
    +
    +	if (dist < fastpos_limit(FULL_DISTANCES_BITS - 1, 1))
    +		return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 1);
    +
    +	return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 2);
    +}
    +#endif
    +
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_table.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_table.c
    new file mode 100644
    index 00000000000..4e10e3795e2
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_table.c
    @@ -0,0 +1,521 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +// This file has been generated by fastpos_tablegen.c.
    +
    +#include "common.h"
    +#include "fastpos.h"
    +
    +const uint8_t lzma_fastpos[1 << FASTPOS_BITS] = {
    +	  0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,
    +	  8,  8,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9,
    +	 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
    +	 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
    +	 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
    +	 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
    +	 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
    +	 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
    +	 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
    +	 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
    +	 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
    +	 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
    +	 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
    +	 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
    +	 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
    +	 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
    +	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    +	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    +	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    +	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    +	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    +	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    +	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    +	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    +	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    +	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    +	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    +	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    +	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    +	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    +	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    +	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
    +	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25
    +};
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_tablegen.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_tablegen.c
    new file mode 100644
    index 00000000000..957ccb7a643
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_tablegen.c
    @@ -0,0 +1,58 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       fastpos_tablegen.c
    +/// \brief      Generates the lzma_fastpos[] lookup table
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include 
    +#include 
    +
    +#define lzma_attr_visibility_hidden
    +#include "fastpos.h"
    +
    +
    +int
    +main(void)
    +{
    +	uint8_t fastpos[1 << FASTPOS_BITS];
    +
    +	const uint8_t fast_slots = 2 * FASTPOS_BITS;
    +	uint32_t c = 2;
    +
    +	fastpos[0] = 0;
    +	fastpos[1] = 1;
    +
    +	for (uint8_t slot_fast = 2; slot_fast < fast_slots; ++slot_fast) {
    +		const uint32_t k = 1 << ((slot_fast >> 1) - 1);
    +		for (uint32_t j = 0; j < k; ++j, ++c)
    +			fastpos[c] = slot_fast;
    +	}
    +
    +	// Split the SPDX string so that it won't accidentally match
    +	// when tools search for the string.
    +	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
    +		"// This file has been generated by fastpos_tablegen.c.\n\n"
    +		"#include \"common.h\"\n"
    +		"#include \"fastpos.h\"\n\n"
    +		"const uint8_t lzma_fastpos[1 << FASTPOS_BITS] = {");
    +
    +	for (size_t i = 0; i < (1 << FASTPOS_BITS); ++i) {
    +		if (i % 16 == 0)
    +			printf("\n\t");
    +
    +		printf("%3u", (unsigned int)(fastpos[i]));
    +
    +		if (i != (1 << FASTPOS_BITS) - 1)
    +			printf(",");
    +	}
    +
    +	printf("\n};\n");
    +
    +	return 0;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.c
    new file mode 100644
    index 00000000000..37ab253f5b0
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.c
    @@ -0,0 +1,310 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma2_decoder.c
    +/// \brief      LZMA2 decoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lzma2_decoder.h"
    +#include "lz_decoder.h"
    +#include "lzma_decoder.h"
    +
    +
    +typedef struct {
    +	enum sequence {
    +		SEQ_CONTROL,
    +		SEQ_UNCOMPRESSED_1,
    +		SEQ_UNCOMPRESSED_2,
    +		SEQ_COMPRESSED_0,
    +		SEQ_COMPRESSED_1,
    +		SEQ_PROPERTIES,
    +		SEQ_LZMA,
    +		SEQ_COPY,
    +	} sequence;
    +
    +	/// Sequence after the size fields have been decoded.
    +	enum sequence next_sequence;
    +
    +	/// LZMA decoder
    +	lzma_lz_decoder lzma;
    +
    +	/// Uncompressed size of LZMA chunk
    +	size_t uncompressed_size;
    +
    +	/// Compressed size of the chunk (naturally equals to uncompressed
    +	/// size of uncompressed chunk)
    +	size_t compressed_size;
    +
    +	/// True if properties are needed. This is false before the
    +	/// first LZMA chunk.
    +	bool need_properties;
    +
    +	/// True if dictionary reset is needed. This is false before the
    +	/// first chunk (LZMA or uncompressed).
    +	bool need_dictionary_reset;
    +
    +	lzma_options_lzma options;
    +} lzma_lzma2_coder;
    +
    +
    +static lzma_ret
    +lzma2_decode(void *coder_ptr, lzma_dict *restrict dict,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size)
    +{
    +	lzma_lzma2_coder *restrict coder = coder_ptr;
    +
    +	// With SEQ_LZMA it is possible that no new input is needed to do
    +	// some progress. The rest of the sequences assume that there is
    +	// at least one byte of input.
    +	while (*in_pos < in_size || coder->sequence == SEQ_LZMA)
    +	switch (coder->sequence) {
    +	case SEQ_CONTROL: {
    +		const uint32_t control = in[*in_pos];
    +		++*in_pos;
    +
    +		// End marker
    +		if (control == 0x00)
    +			return LZMA_STREAM_END;
    +
    +		if (control >= 0xE0 || control == 1) {
    +			// Dictionary reset implies that next LZMA chunk has
    +			// to set new properties.
    +			coder->need_properties = true;
    +			coder->need_dictionary_reset = true;
    +		} else if (coder->need_dictionary_reset) {
    +			return LZMA_DATA_ERROR;
    +		}
    +
    +		if (control >= 0x80) {
    +			// LZMA chunk. The highest five bits of the
    +			// uncompressed size are taken from the control byte.
    +			coder->uncompressed_size = (control & 0x1F) << 16;
    +			coder->sequence = SEQ_UNCOMPRESSED_1;
    +
    +			// See if there are new properties or if we need to
    +			// reset the state.
    +			if (control >= 0xC0) {
    +				// When there are new properties, state reset
    +				// is done at SEQ_PROPERTIES.
    +				coder->need_properties = false;
    +				coder->next_sequence = SEQ_PROPERTIES;
    +
    +			} else if (coder->need_properties) {
    +				return LZMA_DATA_ERROR;
    +
    +			} else {
    +				coder->next_sequence = SEQ_LZMA;
    +
    +				// If only state reset is wanted with old
    +				// properties, do the resetting here for
    +				// simplicity.
    +				if (control >= 0xA0)
    +					coder->lzma.reset(coder->lzma.coder,
    +							&coder->options);
    +			}
    +		} else {
    +			// Invalid control values
    +			if (control > 2)
    +				return LZMA_DATA_ERROR;
    +
    +			// It's uncompressed chunk
    +			coder->sequence = SEQ_COMPRESSED_0;
    +			coder->next_sequence = SEQ_COPY;
    +		}
    +
    +		if (coder->need_dictionary_reset) {
    +			// Finish the dictionary reset and let the caller
    +			// flush the dictionary to the actual output buffer.
    +			coder->need_dictionary_reset = false;
    +			dict_reset(dict);
    +			return LZMA_OK;
    +		}
    +
    +		break;
    +	}
    +
    +	case SEQ_UNCOMPRESSED_1:
    +		coder->uncompressed_size += (uint32_t)(in[(*in_pos)++]) << 8;
    +		coder->sequence = SEQ_UNCOMPRESSED_2;
    +		break;
    +
    +	case SEQ_UNCOMPRESSED_2:
    +		coder->uncompressed_size += in[(*in_pos)++] + 1U;
    +		coder->sequence = SEQ_COMPRESSED_0;
    +		coder->lzma.set_uncompressed(coder->lzma.coder,
    +				coder->uncompressed_size, false);
    +		break;
    +
    +	case SEQ_COMPRESSED_0:
    +		coder->compressed_size = (uint32_t)(in[(*in_pos)++]) << 8;
    +		coder->sequence = SEQ_COMPRESSED_1;
    +		break;
    +
    +	case SEQ_COMPRESSED_1:
    +		coder->compressed_size += in[(*in_pos)++] + 1U;
    +		coder->sequence = coder->next_sequence;
    +		break;
    +
    +	case SEQ_PROPERTIES:
    +		if (lzma_lzma_lclppb_decode(&coder->options, in[(*in_pos)++]))
    +			return LZMA_DATA_ERROR;
    +
    +		coder->lzma.reset(coder->lzma.coder, &coder->options);
    +
    +		coder->sequence = SEQ_LZMA;
    +		break;
    +
    +	case SEQ_LZMA: {
    +		// Store the start offset so that we can update
    +		// coder->compressed_size later.
    +		const size_t in_start = *in_pos;
    +
    +		// Decode from in[] to *dict.
    +		const lzma_ret ret = coder->lzma.code(coder->lzma.coder,
    +				dict, in, in_pos, in_size);
    +
    +		// Validate and update coder->compressed_size.
    +		const size_t in_used = *in_pos - in_start;
    +		if (in_used > coder->compressed_size)
    +			return LZMA_DATA_ERROR;
    +
    +		coder->compressed_size -= in_used;
    +
    +		// Return if we didn't finish the chunk, or an error occurred.
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +
    +		// The LZMA decoder must have consumed the whole chunk now.
    +		// We don't need to worry about uncompressed size since it
    +		// is checked by the LZMA decoder.
    +		if (coder->compressed_size != 0)
    +			return LZMA_DATA_ERROR;
    +
    +		coder->sequence = SEQ_CONTROL;
    +		break;
    +	}
    +
    +	case SEQ_COPY: {
    +		// Copy from input to the dictionary as is.
    +		dict_write(dict, in, in_pos, in_size, &coder->compressed_size);
    +		if (coder->compressed_size != 0)
    +			return LZMA_OK;
    +
    +		coder->sequence = SEQ_CONTROL;
    +		break;
    +	}
    +
    +	default:
    +		assert(0);
    +		return LZMA_PROG_ERROR;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +lzma2_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_lzma2_coder *coder = coder_ptr;
    +
    +	assert(coder->lzma.end == NULL);
    +	lzma_free(coder->lzma.coder, allocator);
    +
    +	lzma_free(coder, allocator);
    +
    +	return;
    +}
    +
    +
    +static lzma_ret
    +lzma2_decoder_init(lzma_lz_decoder *lz, const lzma_allocator *allocator,
    +		lzma_vli id lzma_attribute((__unused__)), const void *opt,
    +		lzma_lz_options *lz_options)
    +{
    +	lzma_lzma2_coder *coder = lz->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_lzma2_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		lz->coder = coder;
    +		lz->code = &lzma2_decode;
    +		lz->end = &lzma2_decoder_end;
    +
    +		coder->lzma = LZMA_LZ_DECODER_INIT;
    +	}
    +
    +	const lzma_options_lzma *options = opt;
    +
    +	coder->sequence = SEQ_CONTROL;
    +	coder->need_properties = true;
    +	coder->need_dictionary_reset = options->preset_dict == NULL
    +			|| options->preset_dict_size == 0;
    +
    +	return lzma_lzma_decoder_create(&coder->lzma,
    +			allocator, options, lz_options);
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma2_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	// LZMA2 can only be the last filter in the chain. This is enforced
    +	// by the raw_decoder initialization.
    +	assert(filters[1].init == NULL);
    +
    +	return lzma_lz_decoder_init(next, allocator, filters,
    +			&lzma2_decoder_init);
    +}
    +
    +
    +extern uint64_t
    +lzma_lzma2_decoder_memusage(const void *options)
    +{
    +	return sizeof(lzma_lzma2_coder)
    +			+ lzma_lzma_decoder_memusage_nocheck(options);
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma2_props_decode(void **options, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size)
    +{
    +	if (props_size != 1)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Check that reserved bits are unset.
    +	if (props[0] & 0xC0)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Decode the dictionary size.
    +	if (props[0] > 40)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	lzma_options_lzma *opt = lzma_alloc(
    +			sizeof(lzma_options_lzma), allocator);
    +	if (opt == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	if (props[0] == 40) {
    +		opt->dict_size = UINT32_MAX;
    +	} else {
    +		opt->dict_size = 2 | (props[0] & 1U);
    +		opt->dict_size <<= props[0] / 2U + 11;
    +	}
    +
    +	opt->preset_dict = NULL;
    +	opt->preset_dict_size = 0;
    +
    +	*options = opt;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.h
    new file mode 100644
    index 00000000000..cdd8b463abf
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.h
    @@ -0,0 +1,28 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma2_decoder.h
    +/// \brief      LZMA2 decoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZMA2_DECODER_H
    +#define LZMA_LZMA2_DECODER_H
    +
    +#include "common.h"
    +
    +extern lzma_ret lzma_lzma2_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern uint64_t lzma_lzma2_decoder_memusage(const void *options);
    +
    +extern lzma_ret lzma_lzma2_props_decode(
    +		void **options, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.c
    new file mode 100644
    index 00000000000..e20b75b3003
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.c
    @@ -0,0 +1,416 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma2_encoder.c
    +/// \brief      LZMA2 encoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lz_encoder.h"
    +#include "lzma_encoder.h"
    +#include "fastpos.h"
    +#include "lzma2_encoder.h"
    +
    +
    +typedef struct {
    +	enum {
    +		SEQ_INIT,
    +		SEQ_LZMA_ENCODE,
    +		SEQ_LZMA_COPY,
    +		SEQ_UNCOMPRESSED_HEADER,
    +		SEQ_UNCOMPRESSED_COPY,
    +	} sequence;
    +
    +	/// LZMA encoder
    +	void *lzma;
    +
    +	/// LZMA options currently in use.
    +	lzma_options_lzma opt_cur;
    +
    +	bool need_properties;
    +	bool need_state_reset;
    +	bool need_dictionary_reset;
    +
    +	/// Uncompressed size of a chunk
    +	size_t uncompressed_size;
    +
    +	/// Compressed size of a chunk (excluding headers); this is also used
    +	/// to indicate the end of buf[] in SEQ_LZMA_COPY.
    +	size_t compressed_size;
    +
    +	/// Read position in buf[]
    +	size_t buf_pos;
    +
    +	/// Buffer to hold the chunk header and LZMA compressed data
    +	uint8_t buf[LZMA2_HEADER_MAX + LZMA2_CHUNK_MAX];
    +} lzma_lzma2_coder;
    +
    +
    +static void
    +lzma2_header_lzma(lzma_lzma2_coder *coder)
    +{
    +	assert(coder->uncompressed_size > 0);
    +	assert(coder->uncompressed_size <= LZMA2_UNCOMPRESSED_MAX);
    +	assert(coder->compressed_size > 0);
    +	assert(coder->compressed_size <= LZMA2_CHUNK_MAX);
    +
    +	size_t pos;
    +
    +	if (coder->need_properties) {
    +		pos = 0;
    +
    +		if (coder->need_dictionary_reset)
    +			coder->buf[pos] = 0x80 + (3 << 5);
    +		else
    +			coder->buf[pos] = 0x80 + (2 << 5);
    +	} else {
    +		pos = 1;
    +
    +		if (coder->need_state_reset)
    +			coder->buf[pos] = 0x80 + (1 << 5);
    +		else
    +			coder->buf[pos] = 0x80;
    +	}
    +
    +	// Set the start position for copying.
    +	coder->buf_pos = pos;
    +
    +	// Uncompressed size
    +	size_t size = coder->uncompressed_size - 1;
    +	coder->buf[pos++] += size >> 16;
    +	coder->buf[pos++] = (size >> 8) & 0xFF;
    +	coder->buf[pos++] = size & 0xFF;
    +
    +	// Compressed size
    +	size = coder->compressed_size - 1;
    +	coder->buf[pos++] = size >> 8;
    +	coder->buf[pos++] = size & 0xFF;
    +
    +	// Properties, if needed
    +	if (coder->need_properties)
    +		lzma_lzma_lclppb_encode(&coder->opt_cur, coder->buf + pos);
    +
    +	coder->need_properties = false;
    +	coder->need_state_reset = false;
    +	coder->need_dictionary_reset = false;
    +
    +	// The copying code uses coder->compressed_size to indicate the end
    +	// of coder->buf[], so we need add the maximum size of the header here.
    +	coder->compressed_size += LZMA2_HEADER_MAX;
    +
    +	return;
    +}
    +
    +
    +static void
    +lzma2_header_uncompressed(lzma_lzma2_coder *coder)
    +{
    +	assert(coder->uncompressed_size > 0);
    +	assert(coder->uncompressed_size <= LZMA2_CHUNK_MAX);
    +
    +	// If this is the first chunk, we need to include dictionary
    +	// reset indicator.
    +	if (coder->need_dictionary_reset)
    +		coder->buf[0] = 1;
    +	else
    +		coder->buf[0] = 2;
    +
    +	coder->need_dictionary_reset = false;
    +
    +	// "Compressed" size
    +	coder->buf[1] = (coder->uncompressed_size - 1) >> 8;
    +	coder->buf[2] = (coder->uncompressed_size - 1) & 0xFF;
    +
    +	// Set the start position for copying.
    +	coder->buf_pos = 0;
    +	return;
    +}
    +
    +
    +static lzma_ret
    +lzma2_encode(void *coder_ptr, lzma_mf *restrict mf,
    +		uint8_t *restrict out, size_t *restrict out_pos,
    +		size_t out_size)
    +{
    +	lzma_lzma2_coder *restrict coder = coder_ptr;
    +
    +	while (*out_pos < out_size)
    +	switch (coder->sequence) {
    +	case SEQ_INIT:
    +		// If there's no input left and we are flushing or finishing,
    +		// don't start a new chunk.
    +		if (mf_unencoded(mf) == 0) {
    +			// Write end of payload marker if finishing.
    +			if (mf->action == LZMA_FINISH)
    +				out[(*out_pos)++] = 0;
    +
    +			return mf->action == LZMA_RUN
    +					? LZMA_OK : LZMA_STREAM_END;
    +		}
    +
    +		if (coder->need_state_reset)
    +			return_if_error(lzma_lzma_encoder_reset(
    +					coder->lzma, &coder->opt_cur));
    +
    +		coder->uncompressed_size = 0;
    +		coder->compressed_size = 0;
    +		coder->sequence = SEQ_LZMA_ENCODE;
    +
    +	// Fall through
    +
    +	case SEQ_LZMA_ENCODE: {
    +		// Calculate how much more uncompressed data this chunk
    +		// could accept.
    +		const uint32_t left = LZMA2_UNCOMPRESSED_MAX
    +				- coder->uncompressed_size;
    +		uint32_t limit;
    +
    +		if (left < mf->match_len_max) {
    +			// Must flush immediately since the next LZMA symbol
    +			// could make the uncompressed size of the chunk too
    +			// big.
    +			limit = 0;
    +		} else {
    +			// Calculate maximum read_limit that is OK from point
    +			// of view of LZMA2 chunk size.
    +			limit = mf->read_pos - mf->read_ahead
    +					+ left - mf->match_len_max;
    +		}
    +
    +		// Save the start position so that we can update
    +		// coder->uncompressed_size.
    +		const uint32_t read_start = mf->read_pos - mf->read_ahead;
    +
    +		// Call the LZMA encoder until the chunk is finished.
    +		const lzma_ret ret = lzma_lzma_encode(coder->lzma, mf,
    +				coder->buf + LZMA2_HEADER_MAX,
    +				&coder->compressed_size,
    +				LZMA2_CHUNK_MAX, limit);
    +
    +		coder->uncompressed_size += mf->read_pos - mf->read_ahead
    +				- read_start;
    +
    +		assert(coder->compressed_size <= LZMA2_CHUNK_MAX);
    +		assert(coder->uncompressed_size <= LZMA2_UNCOMPRESSED_MAX);
    +
    +		if (ret != LZMA_STREAM_END)
    +			return LZMA_OK;
    +
    +		// See if the chunk compressed. If it didn't, we encode it
    +		// as uncompressed chunk. This saves a few bytes of space
    +		// and makes decoding faster.
    +		if (coder->compressed_size >= coder->uncompressed_size) {
    +			coder->uncompressed_size += mf->read_ahead;
    +			assert(coder->uncompressed_size
    +					<= LZMA2_UNCOMPRESSED_MAX);
    +			mf->read_ahead = 0;
    +			lzma2_header_uncompressed(coder);
    +			coder->need_state_reset = true;
    +			coder->sequence = SEQ_UNCOMPRESSED_HEADER;
    +			break;
    +		}
    +
    +		// The chunk did compress at least by one byte, so we store
    +		// the chunk as LZMA.
    +		lzma2_header_lzma(coder);
    +
    +		coder->sequence = SEQ_LZMA_COPY;
    +	}
    +
    +	// Fall through
    +
    +	case SEQ_LZMA_COPY:
    +		// Copy the compressed chunk along its headers to the
    +		// output buffer.
    +		lzma_bufcpy(coder->buf, &coder->buf_pos,
    +				coder->compressed_size,
    +				out, out_pos, out_size);
    +		if (coder->buf_pos != coder->compressed_size)
    +			return LZMA_OK;
    +
    +		coder->sequence = SEQ_INIT;
    +		break;
    +
    +	case SEQ_UNCOMPRESSED_HEADER:
    +		// Copy the three-byte header to indicate uncompressed chunk.
    +		lzma_bufcpy(coder->buf, &coder->buf_pos,
    +				LZMA2_HEADER_UNCOMPRESSED,
    +				out, out_pos, out_size);
    +		if (coder->buf_pos != LZMA2_HEADER_UNCOMPRESSED)
    +			return LZMA_OK;
    +
    +		coder->sequence = SEQ_UNCOMPRESSED_COPY;
    +
    +	// Fall through
    +
    +	case SEQ_UNCOMPRESSED_COPY:
    +		// Copy the uncompressed data as is from the dictionary
    +		// to the output buffer.
    +		mf_read(mf, out, out_pos, out_size, &coder->uncompressed_size);
    +		if (coder->uncompressed_size != 0)
    +			return LZMA_OK;
    +
    +		coder->sequence = SEQ_INIT;
    +		break;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +lzma2_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_lzma2_coder *coder = coder_ptr;
    +	lzma_free(coder->lzma, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +lzma2_encoder_options_update(void *coder_ptr, const lzma_filter *filter)
    +{
    +	lzma_lzma2_coder *coder = coder_ptr;
    +
    +	// New options can be set only when there is no incomplete chunk.
    +	// This is the case at the beginning of the raw stream and right
    +	// after LZMA_SYNC_FLUSH.
    +	if (filter->options == NULL || coder->sequence != SEQ_INIT)
    +		return LZMA_PROG_ERROR;
    +
    +	// Look if there are new options. At least for now,
    +	// only lc/lp/pb can be changed.
    +	const lzma_options_lzma *opt = filter->options;
    +	if (coder->opt_cur.lc != opt->lc || coder->opt_cur.lp != opt->lp
    +			|| coder->opt_cur.pb != opt->pb) {
    +		// Validate the options.
    +		if (opt->lc > LZMA_LCLP_MAX || opt->lp > LZMA_LCLP_MAX
    +				|| opt->lc + opt->lp > LZMA_LCLP_MAX
    +				|| opt->pb > LZMA_PB_MAX)
    +			return LZMA_OPTIONS_ERROR;
    +
    +		// The new options will be used when the encoder starts
    +		// a new LZMA2 chunk.
    +		coder->opt_cur.lc = opt->lc;
    +		coder->opt_cur.lp = opt->lp;
    +		coder->opt_cur.pb = opt->pb;
    +		coder->need_properties = true;
    +		coder->need_state_reset = true;
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static lzma_ret
    +lzma2_encoder_init(lzma_lz_encoder *lz, const lzma_allocator *allocator,
    +		lzma_vli id lzma_attribute((__unused__)), const void *options,
    +		lzma_lz_options *lz_options)
    +{
    +	if (options == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	lzma_lzma2_coder *coder = lz->coder;
    +	if (coder == NULL) {
    +		coder = lzma_alloc(sizeof(lzma_lzma2_coder), allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		lz->coder = coder;
    +		lz->code = &lzma2_encode;
    +		lz->end = &lzma2_encoder_end;
    +		lz->options_update = &lzma2_encoder_options_update;
    +
    +		coder->lzma = NULL;
    +	}
    +
    +	coder->opt_cur = *(const lzma_options_lzma *)(options);
    +
    +	coder->sequence = SEQ_INIT;
    +	coder->need_properties = true;
    +	coder->need_state_reset = false;
    +	coder->need_dictionary_reset
    +			= coder->opt_cur.preset_dict == NULL
    +			|| coder->opt_cur.preset_dict_size == 0;
    +
    +	// Initialize LZMA encoder
    +	return_if_error(lzma_lzma_encoder_create(&coder->lzma, allocator,
    +			LZMA_FILTER_LZMA2, &coder->opt_cur, lz_options));
    +
    +	// Make sure that we will always have enough history available in
    +	// case we need to use uncompressed chunks. They are used when the
    +	// compressed size of a chunk is not smaller than the uncompressed
    +	// size, so we need to have at least LZMA2_COMPRESSED_MAX bytes
    +	// history available.
    +	if (lz_options->before_size + lz_options->dict_size < LZMA2_CHUNK_MAX)
    +		lz_options->before_size
    +				= LZMA2_CHUNK_MAX - lz_options->dict_size;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma2_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return lzma_lz_encoder_init(
    +			next, allocator, filters, &lzma2_encoder_init);
    +}
    +
    +
    +extern uint64_t
    +lzma_lzma2_encoder_memusage(const void *options)
    +{
    +	const uint64_t lzma_mem = lzma_lzma_encoder_memusage(options);
    +	if (lzma_mem == UINT64_MAX)
    +		return UINT64_MAX;
    +
    +	return sizeof(lzma_lzma2_coder) + lzma_mem;
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma2_props_encode(const void *options, uint8_t *out)
    +{
    +	if (options == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	const lzma_options_lzma *const opt = options;
    +	uint32_t d = my_max(opt->dict_size, LZMA_DICT_SIZE_MIN);
    +
    +	// Round up to the next 2^n - 1 or 2^n + 2^(n - 1) - 1 depending
    +	// on which one is the next:
    +	--d;
    +	d |= d >> 2;
    +	d |= d >> 3;
    +	d |= d >> 4;
    +	d |= d >> 8;
    +	d |= d >> 16;
    +
    +	// Get the highest two bits using the proper encoding:
    +	if (d == UINT32_MAX)
    +		out[0] = 40;
    +	else
    +		out[0] = get_dist_slot(d + 1) - 24;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern uint64_t
    +lzma_lzma2_block_size(const void *options)
    +{
    +	const lzma_options_lzma *const opt = options;
    +
    +	if (!IS_ENC_DICT_SIZE_VALID(opt->dict_size))
    +		return UINT64_MAX;
    +
    +	// Use at least 1 MiB to keep compression ratio better.
    +	return my_max((uint64_t)(opt->dict_size) * 3, UINT64_C(1) << 20);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.h
    new file mode 100644
    index 00000000000..29966a66d23
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.h
    @@ -0,0 +1,42 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma2_encoder.h
    +/// \brief      LZMA2 encoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZMA2_ENCODER_H
    +#define LZMA_LZMA2_ENCODER_H
    +
    +#include "common.h"
    +
    +
    +/// Maximum number of bytes of actual data per chunk (no headers)
    +#define LZMA2_CHUNK_MAX (UINT32_C(1) << 16)
    +
    +/// Maximum uncompressed size of LZMA chunk (no headers)
    +#define LZMA2_UNCOMPRESSED_MAX (UINT32_C(1) << 21)
    +
    +/// Maximum size of LZMA2 headers
    +#define LZMA2_HEADER_MAX 6
    +
    +/// Size of a header for uncompressed chunk
    +#define LZMA2_HEADER_UNCOMPRESSED 3
    +
    +
    +extern lzma_ret lzma_lzma2_encoder_init(
    +		lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern uint64_t lzma_lzma2_encoder_memusage(const void *options);
    +
    +extern lzma_ret lzma_lzma2_props_encode(const void *options, uint8_t *out);
    +
    +extern uint64_t lzma_lzma2_block_size(const void *options);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_common.h
    new file mode 100644
    index 00000000000..c3c587f090e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_common.h
    @@ -0,0 +1,240 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma_common.h
    +/// \brief      Private definitions common to LZMA encoder and decoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZMA_COMMON_H
    +#define LZMA_LZMA_COMMON_H
    +
    +#include "common.h"
    +#include "range_common.h"
    +
    +
    +///////////////////
    +// Miscellaneous //
    +///////////////////
    +
    +/// Maximum number of position states. A position state is the lowest pos bits
    +/// number of bits of the current uncompressed offset. In some places there
    +/// are different sets of probabilities for different pos states.
    +#define POS_STATES_MAX (1 << LZMA_PB_MAX)
    +
    +
    +/// Validates lc, lp, and pb.
    +static inline bool
    +is_lclppb_valid(const lzma_options_lzma *options)
    +{
    +	return options->lc <= LZMA_LCLP_MAX && options->lp <= LZMA_LCLP_MAX
    +			&& options->lc + options->lp <= LZMA_LCLP_MAX
    +			&& options->pb <= LZMA_PB_MAX;
    +}
    +
    +
    +///////////
    +// State //
    +///////////
    +
    +/// This enum is used to track which events have occurred most recently and
    +/// in which order. This information is used to predict the next event.
    +///
    +/// Events:
    +///  - Literal: One 8-bit byte
    +///  - Match: Repeat a chunk of data at some distance
    +///  - Long repeat: Multi-byte match at a recently seen distance
    +///  - Short repeat: One-byte repeat at a recently seen distance
    +///
    +/// The event names are in from STATE_oldest_older_previous. REP means
    +/// either short or long repeated match, and NONLIT means any non-literal.
    +typedef enum {
    +	STATE_LIT_LIT,
    +	STATE_MATCH_LIT_LIT,
    +	STATE_REP_LIT_LIT,
    +	STATE_SHORTREP_LIT_LIT,
    +	STATE_MATCH_LIT,
    +	STATE_REP_LIT,
    +	STATE_SHORTREP_LIT,
    +	STATE_LIT_MATCH,
    +	STATE_LIT_LONGREP,
    +	STATE_LIT_SHORTREP,
    +	STATE_NONLIT_MATCH,
    +	STATE_NONLIT_REP,
    +} lzma_lzma_state;
    +
    +
    +/// Total number of states
    +#define STATES 12
    +
    +/// The lowest 7 states indicate that the previous state was a literal.
    +#define LIT_STATES 7
    +
    +
    +/// Indicate that the latest state was a literal.
    +#define update_literal(state) \
    +	state = ((state) <= STATE_SHORTREP_LIT_LIT \
    +			? STATE_LIT_LIT \
    +			: ((state) <= STATE_LIT_SHORTREP \
    +				? (state) - 3 \
    +				: (state) - 6))
    +
    +/// Like update_literal(state) but when it is already known that
    +/// is_literal_state(state) is true.
    +#define update_literal_normal(state) \
    +	state = ((state) <= STATE_SHORTREP_LIT_LIT \
    +			? STATE_LIT_LIT \
    +			: (state) - 3);
    +
    +/// Like update_literal(state) but when it is already known that
    +/// is_literal_state(state) is false.
    +#define update_literal_matched(state) \
    +	state = ((state) <= STATE_LIT_SHORTREP \
    +			? (state) - 3 \
    +			: (state) - 6);
    +
    +/// Indicate that the latest state was a match.
    +#define update_match(state) \
    +	state = ((state) < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH)
    +
    +/// Indicate that the latest state was a long repeated match.
    +#define update_long_rep(state) \
    +	state = ((state) < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP)
    +
    +/// Indicate that the latest state was a short match.
    +#define update_short_rep(state) \
    +	state = ((state) < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP)
    +
    +/// Test if the previous state was a literal.
    +#define is_literal_state(state) \
    +	((state) < LIT_STATES)
    +
    +
    +/////////////
    +// Literal //
    +/////////////
    +
    +/// Each literal coder is divided in three sections:
    +///   - 0x001-0x0FF: Without match byte
    +///   - 0x101-0x1FF: With match byte; match bit is 0
    +///   - 0x201-0x2FF: With match byte; match bit is 1
    +///
    +/// Match byte is used when the previous LZMA symbol was something else than
    +/// a literal (that is, it was some kind of match).
    +#define LITERAL_CODER_SIZE UINT32_C(0x300)
    +
    +/// Maximum number of literal coders
    +#define LITERAL_CODERS_MAX (1 << LZMA_LCLP_MAX)
    +
    +/// Calculates the literal_mask that literal_subcoder() needs.
    +#define literal_mask_calc(lc, lp) \
    +	((UINT32_C(0x100) << (lp)) - (UINT32_C(0x100) >> (lc)))
    +
    +/// Locate the literal coder for the next literal byte. The choice depends on
    +///   - the lowest literal_pos_bits bits of the position of the current
    +///     byte; and
    +///   - the highest literal_context_bits bits of the previous byte.
    +#define literal_subcoder(probs, lc, literal_mask, pos, prev_byte) \
    +	((probs) + UINT32_C(3) * \
    +		(((((pos) << 8) + (prev_byte)) & (literal_mask)) << (lc)))
    +
    +
    +static inline void
    +literal_init(probability *probs, uint32_t lc, uint32_t lp)
    +{
    +	assert(lc + lp <= LZMA_LCLP_MAX);
    +
    +	const size_t coders = LITERAL_CODER_SIZE << (lc + lp);
    +
    +	for (size_t i = 0; i < coders; ++i)
    +		bit_reset(probs[i]);
    +
    +	return;
    +}
    +
    +
    +//////////////////
    +// Match length //
    +//////////////////
    +
    +// Minimum length of a match is two bytes.
    +#define MATCH_LEN_MIN 2
    +
    +// Match length is encoded with 4, 5, or 10 bits.
    +//
    +// Length   Bits
    +//  2-9      4 = Choice=0 + 3 bits
    +// 10-17     5 = Choice=1 + Choice2=0 + 3 bits
    +// 18-273   10 = Choice=1 + Choice2=1 + 8 bits
    +#define LEN_LOW_BITS 3
    +#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
    +#define LEN_MID_BITS 3
    +#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
    +#define LEN_HIGH_BITS 8
    +#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
    +#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
    +
    +// Maximum length of a match is 273 which is a result of the encoding
    +// described above.
    +#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
    +
    +
    +////////////////////
    +// Match distance //
    +////////////////////
    +
    +// Different sets of probabilities are used for match distances that have very
    +// short match length: Lengths of 2, 3, and 4 bytes have a separate set of
    +// probabilities for each length. The matches with longer length use a shared
    +// set of probabilities.
    +#define DIST_STATES 4
    +
    +// Macro to get the index of the appropriate probability array.
    +#define get_dist_state(len) \
    +	((len) < DIST_STATES + MATCH_LEN_MIN \
    +		? (len) - MATCH_LEN_MIN \
    +		: DIST_STATES - 1)
    +
    +// The highest two bits of a match distance (distance slot) are encoded
    +// using six bits. See fastpos.h for more explanation.
    +#define DIST_SLOT_BITS 6
    +#define DIST_SLOTS (1 << DIST_SLOT_BITS)
    +
    +// Match distances up to 127 are fully encoded using probabilities. Since
    +// the highest two bits (distance slot) are always encoded using six bits,
    +// the distances 0-3 don't need any additional bits to encode, since the
    +// distance slot itself is the same as the actual distance. DIST_MODEL_START
    +// indicates the first distance slot where at least one additional bit is
    +// needed.
    +#define DIST_MODEL_START 4
    +
    +// Match distances greater than 127 are encoded in three pieces:
    +//   - distance slot: the highest two bits
    +//   - direct bits: 2-26 bits below the highest two bits
    +//   - alignment bits: four lowest bits
    +//
    +// Direct bits don't use any probabilities.
    +//
    +// The distance slot value of 14 is for distances 128-191 (see the table in
    +// fastpos.h to understand why).
    +#define DIST_MODEL_END 14
    +
    +// Distance slots that indicate a distance <= 127.
    +#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
    +#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
    +
    +// For match distances greater than 127, only the highest two bits and the
    +// lowest four bits (alignment) is encoded using probabilities.
    +#define ALIGN_BITS 4
    +#define ALIGN_SIZE (1 << ALIGN_BITS)
    +#define ALIGN_MASK (ALIGN_SIZE - 1)
    +
    +// LZMA remembers the four most recent match distances. Reusing these distances
    +// tends to take less space than re-encoding the actual distance value.
    +#define REPS 4
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.c
    new file mode 100644
    index 00000000000..0abed02b815
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.c
    @@ -0,0 +1,1263 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma_decoder.c
    +/// \brief      LZMA decoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//              Jia Tan
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lz_decoder.h"
    +#include "lzma_common.h"
    +#include "lzma_decoder.h"
    +#include "range_decoder.h"
    +
    +// The macros unroll loops with switch statements.
    +// Silence warnings about missing fall-through comments.
    +#if TUKLIB_GNUC_REQ(7, 0)
    +#	pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
    +#endif
    +
    +// Minimum number of input bytes to safely decode one LZMA symbol.
    +// The worst case is that we decode 22 bits using probabilities and 26
    +// direct bits. This may decode at maximum 20 bytes of input.
    +#define LZMA_IN_REQUIRED 20
    +
    +
    +// Macros for (somewhat) size-optimized code.
    +// This is used to decode the match length (how many bytes must be repeated
    +// from the dictionary). This version is used in the Resumable mode and
    +// does not unroll any loops.
    +#define len_decode(target, ld, pos_state, seq) \
    +do { \
    +case seq ## _CHOICE: \
    +	rc_if_0_safe(ld.choice, seq ## _CHOICE) { \
    +		rc_update_0(ld.choice); \
    +		probs = ld.low[pos_state];\
    +		limit = LEN_LOW_SYMBOLS; \
    +		target = MATCH_LEN_MIN; \
    +	} else { \
    +		rc_update_1(ld.choice); \
    +case seq ## _CHOICE2: \
    +		rc_if_0_safe(ld.choice2, seq ## _CHOICE2) { \
    +			rc_update_0(ld.choice2); \
    +			probs = ld.mid[pos_state]; \
    +			limit = LEN_MID_SYMBOLS; \
    +			target = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; \
    +		} else { \
    +			rc_update_1(ld.choice2); \
    +			probs = ld.high; \
    +			limit = LEN_HIGH_SYMBOLS; \
    +			target = MATCH_LEN_MIN + LEN_LOW_SYMBOLS \
    +					+ LEN_MID_SYMBOLS; \
    +		} \
    +	} \
    +	symbol = 1; \
    +case seq ## _BITTREE: \
    +	do { \
    +		rc_bit_safe(probs[symbol], , , seq ## _BITTREE); \
    +	} while (symbol < limit); \
    +	target += symbol - limit; \
    +} while (0)
    +
    +
    +// This is the faster version of the match length decoder that does not
    +// worry about being resumable. It unrolls the bittree decoding loop.
    +#define len_decode_fast(target, ld, pos_state) \
    +do { \
    +	symbol = 1; \
    +	rc_if_0(ld.choice) { \
    +		rc_update_0(ld.choice); \
    +		rc_bittree3(ld.low[pos_state], \
    +				-LEN_LOW_SYMBOLS + MATCH_LEN_MIN); \
    +		target = symbol; \
    +	} else { \
    +		rc_update_1(ld.choice); \
    +		rc_if_0(ld.choice2) { \
    +			rc_update_0(ld.choice2); \
    +			rc_bittree3(ld.mid[pos_state], -LEN_MID_SYMBOLS \
    +					+ MATCH_LEN_MIN + LEN_LOW_SYMBOLS); \
    +			target = symbol; \
    +		} else { \
    +			rc_update_1(ld.choice2); \
    +			rc_bittree8(ld.high, -LEN_HIGH_SYMBOLS \
    +					+ MATCH_LEN_MIN \
    +					+ LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS); \
    +			target = symbol; \
    +		} \
    +	} \
    +} while (0)
    +
    +
    +/// Length decoder probabilities; see comments in lzma_common.h.
    +typedef struct {
    +	probability choice;
    +	probability choice2;
    +	probability low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
    +	probability mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
    +	probability high[LEN_HIGH_SYMBOLS];
    +} lzma_length_decoder;
    +
    +
    +typedef struct {
    +	///////////////////
    +	// Probabilities //
    +	///////////////////
    +
    +	/// Literals; see comments in lzma_common.h.
    +	probability literal[LITERAL_CODERS_MAX * LITERAL_CODER_SIZE];
    +
    +	/// If 1, it's a match. Otherwise it's a single 8-bit literal.
    +	probability is_match[STATES][POS_STATES_MAX];
    +
    +	/// If 1, it's a repeated match. The distance is one of rep0 .. rep3.
    +	probability is_rep[STATES];
    +
    +	/// If 0, distance of a repeated match is rep0.
    +	/// Otherwise check is_rep1.
    +	probability is_rep0[STATES];
    +
    +	/// If 0, distance of a repeated match is rep1.
    +	/// Otherwise check is_rep2.
    +	probability is_rep1[STATES];
    +
    +	/// If 0, distance of a repeated match is rep2. Otherwise it is rep3.
    +	probability is_rep2[STATES];
    +
    +	/// If 1, the repeated match has length of one byte. Otherwise
    +	/// the length is decoded from rep_len_decoder.
    +	probability is_rep0_long[STATES][POS_STATES_MAX];
    +
    +	/// Probability tree for the highest two bits of the match distance.
    +	/// There is a separate probability tree for match lengths of
    +	/// 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
    +	probability dist_slot[DIST_STATES][DIST_SLOTS];
    +
    +	/// Probability trees for additional bits for match distance when the
    +	/// distance is in the range [4, 127].
    +	probability pos_special[FULL_DISTANCES - DIST_MODEL_END];
    +
    +	/// Probability tree for the lowest four bits of a match distance
    +	/// that is equal to or greater than 128.
    +	probability pos_align[ALIGN_SIZE];
    +
    +	/// Length of a normal match
    +	lzma_length_decoder match_len_decoder;
    +
    +	/// Length of a repeated match
    +	lzma_length_decoder rep_len_decoder;
    +
    +	///////////////////
    +	// Decoder state //
    +	///////////////////
    +
    +	// Range coder
    +	lzma_range_decoder rc;
    +
    +	// Types of the most recently seen LZMA symbols
    +	lzma_lzma_state state;
    +
    +	uint32_t rep0;      ///< Distance of the latest match
    +	uint32_t rep1;      ///< Distance of second latest match
    +	uint32_t rep2;      ///< Distance of third latest match
    +	uint32_t rep3;      ///< Distance of fourth latest match
    +
    +	uint32_t pos_mask; // (1U << pb) - 1
    +	uint32_t literal_context_bits;
    +	uint32_t literal_mask;
    +
    +	/// Uncompressed size as bytes, or LZMA_VLI_UNKNOWN if end of
    +	/// payload marker is expected.
    +	lzma_vli uncompressed_size;
    +
    +	/// True if end of payload marker (EOPM) is allowed even when
    +	/// uncompressed_size is known; false if EOPM must not be present.
    +	/// This is ignored if uncompressed_size == LZMA_VLI_UNKNOWN.
    +	bool allow_eopm;
    +
    +	////////////////////////////////
    +	// State of incomplete symbol //
    +	////////////////////////////////
    +
    +	/// Position where to continue the decoder loop
    +	enum {
    +		SEQ_NORMALIZE,
    +		SEQ_IS_MATCH,
    +		SEQ_LITERAL,
    +		SEQ_LITERAL_MATCHED,
    +		SEQ_LITERAL_WRITE,
    +		SEQ_IS_REP,
    +		SEQ_MATCH_LEN_CHOICE,
    +		SEQ_MATCH_LEN_CHOICE2,
    +		SEQ_MATCH_LEN_BITTREE,
    +		SEQ_DIST_SLOT,
    +		SEQ_DIST_MODEL,
    +		SEQ_DIRECT,
    +		SEQ_ALIGN,
    +		SEQ_EOPM,
    +		SEQ_IS_REP0,
    +		SEQ_SHORTREP,
    +		SEQ_IS_REP0_LONG,
    +		SEQ_IS_REP1,
    +		SEQ_IS_REP2,
    +		SEQ_REP_LEN_CHOICE,
    +		SEQ_REP_LEN_CHOICE2,
    +		SEQ_REP_LEN_BITTREE,
    +		SEQ_COPY,
    +	} sequence;
    +
    +	/// Base of the current probability tree
    +	probability *probs;
    +
    +	/// Symbol being decoded. This is also used as an index variable in
    +	/// bittree decoders: probs[symbol]
    +	uint32_t symbol;
    +
    +	/// Used as a loop termination condition on bittree decoders and
    +	/// direct bits decoder.
    +	uint32_t limit;
    +
    +	/// Matched literal decoder: 0x100 or 0 to help avoiding branches.
    +	/// Bittree reverse decoders: Offset of the next bit: 1 << offset
    +	uint32_t offset;
    +
    +	/// If decoding a literal: match byte.
    +	/// If decoding a match: length of the match.
    +	uint32_t len;
    +} lzma_lzma1_decoder;
    +
    +
    +static lzma_ret
    +lzma_decode(void *coder_ptr, lzma_dict *restrict dictptr,
    +		const uint8_t *restrict in,
    +		size_t *restrict in_pos, size_t in_size)
    +{
    +	lzma_lzma1_decoder *restrict coder = coder_ptr;
    +
    +	////////////////////
    +	// Initialization //
    +	////////////////////
    +
    +	{
    +		const lzma_ret ret = rc_read_init(
    +				&coder->rc, in, in_pos, in_size);
    +		if (ret != LZMA_STREAM_END)
    +			return ret;
    +	}
    +
    +	///////////////
    +	// Variables //
    +	///////////////
    +
    +	// Making local copies of often-used variables improves both
    +	// speed and readability.
    +
    +	lzma_dict dict = *dictptr;
    +
    +	const size_t dict_start = dict.pos;
    +
    +	// Range decoder
    +	rc_to_local(coder->rc, *in_pos, LZMA_IN_REQUIRED);
    +
    +	// State
    +	uint32_t state = coder->state;
    +	uint32_t rep0 = coder->rep0;
    +	uint32_t rep1 = coder->rep1;
    +	uint32_t rep2 = coder->rep2;
    +	uint32_t rep3 = coder->rep3;
    +
    +	const uint32_t pos_mask = coder->pos_mask;
    +
    +	// These variables are actually needed only if we last time ran
    +	// out of input in the middle of the decoder loop.
    +	probability *probs = coder->probs;
    +	uint32_t symbol = coder->symbol;
    +	uint32_t limit = coder->limit;
    +	uint32_t offset = coder->offset;
    +	uint32_t len = coder->len;
    +
    +	const uint32_t literal_mask = coder->literal_mask;
    +	const uint32_t literal_context_bits = coder->literal_context_bits;
    +
    +	// Temporary variables
    +	uint32_t pos_state = dict.pos & pos_mask;
    +
    +	lzma_ret ret = LZMA_OK;
    +
    +	// This is true when the next LZMA symbol is allowed to be EOPM.
    +	// That is, if this is false, then EOPM is considered
    +	// an invalid symbol and we will return LZMA_DATA_ERROR.
    +	//
    +	// EOPM is always required (not just allowed) when
    +	// the uncompressed size isn't known. When uncompressed size
    +	// is known, eopm_is_valid may be set to true later.
    +	bool eopm_is_valid = coder->uncompressed_size == LZMA_VLI_UNKNOWN;
    +
    +	// If uncompressed size is known and there is enough output space
    +	// to decode all the data, limit the available buffer space so that
    +	// the main loop won't try to decode past the end of the stream.
    +	bool might_finish_without_eopm = false;
    +	if (coder->uncompressed_size != LZMA_VLI_UNKNOWN
    +			&& coder->uncompressed_size <= dict.limit - dict.pos) {
    +		dict.limit = dict.pos + (size_t)(coder->uncompressed_size);
    +		might_finish_without_eopm = true;
    +	}
    +
    +	// The main decoder loop. The "switch" is used to resume the decoder at
    +	// correct location. Once resumed, the "switch" is no longer used.
    +	// The decoder loops is split into two modes:
    +	//
    +	// 1 - Non-resumable mode (fast). This is used when it is guaranteed
    +	//     there is enough input to decode the next symbol. If the output
    +	//     limit is reached, then the decoder loop will save the place
    +	//     for the resumable mode to continue. This mode is not used if
    +	//     HAVE_SMALL is defined. This is faster than Resumable mode
    +	//     because it reduces the number of branches needed and allows
    +	//     for more compiler optimizations.
    +	//
    +	// 2 - Resumable mode (slow). This is used when a previous decoder
    +	//     loop did not have enough space in the input or output buffers
    +	//     to complete. It uses sequence enum values to set remind
    +	//     coder->sequence where to resume in the decoder loop. This
    +	//     is the only mode used when HAVE_SMALL is defined.
    +
    +	switch (coder->sequence)
    +	while (true) {
    +		// Calculate new pos_state. This is skipped on the first loop
    +		// since we already calculated it when setting up the local
    +		// variables.
    +		pos_state = dict.pos & pos_mask;
    +
    +#ifndef HAVE_SMALL
    +
    +		///////////////////////////////
    +		// Non-resumable Mode (fast) //
    +		///////////////////////////////
    +
    +		// Go to Resumable mode (1) if there is not enough input to
    +		// safely decode any possible LZMA symbol or (2) if the
    +		// dictionary is full, which may need special checks that
    +		// are only done in the Resumable mode.
    +		if (unlikely(!rc_is_fast_allowed()
    +				|| dict.pos == dict.limit))
    +			goto slow;
    +
    +		// Decode the first bit from the next LZMA symbol.
    +		// If the bit is a 0, then we handle it as a literal.
    +		// If the bit is a 1, then it is a match of previously
    +		// decoded data.
    +		rc_if_0(coder->is_match[state][pos_state]) {
    +			/////////////////////
    +			// Decode literal. //
    +			/////////////////////
    +
    +			// Update the RC that we have decoded a 0.
    +			rc_update_0(coder->is_match[state][pos_state]);
    +
    +			// Get the correct probability array from lp and
    +			// lc params.
    +			probs = literal_subcoder(coder->literal,
    +					literal_context_bits, literal_mask,
    +					dict.pos, dict_get0(&dict));
    +
    +			if (is_literal_state(state)) {
    +				update_literal_normal(state);
    +
    +				// Decode literal without match byte.
    +				rc_bittree8(probs, 0);
    +			} else {
    +				update_literal_matched(state);
    +
    +				// Decode literal with match byte.
    +				rc_matched_literal(probs,
    +						dict_get(&dict, rep0));
    +			}
    +
    +			// Write decoded literal to dictionary
    +			dict_put(&dict, symbol);
    +			continue;
    +		}
    +
    +		///////////////////
    +		// Decode match. //
    +		///////////////////
    +
    +		// Instead of a new byte we are going to decode a
    +		// distance-length pair. The distance represents how far
    +		// back in the dictionary to begin copying. The length
    +		// represents how many bytes to copy.
    +
    +		rc_update_1(coder->is_match[state][pos_state]);
    +
    +		rc_if_0(coder->is_rep[state]) {
    +			///////////////////
    +			// Simple match. //
    +			///////////////////
    +
    +			// Not a repeated match. In this case,
    +			// the length (how many bytes to copy) must be
    +			// decoded first. Then, the distance (where to
    +			// start copying) is decoded.
    +			//
    +			// This is also how we know when we are done
    +			// decoding. If the distance decodes to UINT32_MAX,
    +			// then we know to stop decoding (end of payload
    +			// marker).
    +
    +			rc_update_0(coder->is_rep[state]);
    +			update_match(state);
    +
    +			// The latest three match distances are kept in
    +			// memory in case there are repeated matches.
    +			rep3 = rep2;
    +			rep2 = rep1;
    +			rep1 = rep0;
    +
    +			// Decode the length of the match.
    +			len_decode_fast(len, coder->match_len_decoder,
    +					pos_state);
    +
    +			// Next, decode the distance into rep0.
    +
    +			// The next 6 bits determine how to decode the
    +			// rest of the distance.
    +			probs = coder->dist_slot[get_dist_state(len)];
    +
    +			rc_bittree6(probs, -DIST_SLOTS);
    +			assert(symbol <= 63);
    +
    +			if (symbol < DIST_MODEL_START) {
    +				// If the decoded symbol is < DIST_MODEL_START
    +				// then we use its value directly as the
    +				// match distance. No other bits are needed.
    +				// The only possible distance values
    +				// are [0, 3].
    +				rep0 = symbol;
    +			} else {
    +				// Use the first two bits of symbol as the
    +				// highest bits of the match distance.
    +
    +				// "limit" represents the number of low bits
    +				// to decode.
    +				limit = (symbol >> 1) - 1;
    +				assert(limit >= 1 && limit <= 30);
    +				rep0 = 2 + (symbol & 1);
    +
    +				if (symbol < DIST_MODEL_END) {
    +					// When symbol is > DIST_MODEL_START,
    +					// but symbol < DIST_MODEL_END, then
    +					// it can decode distances between
    +					// [4, 127].
    +					assert(limit <= 5);
    +					rep0 <<= limit;
    +					assert(rep0 <= 96);
    +
    +					// -1 is fine, because we start
    +					// decoding at probs[1], not probs[0].
    +					// NOTE: This violates the C standard,
    +					// since we are doing pointer
    +					// arithmetic past the beginning of
    +					// the array.
    +					assert((int32_t)(rep0 - symbol - 1)
    +							>= -1);
    +					assert((int32_t)(rep0 - symbol - 1)
    +							<= 82);
    +					probs = coder->pos_special + rep0
    +							- symbol - 1;
    +					symbol = 1;
    +					offset = 1;
    +
    +					// Variable number (1-5) of bits
    +					// from a reverse bittree. This
    +					// isn't worth manual unrolling.
    +					//
    +					// NOTE: Making one or many of the
    +					// variables (probs, symbol, offset,
    +					// or limit) local here (instead of
    +					// using those declared outside the
    +					// main loop) can affect code size
    +					// and performance which isn't a
    +					// surprise but it's not so clear
    +					// what is the best.
    +					do {
    +						rc_bit_add_if_1(probs,
    +								rep0, offset);
    +						offset <<= 1;
    +					} while (--limit > 0);
    +				} else {
    +					// The distance is >= 128. Decode the
    +					// lower bits without probabilities
    +					// except the lowest four bits.
    +					assert(symbol >= 14);
    +					assert(limit >= 6);
    +
    +					limit -= ALIGN_BITS;
    +					assert(limit >= 2);
    +
    +					rc_direct(rep0, limit);
    +
    +					// Decode the lowest four bits using
    +					// probabilities.
    +					rep0 <<= ALIGN_BITS;
    +					rc_bittree_rev4(coder->pos_align);
    +					rep0 += symbol;
    +
    +					// If the end of payload marker (EOPM)
    +					// is detected, jump to the safe code.
    +					// The EOPM handling isn't speed
    +					// critical at all.
    +					//
    +					// A final normalization is needed
    +					// after the EOPM (there can be a
    +					// dummy byte to read in some cases).
    +					// If the normalization was done here
    +					// in the fast code, it would need to
    +					// be taken into account in the value
    +					// of LZMA_IN_REQUIRED. Using the
    +					// safe code allows keeping
    +					// LZMA_IN_REQUIRED as 20 instead of
    +					// 21.
    +					if (rep0 == UINT32_MAX)
    +						goto eopm;
    +				}
    +			}
    +
    +			// Validate the distance we just decoded.
    +			if (unlikely(!dict_is_distance_valid(&dict, rep0))) {
    +				ret = LZMA_DATA_ERROR;
    +				goto out;
    +			}
    +
    +		} else {
    +			rc_update_1(coder->is_rep[state]);
    +
    +			/////////////////////
    +			// Repeated match. //
    +			/////////////////////
    +
    +			// The match distance is a value that we have decoded
    +			// recently. The latest four match distances are
    +			// available as rep0, rep1, rep2 and rep3. We will
    +			// now decode which of them is the new distance.
    +			//
    +			// There cannot be a match if we haven't produced
    +			// any output, so check that first.
    +			if (unlikely(!dict_is_distance_valid(&dict, 0))) {
    +				ret = LZMA_DATA_ERROR;
    +				goto out;
    +			}
    +
    +			rc_if_0(coder->is_rep0[state]) {
    +				rc_update_0(coder->is_rep0[state]);
    +				// The distance is rep0.
    +
    +				// Decode the next bit to determine if 1 byte
    +				// should be copied from rep0 distance or
    +				// if the number of bytes needs to be decoded.
    +
    +				// If the next bit is 0, then it is a
    +				// "Short Rep Match" and only 1 bit is copied.
    +				// Otherwise, the length of the match is
    +				// decoded after the "else" statement.
    +				rc_if_0(coder->is_rep0_long[state][pos_state]) {
    +					rc_update_0(coder->is_rep0_long[
    +							state][pos_state]);
    +
    +					update_short_rep(state);
    +					dict_put(&dict, dict_get(&dict, rep0));
    +					continue;
    +				}
    +
    +				// Repeating more than one byte at
    +				// distance of rep0.
    +				rc_update_1(coder->is_rep0_long[
    +						state][pos_state]);
    +
    +			} else {
    +				rc_update_1(coder->is_rep0[state]);
    +
    +				// The distance is rep1, rep2 or rep3. Once
    +				// we find out which one of these three, it
    +				// is stored to rep0 and rep1, rep2 and rep3
    +				// are updated accordingly. There is no
    +				// "Short Rep Match" option, so the length
    +				// of the match must always be decoded next.
    +				rc_if_0(coder->is_rep1[state]) {
    +					// The distance is rep1.
    +					rc_update_0(coder->is_rep1[state]);
    +
    +					const uint32_t distance = rep1;
    +					rep1 = rep0;
    +					rep0 = distance;
    +
    +				} else {
    +					rc_update_1(coder->is_rep1[state]);
    +
    +					rc_if_0(coder->is_rep2[state]) {
    +						// The distance is rep2.
    +						rc_update_0(coder->is_rep2[
    +								state]);
    +
    +						const uint32_t distance = rep2;
    +						rep2 = rep1;
    +						rep1 = rep0;
    +						rep0 = distance;
    +
    +					} else {
    +						// The distance is rep3.
    +						rc_update_1(coder->is_rep2[
    +								state]);
    +
    +						const uint32_t distance = rep3;
    +						rep3 = rep2;
    +						rep2 = rep1;
    +						rep1 = rep0;
    +						rep0 = distance;
    +					}
    +				}
    +			}
    +
    +			update_long_rep(state);
    +
    +			// Decode the length of the repeated match.
    +			len_decode_fast(len, coder->rep_len_decoder,
    +					pos_state);
    +		}
    +
    +		/////////////////////////////////
    +		// Repeat from history buffer. //
    +		/////////////////////////////////
    +
    +		// The length is always between these limits. There is no way
    +		// to trigger the algorithm to set len outside this range.
    +		assert(len >= MATCH_LEN_MIN);
    +		assert(len <= MATCH_LEN_MAX);
    +
    +		// Repeat len bytes from distance of rep0.
    +		if (unlikely(dict_repeat(&dict, rep0, &len))) {
    +			coder->sequence = SEQ_COPY;
    +			goto out;
    +		}
    +
    +		continue;
    +
    +slow:
    +#endif
    +	///////////////////////////
    +	// Resumable Mode (slow) //
    +	///////////////////////////
    +
    +	// This is very similar to Non-resumable Mode, so most of the
    +	// comments are not repeated. The main differences are:
    +	// - case labels are used to resume at the correct location.
    +	// - Loops are not unrolled.
    +	// - Range coder macros take an extra sequence argument
    +	//   so they can save to coder->sequence the location to
    +	//   resume in case there is not enough input.
    +	case SEQ_NORMALIZE:
    +	case SEQ_IS_MATCH:
    +		if (unlikely(might_finish_without_eopm
    +				&& dict.pos == dict.limit)) {
    +			// In rare cases there is a useless byte that needs
    +			// to be read anyway.
    +			rc_normalize_safe(SEQ_NORMALIZE);
    +
    +			// If the range decoder state is such that we can
    +			// be at the end of the LZMA stream, then the
    +			// decoding is finished.
    +			if (rc_is_finished(rc)) {
    +				ret = LZMA_STREAM_END;
    +				goto out;
    +			}
    +
    +			// If the caller hasn't allowed EOPM to be present
    +			// together with known uncompressed size, then the
    +			// LZMA stream is corrupt.
    +			if (!coder->allow_eopm) {
    +				ret = LZMA_DATA_ERROR;
    +				goto out;
    +			}
    +
    +			// Otherwise continue decoding with the expectation
    +			// that the next LZMA symbol is EOPM.
    +			eopm_is_valid = true;
    +		}
    +
    +		rc_if_0_safe(coder->is_match[state][pos_state], SEQ_IS_MATCH) {
    +			/////////////////////
    +			// Decode literal. //
    +			/////////////////////
    +
    +			rc_update_0(coder->is_match[state][pos_state]);
    +
    +			probs = literal_subcoder(coder->literal,
    +					literal_context_bits, literal_mask,
    +					dict.pos, dict_get0(&dict));
    +			symbol = 1;
    +
    +			if (is_literal_state(state)) {
    +				update_literal_normal(state);
    +
    +				// Decode literal without match byte.
    +				// The "slow" version does not unroll
    +				// the loop.
    +	case SEQ_LITERAL:
    +				do {
    +					rc_bit_safe(probs[symbol], , ,
    +							SEQ_LITERAL);
    +				} while (symbol < (1 << 8));
    +			} else {
    +				update_literal_matched(state);
    +
    +				// Decode literal with match byte.
    +				len = (uint32_t)(dict_get(&dict, rep0)) << 1;
    +
    +				offset = 0x100;
    +
    +	case SEQ_LITERAL_MATCHED:
    +				do {
    +					const uint32_t match_bit
    +							= len & offset;
    +					const uint32_t subcoder_index
    +							= offset + match_bit
    +							+ symbol;
    +
    +					rc_bit_safe(probs[subcoder_index],
    +							offset &= ~match_bit,
    +							offset &= match_bit,
    +							SEQ_LITERAL_MATCHED);
    +
    +					// It seems to be faster to do this
    +					// here instead of putting it to the
    +					// beginning of the loop and then
    +					// putting the "case" in the middle
    +					// of the loop.
    +					len <<= 1;
    +
    +				} while (symbol < (1 << 8));
    +			}
    +
    +	case SEQ_LITERAL_WRITE:
    +			if (dict_put_safe(&dict, symbol)) {
    +				coder->sequence = SEQ_LITERAL_WRITE;
    +				goto out;
    +			}
    +
    +			continue;
    +		}
    +
    +		///////////////////
    +		// Decode match. //
    +		///////////////////
    +
    +		rc_update_1(coder->is_match[state][pos_state]);
    +
    +	case SEQ_IS_REP:
    +		rc_if_0_safe(coder->is_rep[state], SEQ_IS_REP) {
    +			///////////////////
    +			// Simple match. //
    +			///////////////////
    +
    +			rc_update_0(coder->is_rep[state]);
    +			update_match(state);
    +
    +			rep3 = rep2;
    +			rep2 = rep1;
    +			rep1 = rep0;
    +
    +			len_decode(len, coder->match_len_decoder,
    +					pos_state, SEQ_MATCH_LEN);
    +
    +			probs = coder->dist_slot[get_dist_state(len)];
    +			symbol = 1;
    +
    +	case SEQ_DIST_SLOT:
    +			do {
    +				rc_bit_safe(probs[symbol], , , SEQ_DIST_SLOT);
    +			} while (symbol < DIST_SLOTS);
    +
    +			symbol -= DIST_SLOTS;
    +			assert(symbol <= 63);
    +
    +			if (symbol < DIST_MODEL_START) {
    +				rep0 = symbol;
    +			} else {
    +				limit = (symbol >> 1) - 1;
    +				assert(limit >= 1 && limit <= 30);
    +				rep0 = 2 + (symbol & 1);
    +
    +				if (symbol < DIST_MODEL_END) {
    +					assert(limit <= 5);
    +					rep0 <<= limit;
    +					assert(rep0 <= 96);
    +					// -1 is fine, because we start
    +					// decoding at probs[1], not probs[0].
    +					// NOTE: This violates the C standard,
    +					// since we are doing pointer
    +					// arithmetic past the beginning of
    +					// the array.
    +					assert((int32_t)(rep0 - symbol - 1)
    +							>= -1);
    +					assert((int32_t)(rep0 - symbol - 1)
    +							<= 82);
    +					probs = coder->pos_special + rep0
    +							- symbol - 1;
    +					symbol = 1;
    +					offset = 0;
    +	case SEQ_DIST_MODEL:
    +					do {
    +						rc_bit_safe(probs[symbol], ,
    +							rep0 += 1U << offset,
    +							SEQ_DIST_MODEL);
    +					} while (++offset < limit);
    +				} else {
    +					assert(symbol >= 14);
    +					assert(limit >= 6);
    +					limit -= ALIGN_BITS;
    +					assert(limit >= 2);
    +	case SEQ_DIRECT:
    +					rc_direct_safe(rep0, limit,
    +							SEQ_DIRECT);
    +
    +					rep0 <<= ALIGN_BITS;
    +					symbol = 0;
    +					offset = 1;
    +	case SEQ_ALIGN:
    +					do {
    +						rc_bit_last_safe(
    +							coder->pos_align[
    +								offset
    +								+ symbol],
    +							,
    +							symbol += offset,
    +							SEQ_ALIGN);
    +						offset <<= 1;
    +					} while (offset < ALIGN_SIZE);
    +
    +					rep0 += symbol;
    +
    +					if (rep0 == UINT32_MAX) {
    +						// End of payload marker was
    +						// found. It may only be
    +						// present if
    +						//   - uncompressed size is
    +						//     unknown or
    +						//   - after known uncompressed
    +						//     size amount of bytes has
    +						//     been decompressed and
    +						//     caller has indicated
    +						//     that EOPM might be used
    +						//     (it's not allowed in
    +						//     LZMA2).
    +#ifndef HAVE_SMALL
    +eopm:
    +#endif
    +						if (!eopm_is_valid) {
    +							ret = LZMA_DATA_ERROR;
    +							goto out;
    +						}
    +
    +	case SEQ_EOPM:
    +						// LZMA1 stream with
    +						// end-of-payload marker.
    +						rc_normalize_safe(SEQ_EOPM);
    +						ret = rc_is_finished(rc)
    +							? LZMA_STREAM_END
    +							: LZMA_DATA_ERROR;
    +						goto out;
    +					}
    +				}
    +			}
    +
    +			if (unlikely(!dict_is_distance_valid(&dict, rep0))) {
    +				ret = LZMA_DATA_ERROR;
    +				goto out;
    +			}
    +
    +		} else {
    +			/////////////////////
    +			// Repeated match. //
    +			/////////////////////
    +
    +			rc_update_1(coder->is_rep[state]);
    +
    +			if (unlikely(!dict_is_distance_valid(&dict, 0))) {
    +				ret = LZMA_DATA_ERROR;
    +				goto out;
    +			}
    +
    +	case SEQ_IS_REP0:
    +			rc_if_0_safe(coder->is_rep0[state], SEQ_IS_REP0) {
    +				rc_update_0(coder->is_rep0[state]);
    +
    +	case SEQ_IS_REP0_LONG:
    +				rc_if_0_safe(coder->is_rep0_long
    +						[state][pos_state],
    +						SEQ_IS_REP0_LONG) {
    +					rc_update_0(coder->is_rep0_long[
    +							state][pos_state]);
    +
    +					update_short_rep(state);
    +
    +	case SEQ_SHORTREP:
    +					if (dict_put_safe(&dict,
    +							dict_get(&dict,
    +							rep0))) {
    +						coder->sequence = SEQ_SHORTREP;
    +						goto out;
    +					}
    +
    +					continue;
    +				}
    +
    +				rc_update_1(coder->is_rep0_long[
    +						state][pos_state]);
    +
    +			} else {
    +				rc_update_1(coder->is_rep0[state]);
    +
    +	case SEQ_IS_REP1:
    +				rc_if_0_safe(coder->is_rep1[state], SEQ_IS_REP1) {
    +					rc_update_0(coder->is_rep1[state]);
    +
    +					const uint32_t distance = rep1;
    +					rep1 = rep0;
    +					rep0 = distance;
    +
    +				} else {
    +					rc_update_1(coder->is_rep1[state]);
    +	case SEQ_IS_REP2:
    +					rc_if_0_safe(coder->is_rep2[state],
    +							SEQ_IS_REP2) {
    +						rc_update_0(coder->is_rep2[
    +								state]);
    +
    +						const uint32_t distance = rep2;
    +						rep2 = rep1;
    +						rep1 = rep0;
    +						rep0 = distance;
    +
    +					} else {
    +						rc_update_1(coder->is_rep2[
    +								state]);
    +
    +						const uint32_t distance = rep3;
    +						rep3 = rep2;
    +						rep2 = rep1;
    +						rep1 = rep0;
    +						rep0 = distance;
    +					}
    +				}
    +			}
    +
    +			update_long_rep(state);
    +
    +			len_decode(len, coder->rep_len_decoder,
    +					pos_state, SEQ_REP_LEN);
    +		}
    +
    +		/////////////////////////////////
    +		// Repeat from history buffer. //
    +		/////////////////////////////////
    +
    +		assert(len >= MATCH_LEN_MIN);
    +		assert(len <= MATCH_LEN_MAX);
    +
    +	case SEQ_COPY:
    +		if (unlikely(dict_repeat(&dict, rep0, &len))) {
    +			coder->sequence = SEQ_COPY;
    +			goto out;
    +		}
    +	}
    +
    +out:
    +	// Save state
    +
    +	// NOTE: Must not copy dict.limit.
    +	dictptr->pos = dict.pos;
    +	dictptr->full = dict.full;
    +
    +	rc_from_local(coder->rc, *in_pos);
    +
    +	coder->state = state;
    +	coder->rep0 = rep0;
    +	coder->rep1 = rep1;
    +	coder->rep2 = rep2;
    +	coder->rep3 = rep3;
    +
    +	coder->probs = probs;
    +	coder->symbol = symbol;
    +	coder->limit = limit;
    +	coder->offset = offset;
    +	coder->len = len;
    +
    +	// Update the remaining amount of uncompressed data if uncompressed
    +	// size was known.
    +	if (coder->uncompressed_size != LZMA_VLI_UNKNOWN) {
    +		coder->uncompressed_size -= dict.pos - dict_start;
    +
    +		// If we have gotten all the output but the decoder wants
    +		// to write more output, the file is corrupt. There are
    +		// three SEQ values where output is produced.
    +		if (coder->uncompressed_size == 0 && ret == LZMA_OK
    +				&& (coder->sequence == SEQ_LITERAL_WRITE
    +					|| coder->sequence == SEQ_SHORTREP
    +					|| coder->sequence == SEQ_COPY))
    +			ret = LZMA_DATA_ERROR;
    +	}
    +
    +	if (ret == LZMA_STREAM_END) {
    +		// Reset the range decoder so that it is ready to reinitialize
    +		// for a new LZMA2 chunk.
    +		rc_reset(coder->rc);
    +		coder->sequence = SEQ_IS_MATCH;
    +	}
    +
    +	return ret;
    +}
    +
    +
    +static void
    +lzma_decoder_uncompressed(void *coder_ptr, lzma_vli uncompressed_size,
    +		bool allow_eopm)
    +{
    +	lzma_lzma1_decoder *coder = coder_ptr;
    +	coder->uncompressed_size = uncompressed_size;
    +	coder->allow_eopm = allow_eopm;
    +}
    +
    +
    +static void
    +lzma_decoder_reset(void *coder_ptr, const void *opt)
    +{
    +	lzma_lzma1_decoder *coder = coder_ptr;
    +	const lzma_options_lzma *options = opt;
    +
    +	// NOTE: We assume that lc/lp/pb are valid since they were
    +	// successfully decoded with lzma_lzma_decode_properties().
    +
    +	// Calculate pos_mask. We don't need pos_bits as is for anything.
    +	coder->pos_mask = (1U << options->pb) - 1;
    +
    +	// Initialize the literal decoder.
    +	literal_init(coder->literal, options->lc, options->lp);
    +
    +	coder->literal_context_bits = options->lc;
    +	coder->literal_mask = literal_mask_calc(options->lc, options->lp);
    +
    +	// State
    +	coder->state = STATE_LIT_LIT;
    +	coder->rep0 = 0;
    +	coder->rep1 = 0;
    +	coder->rep2 = 0;
    +	coder->rep3 = 0;
    +	coder->pos_mask = (1U << options->pb) - 1;
    +
    +	// Range decoder
    +	rc_reset(coder->rc);
    +
    +	// Bit and bittree decoders
    +	for (uint32_t i = 0; i < STATES; ++i) {
    +		for (uint32_t j = 0; j <= coder->pos_mask; ++j) {
    +			bit_reset(coder->is_match[i][j]);
    +			bit_reset(coder->is_rep0_long[i][j]);
    +		}
    +
    +		bit_reset(coder->is_rep[i]);
    +		bit_reset(coder->is_rep0[i]);
    +		bit_reset(coder->is_rep1[i]);
    +		bit_reset(coder->is_rep2[i]);
    +	}
    +
    +	for (uint32_t i = 0; i < DIST_STATES; ++i)
    +		bittree_reset(coder->dist_slot[i], DIST_SLOT_BITS);
    +
    +	for (uint32_t i = 0; i < FULL_DISTANCES - DIST_MODEL_END; ++i)
    +		bit_reset(coder->pos_special[i]);
    +
    +	bittree_reset(coder->pos_align, ALIGN_BITS);
    +
    +	// Len decoders (also bit/bittree)
    +	const uint32_t num_pos_states = 1U << options->pb;
    +	bit_reset(coder->match_len_decoder.choice);
    +	bit_reset(coder->match_len_decoder.choice2);
    +	bit_reset(coder->rep_len_decoder.choice);
    +	bit_reset(coder->rep_len_decoder.choice2);
    +
    +	for (uint32_t pos_state = 0; pos_state < num_pos_states; ++pos_state) {
    +		bittree_reset(coder->match_len_decoder.low[pos_state],
    +				LEN_LOW_BITS);
    +		bittree_reset(coder->match_len_decoder.mid[pos_state],
    +				LEN_MID_BITS);
    +
    +		bittree_reset(coder->rep_len_decoder.low[pos_state],
    +				LEN_LOW_BITS);
    +		bittree_reset(coder->rep_len_decoder.mid[pos_state],
    +				LEN_MID_BITS);
    +	}
    +
    +	bittree_reset(coder->match_len_decoder.high, LEN_HIGH_BITS);
    +	bittree_reset(coder->rep_len_decoder.high, LEN_HIGH_BITS);
    +
    +	coder->sequence = SEQ_IS_MATCH;
    +	coder->probs = NULL;
    +	coder->symbol = 0;
    +	coder->limit = 0;
    +	coder->offset = 0;
    +	coder->len = 0;
    +
    +	return;
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma_decoder_create(lzma_lz_decoder *lz, const lzma_allocator *allocator,
    +		const lzma_options_lzma *options, lzma_lz_options *lz_options)
    +{
    +	if (lz->coder == NULL) {
    +		lz->coder = lzma_alloc(sizeof(lzma_lzma1_decoder), allocator);
    +		if (lz->coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		lz->code = &lzma_decode;
    +		lz->reset = &lzma_decoder_reset;
    +		lz->set_uncompressed = &lzma_decoder_uncompressed;
    +	}
    +
    +	// All dictionary sizes are OK here. LZ decoder will take care of
    +	// the special cases.
    +	lz_options->dict_size = options->dict_size;
    +	lz_options->preset_dict = options->preset_dict;
    +	lz_options->preset_dict_size = options->preset_dict_size;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +/// Allocate and initialize LZMA decoder. This is used only via LZ
    +/// initialization (lzma_lzma_decoder_init() passes function pointer to
    +/// the LZ initialization).
    +static lzma_ret
    +lzma_decoder_init(lzma_lz_decoder *lz, const lzma_allocator *allocator,
    +		lzma_vli id, const void *options, lzma_lz_options *lz_options)
    +{
    +	if (!is_lclppb_valid(options))
    +		return LZMA_PROG_ERROR;
    +
    +	lzma_vli uncomp_size = LZMA_VLI_UNKNOWN;
    +	bool allow_eopm = true;
    +
    +	if (id == LZMA_FILTER_LZMA1EXT) {
    +		const lzma_options_lzma *opt = options;
    +
    +		// Only one flag is supported.
    +		if (opt->ext_flags & ~LZMA_LZMA1EXT_ALLOW_EOPM)
    +			return LZMA_OPTIONS_ERROR;
    +
    +		// FIXME? Using lzma_vli instead of uint64_t is weird because
    +		// this has nothing to do with .xz headers and variable-length
    +		// integer encoding. On the other hand, using LZMA_VLI_UNKNOWN
    +		// instead of UINT64_MAX is clearer when unknown size is
    +		// meant. A problem with using lzma_vli is that now we
    +		// allow > LZMA_VLI_MAX which is fine in this file but
    +		// it's still confusing. Note that alone_decoder.c also
    +		// allows > LZMA_VLI_MAX when setting uncompressed size.
    +		uncomp_size = opt->ext_size_low
    +				+ ((uint64_t)(opt->ext_size_high) << 32);
    +		allow_eopm = (opt->ext_flags & LZMA_LZMA1EXT_ALLOW_EOPM) != 0
    +				|| uncomp_size == LZMA_VLI_UNKNOWN;
    +	}
    +
    +	return_if_error(lzma_lzma_decoder_create(
    +			lz, allocator, options, lz_options));
    +
    +	lzma_decoder_reset(lz->coder, options);
    +	lzma_decoder_uncompressed(lz->coder, uncomp_size, allow_eopm);
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	// LZMA can only be the last filter in the chain. This is enforced
    +	// by the raw_decoder initialization.
    +	assert(filters[1].init == NULL);
    +
    +	return lzma_lz_decoder_init(next, allocator, filters,
    +			&lzma_decoder_init);
    +}
    +
    +
    +extern bool
    +lzma_lzma_lclppb_decode(lzma_options_lzma *options, uint8_t byte)
    +{
    +	if (byte > (4 * 5 + 4) * 9 + 8)
    +		return true;
    +
    +	// See the file format specification to understand this.
    +	options->pb = byte / (9 * 5);
    +	byte -= options->pb * 9 * 5;
    +	options->lp = byte / 9;
    +	options->lc = byte - options->lp * 9;
    +
    +	return options->lc + options->lp > LZMA_LCLP_MAX;
    +}
    +
    +
    +extern uint64_t
    +lzma_lzma_decoder_memusage_nocheck(const void *options)
    +{
    +	const lzma_options_lzma *const opt = options;
    +	return sizeof(lzma_lzma1_decoder)
    +			+ lzma_lz_decoder_memusage(opt->dict_size);
    +}
    +
    +
    +extern uint64_t
    +lzma_lzma_decoder_memusage(const void *options)
    +{
    +	if (!is_lclppb_valid(options))
    +		return UINT64_MAX;
    +
    +	return lzma_lzma_decoder_memusage_nocheck(options);
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma_props_decode(void **options, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size)
    +{
    +	if (props_size != 5)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	lzma_options_lzma *opt
    +			= lzma_alloc(sizeof(lzma_options_lzma), allocator);
    +	if (opt == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	if (lzma_lzma_lclppb_decode(opt, props[0]))
    +		goto error;
    +
    +	// All dictionary sizes are accepted, including zero. LZ decoder
    +	// will automatically use a dictionary at least a few KiB even if
    +	// a smaller dictionary is requested.
    +	opt->dict_size = read32le(props + 1);
    +
    +	opt->preset_dict = NULL;
    +	opt->preset_dict_size = 0;
    +
    +	*options = opt;
    +
    +	return LZMA_OK;
    +
    +error:
    +	lzma_free(opt, allocator);
    +	return LZMA_OPTIONS_ERROR;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.h
    new file mode 100644
    index 00000000000..9730f56fc26
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.h
    @@ -0,0 +1,52 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma_decoder.h
    +/// \brief      LZMA decoder API
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZMA_DECODER_H
    +#define LZMA_LZMA_DECODER_H
    +
    +#include "common.h"
    +
    +
    +/// Allocates and initializes LZMA decoder
    +extern lzma_ret lzma_lzma_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern uint64_t lzma_lzma_decoder_memusage(const void *options);
    +
    +extern lzma_ret lzma_lzma_props_decode(
    +		void **options, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size);
    +
    +
    +/// \brief      Decodes the LZMA Properties byte (lc/lp/pb)
    +///
    +/// \return     true if error occurred, false on success
    +///
    +extern bool lzma_lzma_lclppb_decode(
    +		lzma_options_lzma *options, uint8_t byte);
    +
    +
    +#ifdef LZMA_LZ_DECODER_H
    +/// Allocate and setup function pointers only. This is used by LZMA1 and
    +/// LZMA2 decoders.
    +extern lzma_ret lzma_lzma_decoder_create(
    +		lzma_lz_decoder *lz, const lzma_allocator *allocator,
    +		const lzma_options_lzma *opt, lzma_lz_options *lz_options);
    +
    +/// Gets memory usage without validating lc/lp/pb. This is used by LZMA2
    +/// decoder, because raw LZMA2 decoding doesn't need lc/lp/pb.
    +extern uint64_t lzma_lzma_decoder_memusage_nocheck(const void *options);
    +
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.c
    new file mode 100644
    index 00000000000..543ca321c3c
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.c
    @@ -0,0 +1,786 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma_encoder.c
    +/// \brief      LZMA encoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lzma2_encoder.h"
    +#include "lzma_encoder_private.h"
    +#include "fastpos.h"
    +
    +
    +/////////////
    +// Literal //
    +/////////////
    +
    +static inline void
    +literal_matched(lzma_range_encoder *rc, probability *subcoder,
    +		uint32_t match_byte, uint32_t symbol)
    +{
    +	uint32_t offset = 0x100;
    +	symbol += UINT32_C(1) << 8;
    +
    +	do {
    +		match_byte <<= 1;
    +		const uint32_t match_bit = match_byte & offset;
    +		const uint32_t subcoder_index
    +				= offset + match_bit + (symbol >> 8);
    +		const uint32_t bit = (symbol >> 7) & 1;
    +		rc_bit(rc, &subcoder[subcoder_index], bit);
    +
    +		symbol <<= 1;
    +		offset &= ~(match_byte ^ symbol);
    +
    +	} while (symbol < (UINT32_C(1) << 16));
    +}
    +
    +
    +static inline void
    +literal(lzma_lzma1_encoder *coder, lzma_mf *mf, uint32_t position)
    +{
    +	// Locate the literal byte to be encoded and the subcoder.
    +	const uint8_t cur_byte = mf->buffer[
    +			mf->read_pos - mf->read_ahead];
    +	probability *subcoder = literal_subcoder(coder->literal,
    +			coder->literal_context_bits, coder->literal_mask,
    +			position, mf->buffer[mf->read_pos - mf->read_ahead - 1]);
    +
    +	if (is_literal_state(coder->state)) {
    +		// Previous LZMA-symbol was a literal. Encode a normal
    +		// literal without a match byte.
    +		update_literal_normal(coder->state);
    +		rc_bittree(&coder->rc, subcoder, 8, cur_byte);
    +	} else {
    +		// Previous LZMA-symbol was a match. Use the last byte of
    +		// the match as a "match byte". That is, compare the bits
    +		// of the current literal and the match byte.
    +		update_literal_matched(coder->state);
    +		const uint8_t match_byte = mf->buffer[
    +				mf->read_pos - coder->reps[0] - 1
    +				- mf->read_ahead];
    +		literal_matched(&coder->rc, subcoder, match_byte, cur_byte);
    +	}
    +}
    +
    +
    +//////////////////
    +// Match length //
    +//////////////////
    +
    +static void
    +length_update_prices(lzma_length_encoder *lc, const uint32_t pos_state)
    +{
    +	const uint32_t table_size = lc->table_size;
    +	lc->counters[pos_state] = table_size;
    +
    +	const uint32_t a0 = rc_bit_0_price(lc->choice);
    +	const uint32_t a1 = rc_bit_1_price(lc->choice);
    +	const uint32_t b0 = a1 + rc_bit_0_price(lc->choice2);
    +	const uint32_t b1 = a1 + rc_bit_1_price(lc->choice2);
    +	uint32_t *const prices = lc->prices[pos_state];
    +
    +	uint32_t i;
    +	for (i = 0; i < table_size && i < LEN_LOW_SYMBOLS; ++i)
    +		prices[i] = a0 + rc_bittree_price(lc->low[pos_state],
    +				LEN_LOW_BITS, i);
    +
    +	for (; i < table_size && i < LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; ++i)
    +		prices[i] = b0 + rc_bittree_price(lc->mid[pos_state],
    +				LEN_MID_BITS, i - LEN_LOW_SYMBOLS);
    +
    +	for (; i < table_size; ++i)
    +		prices[i] = b1 + rc_bittree_price(lc->high, LEN_HIGH_BITS,
    +				i - LEN_LOW_SYMBOLS - LEN_MID_SYMBOLS);
    +
    +	return;
    +}
    +
    +
    +static inline void
    +length(lzma_range_encoder *rc, lzma_length_encoder *lc,
    +		const uint32_t pos_state, uint32_t len, const bool fast_mode)
    +{
    +	assert(len <= MATCH_LEN_MAX);
    +	len -= MATCH_LEN_MIN;
    +
    +	if (len < LEN_LOW_SYMBOLS) {
    +		rc_bit(rc, &lc->choice, 0);
    +		rc_bittree(rc, lc->low[pos_state], LEN_LOW_BITS, len);
    +	} else {
    +		rc_bit(rc, &lc->choice, 1);
    +		len -= LEN_LOW_SYMBOLS;
    +
    +		if (len < LEN_MID_SYMBOLS) {
    +			rc_bit(rc, &lc->choice2, 0);
    +			rc_bittree(rc, lc->mid[pos_state], LEN_MID_BITS, len);
    +		} else {
    +			rc_bit(rc, &lc->choice2, 1);
    +			len -= LEN_MID_SYMBOLS;
    +			rc_bittree(rc, lc->high, LEN_HIGH_BITS, len);
    +		}
    +	}
    +
    +	// Only getoptimum uses the prices so don't update the table when
    +	// in fast mode.
    +	if (!fast_mode)
    +		if (--lc->counters[pos_state] == 0)
    +			length_update_prices(lc, pos_state);
    +}
    +
    +
    +///////////
    +// Match //
    +///////////
    +
    +static inline void
    +match(lzma_lzma1_encoder *coder, const uint32_t pos_state,
    +		const uint32_t distance, const uint32_t len)
    +{
    +	update_match(coder->state);
    +
    +	length(&coder->rc, &coder->match_len_encoder, pos_state, len,
    +			coder->fast_mode);
    +
    +	const uint32_t dist_slot = get_dist_slot(distance);
    +	const uint32_t dist_state = get_dist_state(len);
    +	rc_bittree(&coder->rc, coder->dist_slot[dist_state],
    +			DIST_SLOT_BITS, dist_slot);
    +
    +	if (dist_slot >= DIST_MODEL_START) {
    +		const uint32_t footer_bits = (dist_slot >> 1) - 1;
    +		const uint32_t base = (2 | (dist_slot & 1)) << footer_bits;
    +		const uint32_t dist_reduced = distance - base;
    +
    +		if (dist_slot < DIST_MODEL_END) {
    +			// Careful here: base - dist_slot - 1 can be -1, but
    +			// rc_bittree_reverse starts at probs[1], not probs[0].
    +			rc_bittree_reverse(&coder->rc,
    +				coder->dist_special + base - dist_slot - 1,
    +				footer_bits, dist_reduced);
    +		} else {
    +			rc_direct(&coder->rc, dist_reduced >> ALIGN_BITS,
    +					footer_bits - ALIGN_BITS);
    +			rc_bittree_reverse(
    +					&coder->rc, coder->dist_align,
    +					ALIGN_BITS, dist_reduced & ALIGN_MASK);
    +			++coder->align_price_count;
    +		}
    +	}
    +
    +	coder->reps[3] = coder->reps[2];
    +	coder->reps[2] = coder->reps[1];
    +	coder->reps[1] = coder->reps[0];
    +	coder->reps[0] = distance;
    +	++coder->match_price_count;
    +}
    +
    +
    +////////////////////
    +// Repeated match //
    +////////////////////
    +
    +static inline void
    +rep_match(lzma_lzma1_encoder *coder, const uint32_t pos_state,
    +		const uint32_t rep, const uint32_t len)
    +{
    +	if (rep == 0) {
    +		rc_bit(&coder->rc, &coder->is_rep0[coder->state], 0);
    +		rc_bit(&coder->rc,
    +				&coder->is_rep0_long[coder->state][pos_state],
    +				len != 1);
    +	} else {
    +		const uint32_t distance = coder->reps[rep];
    +		rc_bit(&coder->rc, &coder->is_rep0[coder->state], 1);
    +
    +		if (rep == 1) {
    +			rc_bit(&coder->rc, &coder->is_rep1[coder->state], 0);
    +		} else {
    +			rc_bit(&coder->rc, &coder->is_rep1[coder->state], 1);
    +			rc_bit(&coder->rc, &coder->is_rep2[coder->state],
    +					rep - 2);
    +
    +			if (rep == 3)
    +				coder->reps[3] = coder->reps[2];
    +
    +			coder->reps[2] = coder->reps[1];
    +		}
    +
    +		coder->reps[1] = coder->reps[0];
    +		coder->reps[0] = distance;
    +	}
    +
    +	if (len == 1) {
    +		update_short_rep(coder->state);
    +	} else {
    +		length(&coder->rc, &coder->rep_len_encoder, pos_state, len,
    +				coder->fast_mode);
    +		update_long_rep(coder->state);
    +	}
    +}
    +
    +
    +//////////
    +// Main //
    +//////////
    +
    +static void
    +encode_symbol(lzma_lzma1_encoder *coder, lzma_mf *mf,
    +		uint32_t back, uint32_t len, uint32_t position)
    +{
    +	const uint32_t pos_state = position & coder->pos_mask;
    +
    +	if (back == UINT32_MAX) {
    +		// Literal i.e. eight-bit byte
    +		assert(len == 1);
    +		rc_bit(&coder->rc,
    +				&coder->is_match[coder->state][pos_state], 0);
    +		literal(coder, mf, position);
    +	} else {
    +		// Some type of match
    +		rc_bit(&coder->rc,
    +			&coder->is_match[coder->state][pos_state], 1);
    +
    +		if (back < REPS) {
    +			// It's a repeated match i.e. the same distance
    +			// has been used earlier.
    +			rc_bit(&coder->rc, &coder->is_rep[coder->state], 1);
    +			rep_match(coder, pos_state, back, len);
    +		} else {
    +			// Normal match
    +			rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);
    +			match(coder, pos_state, back - REPS, len);
    +		}
    +	}
    +
    +	assert(mf->read_ahead >= len);
    +	mf->read_ahead -= len;
    +}
    +
    +
    +static bool
    +encode_init(lzma_lzma1_encoder *coder, lzma_mf *mf)
    +{
    +	assert(mf_position(mf) == 0);
    +	assert(coder->uncomp_size == 0);
    +
    +	if (mf->read_pos == mf->read_limit) {
    +		if (mf->action == LZMA_RUN)
    +			return false; // We cannot do anything.
    +
    +		// We are finishing (we cannot get here when flushing).
    +		assert(mf->write_pos == mf->read_pos);
    +		assert(mf->action == LZMA_FINISH);
    +	} else {
    +		// Do the actual initialization. The first LZMA symbol must
    +		// always be a literal.
    +		mf_skip(mf, 1);
    +		mf->read_ahead = 0;
    +		rc_bit(&coder->rc, &coder->is_match[0][0], 0);
    +		rc_bittree(&coder->rc, coder->literal + 0, 8, mf->buffer[0]);
    +		++coder->uncomp_size;
    +	}
    +
    +	// Initialization is done (except if empty file).
    +	coder->is_initialized = true;
    +
    +	return true;
    +}
    +
    +
    +static void
    +encode_eopm(lzma_lzma1_encoder *coder, uint32_t position)
    +{
    +	const uint32_t pos_state = position & coder->pos_mask;
    +	rc_bit(&coder->rc, &coder->is_match[coder->state][pos_state], 1);
    +	rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);
    +	match(coder, pos_state, UINT32_MAX, MATCH_LEN_MIN);
    +}
    +
    +
    +/// Number of bytes that a single encoding loop in lzma_lzma_encode() can
    +/// consume from the dictionary. This limit comes from lzma_lzma_optimum()
    +/// and may need to be updated if that function is significantly modified.
    +#define LOOP_INPUT_MAX (OPTS + 1)
    +
    +
    +extern lzma_ret
    +lzma_lzma_encode(lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,
    +		uint8_t *restrict out, size_t *restrict out_pos,
    +		size_t out_size, uint32_t limit)
    +{
    +	// Initialize the stream if no data has been encoded yet.
    +	if (!coder->is_initialized && !encode_init(coder, mf))
    +		return LZMA_OK;
    +
    +	// Encode pending output bytes from the range encoder.
    +	// At the start of the stream, encode_init() encodes one literal.
    +	// Later there can be pending output only with LZMA1 because LZMA2
    +	// ensures that there is always enough output space. Thus when using
    +	// LZMA2, rc_encode() calls in this function will always return false.
    +	if (rc_encode(&coder->rc, out, out_pos, out_size)) {
    +		// We don't get here with LZMA2.
    +		assert(limit == UINT32_MAX);
    +		return LZMA_OK;
    +	}
    +
    +	// If the range encoder was flushed in an earlier call to this
    +	// function but there wasn't enough output buffer space, those
    +	// bytes would have now been encoded by the above rc_encode() call
    +	// and the stream has now been finished. This can only happen with
    +	// LZMA1 as LZMA2 always provides enough output buffer space.
    +	if (coder->is_flushed) {
    +		assert(limit == UINT32_MAX);
    +		return LZMA_STREAM_END;
    +	}
    +
    +	while (true) {
    +		// With LZMA2 we need to take care that compressed size of
    +		// a chunk doesn't get too big.
    +		// FIXME? Check if this could be improved.
    +		if (limit != UINT32_MAX
    +				&& (mf->read_pos - mf->read_ahead >= limit
    +					|| *out_pos + rc_pending(&coder->rc)
    +						>= LZMA2_CHUNK_MAX
    +							- LOOP_INPUT_MAX))
    +			break;
    +
    +		// Check that there is some input to process.
    +		if (mf->read_pos >= mf->read_limit) {
    +			if (mf->action == LZMA_RUN)
    +				return LZMA_OK;
    +
    +			if (mf->read_ahead == 0)
    +				break;
    +		}
    +
    +		// Get optimal match (repeat position and length).
    +		// Value ranges for pos:
    +		//   - [0, REPS): repeated match
    +		//   - [REPS, UINT32_MAX):
    +		//     match at (pos - REPS)
    +		//   - UINT32_MAX: not a match but a literal
    +		// Value ranges for len:
    +		//   - [MATCH_LEN_MIN, MATCH_LEN_MAX]
    +		uint32_t len;
    +		uint32_t back;
    +
    +		if (coder->fast_mode)
    +			lzma_lzma_optimum_fast(coder, mf, &back, &len);
    +		else
    +			lzma_lzma_optimum_normal(coder, mf, &back, &len,
    +					(uint32_t)(coder->uncomp_size));
    +
    +		encode_symbol(coder, mf, back, len,
    +				(uint32_t)(coder->uncomp_size));
    +
    +		// If output size limiting is active (out_limit != 0), check
    +		// if encoding this LZMA symbol would make the output size
    +		// exceed the specified limit.
    +		if (coder->out_limit != 0 && rc_encode_dummy(
    +				&coder->rc, coder->out_limit)) {
    +			// The most recent LZMA symbol would make the output
    +			// too big. Throw it away.
    +			rc_forget(&coder->rc);
    +
    +			// FIXME: Tell the LZ layer to not read more input as
    +			// it would be waste of time. This doesn't matter if
    +			// output-size-limited encoding is done with a single
    +			// call though.
    +
    +			break;
    +		}
    +
    +		// This symbol will be encoded so update the uncompressed size.
    +		coder->uncomp_size += len;
    +
    +		// Encode the LZMA symbol.
    +		if (rc_encode(&coder->rc, out, out_pos, out_size)) {
    +			// Once again, this can only happen with LZMA1.
    +			assert(limit == UINT32_MAX);
    +			return LZMA_OK;
    +		}
    +	}
    +
    +	// Make the uncompressed size available to the application.
    +	if (coder->uncomp_size_ptr != NULL)
    +		*coder->uncomp_size_ptr = coder->uncomp_size;
    +
    +	// LZMA2 doesn't use EOPM at LZMA level.
    +	//
    +	// Plain LZMA streams without EOPM aren't supported except when
    +	// output size limiting is enabled.
    +	if (coder->use_eopm)
    +		encode_eopm(coder, (uint32_t)(coder->uncomp_size));
    +
    +	// Flush the remaining bytes from the range encoder.
    +	rc_flush(&coder->rc);
    +
    +	// Copy the remaining bytes to the output buffer. If there
    +	// isn't enough output space, we will copy out the remaining
    +	// bytes on the next call to this function.
    +	if (rc_encode(&coder->rc, out, out_pos, out_size)) {
    +		// This cannot happen with LZMA2.
    +		assert(limit == UINT32_MAX);
    +
    +		coder->is_flushed = true;
    +		return LZMA_OK;
    +	}
    +
    +	return LZMA_STREAM_END;
    +}
    +
    +
    +static lzma_ret
    +lzma_encode(void *coder, lzma_mf *restrict mf,
    +		uint8_t *restrict out, size_t *restrict out_pos,
    +		size_t out_size)
    +{
    +	// Plain LZMA has no support for sync-flushing.
    +	if (unlikely(mf->action == LZMA_SYNC_FLUSH))
    +		return LZMA_OPTIONS_ERROR;
    +
    +	return lzma_lzma_encode(coder, mf, out, out_pos, out_size, UINT32_MAX);
    +}
    +
    +
    +static lzma_ret
    +lzma_lzma_set_out_limit(
    +		void *coder_ptr, uint64_t *uncomp_size, uint64_t out_limit)
    +{
    +	// Minimum output size is 5 bytes but that cannot hold any output
    +	// so we use 6 bytes.
    +	if (out_limit < 6)
    +		return LZMA_BUF_ERROR;
    +
    +	lzma_lzma1_encoder *coder = coder_ptr;
    +	coder->out_limit = out_limit;
    +	coder->uncomp_size_ptr = uncomp_size;
    +	coder->use_eopm = false;
    +	return LZMA_OK;
    +}
    +
    +
    +////////////////////
    +// Initialization //
    +////////////////////
    +
    +static bool
    +is_options_valid(const lzma_options_lzma *options)
    +{
    +	// Validate some of the options. LZ encoder validates nice_len too
    +	// but we need a valid value here earlier.
    +	return is_lclppb_valid(options)
    +			&& options->nice_len >= MATCH_LEN_MIN
    +			&& options->nice_len <= MATCH_LEN_MAX
    +			&& (options->mode == LZMA_MODE_FAST
    +				|| options->mode == LZMA_MODE_NORMAL);
    +}
    +
    +
    +static void
    +set_lz_options(lzma_lz_options *lz_options, const lzma_options_lzma *options)
    +{
    +	// LZ encoder initialization does the validation for these so we
    +	// don't need to validate here.
    +	lz_options->before_size = OPTS;
    +	lz_options->dict_size = options->dict_size;
    +	lz_options->after_size = LOOP_INPUT_MAX;
    +	lz_options->match_len_max = MATCH_LEN_MAX;
    +	lz_options->nice_len = my_max(mf_get_hash_bytes(options->mf),
    +				options->nice_len);
    +	lz_options->match_finder = options->mf;
    +	lz_options->depth = options->depth;
    +	lz_options->preset_dict = options->preset_dict;
    +	lz_options->preset_dict_size = options->preset_dict_size;
    +	return;
    +}
    +
    +
    +static void
    +length_encoder_reset(lzma_length_encoder *lencoder,
    +		const uint32_t num_pos_states, const bool fast_mode)
    +{
    +	bit_reset(lencoder->choice);
    +	bit_reset(lencoder->choice2);
    +
    +	for (size_t pos_state = 0; pos_state < num_pos_states; ++pos_state) {
    +		bittree_reset(lencoder->low[pos_state], LEN_LOW_BITS);
    +		bittree_reset(lencoder->mid[pos_state], LEN_MID_BITS);
    +	}
    +
    +	bittree_reset(lencoder->high, LEN_HIGH_BITS);
    +
    +	if (!fast_mode)
    +		for (uint32_t pos_state = 0; pos_state < num_pos_states;
    +				++pos_state)
    +			length_update_prices(lencoder, pos_state);
    +
    +	return;
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma_encoder_reset(lzma_lzma1_encoder *coder,
    +		const lzma_options_lzma *options)
    +{
    +	if (!is_options_valid(options))
    +		return LZMA_OPTIONS_ERROR;
    +
    +	coder->pos_mask = (1U << options->pb) - 1;
    +	coder->literal_context_bits = options->lc;
    +	coder->literal_mask = literal_mask_calc(options->lc, options->lp);
    +
    +	// Range coder
    +	rc_reset(&coder->rc);
    +
    +	// State
    +	coder->state = STATE_LIT_LIT;
    +	for (size_t i = 0; i < REPS; ++i)
    +		coder->reps[i] = 0;
    +
    +	literal_init(coder->literal, options->lc, options->lp);
    +
    +	// Bit encoders
    +	for (size_t i = 0; i < STATES; ++i) {
    +		for (size_t j = 0; j <= coder->pos_mask; ++j) {
    +			bit_reset(coder->is_match[i][j]);
    +			bit_reset(coder->is_rep0_long[i][j]);
    +		}
    +
    +		bit_reset(coder->is_rep[i]);
    +		bit_reset(coder->is_rep0[i]);
    +		bit_reset(coder->is_rep1[i]);
    +		bit_reset(coder->is_rep2[i]);
    +	}
    +
    +	for (size_t i = 0; i < FULL_DISTANCES - DIST_MODEL_END; ++i)
    +		bit_reset(coder->dist_special[i]);
    +
    +	// Bit tree encoders
    +	for (size_t i = 0; i < DIST_STATES; ++i)
    +		bittree_reset(coder->dist_slot[i], DIST_SLOT_BITS);
    +
    +	bittree_reset(coder->dist_align, ALIGN_BITS);
    +
    +	// Length encoders
    +	length_encoder_reset(&coder->match_len_encoder,
    +			1U << options->pb, coder->fast_mode);
    +
    +	length_encoder_reset(&coder->rep_len_encoder,
    +			1U << options->pb, coder->fast_mode);
    +
    +	// Price counts are incremented every time appropriate probabilities
    +	// are changed. price counts are set to zero when the price tables
    +	// are updated, which is done when the appropriate price counts have
    +	// big enough value, and lzma_mf.read_ahead == 0 which happens at
    +	// least every OPTS (a few thousand) possible price count increments.
    +	//
    +	// By resetting price counts to UINT32_MAX / 2, we make sure that the
    +	// price tables will be initialized before they will be used (since
    +	// the value is definitely big enough), and that it is OK to increment
    +	// price counts without risk of integer overflow (since UINT32_MAX / 2
    +	// is small enough). The current code doesn't increment price counts
    +	// before initializing price tables, but it maybe done in future if
    +	// we add support for saving the state between LZMA2 chunks.
    +	coder->match_price_count = UINT32_MAX / 2;
    +	coder->align_price_count = UINT32_MAX / 2;
    +
    +	coder->opts_end_index = 0;
    +	coder->opts_current_index = 0;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma_encoder_create(void **coder_ptr, const lzma_allocator *allocator,
    +		lzma_vli id, const lzma_options_lzma *options,
    +		lzma_lz_options *lz_options)
    +{
    +	assert(id == LZMA_FILTER_LZMA1 || id == LZMA_FILTER_LZMA1EXT
    +			|| id == LZMA_FILTER_LZMA2);
    +
    +	// Allocate lzma_lzma1_encoder if it wasn't already allocated.
    +	if (*coder_ptr == NULL) {
    +		*coder_ptr = lzma_alloc(sizeof(lzma_lzma1_encoder), allocator);
    +		if (*coder_ptr == NULL)
    +			return LZMA_MEM_ERROR;
    +	}
    +
    +	lzma_lzma1_encoder *coder = *coder_ptr;
    +
    +	// Set compression mode. Note that we haven't validated the options
    +	// yet. Invalid options will get rejected by lzma_lzma_encoder_reset()
    +	// call at the end of this function.
    +	switch (options->mode) {
    +		case LZMA_MODE_FAST:
    +			coder->fast_mode = true;
    +			break;
    +
    +		case LZMA_MODE_NORMAL: {
    +			coder->fast_mode = false;
    +
    +			// Set dist_table_size.
    +			// Round the dictionary size up to next 2^n.
    +			//
    +			// Currently the maximum encoder dictionary size
    +			// is 1.5 GiB due to lz_encoder.c and here we need
    +			// to be below 2 GiB to make the rounded up value
    +			// fit in an uint32_t and avoid an infinite while-loop
    +			// (and undefined behavior due to a too large shift).
    +			// So do the same check as in LZ encoder,
    +			// limiting to 1.5 GiB.
    +			if (options->dict_size > (UINT32_C(1) << 30)
    +					+ (UINT32_C(1) << 29))
    +				return LZMA_OPTIONS_ERROR;
    +
    +			uint32_t log_size = 0;
    +			while ((UINT32_C(1) << log_size) < options->dict_size)
    +				++log_size;
    +
    +			coder->dist_table_size = log_size * 2;
    +
    +			// Length encoders' price table size
    +			const uint32_t nice_len = my_max(
    +					mf_get_hash_bytes(options->mf),
    +					options->nice_len);
    +
    +			coder->match_len_encoder.table_size
    +					= nice_len + 1 - MATCH_LEN_MIN;
    +			coder->rep_len_encoder.table_size
    +					= nice_len + 1 - MATCH_LEN_MIN;
    +			break;
    +		}
    +
    +		default:
    +			return LZMA_OPTIONS_ERROR;
    +	}
    +
    +	// We don't need to write the first byte as literal if there is
    +	// a non-empty preset dictionary. encode_init() wouldn't even work
    +	// if there is a non-empty preset dictionary, because encode_init()
    +	// assumes that position is zero and previous byte is also zero.
    +	coder->is_initialized = options->preset_dict != NULL
    +			&& options->preset_dict_size > 0;
    +	coder->is_flushed = false;
    +	coder->uncomp_size = 0;
    +	coder->uncomp_size_ptr = NULL;
    +
    +	// Output size limiting is disabled by default.
    +	coder->out_limit = 0;
    +
    +	// Determine if end marker is wanted:
    +	//   - It is never used with LZMA2.
    +	//   - It is always used with LZMA_FILTER_LZMA1 (unless
    +	//     lzma_lzma_set_out_limit() is called later).
    +	//   - LZMA_FILTER_LZMA1EXT has a flag for it in the options.
    +	coder->use_eopm = (id == LZMA_FILTER_LZMA1);
    +	if (id == LZMA_FILTER_LZMA1EXT) {
    +		// Check if unsupported flags are present.
    +		if (options->ext_flags & ~LZMA_LZMA1EXT_ALLOW_EOPM)
    +			return LZMA_OPTIONS_ERROR;
    +
    +		coder->use_eopm = (options->ext_flags
    +				& LZMA_LZMA1EXT_ALLOW_EOPM) != 0;
    +
    +		// TODO? As long as there are no filters that change the size
    +		// of the data, it is enough to look at lzma_stream.total_in
    +		// after encoding has been finished to know the uncompressed
    +		// size of the LZMA1 stream. But in the future there could be
    +		// filters that change the size of the data and then total_in
    +		// doesn't work as the LZMA1 stream size might be different
    +		// due to another filter in the chain. The problem is simple
    +		// to solve: Add another flag to ext_flags and then set
    +		// coder->uncomp_size_ptr to the address stored in
    +		// lzma_options_lzma.reserved_ptr2 (or _ptr1).
    +	}
    +
    +	set_lz_options(lz_options, options);
    +
    +	return lzma_lzma_encoder_reset(coder, options);
    +}
    +
    +
    +static lzma_ret
    +lzma_encoder_init(lzma_lz_encoder *lz, const lzma_allocator *allocator,
    +		lzma_vli id, const void *options, lzma_lz_options *lz_options)
    +{
    +        if (options == NULL)
    +                return LZMA_PROG_ERROR;
    +
    +	lz->code = &lzma_encode;
    +	lz->set_out_limit = &lzma_lzma_set_out_limit;
    +	return lzma_lzma_encoder_create(
    +			&lz->coder, allocator, id, options, lz_options);
    +}
    +
    +
    +extern lzma_ret
    +lzma_lzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return lzma_lz_encoder_init(
    +			next, allocator, filters, &lzma_encoder_init);
    +}
    +
    +
    +extern uint64_t
    +lzma_lzma_encoder_memusage(const void *options)
    +{
    +	if (!is_options_valid(options))
    +		return UINT64_MAX;
    +
    +	lzma_lz_options lz_options;
    +	set_lz_options(&lz_options, options);
    +
    +	const uint64_t lz_memusage = lzma_lz_encoder_memusage(&lz_options);
    +	if (lz_memusage == UINT64_MAX)
    +		return UINT64_MAX;
    +
    +	return (uint64_t)(sizeof(lzma_lzma1_encoder)) + lz_memusage;
    +}
    +
    +
    +extern bool
    +lzma_lzma_lclppb_encode(const lzma_options_lzma *options, uint8_t *byte)
    +{
    +	if (!is_lclppb_valid(options))
    +		return true;
    +
    +	*byte = (options->pb * 5 + options->lp) * 9 + options->lc;
    +	assert(*byte <= (4 * 5 + 4) * 9 + 8);
    +
    +	return false;
    +}
    +
    +
    +#ifdef HAVE_ENCODER_LZMA1
    +extern lzma_ret
    +lzma_lzma_props_encode(const void *options, uint8_t *out)
    +{
    +	if (options == NULL)
    +		return LZMA_PROG_ERROR;
    +
    +	const lzma_options_lzma *const opt = options;
    +
    +	if (lzma_lzma_lclppb_encode(opt, out))
    +		return LZMA_PROG_ERROR;
    +
    +	write32le(out + 1, opt->dict_size);
    +
    +	return LZMA_OK;
    +}
    +#endif
    +
    +
    +extern LZMA_API(lzma_bool)
    +lzma_mode_is_supported(lzma_mode mode)
    +{
    +	return mode == LZMA_MODE_FAST || mode == LZMA_MODE_NORMAL;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.h
    new file mode 100644
    index 00000000000..e8ae8079306
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.h
    @@ -0,0 +1,58 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma_encoder.h
    +/// \brief      LZMA encoder API
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZMA_ENCODER_H
    +#define LZMA_LZMA_ENCODER_H
    +
    +#include "common.h"
    +
    +
    +typedef struct lzma_lzma1_encoder_s lzma_lzma1_encoder;
    +
    +
    +extern lzma_ret lzma_lzma_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +
    +extern uint64_t lzma_lzma_encoder_memusage(const void *options);
    +
    +extern lzma_ret lzma_lzma_props_encode(const void *options, uint8_t *out);
    +
    +
    +/// Encodes lc/lp/pb into one byte. Returns false on success and true on error.
    +extern bool lzma_lzma_lclppb_encode(
    +		const lzma_options_lzma *options, uint8_t *byte);
    +
    +
    +#ifdef LZMA_LZ_ENCODER_H
    +
    +/// Initializes raw LZMA encoder; this is used by LZMA2.
    +extern lzma_ret lzma_lzma_encoder_create(
    +		void **coder_ptr, const lzma_allocator *allocator,
    +		lzma_vli id, const lzma_options_lzma *options,
    +		lzma_lz_options *lz_options);
    +
    +
    +/// Resets an already initialized LZMA encoder; this is used by LZMA2.
    +extern lzma_ret lzma_lzma_encoder_reset(
    +		lzma_lzma1_encoder *coder, const lzma_options_lzma *options);
    +
    +
    +extern lzma_ret lzma_lzma_encode(lzma_lzma1_encoder *restrict coder,
    +		lzma_mf *restrict mf, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size,
    +		uint32_t read_limit);
    +
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c
    new file mode 100644
    index 00000000000..0f063d5be7a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c
    @@ -0,0 +1,169 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma_encoder_optimum_fast.c
    +//
    +//  Author:     Igor Pavlov
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lzma_encoder_private.h"
    +#include "memcmplen.h"
    +
    +
    +#define change_pair(small_dist, big_dist) \
    +	(((big_dist) >> 7) > (small_dist))
    +
    +
    +extern void
    +lzma_lzma_optimum_fast(lzma_lzma1_encoder *restrict coder,
    +		lzma_mf *restrict mf,
    +		uint32_t *restrict back_res, uint32_t *restrict len_res)
    +{
    +	const uint32_t nice_len = mf->nice_len;
    +
    +	uint32_t len_main;
    +	uint32_t matches_count;
    +	if (mf->read_ahead == 0) {
    +		len_main = mf_find(mf, &matches_count, coder->matches);
    +	} else {
    +		assert(mf->read_ahead == 1);
    +		len_main = coder->longest_match_length;
    +		matches_count = coder->matches_count;
    +	}
    +
    +	const uint8_t *buf = mf_ptr(mf) - 1;
    +	const uint32_t buf_avail = my_min(mf_avail(mf) + 1, MATCH_LEN_MAX);
    +
    +	if (buf_avail < 2) {
    +		// There's not enough input left to encode a match.
    +		*back_res = UINT32_MAX;
    +		*len_res = 1;
    +		return;
    +	}
    +
    +	// Look for repeated matches; scan the previous four match distances
    +	uint32_t rep_len = 0;
    +	uint32_t rep_index = 0;
    +
    +	for (uint32_t i = 0; i < REPS; ++i) {
    +		// Pointer to the beginning of the match candidate
    +		const uint8_t *const buf_back = buf - coder->reps[i] - 1;
    +
    +		// If the first two bytes (2 == MATCH_LEN_MIN) do not match,
    +		// this rep is not useful.
    +		if (not_equal_16(buf, buf_back))
    +			continue;
    +
    +		// The first two bytes matched.
    +		// Calculate the length of the match.
    +		const uint32_t len = lzma_memcmplen(
    +				buf, buf_back, 2, buf_avail);
    +
    +		// If we have found a repeated match that is at least
    +		// nice_len long, return it immediately.
    +		if (len >= nice_len) {
    +			*back_res = i;
    +			*len_res = len;
    +			mf_skip(mf, len - 1);
    +			return;
    +		}
    +
    +		if (len > rep_len) {
    +			rep_index = i;
    +			rep_len = len;
    +		}
    +	}
    +
    +	// We didn't find a long enough repeated match. Encode it as a normal
    +	// match if the match length is at least nice_len.
    +	if (len_main >= nice_len) {
    +		*back_res = coder->matches[matches_count - 1].dist + REPS;
    +		*len_res = len_main;
    +		mf_skip(mf, len_main - 1);
    +		return;
    +	}
    +
    +	uint32_t back_main = 0;
    +	if (len_main >= 2) {
    +		back_main = coder->matches[matches_count - 1].dist;
    +
    +		while (matches_count > 1 && len_main ==
    +				coder->matches[matches_count - 2].len + 1) {
    +			if (!change_pair(coder->matches[
    +						matches_count - 2].dist,
    +					back_main))
    +				break;
    +
    +			--matches_count;
    +			len_main = coder->matches[matches_count - 1].len;
    +			back_main = coder->matches[matches_count - 1].dist;
    +		}
    +
    +		if (len_main == 2 && back_main >= 0x80)
    +			len_main = 1;
    +	}
    +
    +	if (rep_len >= 2) {
    +		if (rep_len + 1 >= len_main
    +				|| (rep_len + 2 >= len_main
    +					&& back_main > (UINT32_C(1) << 9))
    +				|| (rep_len + 3 >= len_main
    +					&& back_main > (UINT32_C(1) << 15))) {
    +			*back_res = rep_index;
    +			*len_res = rep_len;
    +			mf_skip(mf, rep_len - 1);
    +			return;
    +		}
    +	}
    +
    +	if (len_main < 2 || buf_avail <= 2) {
    +		*back_res = UINT32_MAX;
    +		*len_res = 1;
    +		return;
    +	}
    +
    +	// Get the matches for the next byte. If we find a better match,
    +	// the current byte is encoded as a literal.
    +	coder->longest_match_length = mf_find(mf,
    +			&coder->matches_count, coder->matches);
    +
    +	if (coder->longest_match_length >= 2) {
    +		const uint32_t new_dist = coder->matches[
    +				coder->matches_count - 1].dist;
    +
    +		if ((coder->longest_match_length >= len_main
    +					&& new_dist < back_main)
    +				|| (coder->longest_match_length == len_main + 1
    +					&& !change_pair(back_main, new_dist))
    +				|| (coder->longest_match_length > len_main + 1)
    +				|| (coder->longest_match_length + 1 >= len_main
    +					&& len_main >= 3
    +					&& change_pair(new_dist, back_main))) {
    +			*back_res = UINT32_MAX;
    +			*len_res = 1;
    +			return;
    +		}
    +	}
    +
    +	// In contrast to LZMA SDK, dictionary could not have been moved
    +	// between mf_find() calls, thus it is safe to just increment
    +	// the old buf pointer instead of recalculating it with mf_ptr().
    +	++buf;
    +
    +	const uint32_t limit = my_max(2, len_main - 1);
    +
    +	for (uint32_t i = 0; i < REPS; ++i) {
    +		if (memcmp(buf, buf - coder->reps[i] - 1, limit) == 0) {
    +			*back_res = UINT32_MAX;
    +			*len_res = 1;
    +			return;
    +		}
    +	}
    +
    +	*back_res = back_main + REPS;
    +	*len_res = len_main;
    +	mf_skip(mf, len_main - 2);
    +	return;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c
    new file mode 100644
    index 00000000000..a6c0398f3af
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c
    @@ -0,0 +1,858 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma_encoder_optimum_normal.c
    +//
    +//  Author:     Igor Pavlov
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "lzma_encoder_private.h"
    +#include "fastpos.h"
    +#include "memcmplen.h"
    +
    +
    +////////////
    +// Prices //
    +////////////
    +
    +static uint32_t
    +get_literal_price(const lzma_lzma1_encoder *const coder, const uint32_t pos,
    +		const uint32_t prev_byte, const bool match_mode,
    +		uint32_t match_byte, uint32_t symbol)
    +{
    +	const probability *const subcoder = literal_subcoder(coder->literal,
    +			coder->literal_context_bits, coder->literal_mask,
    +			pos, prev_byte);
    +
    +	uint32_t price = 0;
    +
    +	if (!match_mode) {
    +		price = rc_bittree_price(subcoder, 8, symbol);
    +	} else {
    +		uint32_t offset = 0x100;
    +		symbol += UINT32_C(1) << 8;
    +
    +		do {
    +			match_byte <<= 1;
    +
    +			const uint32_t match_bit = match_byte & offset;
    +			const uint32_t subcoder_index
    +					= offset + match_bit + (symbol >> 8);
    +			const uint32_t bit = (symbol >> 7) & 1;
    +			price += rc_bit_price(subcoder[subcoder_index], bit);
    +
    +			symbol <<= 1;
    +			offset &= ~(match_byte ^ symbol);
    +
    +		} while (symbol < (UINT32_C(1) << 16));
    +	}
    +
    +	return price;
    +}
    +
    +
    +static inline uint32_t
    +get_len_price(const lzma_length_encoder *const lencoder,
    +		const uint32_t len, const uint32_t pos_state)
    +{
    +	// NOTE: Unlike the other price tables, length prices are updated
    +	// in lzma_encoder.c
    +	return lencoder->prices[pos_state][len - MATCH_LEN_MIN];
    +}
    +
    +
    +static inline uint32_t
    +get_short_rep_price(const lzma_lzma1_encoder *const coder,
    +		const lzma_lzma_state state, const uint32_t pos_state)
    +{
    +	return rc_bit_0_price(coder->is_rep0[state])
    +		+ rc_bit_0_price(coder->is_rep0_long[state][pos_state]);
    +}
    +
    +
    +static inline uint32_t
    +get_pure_rep_price(const lzma_lzma1_encoder *const coder, const uint32_t rep_index,
    +		const lzma_lzma_state state, uint32_t pos_state)
    +{
    +	uint32_t price;
    +
    +	if (rep_index == 0) {
    +		price = rc_bit_0_price(coder->is_rep0[state]);
    +		price += rc_bit_1_price(coder->is_rep0_long[state][pos_state]);
    +	} else {
    +		price = rc_bit_1_price(coder->is_rep0[state]);
    +
    +		if (rep_index == 1) {
    +			price += rc_bit_0_price(coder->is_rep1[state]);
    +		} else {
    +			price += rc_bit_1_price(coder->is_rep1[state]);
    +			price += rc_bit_price(coder->is_rep2[state],
    +					rep_index - 2);
    +		}
    +	}
    +
    +	return price;
    +}
    +
    +
    +static inline uint32_t
    +get_rep_price(const lzma_lzma1_encoder *const coder, const uint32_t rep_index,
    +		const uint32_t len, const lzma_lzma_state state,
    +		const uint32_t pos_state)
    +{
    +	return get_len_price(&coder->rep_len_encoder, len, pos_state)
    +		+ get_pure_rep_price(coder, rep_index, state, pos_state);
    +}
    +
    +
    +static inline uint32_t
    +get_dist_len_price(const lzma_lzma1_encoder *const coder, const uint32_t dist,
    +		const uint32_t len, const uint32_t pos_state)
    +{
    +	const uint32_t dist_state = get_dist_state(len);
    +	uint32_t price;
    +
    +	if (dist < FULL_DISTANCES) {
    +		price = coder->dist_prices[dist_state][dist];
    +	} else {
    +		const uint32_t dist_slot = get_dist_slot_2(dist);
    +		price = coder->dist_slot_prices[dist_state][dist_slot]
    +				+ coder->align_prices[dist & ALIGN_MASK];
    +	}
    +
    +	price += get_len_price(&coder->match_len_encoder, len, pos_state);
    +
    +	return price;
    +}
    +
    +
    +static void
    +fill_dist_prices(lzma_lzma1_encoder *coder)
    +{
    +	for (uint32_t dist_state = 0; dist_state < DIST_STATES; ++dist_state) {
    +
    +		uint32_t *const dist_slot_prices
    +				= coder->dist_slot_prices[dist_state];
    +
    +		// Price to encode the dist_slot.
    +		for (uint32_t dist_slot = 0;
    +				dist_slot < coder->dist_table_size; ++dist_slot)
    +			dist_slot_prices[dist_slot] = rc_bittree_price(
    +					coder->dist_slot[dist_state],
    +					DIST_SLOT_BITS, dist_slot);
    +
    +		// For matches with distance >= FULL_DISTANCES, add the price
    +		// of the direct bits part of the match distance. (Align bits
    +		// are handled by fill_align_prices()).
    +		for (uint32_t dist_slot = DIST_MODEL_END;
    +				dist_slot < coder->dist_table_size;
    +				++dist_slot)
    +			dist_slot_prices[dist_slot] += rc_direct_price(
    +					((dist_slot >> 1) - 1) - ALIGN_BITS);
    +
    +		// Distances in the range [0, 3] are fully encoded with
    +		// dist_slot, so they are used for coder->dist_prices
    +		// as is.
    +		for (uint32_t i = 0; i < DIST_MODEL_START; ++i)
    +			coder->dist_prices[dist_state][i]
    +					= dist_slot_prices[i];
    +	}
    +
    +	// Distances in the range [4, 127] depend on dist_slot and
    +	// dist_special. We do this in a loop separate from the above
    +	// loop to avoid redundant calls to get_dist_slot().
    +	for (uint32_t i = DIST_MODEL_START; i < FULL_DISTANCES; ++i) {
    +		const uint32_t dist_slot = get_dist_slot(i);
    +		const uint32_t footer_bits = ((dist_slot >> 1) - 1);
    +		const uint32_t base = (2 | (dist_slot & 1)) << footer_bits;
    +		const uint32_t price = rc_bittree_reverse_price(
    +				coder->dist_special + base - dist_slot - 1,
    +				footer_bits, i - base);
    +
    +		for (uint32_t dist_state = 0; dist_state < DIST_STATES;
    +				++dist_state)
    +			coder->dist_prices[dist_state][i]
    +					= price + coder->dist_slot_prices[
    +						dist_state][dist_slot];
    +	}
    +
    +	coder->match_price_count = 0;
    +	return;
    +}
    +
    +
    +static void
    +fill_align_prices(lzma_lzma1_encoder *coder)
    +{
    +	for (uint32_t i = 0; i < ALIGN_SIZE; ++i)
    +		coder->align_prices[i] = rc_bittree_reverse_price(
    +				coder->dist_align, ALIGN_BITS, i);
    +
    +	coder->align_price_count = 0;
    +	return;
    +}
    +
    +
    +/////////////
    +// Optimal //
    +/////////////
    +
    +static inline void
    +make_literal(lzma_optimal *optimal)
    +{
    +	optimal->back_prev = UINT32_MAX;
    +	optimal->prev_1_is_literal = false;
    +}
    +
    +
    +static inline void
    +make_short_rep(lzma_optimal *optimal)
    +{
    +	optimal->back_prev = 0;
    +	optimal->prev_1_is_literal = false;
    +}
    +
    +
    +#define is_short_rep(optimal) \
    +	((optimal).back_prev == 0)
    +
    +
    +static void
    +backward(lzma_lzma1_encoder *restrict coder, uint32_t *restrict len_res,
    +		uint32_t *restrict back_res, uint32_t cur)
    +{
    +	coder->opts_end_index = cur;
    +
    +	uint32_t pos_mem = coder->opts[cur].pos_prev;
    +	uint32_t back_mem = coder->opts[cur].back_prev;
    +
    +	do {
    +		if (coder->opts[cur].prev_1_is_literal) {
    +			make_literal(&coder->opts[pos_mem]);
    +			coder->opts[pos_mem].pos_prev = pos_mem - 1;
    +
    +			if (coder->opts[cur].prev_2) {
    +				coder->opts[pos_mem - 1].prev_1_is_literal
    +						= false;
    +				coder->opts[pos_mem - 1].pos_prev
    +						= coder->opts[cur].pos_prev_2;
    +				coder->opts[pos_mem - 1].back_prev
    +						= coder->opts[cur].back_prev_2;
    +			}
    +		}
    +
    +		const uint32_t pos_prev = pos_mem;
    +		const uint32_t back_cur = back_mem;
    +
    +		back_mem = coder->opts[pos_prev].back_prev;
    +		pos_mem = coder->opts[pos_prev].pos_prev;
    +
    +		coder->opts[pos_prev].back_prev = back_cur;
    +		coder->opts[pos_prev].pos_prev = cur;
    +		cur = pos_prev;
    +
    +	} while (cur != 0);
    +
    +	coder->opts_current_index = coder->opts[0].pos_prev;
    +	*len_res = coder->opts[0].pos_prev;
    +	*back_res = coder->opts[0].back_prev;
    +
    +	return;
    +}
    +
    +
    +//////////
    +// Main //
    +//////////
    +
    +static inline uint32_t
    +helper1(lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,
    +		uint32_t *restrict back_res, uint32_t *restrict len_res,
    +		uint32_t position)
    +{
    +	const uint32_t nice_len = mf->nice_len;
    +
    +	uint32_t len_main;
    +	uint32_t matches_count;
    +
    +	if (mf->read_ahead == 0) {
    +		len_main = mf_find(mf, &matches_count, coder->matches);
    +	} else {
    +		assert(mf->read_ahead == 1);
    +		len_main = coder->longest_match_length;
    +		matches_count = coder->matches_count;
    +	}
    +
    +	const uint32_t buf_avail = my_min(mf_avail(mf) + 1, MATCH_LEN_MAX);
    +	if (buf_avail < 2) {
    +		*back_res = UINT32_MAX;
    +		*len_res = 1;
    +		return UINT32_MAX;
    +	}
    +
    +	const uint8_t *const buf = mf_ptr(mf) - 1;
    +
    +	uint32_t rep_lens[REPS];
    +	uint32_t rep_max_index = 0;
    +
    +	for (uint32_t i = 0; i < REPS; ++i) {
    +		const uint8_t *const buf_back = buf - coder->reps[i] - 1;
    +
    +		if (not_equal_16(buf, buf_back)) {
    +			rep_lens[i] = 0;
    +			continue;
    +		}
    +
    +		rep_lens[i] = lzma_memcmplen(buf, buf_back, 2, buf_avail);
    +
    +		if (rep_lens[i] > rep_lens[rep_max_index])
    +			rep_max_index = i;
    +	}
    +
    +	if (rep_lens[rep_max_index] >= nice_len) {
    +		*back_res = rep_max_index;
    +		*len_res = rep_lens[rep_max_index];
    +		mf_skip(mf, *len_res - 1);
    +		return UINT32_MAX;
    +	}
    +
    +
    +	if (len_main >= nice_len) {
    +		*back_res = coder->matches[matches_count - 1].dist + REPS;
    +		*len_res = len_main;
    +		mf_skip(mf, len_main - 1);
    +		return UINT32_MAX;
    +	}
    +
    +	const uint8_t current_byte = *buf;
    +	const uint8_t match_byte = *(buf - coder->reps[0] - 1);
    +
    +	if (len_main < 2 && current_byte != match_byte
    +			&& rep_lens[rep_max_index] < 2) {
    +		*back_res = UINT32_MAX;
    +		*len_res = 1;
    +		return UINT32_MAX;
    +	}
    +
    +	coder->opts[0].state = coder->state;
    +
    +	const uint32_t pos_state = position & coder->pos_mask;
    +
    +	coder->opts[1].price = rc_bit_0_price(
    +				coder->is_match[coder->state][pos_state])
    +			+ get_literal_price(coder, position, buf[-1],
    +				!is_literal_state(coder->state),
    +				match_byte, current_byte);
    +
    +	make_literal(&coder->opts[1]);
    +
    +	const uint32_t match_price = rc_bit_1_price(
    +			coder->is_match[coder->state][pos_state]);
    +	const uint32_t rep_match_price = match_price
    +			+ rc_bit_1_price(coder->is_rep[coder->state]);
    +
    +	if (match_byte == current_byte) {
    +		const uint32_t short_rep_price = rep_match_price
    +				+ get_short_rep_price(
    +					coder, coder->state, pos_state);
    +
    +		if (short_rep_price < coder->opts[1].price) {
    +			coder->opts[1].price = short_rep_price;
    +			make_short_rep(&coder->opts[1]);
    +		}
    +	}
    +
    +	const uint32_t len_end = my_max(len_main, rep_lens[rep_max_index]);
    +
    +	if (len_end < 2) {
    +		*back_res = coder->opts[1].back_prev;
    +		*len_res = 1;
    +		return UINT32_MAX;
    +	}
    +
    +	coder->opts[1].pos_prev = 0;
    +
    +	for (uint32_t i = 0; i < REPS; ++i)
    +		coder->opts[0].backs[i] = coder->reps[i];
    +
    +	uint32_t len = len_end;
    +	do {
    +		coder->opts[len].price = RC_INFINITY_PRICE;
    +	} while (--len >= 2);
    +
    +
    +	for (uint32_t i = 0; i < REPS; ++i) {
    +		uint32_t rep_len = rep_lens[i];
    +		if (rep_len < 2)
    +			continue;
    +
    +		const uint32_t price = rep_match_price + get_pure_rep_price(
    +				coder, i, coder->state, pos_state);
    +
    +		do {
    +			const uint32_t cur_and_len_price = price
    +					+ get_len_price(
    +						&coder->rep_len_encoder,
    +						rep_len, pos_state);
    +
    +			if (cur_and_len_price < coder->opts[rep_len].price) {
    +				coder->opts[rep_len].price = cur_and_len_price;
    +				coder->opts[rep_len].pos_prev = 0;
    +				coder->opts[rep_len].back_prev = i;
    +				coder->opts[rep_len].prev_1_is_literal = false;
    +			}
    +		} while (--rep_len >= 2);
    +	}
    +
    +
    +	const uint32_t normal_match_price = match_price
    +			+ rc_bit_0_price(coder->is_rep[coder->state]);
    +
    +	len = rep_lens[0] >= 2 ? rep_lens[0] + 1 : 2;
    +	if (len <= len_main) {
    +		uint32_t i = 0;
    +		while (len > coder->matches[i].len)
    +			++i;
    +
    +		for(; ; ++len) {
    +			const uint32_t dist = coder->matches[i].dist;
    +			const uint32_t cur_and_len_price = normal_match_price
    +					+ get_dist_len_price(coder,
    +						dist, len, pos_state);
    +
    +			if (cur_and_len_price < coder->opts[len].price) {
    +				coder->opts[len].price = cur_and_len_price;
    +				coder->opts[len].pos_prev = 0;
    +				coder->opts[len].back_prev = dist + REPS;
    +				coder->opts[len].prev_1_is_literal = false;
    +			}
    +
    +			if (len == coder->matches[i].len)
    +				if (++i == matches_count)
    +					break;
    +		}
    +	}
    +
    +	return len_end;
    +}
    +
    +
    +static inline uint32_t
    +helper2(lzma_lzma1_encoder *coder, uint32_t *reps, const uint8_t *buf,
    +		uint32_t len_end, uint32_t position, const uint32_t cur,
    +		const uint32_t nice_len, const uint32_t buf_avail_full)
    +{
    +	uint32_t matches_count = coder->matches_count;
    +	uint32_t new_len = coder->longest_match_length;
    +	uint32_t pos_prev = coder->opts[cur].pos_prev;
    +	lzma_lzma_state state;
    +
    +	if (coder->opts[cur].prev_1_is_literal) {
    +		--pos_prev;
    +
    +		if (coder->opts[cur].prev_2) {
    +			state = coder->opts[coder->opts[cur].pos_prev_2].state;
    +
    +			if (coder->opts[cur].back_prev_2 < REPS)
    +				update_long_rep(state);
    +			else
    +				update_match(state);
    +
    +		} else {
    +			state = coder->opts[pos_prev].state;
    +		}
    +
    +		update_literal(state);
    +
    +	} else {
    +		state = coder->opts[pos_prev].state;
    +	}
    +
    +	if (pos_prev == cur - 1) {
    +		if (is_short_rep(coder->opts[cur]))
    +			update_short_rep(state);
    +		else
    +			update_literal(state);
    +	} else {
    +		uint32_t pos;
    +		if (coder->opts[cur].prev_1_is_literal
    +				&& coder->opts[cur].prev_2) {
    +			pos_prev = coder->opts[cur].pos_prev_2;
    +			pos = coder->opts[cur].back_prev_2;
    +			update_long_rep(state);
    +		} else {
    +			pos = coder->opts[cur].back_prev;
    +			if (pos < REPS)
    +				update_long_rep(state);
    +			else
    +				update_match(state);
    +		}
    +
    +		if (pos < REPS) {
    +			reps[0] = coder->opts[pos_prev].backs[pos];
    +
    +			uint32_t i;
    +			for (i = 1; i <= pos; ++i)
    +				reps[i] = coder->opts[pos_prev].backs[i - 1];
    +
    +			for (; i < REPS; ++i)
    +				reps[i] = coder->opts[pos_prev].backs[i];
    +
    +		} else {
    +			reps[0] = pos - REPS;
    +
    +			for (uint32_t i = 1; i < REPS; ++i)
    +				reps[i] = coder->opts[pos_prev].backs[i - 1];
    +		}
    +	}
    +
    +	coder->opts[cur].state = state;
    +
    +	for (uint32_t i = 0; i < REPS; ++i)
    +		coder->opts[cur].backs[i] = reps[i];
    +
    +	const uint32_t cur_price = coder->opts[cur].price;
    +
    +	const uint8_t current_byte = *buf;
    +	const uint8_t match_byte = *(buf - reps[0] - 1);
    +
    +	const uint32_t pos_state = position & coder->pos_mask;
    +
    +	const uint32_t cur_and_1_price = cur_price
    +			+ rc_bit_0_price(coder->is_match[state][pos_state])
    +			+ get_literal_price(coder, position, buf[-1],
    +			!is_literal_state(state), match_byte, current_byte);
    +
    +	bool next_is_literal = false;
    +
    +	if (cur_and_1_price < coder->opts[cur + 1].price) {
    +		coder->opts[cur + 1].price = cur_and_1_price;
    +		coder->opts[cur + 1].pos_prev = cur;
    +		make_literal(&coder->opts[cur + 1]);
    +		next_is_literal = true;
    +	}
    +
    +	const uint32_t match_price = cur_price
    +			+ rc_bit_1_price(coder->is_match[state][pos_state]);
    +	const uint32_t rep_match_price = match_price
    +			+ rc_bit_1_price(coder->is_rep[state]);
    +
    +	if (match_byte == current_byte
    +			&& !(coder->opts[cur + 1].pos_prev < cur
    +				&& coder->opts[cur + 1].back_prev == 0)) {
    +
    +		const uint32_t short_rep_price = rep_match_price
    +				+ get_short_rep_price(coder, state, pos_state);
    +
    +		if (short_rep_price <= coder->opts[cur + 1].price) {
    +			coder->opts[cur + 1].price = short_rep_price;
    +			coder->opts[cur + 1].pos_prev = cur;
    +			make_short_rep(&coder->opts[cur + 1]);
    +			next_is_literal = true;
    +		}
    +	}
    +
    +	if (buf_avail_full < 2)
    +		return len_end;
    +
    +	const uint32_t buf_avail = my_min(buf_avail_full, nice_len);
    +
    +	if (!next_is_literal && match_byte != current_byte) { // speed optimization
    +		// try literal + rep0
    +		const uint8_t *const buf_back = buf - reps[0] - 1;
    +		const uint32_t limit = my_min(buf_avail_full, nice_len + 1);
    +
    +		const uint32_t len_test = lzma_memcmplen(buf, buf_back, 1, limit) - 1;
    +
    +		if (len_test >= 2) {
    +			lzma_lzma_state state_2 = state;
    +			update_literal(state_2);
    +
    +			const uint32_t pos_state_next = (position + 1) & coder->pos_mask;
    +			const uint32_t next_rep_match_price = cur_and_1_price
    +					+ rc_bit_1_price(coder->is_match[state_2][pos_state_next])
    +					+ rc_bit_1_price(coder->is_rep[state_2]);
    +
    +			//for (; len_test >= 2; --len_test) {
    +			const uint32_t offset = cur + 1 + len_test;
    +
    +			while (len_end < offset)
    +				coder->opts[++len_end].price = RC_INFINITY_PRICE;
    +
    +			const uint32_t cur_and_len_price = next_rep_match_price
    +					+ get_rep_price(coder, 0, len_test,
    +						state_2, pos_state_next);
    +
    +			if (cur_and_len_price < coder->opts[offset].price) {
    +				coder->opts[offset].price = cur_and_len_price;
    +				coder->opts[offset].pos_prev = cur + 1;
    +				coder->opts[offset].back_prev = 0;
    +				coder->opts[offset].prev_1_is_literal = true;
    +				coder->opts[offset].prev_2 = false;
    +			}
    +			//}
    +		}
    +	}
    +
    +
    +	uint32_t start_len = 2; // speed optimization
    +
    +	for (uint32_t rep_index = 0; rep_index < REPS; ++rep_index) {
    +		const uint8_t *const buf_back = buf - reps[rep_index] - 1;
    +		if (not_equal_16(buf, buf_back))
    +			continue;
    +
    +		uint32_t len_test = lzma_memcmplen(buf, buf_back, 2, buf_avail);
    +
    +		while (len_end < cur + len_test)
    +			coder->opts[++len_end].price = RC_INFINITY_PRICE;
    +
    +		const uint32_t len_test_temp = len_test;
    +		const uint32_t price = rep_match_price + get_pure_rep_price(
    +				coder, rep_index, state, pos_state);
    +
    +		do {
    +			const uint32_t cur_and_len_price = price
    +					+ get_len_price(&coder->rep_len_encoder,
    +							len_test, pos_state);
    +
    +			if (cur_and_len_price < coder->opts[cur + len_test].price) {
    +				coder->opts[cur + len_test].price = cur_and_len_price;
    +				coder->opts[cur + len_test].pos_prev = cur;
    +				coder->opts[cur + len_test].back_prev = rep_index;
    +				coder->opts[cur + len_test].prev_1_is_literal = false;
    +			}
    +		} while (--len_test >= 2);
    +
    +		len_test = len_test_temp;
    +
    +		if (rep_index == 0)
    +			start_len = len_test + 1;
    +
    +
    +		uint32_t len_test_2 = len_test + 1;
    +		const uint32_t limit = my_min(buf_avail_full,
    +				len_test_2 + nice_len);
    +		// NOTE: len_test_2 may be greater than limit so the call to
    +		// lzma_memcmplen() must be done conditionally.
    +		if (len_test_2 < limit)
    +			len_test_2 = lzma_memcmplen(buf, buf_back, len_test_2, limit);
    +
    +		len_test_2 -= len_test + 1;
    +
    +		if (len_test_2 >= 2) {
    +			lzma_lzma_state state_2 = state;
    +			update_long_rep(state_2);
    +
    +			uint32_t pos_state_next = (position + len_test) & coder->pos_mask;
    +
    +			const uint32_t cur_and_len_literal_price = price
    +					+ get_len_price(&coder->rep_len_encoder,
    +						len_test, pos_state)
    +					+ rc_bit_0_price(coder->is_match[state_2][pos_state_next])
    +					+ get_literal_price(coder, position + len_test,
    +						buf[len_test - 1], true,
    +						buf_back[len_test], buf[len_test]);
    +
    +			update_literal(state_2);
    +
    +			pos_state_next = (position + len_test + 1) & coder->pos_mask;
    +
    +			const uint32_t next_rep_match_price = cur_and_len_literal_price
    +					+ rc_bit_1_price(coder->is_match[state_2][pos_state_next])
    +					+ rc_bit_1_price(coder->is_rep[state_2]);
    +
    +			//for(; len_test_2 >= 2; len_test_2--) {
    +			const uint32_t offset = cur + len_test + 1 + len_test_2;
    +
    +			while (len_end < offset)
    +				coder->opts[++len_end].price = RC_INFINITY_PRICE;
    +
    +			const uint32_t cur_and_len_price = next_rep_match_price
    +					+ get_rep_price(coder, 0, len_test_2,
    +						state_2, pos_state_next);
    +
    +			if (cur_and_len_price < coder->opts[offset].price) {
    +				coder->opts[offset].price = cur_and_len_price;
    +				coder->opts[offset].pos_prev = cur + len_test + 1;
    +				coder->opts[offset].back_prev = 0;
    +				coder->opts[offset].prev_1_is_literal = true;
    +				coder->opts[offset].prev_2 = true;
    +				coder->opts[offset].pos_prev_2 = cur;
    +				coder->opts[offset].back_prev_2 = rep_index;
    +			}
    +			//}
    +		}
    +	}
    +
    +
    +	//for (uint32_t len_test = 2; len_test <= new_len; ++len_test)
    +	if (new_len > buf_avail) {
    +		new_len = buf_avail;
    +
    +		matches_count = 0;
    +		while (new_len > coder->matches[matches_count].len)
    +			++matches_count;
    +
    +		coder->matches[matches_count++].len = new_len;
    +	}
    +
    +
    +	if (new_len >= start_len) {
    +		const uint32_t normal_match_price = match_price
    +				+ rc_bit_0_price(coder->is_rep[state]);
    +
    +		while (len_end < cur + new_len)
    +			coder->opts[++len_end].price = RC_INFINITY_PRICE;
    +
    +		uint32_t i = 0;
    +		while (start_len > coder->matches[i].len)
    +			++i;
    +
    +		for (uint32_t len_test = start_len; ; ++len_test) {
    +			const uint32_t cur_back = coder->matches[i].dist;
    +			uint32_t cur_and_len_price = normal_match_price
    +					+ get_dist_len_price(coder,
    +						cur_back, len_test, pos_state);
    +
    +			if (cur_and_len_price < coder->opts[cur + len_test].price) {
    +				coder->opts[cur + len_test].price = cur_and_len_price;
    +				coder->opts[cur + len_test].pos_prev = cur;
    +				coder->opts[cur + len_test].back_prev
    +						= cur_back + REPS;
    +				coder->opts[cur + len_test].prev_1_is_literal = false;
    +			}
    +
    +			if (len_test == coder->matches[i].len) {
    +				// Try Match + Literal + Rep0
    +				const uint8_t *const buf_back = buf - cur_back - 1;
    +				uint32_t len_test_2 = len_test + 1;
    +				const uint32_t limit = my_min(buf_avail_full,
    +						len_test_2 + nice_len);
    +
    +				// NOTE: len_test_2 may be greater than limit
    +				// so the call to lzma_memcmplen() must be
    +				// done conditionally.
    +				if (len_test_2 < limit)
    +					len_test_2 = lzma_memcmplen(buf, buf_back,
    +							len_test_2, limit);
    +
    +				len_test_2 -= len_test + 1;
    +
    +				if (len_test_2 >= 2) {
    +					lzma_lzma_state state_2 = state;
    +					update_match(state_2);
    +					uint32_t pos_state_next
    +							= (position + len_test) & coder->pos_mask;
    +
    +					const uint32_t cur_and_len_literal_price = cur_and_len_price
    +							+ rc_bit_0_price(
    +								coder->is_match[state_2][pos_state_next])
    +							+ get_literal_price(coder,
    +								position + len_test,
    +								buf[len_test - 1],
    +								true,
    +								buf_back[len_test],
    +								buf[len_test]);
    +
    +					update_literal(state_2);
    +					pos_state_next = (pos_state_next + 1) & coder->pos_mask;
    +
    +					const uint32_t next_rep_match_price
    +							= cur_and_len_literal_price
    +							+ rc_bit_1_price(
    +								coder->is_match[state_2][pos_state_next])
    +							+ rc_bit_1_price(coder->is_rep[state_2]);
    +
    +					// for(; len_test_2 >= 2; --len_test_2) {
    +					const uint32_t offset = cur + len_test + 1 + len_test_2;
    +
    +					while (len_end < offset)
    +						coder->opts[++len_end].price = RC_INFINITY_PRICE;
    +
    +					cur_and_len_price = next_rep_match_price
    +							+ get_rep_price(coder, 0, len_test_2,
    +								state_2, pos_state_next);
    +
    +					if (cur_and_len_price < coder->opts[offset].price) {
    +						coder->opts[offset].price = cur_and_len_price;
    +						coder->opts[offset].pos_prev = cur + len_test + 1;
    +						coder->opts[offset].back_prev = 0;
    +						coder->opts[offset].prev_1_is_literal = true;
    +						coder->opts[offset].prev_2 = true;
    +						coder->opts[offset].pos_prev_2 = cur;
    +						coder->opts[offset].back_prev_2
    +								= cur_back + REPS;
    +					}
    +					//}
    +				}
    +
    +				if (++i == matches_count)
    +					break;
    +			}
    +		}
    +	}
    +
    +	return len_end;
    +}
    +
    +
    +extern void
    +lzma_lzma_optimum_normal(lzma_lzma1_encoder *restrict coder,
    +		lzma_mf *restrict mf,
    +		uint32_t *restrict back_res, uint32_t *restrict len_res,
    +		uint32_t position)
    +{
    +	// If we have symbols pending, return the next pending symbol.
    +	if (coder->opts_end_index != coder->opts_current_index) {
    +		assert(mf->read_ahead > 0);
    +		*len_res = coder->opts[coder->opts_current_index].pos_prev
    +				- coder->opts_current_index;
    +		*back_res = coder->opts[coder->opts_current_index].back_prev;
    +		coder->opts_current_index = coder->opts[
    +				coder->opts_current_index].pos_prev;
    +		return;
    +	}
    +
    +	// Update the price tables. In LZMA SDK <= 4.60 (and possibly later)
    +	// this was done in both initialization function and in the main loop.
    +	// In liblzma they were moved into this single place.
    +	if (mf->read_ahead == 0) {
    +		if (coder->match_price_count >= (1 << 7))
    +			fill_dist_prices(coder);
    +
    +		if (coder->align_price_count >= ALIGN_SIZE)
    +			fill_align_prices(coder);
    +	}
    +
    +	// TODO: This needs quite a bit of cleaning still. But splitting
    +	// the original function into two pieces makes it at least a little
    +	// more readable, since those two parts don't share many variables.
    +
    +	uint32_t len_end = helper1(coder, mf, back_res, len_res, position);
    +	if (len_end == UINT32_MAX)
    +		return;
    +
    +	uint32_t reps[REPS];
    +	memcpy(reps, coder->reps, sizeof(reps));
    +
    +	uint32_t cur;
    +	for (cur = 1; cur < len_end; ++cur) {
    +		assert(cur < OPTS);
    +
    +		coder->longest_match_length = mf_find(
    +				mf, &coder->matches_count, coder->matches);
    +
    +		if (coder->longest_match_length >= mf->nice_len)
    +			break;
    +
    +		len_end = helper2(coder, reps, mf_ptr(mf) - 1, len_end,
    +				position + cur, cur, mf->nice_len,
    +				my_min(mf_avail(mf) + 1, OPTS - 1 - cur));
    +	}
    +
    +	backward(coder, len_res, back_res, cur);
    +	return;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_presets.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_presets.c
    new file mode 100644
    index 00000000000..e53483f9958
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_presets.c
    @@ -0,0 +1,63 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma_encoder_presets.c
    +/// \brief      Encoder presets
    +/// \note       xz needs this even when only decoding is enabled.
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "common.h"
    +
    +
    +extern LZMA_API(lzma_bool)
    +lzma_lzma_preset(lzma_options_lzma *options, uint32_t preset)
    +{
    +	const uint32_t level = preset & LZMA_PRESET_LEVEL_MASK;
    +	const uint32_t flags = preset & ~LZMA_PRESET_LEVEL_MASK;
    +	const uint32_t supported_flags = LZMA_PRESET_EXTREME;
    +
    +	if (level > 9 || (flags & ~supported_flags))
    +		return true;
    +
    +	options->preset_dict = NULL;
    +	options->preset_dict_size = 0;
    +
    +	options->lc = LZMA_LC_DEFAULT;
    +	options->lp = LZMA_LP_DEFAULT;
    +	options->pb = LZMA_PB_DEFAULT;
    +
    +	static const uint8_t dict_pow2[]
    +			= { 18, 20, 21, 22, 22, 23, 23, 24, 25, 26 };
    +	options->dict_size = UINT32_C(1) << dict_pow2[level];
    +
    +	if (level <= 3) {
    +		options->mode = LZMA_MODE_FAST;
    +		options->mf = level == 0 ? LZMA_MF_HC3 : LZMA_MF_HC4;
    +		options->nice_len = level <= 1 ? 128 : 273;
    +		static const uint8_t depths[] = { 4, 8, 24, 48 };
    +		options->depth = depths[level];
    +	} else {
    +		options->mode = LZMA_MODE_NORMAL;
    +		options->mf = LZMA_MF_BT4;
    +		options->nice_len = level == 4 ? 16 : level == 5 ? 32 : 64;
    +		options->depth = 0;
    +	}
    +
    +	if (flags & LZMA_PRESET_EXTREME) {
    +		options->mode = LZMA_MODE_NORMAL;
    +		options->mf = LZMA_MF_BT4;
    +		if (level == 3 || level == 5) {
    +			options->nice_len = 192;
    +			options->depth = 0;
    +		} else {
    +			options->nice_len = 273;
    +			options->depth = 512;
    +		}
    +	}
    +
    +	return false;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_private.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_private.h
    new file mode 100644
    index 00000000000..eeea5e9c128
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_private.h
    @@ -0,0 +1,161 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       lzma_encoder_private.h
    +/// \brief      Private definitions for LZMA encoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_LZMA_ENCODER_PRIVATE_H
    +#define LZMA_LZMA_ENCODER_PRIVATE_H
    +
    +#include "lz_encoder.h"
    +#include "range_encoder.h"
    +#include "lzma_common.h"
    +#include "lzma_encoder.h"
    +
    +
    +// Macro to compare if the first two bytes in two buffers differ. This is
    +// needed in lzma_lzma_optimum_*() to test if the match is at least
    +// MATCH_LEN_MIN bytes. Unaligned access gives tiny gain so there's no
    +// reason to not use it when it is supported.
    +#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
    +#	define not_equal_16(a, b) (read16ne(a) != read16ne(b))
    +#else
    +#	define not_equal_16(a, b) \
    +		((a)[0] != (b)[0] || (a)[1] != (b)[1])
    +#endif
    +
    +
    +// Optimal - Number of entries in the optimum array.
    +#define OPTS (1 << 12)
    +
    +
    +typedef struct {
    +	probability choice;
    +	probability choice2;
    +	probability low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
    +	probability mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
    +	probability high[LEN_HIGH_SYMBOLS];
    +
    +	uint32_t prices[POS_STATES_MAX][LEN_SYMBOLS];
    +	uint32_t table_size;
    +	uint32_t counters[POS_STATES_MAX];
    +
    +} lzma_length_encoder;
    +
    +
    +typedef struct {
    +	lzma_lzma_state state;
    +
    +	bool prev_1_is_literal;
    +	bool prev_2;
    +
    +	uint32_t pos_prev_2;
    +	uint32_t back_prev_2;
    +
    +	uint32_t price;
    +	uint32_t pos_prev;  // pos_next;
    +	uint32_t back_prev;
    +
    +	uint32_t backs[REPS];
    +
    +} lzma_optimal;
    +
    +
    +struct lzma_lzma1_encoder_s {
    +	/// Range encoder
    +	lzma_range_encoder rc;
    +
    +	/// Uncompressed size (doesn't include possible preset dictionary)
    +	uint64_t uncomp_size;
    +
    +	/// If non-zero, produce at most this much output.
    +	/// Some input may then be missing from the output.
    +	uint64_t out_limit;
    +
    +	/// If the above out_limit is non-zero, *uncomp_size_ptr is set to
    +	/// the amount of uncompressed data that we were able to fit
    +	/// in the output buffer.
    +	uint64_t *uncomp_size_ptr;
    +
    +	/// State
    +	lzma_lzma_state state;
    +
    +	/// The four most recent match distances
    +	uint32_t reps[REPS];
    +
    +	/// Array of match candidates
    +	lzma_match matches[MATCH_LEN_MAX + 1];
    +
    +	/// Number of match candidates in matches[]
    +	uint32_t matches_count;
    +
    +	/// Variable to hold the length of the longest match between calls
    +	/// to lzma_lzma_optimum_*().
    +	uint32_t longest_match_length;
    +
    +	/// True if using getoptimumfast
    +	bool fast_mode;
    +
    +	/// True if the encoder has been initialized by encoding the first
    +	/// byte as a literal.
    +	bool is_initialized;
    +
    +	/// True if the range encoder has been flushed, but not all bytes
    +	/// have been written to the output buffer yet.
    +	bool is_flushed;
    +
    +	/// True if end of payload marker will be written.
    +	bool use_eopm;
    +
    +	uint32_t pos_mask;         ///< (1 << pos_bits) - 1
    +	uint32_t literal_context_bits;
    +	uint32_t literal_mask;
    +
    +	// These are the same as in lzma_decoder.c. See comments there.
    +	probability literal[LITERAL_CODERS_MAX * LITERAL_CODER_SIZE];
    +	probability is_match[STATES][POS_STATES_MAX];
    +	probability is_rep[STATES];
    +	probability is_rep0[STATES];
    +	probability is_rep1[STATES];
    +	probability is_rep2[STATES];
    +	probability is_rep0_long[STATES][POS_STATES_MAX];
    +	probability dist_slot[DIST_STATES][DIST_SLOTS];
    +	probability dist_special[FULL_DISTANCES - DIST_MODEL_END];
    +	probability dist_align[ALIGN_SIZE];
    +
    +	// These are the same as in lzma_decoder.c except that the encoders
    +	// include also price tables.
    +	lzma_length_encoder match_len_encoder;
    +	lzma_length_encoder rep_len_encoder;
    +
    +	// Price tables
    +	uint32_t dist_slot_prices[DIST_STATES][DIST_SLOTS];
    +	uint32_t dist_prices[DIST_STATES][FULL_DISTANCES];
    +	uint32_t dist_table_size;
    +	uint32_t match_price_count;
    +
    +	uint32_t align_prices[ALIGN_SIZE];
    +	uint32_t align_price_count;
    +
    +	// Optimal
    +	uint32_t opts_end_index;
    +	uint32_t opts_current_index;
    +	lzma_optimal opts[OPTS];
    +};
    +
    +
    +extern void lzma_lzma_optimum_fast(
    +		lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,
    +		uint32_t *restrict back_res, uint32_t *restrict len_res);
    +
    +extern void lzma_lzma_optimum_normal(lzma_lzma1_encoder *restrict coder,
    +		lzma_mf *restrict mf, uint32_t *restrict back_res,
    +		uint32_t *restrict len_res, uint32_t position);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price.h
    new file mode 100644
    index 00000000000..cce6bdae5f9
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price.h
    @@ -0,0 +1,92 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       price.h
    +/// \brief      Probability price calculation
    +//
    +//  Author:     Igor Pavlov
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_PRICE_H
    +#define LZMA_PRICE_H
    +
    +
    +#define RC_MOVE_REDUCING_BITS 4
    +#define RC_BIT_PRICE_SHIFT_BITS 4
    +#define RC_PRICE_TABLE_SIZE (RC_BIT_MODEL_TOTAL >> RC_MOVE_REDUCING_BITS)
    +
    +#define RC_INFINITY_PRICE (UINT32_C(1) << 30)
    +
    +
    +/// Lookup table for the inline functions defined in this file.
    +lzma_attr_visibility_hidden
    +extern const uint8_t lzma_rc_prices[RC_PRICE_TABLE_SIZE];
    +
    +
    +static inline uint32_t
    +rc_bit_price(const probability prob, const uint32_t bit)
    +{
    +	return lzma_rc_prices[(prob ^ ((UINT32_C(0) - bit)
    +			& (RC_BIT_MODEL_TOTAL - 1))) >> RC_MOVE_REDUCING_BITS];
    +}
    +
    +
    +static inline uint32_t
    +rc_bit_0_price(const probability prob)
    +{
    +	return lzma_rc_prices[prob >> RC_MOVE_REDUCING_BITS];
    +}
    +
    +
    +static inline uint32_t
    +rc_bit_1_price(const probability prob)
    +{
    +	return lzma_rc_prices[(prob ^ (RC_BIT_MODEL_TOTAL - 1))
    +			>> RC_MOVE_REDUCING_BITS];
    +}
    +
    +
    +static inline uint32_t
    +rc_bittree_price(const probability *const probs,
    +		const uint32_t bit_levels, uint32_t symbol)
    +{
    +	uint32_t price = 0;
    +	symbol += UINT32_C(1) << bit_levels;
    +
    +	do {
    +		const uint32_t bit = symbol & 1;
    +		symbol >>= 1;
    +		price += rc_bit_price(probs[symbol], bit);
    +	} while (symbol != 1);
    +
    +	return price;
    +}
    +
    +
    +static inline uint32_t
    +rc_bittree_reverse_price(const probability *const probs,
    +		uint32_t bit_levels, uint32_t symbol)
    +{
    +	uint32_t price = 0;
    +	uint32_t model_index = 1;
    +
    +	do {
    +		const uint32_t bit = symbol & 1;
    +		symbol >>= 1;
    +		price += rc_bit_price(probs[model_index], bit);
    +		model_index = (model_index << 1) + bit;
    +	} while (--bit_levels != 0);
    +
    +	return price;
    +}
    +
    +
    +static inline uint32_t
    +rc_direct_price(const uint32_t bits)
    +{
    +	 return bits << RC_BIT_PRICE_SHIFT_BITS;
    +}
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_table.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_table.c
    new file mode 100644
    index 00000000000..c33433f718c
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_table.c
    @@ -0,0 +1,24 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +// This file has been generated by price_tablegen.c.
    +
    +#include "range_encoder.h"
    +
    +const uint8_t lzma_rc_prices[RC_PRICE_TABLE_SIZE] = {
    +	 128, 103,  91,  84,  78,  73,  69,  66,
    +	  63,  61,  58,  56,  54,  52,  51,  49,
    +	  48,  46,  45,  44,  43,  42,  41,  40,
    +	  39,  38,  37,  36,  35,  34,  34,  33,
    +	  32,  31,  31,  30,  29,  29,  28,  28,
    +	  27,  26,  26,  25,  25,  24,  24,  23,
    +	  23,  22,  22,  22,  21,  21,  20,  20,
    +	  19,  19,  19,  18,  18,  17,  17,  17,
    +	  16,  16,  16,  15,  15,  15,  14,  14,
    +	  14,  13,  13,  13,  12,  12,  12,  11,
    +	  11,  11,  11,  10,  10,  10,  10,   9,
    +	   9,   9,   9,   8,   8,   8,   8,   7,
    +	   7,   7,   7,   6,   6,   6,   6,   5,
    +	   5,   5,   5,   5,   4,   4,   4,   4,
    +	   3,   3,   3,   3,   3,   2,   2,   2,
    +	   2,   2,   2,   1,   1,   1,   1,   1
    +};
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_tablegen.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_tablegen.c
    new file mode 100644
    index 00000000000..4b6ca37efad
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_tablegen.c
    @@ -0,0 +1,93 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       price_tablegen.c
    +/// \brief      Probability price table generator
    +///
    +/// Compiling: gcc -std=c99 -o price_tablegen price_tablegen.c
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include 
    +#include 
    +
    +// Make it compile without common.h.
    +#define BUILDING_PRICE_TABLEGEN
    +#define lzma_attr_visibility_hidden
    +
    +#include "range_common.h"
    +#include "price.h"
    +
    +
    +static uint32_t rc_prices[RC_PRICE_TABLE_SIZE];
    +
    +
    +static void
    +init_price_table(void)
    +{
    +	for (uint32_t i = (UINT32_C(1) << RC_MOVE_REDUCING_BITS) / 2;
    +			i < RC_BIT_MODEL_TOTAL;
    +			i += (UINT32_C(1) << RC_MOVE_REDUCING_BITS)) {
    +		const uint32_t cycles_bits = RC_BIT_PRICE_SHIFT_BITS;
    +		uint32_t w = i;
    +		uint32_t bit_count = 0;
    +
    +		for (uint32_t j = 0; j < cycles_bits; ++j) {
    +			w *= w;
    +			bit_count <<= 1;
    +
    +			while (w >= (UINT32_C(1) << 16)) {
    +				w >>= 1;
    +				++bit_count;
    +			}
    +		}
    +
    +		rc_prices[i >> RC_MOVE_REDUCING_BITS]
    +				= (RC_BIT_MODEL_TOTAL_BITS << cycles_bits)
    +				- 15 - bit_count;
    +	}
    +
    +	return;
    +}
    +
    +
    +static void
    +print_price_table(void)
    +{
    +	// Split the SPDX string so that it won't accidentally match
    +	// when tools search for the string.
    +	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
    +		"// This file has been generated by price_tablegen.c.\n\n"
    +		"#include \"range_encoder.h\"\n\n"
    +		"const uint8_t lzma_rc_prices["
    +		"RC_PRICE_TABLE_SIZE] = {");
    +
    +	const size_t array_size = sizeof(lzma_rc_prices)
    +			/ sizeof(lzma_rc_prices[0]);
    +	for (size_t i = 0; i < array_size; ++i) {
    +		if (i % 8 == 0)
    +			printf("\n\t");
    +
    +		printf("%4" PRIu32, rc_prices[i]);
    +
    +		if (i != array_size - 1)
    +			printf(",");
    +	}
    +
    +	printf("\n};\n");
    +
    +	return;
    +}
    +
    +
    +int
    +main(void)
    +{
    +	init_price_table();
    +	print_price_table();
    +	return 0;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_common.h
    new file mode 100644
    index 00000000000..ac4dbe196f5
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_common.h
    @@ -0,0 +1,77 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       range_common.h
    +/// \brief      Common things for range encoder and decoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_RANGE_COMMON_H
    +#define LZMA_RANGE_COMMON_H
    +
    +// Skip common.h if building price_tablegen.c.
    +#ifndef BUILDING_PRICE_TABLEGEN
    +#	include "common.h"
    +#endif
    +
    +
    +///////////////
    +// Constants //
    +///////////////
    +
    +#define RC_SHIFT_BITS 8
    +#define RC_TOP_BITS 24
    +#define RC_TOP_VALUE (UINT32_C(1) << RC_TOP_BITS)
    +#define RC_BIT_MODEL_TOTAL_BITS 11
    +#define RC_BIT_MODEL_TOTAL (UINT32_C(1) << RC_BIT_MODEL_TOTAL_BITS)
    +#define RC_MOVE_BITS 5
    +
    +
    +////////////
    +// Macros //
    +////////////
    +
    +// Resets the probability so that both 0 and 1 have probability of 50 %
    +#define bit_reset(prob) \
    +	prob = RC_BIT_MODEL_TOTAL >> 1
    +
    +// This does the same for a complete bit tree.
    +// (A tree represented as an array.)
    +#define bittree_reset(probs, bit_levels) \
    +	for (uint32_t bt_i = 0; bt_i < (1 << (bit_levels)); ++bt_i) \
    +		bit_reset((probs)[bt_i])
    +
    +
    +//////////////////////
    +// Type definitions //
    +//////////////////////
    +
    +/// \brief      Type of probabilities used with range coder
    +///
    +/// This needs to be at least 12-bit integer, so uint16_t is a logical choice.
    +/// However, on some architecture and compiler combinations, a bigger type
    +/// may give better speed, because the probability variables are accessed
    +/// a lot. On the other hand, bigger probability type increases cache
    +/// footprint, since there are 2 to 14 thousand probability variables in
    +/// LZMA (assuming the limit of lc + lp <= 4; with lc + lp <= 12 there
    +/// would be about 1.5 million variables).
    +///
    +/// With malicious files, the initialization speed of the LZMA decoder can
    +/// become important. In that case, smaller probability variables mean that
    +/// there is less bytes to write to RAM, which makes initialization faster.
    +/// With big probability type, the initialization can become so slow that it
    +/// can be a problem e.g. for email servers doing virus scanning.
    +///
    +/// I will be sticking to uint16_t unless some specific architectures
    +/// are *much* faster (20-50 %) with uint32_t.
    +///
    +/// Update in 2024: The branchless C and x86-64 assembly was written so that
    +/// probability is assumed to be uint16_t. (In contrast, LZMA SDK 23.01
    +/// assembly supports both types.)
    +typedef uint16_t probability;
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_decoder.h
    new file mode 100644
    index 00000000000..a8aca9077c1
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_decoder.h
    @@ -0,0 +1,966 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       range_decoder.h
    +/// \brief      Range Decoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_RANGE_DECODER_H
    +#define LZMA_RANGE_DECODER_H
    +
    +#include "range_common.h"
    +
    +
    +// Choose the range decoder variants to use using a bitmask.
    +// If no bits are set, only the basic version is used.
    +// If more than one version is selected for the same feature,
    +// the last one on the list below is used.
    +//
    +// Bitwise-or of the following enable branchless C versions:
    +//   0x01   normal bittrees
    +//   0x02   fixed-sized reverse bittrees
    +//   0x04   variable-sized reverse bittrees (not faster)
    +//   0x08   matched literal (not faster)
    +//
    +// GCC & Clang compatible x86-64 inline assembly:
    +//   0x010   normal bittrees
    +//   0x020   fixed-sized reverse bittrees
    +//   0x040   variable-sized reverse bittrees
    +//   0x080   matched literal
    +//   0x100   direct bits
    +//
    +// The default can be overridden at build time by defining
    +// LZMA_RANGE_DECODER_CONFIG to the desired mask.
    +//
    +// 2024-02-22: Feedback from benchmarks:
    +//   - Brancless C (0x003) can be better than basic on x86-64 but often it's
    +//     slightly worse on other archs. Since asm is much better on x86-64,
    +//     branchless C is not used at all.
    +//   - With x86-64 asm, there are slight differences between GCC and Clang
    +//     and different processors. Overall 0x1F0 seems to be the best choice.
    +#ifndef LZMA_RANGE_DECODER_CONFIG
    +#	if defined(__x86_64__) && !defined(__ILP32__) \
    +			&& !defined(__NVCOMPILER) \
    +			&& (defined(__GNUC__) || defined(__clang__))
    +#		define LZMA_RANGE_DECODER_CONFIG 0x1F0
    +#	else
    +#		define LZMA_RANGE_DECODER_CONFIG 0
    +#	endif
    +#endif
    +
    +
    +// Negative RC_BIT_MODEL_TOTAL but the lowest RC_MOVE_BITS are flipped.
    +// This is useful for updating probability variables in branchless decoding:
    +//
    +//     uint32_t decoded_bit = ...;
    +//     probability tmp = RC_BIT_MODEL_OFFSET;
    +//     tmp &= decoded_bit - 1;
    +//     prob -= (prob + tmp) >> RC_MOVE_BITS;
    +#define RC_BIT_MODEL_OFFSET \
    +	((UINT32_C(1) << RC_MOVE_BITS) - 1 - RC_BIT_MODEL_TOTAL)
    +
    +
    +typedef struct {
    +	uint32_t range;
    +	uint32_t code;
    +	uint32_t init_bytes_left;
    +} lzma_range_decoder;
    +
    +
    +/// Reads the first five bytes to initialize the range decoder.
    +static inline lzma_ret
    +rc_read_init(lzma_range_decoder *rc, const uint8_t *restrict in,
    +		size_t *restrict in_pos, size_t in_size)
    +{
    +	while (rc->init_bytes_left > 0) {
    +		if (*in_pos == in_size)
    +			return LZMA_OK;
    +
    +		// The first byte is always 0x00. It could have been omitted
    +		// in LZMA2 but it wasn't, so one byte is wasted in every
    +		// LZMA2 chunk.
    +		if (rc->init_bytes_left == 5 && in[*in_pos] != 0x00)
    +			return LZMA_DATA_ERROR;
    +
    +		rc->code = (rc->code << 8) | in[*in_pos];
    +		++*in_pos;
    +		--rc->init_bytes_left;
    +	}
    +
    +	return LZMA_STREAM_END;
    +}
    +
    +
    +/// Makes local copies of range decoder and *in_pos variables. Doing this
    +/// improves speed significantly. The range decoder macros expect also
    +/// variables 'in' and 'in_size' to be defined.
    +#define rc_to_local(range_decoder, in_pos, fast_mode_in_required) \
    +	lzma_range_decoder rc = range_decoder; \
    +	const uint8_t *rc_in_ptr = in + (in_pos); \
    +	const uint8_t *rc_in_end = in + in_size; \
    +	const uint8_t *rc_in_fast_end \
    +			= (rc_in_end - rc_in_ptr) <= (fast_mode_in_required) \
    +			? rc_in_ptr \
    +			: rc_in_end - (fast_mode_in_required); \
    +	(void)rc_in_fast_end; /* Silence a warning with HAVE_SMALL. */ \
    +	uint32_t rc_bound
    +
    +
    +/// Evaluates to true if there is enough input remaining to use fast mode.
    +#define rc_is_fast_allowed() (rc_in_ptr < rc_in_fast_end)
    +
    +
    +/// Stores the local copes back to the range decoder structure.
    +#define rc_from_local(range_decoder, in_pos) \
    +do { \
    +	range_decoder = rc; \
    +	in_pos = (size_t)(rc_in_ptr - in); \
    +} while (0)
    +
    +
    +/// Resets the range decoder structure.
    +#define rc_reset(range_decoder) \
    +do { \
    +	(range_decoder).range = UINT32_MAX; \
    +	(range_decoder).code = 0; \
    +	(range_decoder).init_bytes_left = 5; \
    +} while (0)
    +
    +
    +/// When decoding has been properly finished, rc.code is always zero unless
    +/// the input stream is corrupt. So checking this can catch some corrupt
    +/// files especially if they don't have any other integrity check.
    +#define rc_is_finished(range_decoder) \
    +	((range_decoder).code == 0)
    +
    +
    +// Read the next input byte if needed.
    +#define rc_normalize() \
    +do { \
    +	if (rc.range < RC_TOP_VALUE) { \
    +		rc.range <<= RC_SHIFT_BITS; \
    +		rc.code = (rc.code << RC_SHIFT_BITS) | *rc_in_ptr++; \
    +	} \
    +} while (0)
    +
    +
    +/// If more input is needed but there is
    +/// no more input available, "goto out" is used to jump out of the main
    +/// decoder loop. The "_safe" macros are used in the Resumable decoder
    +/// mode in order to save the sequence to continue decoding from that
    +/// point later.
    +#define rc_normalize_safe(seq) \
    +do { \
    +	if (rc.range < RC_TOP_VALUE) { \
    +		if (rc_in_ptr == rc_in_end) { \
    +			coder->sequence = seq; \
    +			goto out; \
    +		} \
    +		rc.range <<= RC_SHIFT_BITS; \
    +		rc.code = (rc.code << RC_SHIFT_BITS) | *rc_in_ptr++; \
    +	} \
    +} while (0)
    +
    +
    +/// Start decoding a bit. This must be used together with rc_update_0()
    +/// and rc_update_1():
    +///
    +///     rc_if_0(prob) {
    +///         rc_update_0(prob);
    +///         // Do something
    +///     } else {
    +///         rc_update_1(prob);
    +///         // Do something else
    +///     }
    +///
    +#define rc_if_0(prob) \
    +	rc_normalize(); \
    +	rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) * (prob); \
    +	if (rc.code < rc_bound)
    +
    +
    +#define rc_if_0_safe(prob, seq) \
    +	rc_normalize_safe(seq); \
    +	rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) * (prob); \
    +	if (rc.code < rc_bound)
    +
    +
    +/// Update the range decoder state and the used probability variable to
    +/// match a decoded bit of 0.
    +///
    +/// The x86-64 assembly uses the commented method but it seems that,
    +/// at least on x86-64, the first version is slightly faster as C code.
    +#define rc_update_0(prob) \
    +do { \
    +	rc.range = rc_bound; \
    +	prob += (RC_BIT_MODEL_TOTAL - (prob)) >> RC_MOVE_BITS; \
    +	/* prob -= ((prob) + RC_BIT_MODEL_OFFSET) >> RC_MOVE_BITS; */ \
    +} while (0)
    +
    +
    +/// Update the range decoder state and the used probability variable to
    +/// match a decoded bit of 1.
    +#define rc_update_1(prob) \
    +do { \
    +	rc.range -= rc_bound; \
    +	rc.code -= rc_bound; \
    +	prob -= (prob) >> RC_MOVE_BITS; \
    +} while (0)
    +
    +
    +/// Decodes one bit and runs action0 or action1 depending on the decoded bit.
    +/// This macro is used as the last step in bittree reverse decoders since
    +/// those don't use "symbol" for anything else than indexing the probability
    +/// arrays.
    +#define rc_bit_last(prob, action0, action1) \
    +do { \
    +	rc_if_0(prob) { \
    +		rc_update_0(prob); \
    +		action0; \
    +	} else { \
    +		rc_update_1(prob); \
    +		action1; \
    +	} \
    +} while (0)
    +
    +
    +#define rc_bit_last_safe(prob, action0, action1, seq) \
    +do { \
    +	rc_if_0_safe(prob, seq) { \
    +		rc_update_0(prob); \
    +		action0; \
    +	} else { \
    +		rc_update_1(prob); \
    +		action1; \
    +	} \
    +} while (0)
    +
    +
    +/// Decodes one bit, updates "symbol", and runs action0 or action1 depending
    +/// on the decoded bit.
    +#define rc_bit(prob, action0, action1) \
    +	rc_bit_last(prob, \
    +		symbol <<= 1; action0, \
    +		symbol = (symbol << 1) + 1; action1);
    +
    +
    +#define rc_bit_safe(prob, action0, action1, seq) \
    +	rc_bit_last_safe(prob, \
    +		symbol <<= 1; action0, \
    +		symbol = (symbol << 1) + 1; action1, \
    +		seq);
    +
    +// Unroll fixed-sized bittree decoding.
    +//
    +// A compile-time constant in final_add can be used to get rid of the high bit
    +// from symbol that is used for the array indexing (1U << bittree_bits).
    +// final_add may also be used to add offset to the result (LZMA length
    +// decoder does that).
    +//
    +// The reason to have final_add here is that in the asm code the addition
    +// can be done for free: in x86-64 there is SBB instruction with -1 as
    +// the immediate value, and final_add is combined with that value.
    +#define rc_bittree_bit(prob) \
    +	rc_bit(prob, , )
    +
    +#define rc_bittree3(probs, final_add) \
    +do { \
    +	symbol = 1; \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	symbol += (uint32_t)(final_add); \
    +} while (0)
    +
    +#define rc_bittree6(probs, final_add) \
    +do { \
    +	symbol = 1; \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	symbol += (uint32_t)(final_add); \
    +} while (0)
    +
    +#define rc_bittree8(probs, final_add) \
    +do { \
    +	symbol = 1; \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	rc_bittree_bit(probs[symbol]); \
    +	symbol += (uint32_t)(final_add); \
    +} while (0)
    +
    +
    +// Fixed-sized reverse bittree
    +#define rc_bittree_rev4(probs) \
    +do { \
    +	symbol = 0; \
    +	rc_bit_last(probs[symbol + 1], , symbol += 1); \
    +	rc_bit_last(probs[symbol + 2], , symbol += 2); \
    +	rc_bit_last(probs[symbol + 4], , symbol += 4); \
    +	rc_bit_last(probs[symbol + 8], , symbol += 8); \
    +} while (0)
    +
    +
    +// Decode one bit from variable-sized reverse bittree. The loop is done
    +// in the code that uses this macro. This could be changed if the assembly
    +// version benefited from having the loop done in assembly but it didn't
    +// seem so in early 2024.
    +//
    +// Also, if the loop was done here, the loop counter would likely be local
    +// to the macro so that it wouldn't modify yet another input variable.
    +// If a _safe version of a macro with a loop was done then a modifiable
    +// input variable couldn't be avoided though.
    +#define rc_bit_add_if_1(probs, dest, value_to_add_if_1) \
    +	rc_bit(probs[symbol], \
    +		, \
    +		dest += value_to_add_if_1);
    +
    +
    +// Matched literal
    +#define decode_with_match_bit \
    +		t_match_byte <<= 1; \
    +		t_match_bit = t_match_byte & t_offset; \
    +		t_subcoder_index = t_offset + t_match_bit + symbol; \
    +		rc_bit(probs[t_subcoder_index], \
    +				t_offset &= ~t_match_bit, \
    +				t_offset &= t_match_bit)
    +
    +#define rc_matched_literal(probs_base_var, match_byte) \
    +do { \
    +	uint32_t t_match_byte = (match_byte); \
    +	uint32_t t_match_bit; \
    +	uint32_t t_subcoder_index; \
    +	uint32_t t_offset = 0x100; \
    +	symbol = 1; \
    +	decode_with_match_bit; \
    +	decode_with_match_bit; \
    +	decode_with_match_bit; \
    +	decode_with_match_bit; \
    +	decode_with_match_bit; \
    +	decode_with_match_bit; \
    +	decode_with_match_bit; \
    +	decode_with_match_bit; \
    +} while (0)
    +
    +
    +/// Decode a bit without using a probability.
    +//
    +// NOTE: GCC 13 and Clang/LLVM 16 can, at least on x86-64, optimize the bound
    +// calculation to use an arithmetic right shift so there's no need to provide
    +// the alternative code which, according to C99/C11/C23 6.3.1.3-p3 isn't
    +// perfectly portable: rc_bound = (uint32_t)((int32_t)rc.code >> 31);
    +#define rc_direct(dest, count_var) \
    +do { \
    +	dest = (dest << 1) + 1; \
    +	rc_normalize(); \
    +	rc.range >>= 1; \
    +	rc.code -= rc.range; \
    +	rc_bound = UINT32_C(0) - (rc.code >> 31); \
    +	dest += rc_bound; \
    +	rc.code += rc.range & rc_bound; \
    +} while (--count_var > 0)
    +
    +
    +
    +#define rc_direct_safe(dest, count_var, seq) \
    +do { \
    +	rc_normalize_safe(seq); \
    +	rc.range >>= 1; \
    +	rc.code -= rc.range; \
    +	rc_bound = UINT32_C(0) - (rc.code >> 31); \
    +	rc.code += rc.range & rc_bound; \
    +	dest = (dest << 1) + (rc_bound + 1); \
    +} while (--count_var > 0)
    +
    +
    +//////////////////
    +// Branchless C //
    +//////////////////
    +
    +/// Decode a bit using a branchless method. This reduces the number of
    +/// mispredicted branches and thus can improve speed.
    +#define rc_c_bit(prob, action_bit, action_neg) \
    +do { \
    +	probability *p = &(prob); \
    +	rc_normalize(); \
    +	rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) * *p; \
    +	uint32_t rc_mask = rc.code >= rc_bound; /* rc_mask = decoded bit */ \
    +	action_bit; /* action when rc_mask is 0 or 1 */ \
    +	/* rc_mask becomes 0 if bit is 0 and 0xFFFFFFFF if bit is 1: */ \
    +	rc_mask = 0U - rc_mask; \
    +	rc.range &= rc_mask; /* If bit 0: set rc.range = 0 */ \
    +	rc_bound ^= rc_mask; \
    +	rc_bound -= rc_mask; /* If bit 1: rc_bound = 0U - rc_bound */ \
    +	rc.range += rc_bound; \
    +	rc_bound &= rc_mask; \
    +	rc.code += rc_bound; \
    +	action_neg; /* action when rc_mask is 0 or 0xFFFFFFFF */ \
    +	rc_mask = ~rc_mask; /* If bit 0: all bits are set in rc_mask */ \
    +	rc_mask &= RC_BIT_MODEL_OFFSET; \
    +	*p -= (*p + rc_mask) >> RC_MOVE_BITS; \
    +} while (0)
    +
    +
    +// Testing on x86-64 give an impression that only the normal bittrees and
    +// the fixed-sized reverse bittrees are worth the branchless C code.
    +// It should be tested on other archs for which there isn't assembly code
    +// in this file.
    +
    +// Using addition in "(symbol << 1) + rc_mask" allows use of x86 LEA
    +// or RISC-V SH1ADD instructions. Compilers might infer it from
    +// "(symbol << 1) | rc_mask" too if they see that mask is 0 or 1 but
    +// the use of addition doesn't require such analysis from compilers.
    +#if LZMA_RANGE_DECODER_CONFIG & 0x01
    +#undef rc_bittree_bit
    +#define rc_bittree_bit(prob) \
    +	rc_c_bit(prob, \
    +		symbol = (symbol << 1) + rc_mask, \
    +		)
    +#endif // LZMA_RANGE_DECODER_CONFIG & 0x01
    +
    +#if LZMA_RANGE_DECODER_CONFIG & 0x02
    +#undef rc_bittree_rev4
    +#define rc_bittree_rev4(probs) \
    +do { \
    +	symbol = 0; \
    +	rc_c_bit(probs[symbol + 1], symbol += rc_mask, ); \
    +	rc_c_bit(probs[symbol + 2], symbol += rc_mask << 1, ); \
    +	rc_c_bit(probs[symbol + 4], symbol += rc_mask << 2, ); \
    +	rc_c_bit(probs[symbol + 8], symbol += rc_mask << 3, ); \
    +} while (0)
    +#endif // LZMA_RANGE_DECODER_CONFIG & 0x02
    +
    +#if LZMA_RANGE_DECODER_CONFIG & 0x04
    +#undef rc_bit_add_if_1
    +#define rc_bit_add_if_1(probs, dest, value_to_add_if_1) \
    +	rc_c_bit(probs[symbol], \
    +		symbol = (symbol << 1) + rc_mask, \
    +		dest += (value_to_add_if_1) & rc_mask)
    +#endif // LZMA_RANGE_DECODER_CONFIG & 0x04
    +
    +
    +#if LZMA_RANGE_DECODER_CONFIG & 0x08
    +#undef decode_with_match_bit
    +#define decode_with_match_bit \
    +		t_match_byte <<= 1; \
    +		t_match_bit = t_match_byte & t_offset; \
    +		t_subcoder_index = t_offset + t_match_bit + symbol; \
    +		rc_c_bit(probs[t_subcoder_index], \
    +			symbol = (symbol << 1) + rc_mask, \
    +			t_offset &= ~t_match_bit ^ rc_mask)
    +#endif // LZMA_RANGE_DECODER_CONFIG & 0x08
    +
    +
    +////////////
    +// x86-64 //
    +////////////
    +
    +#if LZMA_RANGE_DECODER_CONFIG & 0x1F0
    +
    +// rc_asm_y and rc_asm_n are used as arguments to macros to control which
    +// strings to include or omit.
    +#define rc_asm_y(str) str
    +#define rc_asm_n(str)
    +
    +// There are a few possible variations for normalization.
    +// This is the smallest variant which is also used by LZMA SDK.
    +//
    +//   - This has partial register write (the MOV from (%[in_ptr])).
    +//
    +//   - INC saves one byte in code size over ADD. False dependency on
    +//     partial flags from INC shouldn't become a problem on any processor
    +//     because the instructions after normalization don't read the flags
    +//     until SUB which sets all flags.
    +//
    +#define rc_asm_normalize \
    +	"cmp	%[top_value], %[range]\n\t" \
    +	"jae	1f\n\t" \
    +	"shl	%[shift_bits], %[code]\n\t" \
    +	"mov	(%[in_ptr]), %b[code]\n\t" \
    +	"shl	%[shift_bits], %[range]\n\t" \
    +	"inc	%[in_ptr]\n" \
    +	"1:\n"
    +
    +// rc_asm_calc(prob) is roughly equivalent to the C version of rc_if_0(prob)...
    +//
    +//     rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) * (prob);
    +//     if (rc.code < rc_bound)
    +//
    +// ...but the bound is stored in "range":
    +//
    +//     t0 = range;
    +//     range = (range >> RC_BIT_MODEL_TOTAL_BITS) * (prob);
    +//     t0 -= range;
    +//     t1 = code;
    +//     code -= range;
    +//
    +// The carry flag (CF) from the last subtraction holds the negation of
    +// the decoded bit (if CF==0 then the decoded bit is 1).
    +// The values in t0 and t1 are needed for rc_update_0(prob) and
    +// rc_update_1(prob). If the bit is 0, rc_update_0(prob)...
    +//
    +//     rc.range = rc_bound;
    +//
    +// ...has already been done but the "code -= range" has to be reverted using
    +// the old value stored in t1. (Also, prob needs to be updated.)
    +//
    +// If the bit is 1, rc_update_1(prob)...
    +//
    +//     rc.range -= rc_bound;
    +//     rc.code -= rc_bound;
    +//
    +// ...is already done for "code" but the value for "range" needs to be taken
    +// from t0. (Also, prob needs to be updated here as well.)
    +//
    +// The assignments from t0 and t1 can be done in a branchless manner with CMOV
    +// after the instructions from this macro. The CF from SUB tells which moves
    +// are needed.
    +#define rc_asm_calc(prob) \
    +		"mov	%[range], %[t0]\n\t" \
    +		"shr	%[bit_model_total_bits], %[range]\n\t" \
    +		"imul	%[" prob "], %[range]\n\t" \
    +		"sub	%[range], %[t0]\n\t" \
    +		"mov	%[code], %[t1]\n\t" \
    +		"sub	%[range], %[code]\n\t"
    +
    +// Also, prob needs to be updated: The update math depends on the decoded bit.
    +// It can be expressed in a few slightly different ways but this is fairly
    +// convenient here:
    +//
    +//     prob -= (prob + (bit ? 0 : RC_BIT_MODEL_OFFSET)) >> RC_MOVE_BITS;
    +//
    +// To do it in branchless way when the negation of the decoded bit is in CF,
    +// both "prob" and "prob + RC_BIT_MODEL_OFFSET" are needed. Then the desired
    +// value can be picked with CMOV. The addition can be done using LEA without
    +// affecting CF.
    +//
    +// (This prob update method is a tiny bit different from LZMA SDK 23.01.
    +// In the LZMA SDK a single register is reserved solely for a constant to
    +// be used with CMOV when updating prob. That is fine since there are enough
    +// free registers to do so. The method used here uses one fewer register,
    +// which is valuable with inline assembly.)
    +//
    +// * * *
    +//
    +// In bittree decoding, each (unrolled) loop iteration decodes one bit
    +// and needs one prob variable. To make it faster, the prob variable of
    +// the iteration N+1 is loaded during iteration N. There are two possible
    +// prob variables to choose from for N+1. Both are loaded from memory and
    +// the correct one is chosen with CMOV using the same CF as is used for
    +// other things described above.
    +//
    +// This preloading/prefetching requires an extra register. To avoid
    +// useless moves from "preloaded prob register" to "current prob register",
    +// the macros swap between the two registers for odd and even iterations.
    +//
    +// * * *
    +//
    +// Finally, the decoded bit has to be stored in "symbol". Since the negation
    +// of the bit is in CF, this can be done with SBB: symbol -= CF - 1. That is,
    +// if the decoded bit is 0 (CF==1) the operation is a no-op "symbol -= 0"
    +// and when bit is 1 (CF==0) the operation is "symbol -= 0 - 1" which is
    +// the same as "symbol += 1".
    +//
    +// The instructions for all things are intertwined for a few reasons:
    +//   - freeing temporary registers for new use
    +//   - not modifying CF too early
    +//   - instruction scheduling
    +//
    +// The first and last iterations can cheat a little. For example,
    +// on the first iteration "symbol" is known to start from 1 so it
    +// doesn't need to be read; it can even be immediately initialized
    +// to 2 to prepare for the second iteration of the loop.
    +//
    +// * * *
    +//
    +// a = number of the current prob variable (0 or 1)
    +// b = number of the next prob variable (1 or 0)
    +// *_only = rc_asm_y or _n to include or exclude code marked with them
    +#define rc_asm_bittree(a, b, first_only, middle_only, last_only) \
    +	first_only( \
    +		"movzwl	2(%[probs_base]), %[prob" #a "]\n\t" \
    +		"mov	$2, %[symbol]\n\t" \
    +		"movzwl	4(%[probs_base]), %[prob" #b "]\n\t" \
    +	) \
    +	middle_only( \
    +		/* Note the scaling of 4 instead of 2: */ \
    +		"movzwl	(%[probs_base], %q[symbol], 4), %[prob" #b "]\n\t" \
    +	) \
    +	last_only( \
    +		"add	%[symbol], %[symbol]\n\t" \
    +	) \
    +		\
    +		rc_asm_normalize \
    +		rc_asm_calc("prob" #a) \
    +		\
    +		"cmovae	%[t0], %[range]\n\t" \
    +		\
    +	first_only( \
    +		"movzwl	6(%[probs_base]), %[t0]\n\t" \
    +		"cmovae	%[t0], %[prob" #b "]\n\t" \
    +	) \
    +	middle_only( \
    +		"movzwl	2(%[probs_base], %q[symbol], 4), %[t0]\n\t" \
    +		"lea	(%q[symbol], %q[symbol]), %[symbol]\n\t" \
    +		"cmovae	%[t0], %[prob" #b "]\n\t" \
    +	) \
    +		\
    +		"lea	%c[bit_model_offset](%q[prob" #a "]), %[t0]\n\t" \
    +		"cmovb	%[t1], %[code]\n\t" \
    +		"mov	%[symbol], %[t1]\n\t" \
    +		"cmovae	%[prob" #a "], %[t0]\n\t" \
    +		\
    +	first_only( \
    +		"sbb	$-1, %[symbol]\n\t" \
    +	) \
    +	middle_only( \
    +		"sbb	$-1, %[symbol]\n\t" \
    +	) \
    +	last_only( \
    +		"sbb	%[last_sbb], %[symbol]\n\t" \
    +	) \
    +		\
    +		"shr	%[move_bits], %[t0]\n\t" \
    +		"sub	%[t0], %[prob" #a "]\n\t" \
    +		/* Scaling of 1 instead of 2 because symbol <<= 1. */ \
    +		"mov	%w[prob" #a "], (%[probs_base], %q[t1], 1)\n\t"
    +
    +// NOTE: The order of variables in __asm__ can affect speed and code size.
    +#define rc_asm_bittree_n(probs_base_var, final_add, asm_str) \
    +do { \
    +	uint32_t t0; \
    +	uint32_t t1; \
    +	uint32_t t_prob0; \
    +	uint32_t t_prob1; \
    +	\
    +	__asm__( \
    +		asm_str \
    +		: \
    +		[range]     "+&r"(rc.range), \
    +		[code]      "+&r"(rc.code), \
    +		[t0]        "=&r"(t0), \
    +		[t1]        "=&r"(t1), \
    +		[prob0]     "=&r"(t_prob0), \
    +		[prob1]     "=&r"(t_prob1), \
    +		[symbol]    "=&r"(symbol), \
    +		[in_ptr]    "+&r"(rc_in_ptr) \
    +		: \
    +		[probs_base]           "r"(probs_base_var), \
    +		[last_sbb]             "n"(-1 - (final_add)), \
    +		[top_value]            "n"(RC_TOP_VALUE), \
    +		[shift_bits]           "n"(RC_SHIFT_BITS), \
    +		[bit_model_total_bits] "n"(RC_BIT_MODEL_TOTAL_BITS), \
    +		[bit_model_offset]     "n"(RC_BIT_MODEL_OFFSET), \
    +		[move_bits]            "n"(RC_MOVE_BITS) \
    +		: \
    +		"cc", "memory"); \
    +} while (0)
    +
    +
    +#if LZMA_RANGE_DECODER_CONFIG & 0x010
    +#undef rc_bittree3
    +#define rc_bittree3(probs_base_var, final_add) \
    +	rc_asm_bittree_n(probs_base_var, final_add, \
    +		rc_asm_bittree(0, 1, rc_asm_y, rc_asm_n, rc_asm_n) \
    +		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_n, rc_asm_y) \
    +	)
    +
    +#undef rc_bittree6
    +#define rc_bittree6(probs_base_var, final_add) \
    +	rc_asm_bittree_n(probs_base_var, final_add, \
    +		rc_asm_bittree(0, 1, rc_asm_y, rc_asm_n, rc_asm_n) \
    +		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_n, rc_asm_y) \
    +	)
    +
    +#undef rc_bittree8
    +#define rc_bittree8(probs_base_var, final_add) \
    +	rc_asm_bittree_n(probs_base_var, final_add, \
    +		rc_asm_bittree(0, 1, rc_asm_y, rc_asm_n, rc_asm_n) \
    +		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
    +		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_n, rc_asm_y) \
    +	)
    +#endif // LZMA_RANGE_DECODER_CONFIG & 0x010
    +
    +
    +// Fixed-sized reverse bittree
    +//
    +// This uses the indexing that constructs the final value in symbol directly.
    +// add    = 1,  2,   4,  8
    +// dcur   = -,  4,   8, 16
    +// dnext0 = 4,   8, 16,  -
    +// dnext0 = 6,  12, 24,  -
    +#define rc_asm_bittree_rev(a, b, add, dcur, dnext0, dnext1, \
    +		first_only, middle_only, last_only) \
    +	first_only( \
    +		"movzwl	2(%[probs_base]), %[prob" #a "]\n\t" \
    +		"xor	%[symbol], %[symbol]\n\t" \
    +		"movzwl	4(%[probs_base]), %[prob" #b "]\n\t" \
    +	) \
    +	middle_only( \
    +		"movzwl	" #dnext0 "(%[probs_base], %q[symbol], 2), " \
    +			"%[prob" #b "]\n\t" \
    +	) \
    +		\
    +		rc_asm_normalize \
    +		rc_asm_calc("prob" #a) \
    +		\
    +		"cmovae	%[t0], %[range]\n\t" \
    +		\
    +	first_only( \
    +		"movzwl	6(%[probs_base]), %[t0]\n\t" \
    +		"cmovae	%[t0], %[prob" #b "]\n\t" \
    +	) \
    +	middle_only( \
    +		"movzwl	" #dnext1 "(%[probs_base], %q[symbol], 2), %[t0]\n\t" \
    +		"cmovae	%[t0], %[prob" #b "]\n\t" \
    +	) \
    +		\
    +		"lea	" #add "(%q[symbol]), %[t0]\n\t" \
    +		"cmovb	%[t1], %[code]\n\t" \
    +	middle_only( \
    +		"mov	%[symbol], %[t1]\n\t" \
    +	) \
    +	last_only( \
    +		"mov	%[symbol], %[t1]\n\t" \
    +	) \
    +		"cmovae	%[t0], %[symbol]\n\t" \
    +		"lea	%c[bit_model_offset](%q[prob" #a "]), %[t0]\n\t" \
    +		"cmovae	%[prob" #a "], %[t0]\n\t" \
    +		\
    +		"shr	%[move_bits], %[t0]\n\t" \
    +		"sub	%[t0], %[prob" #a "]\n\t" \
    +	first_only( \
    +		"mov	%w[prob" #a "], 2(%[probs_base])\n\t" \
    +	) \
    +	middle_only( \
    +		"mov	%w[prob" #a "], " \
    +			#dcur "(%[probs_base], %q[t1], 2)\n\t" \
    +	) \
    +	last_only( \
    +		"mov	%w[prob" #a "], " \
    +			#dcur "(%[probs_base], %q[t1], 2)\n\t" \
    +	)
    +
    +#if LZMA_RANGE_DECODER_CONFIG & 0x020
    +#undef rc_bittree_rev4
    +#define rc_bittree_rev4(probs_base_var) \
    +rc_asm_bittree_n(probs_base_var, 4, \
    +	rc_asm_bittree_rev(0, 1, 1,  -,  4,  6, rc_asm_y, rc_asm_n, rc_asm_n) \
    +	rc_asm_bittree_rev(1, 0, 2,  4,  8, 12, rc_asm_n, rc_asm_y, rc_asm_n) \
    +	rc_asm_bittree_rev(0, 1, 4,  8, 16, 24, rc_asm_n, rc_asm_y, rc_asm_n) \
    +	rc_asm_bittree_rev(1, 0, 8, 16,  -,  -, rc_asm_n, rc_asm_n, rc_asm_y) \
    +)
    +#endif // LZMA_RANGE_DECODER_CONFIG & 0x020
    +
    +
    +#if LZMA_RANGE_DECODER_CONFIG & 0x040
    +#undef rc_bit_add_if_1
    +#define rc_bit_add_if_1(probs_base_var, dest_var, value_to_add_if_1) \
    +do { \
    +	uint32_t t0; \
    +	uint32_t t1; \
    +	uint32_t t2 = (value_to_add_if_1); \
    +	uint32_t t_prob; \
    +	uint32_t t_index; \
    +	\
    +	__asm__( \
    +		"movzwl	(%[probs_base], %q[symbol], 2), %[prob]\n\t" \
    +		"mov	%[symbol], %[index]\n\t" \
    +		\
    +		"add	%[dest], %[t2]\n\t" \
    +		"add	%[symbol], %[symbol]\n\t" \
    +		\
    +		rc_asm_normalize \
    +		rc_asm_calc("prob") \
    +		\
    +		"cmovae	%[t0], %[range]\n\t" \
    +		"lea	%c[bit_model_offset](%q[prob]), %[t0]\n\t" \
    +		"cmovb	%[t1], %[code]\n\t" \
    +		"cmovae	%[prob], %[t0]\n\t" \
    +		\
    +		"cmovae	%[t2], %[dest]\n\t" \
    +		"sbb	$-1, %[symbol]\n\t" \
    +		\
    +		"sar	%[move_bits], %[t0]\n\t" \
    +		"sub	%[t0], %[prob]\n\t" \
    +		"mov	%w[prob], (%[probs_base], %q[index], 2)" \
    +		: \
    +		[range]     "+&r"(rc.range), \
    +		[code]      "+&r"(rc.code), \
    +		[t0]        "=&r"(t0), \
    +		[t1]        "=&r"(t1), \
    +		[prob]      "=&r"(t_prob), \
    +		[index]     "=&r"(t_index), \
    +		[symbol]    "+&r"(symbol), \
    +		[t2]        "+&r"(t2), \
    +		[dest]      "+&r"(dest_var), \
    +		[in_ptr]    "+&r"(rc_in_ptr) \
    +		: \
    +		[probs_base]           "r"(probs_base_var), \
    +		[top_value]            "n"(RC_TOP_VALUE), \
    +		[shift_bits]           "n"(RC_SHIFT_BITS), \
    +		[bit_model_total_bits] "n"(RC_BIT_MODEL_TOTAL_BITS), \
    +		[bit_model_offset]     "n"(RC_BIT_MODEL_OFFSET), \
    +		[move_bits]            "n"(RC_MOVE_BITS) \
    +		: \
    +		"cc", "memory"); \
    +} while (0)
    +#endif // LZMA_RANGE_DECODER_CONFIG & 0x040
    +
    +
    +// Literal decoding uses a normal 8-bit bittree but literal with match byte
    +// is more complex in picking the probability variable from the correct
    +// subtree. This doesn't use preloading/prefetching of the next prob because
    +// there are four choices instead of two.
    +//
    +// FIXME? The first iteration starts with symbol = 1 so it could be optimized
    +// by a tiny amount.
    +#define rc_asm_matched_literal(nonlast_only) \
    +		"add	%[offset], %[symbol]\n\t" \
    +		"and	%[offset], %[match_bit]\n\t" \
    +		"add	%[match_bit], %[symbol]\n\t" \
    +		\
    +		"movzwl	(%[probs_base], %q[symbol], 2), %[prob]\n\t" \
    +		\
    +		"add	%[symbol], %[symbol]\n\t" \
    +		\
    +	nonlast_only( \
    +		"xor	%[match_bit], %[offset]\n\t" \
    +		"add	%[match_byte], %[match_byte]\n\t" \
    +	) \
    +		\
    +		rc_asm_normalize \
    +		rc_asm_calc("prob") \
    +		\
    +		"cmovae	%[t0], %[range]\n\t" \
    +		"lea	%c[bit_model_offset](%q[prob]), %[t0]\n\t" \
    +		"cmovb	%[t1], %[code]\n\t" \
    +		"mov	%[symbol], %[t1]\n\t" \
    +		"cmovae	%[prob], %[t0]\n\t" \
    +		\
    +	nonlast_only( \
    +		"cmovae	%[match_bit], %[offset]\n\t" \
    +		"mov	%[match_byte], %[match_bit]\n\t" \
    +	) \
    +		\
    +		"sbb	$-1, %[symbol]\n\t" \
    +		\
    +		"shr	%[move_bits], %[t0]\n\t" \
    +		/* Undo symbol += match_bit + offset: */ \
    +		"and	$0x1FF, %[symbol]\n\t" \
    +		"sub	%[t0], %[prob]\n\t" \
    +		\
    +		/* Scaling of 1 instead of 2 because symbol <<= 1. */ \
    +		"mov	%w[prob], (%[probs_base], %q[t1], 1)\n\t"
    +
    +
    +#if LZMA_RANGE_DECODER_CONFIG & 0x080
    +#undef rc_matched_literal
    +#define rc_matched_literal(probs_base_var, match_byte_value) \
    +do { \
    +	uint32_t t0; \
    +	uint32_t t1; \
    +	uint32_t t_prob; \
    +	uint32_t t_match_byte = (uint32_t)(match_byte_value) << 1; \
    +	uint32_t t_match_bit = t_match_byte; \
    +	uint32_t t_offset = 0x100; \
    +	symbol = 1; \
    +	\
    +	__asm__( \
    +		rc_asm_matched_literal(rc_asm_y) \
    +		rc_asm_matched_literal(rc_asm_y) \
    +		rc_asm_matched_literal(rc_asm_y) \
    +		rc_asm_matched_literal(rc_asm_y) \
    +		rc_asm_matched_literal(rc_asm_y) \
    +		rc_asm_matched_literal(rc_asm_y) \
    +		rc_asm_matched_literal(rc_asm_y) \
    +		rc_asm_matched_literal(rc_asm_n) \
    +		: \
    +		[range]       "+&r"(rc.range), \
    +		[code]        "+&r"(rc.code), \
    +		[t0]          "=&r"(t0), \
    +		[t1]          "=&r"(t1), \
    +		[prob]        "=&r"(t_prob), \
    +		[match_bit]   "+&r"(t_match_bit), \
    +		[symbol]      "+&r"(symbol), \
    +		[match_byte]  "+&r"(t_match_byte), \
    +		[offset]      "+&r"(t_offset), \
    +		[in_ptr]      "+&r"(rc_in_ptr) \
    +		: \
    +		[probs_base]           "r"(probs_base_var), \
    +		[top_value]            "n"(RC_TOP_VALUE), \
    +		[shift_bits]           "n"(RC_SHIFT_BITS), \
    +		[bit_model_total_bits] "n"(RC_BIT_MODEL_TOTAL_BITS), \
    +		[bit_model_offset]     "n"(RC_BIT_MODEL_OFFSET), \
    +		[move_bits]            "n"(RC_MOVE_BITS) \
    +		: \
    +		"cc", "memory"); \
    +} while (0)
    +#endif // LZMA_RANGE_DECODER_CONFIG & 0x080
    +
    +
    +// Doing the loop in asm instead of C seems to help a little.
    +#if LZMA_RANGE_DECODER_CONFIG & 0x100
    +#undef rc_direct
    +#define rc_direct(dest_var, count_var) \
    +do { \
    +	uint32_t t0; \
    +	uint32_t t1; \
    +	\
    +	__asm__( \
    +		"2:\n\t" \
    +		"add	%[dest], %[dest]\n\t" \
    +		"lea	1(%q[dest]), %[t1]\n\t" \
    +		\
    +		rc_asm_normalize \
    +		\
    +		"shr	$1, %[range]\n\t" \
    +		"mov	%[code], %[t0]\n\t" \
    +		"sub	%[range], %[code]\n\t" \
    +		"cmovns	%[t1], %[dest]\n\t" \
    +		"cmovs	%[t0], %[code]\n\t" \
    +		"dec	%[count]\n\t" \
    +		"jnz	2b\n\t" \
    +		: \
    +		[range]       "+&r"(rc.range), \
    +		[code]        "+&r"(rc.code), \
    +		[t0]          "=&r"(t0), \
    +		[t1]          "=&r"(t1), \
    +		[dest]        "+&r"(dest_var), \
    +		[count]       "+&r"(count_var), \
    +		[in_ptr]      "+&r"(rc_in_ptr) \
    +		: \
    +		[top_value]   "n"(RC_TOP_VALUE), \
    +		[shift_bits]  "n"(RC_SHIFT_BITS) \
    +		: \
    +		"cc", "memory"); \
    +} while (0)
    +#endif // LZMA_RANGE_DECODER_CONFIG & 0x100
    +
    +#endif // x86_64
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_encoder.h
    new file mode 100644
    index 00000000000..8f62a47ac0a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_encoder.h
    @@ -0,0 +1,349 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       range_encoder.h
    +/// \brief      Range Encoder
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_RANGE_ENCODER_H
    +#define LZMA_RANGE_ENCODER_H
    +
    +#include "range_common.h"
    +#include "price.h"
    +
    +
    +/// Maximum number of symbols that can be put pending into lzma_range_encoder
    +/// structure between calls to lzma_rc_encode(). For LZMA, 48+5 is enough
    +/// (match with big distance and length followed by range encoder flush).
    +#define RC_SYMBOLS_MAX 53
    +
    +
    +typedef struct {
    +	uint64_t low;
    +	uint64_t cache_size;
    +	uint32_t range;
    +	uint8_t cache;
    +
    +	/// Number of bytes written out by rc_encode() -> rc_shift_low()
    +	uint64_t out_total;
    +
    +	/// Number of symbols in the tables
    +	size_t count;
    +
    +	/// rc_encode()'s position in the tables
    +	size_t pos;
    +
    +	/// Symbols to encode
    +	enum {
    +		RC_BIT_0,
    +		RC_BIT_1,
    +		RC_DIRECT_0,
    +		RC_DIRECT_1,
    +		RC_FLUSH,
    +	} symbols[RC_SYMBOLS_MAX];
    +
    +	/// Probabilities associated with RC_BIT_0 or RC_BIT_1
    +	probability *probs[RC_SYMBOLS_MAX];
    +
    +} lzma_range_encoder;
    +
    +
    +static inline void
    +rc_reset(lzma_range_encoder *rc)
    +{
    +	rc->low = 0;
    +	rc->cache_size = 1;
    +	rc->range = UINT32_MAX;
    +	rc->cache = 0;
    +	rc->out_total = 0;
    +	rc->count = 0;
    +	rc->pos = 0;
    +}
    +
    +
    +static inline void
    +rc_forget(lzma_range_encoder *rc)
    +{
    +	// This must not be called when rc_encode() is partially done.
    +	assert(rc->pos == 0);
    +	rc->count = 0;
    +}
    +
    +
    +static inline void
    +rc_bit(lzma_range_encoder *rc, probability *prob, uint32_t bit)
    +{
    +	rc->symbols[rc->count] = bit;
    +	rc->probs[rc->count] = prob;
    +	++rc->count;
    +}
    +
    +
    +static inline void
    +rc_bittree(lzma_range_encoder *rc, probability *probs,
    +		uint32_t bit_count, uint32_t symbol)
    +{
    +	uint32_t model_index = 1;
    +
    +	do {
    +		const uint32_t bit = (symbol >> --bit_count) & 1;
    +		rc_bit(rc, &probs[model_index], bit);
    +		model_index = (model_index << 1) + bit;
    +	} while (bit_count != 0);
    +}
    +
    +
    +static inline void
    +rc_bittree_reverse(lzma_range_encoder *rc, probability *probs,
    +		uint32_t bit_count, uint32_t symbol)
    +{
    +	uint32_t model_index = 1;
    +
    +	do {
    +		const uint32_t bit = symbol & 1;
    +		symbol >>= 1;
    +		rc_bit(rc, &probs[model_index], bit);
    +		model_index = (model_index << 1) + bit;
    +	} while (--bit_count != 0);
    +}
    +
    +
    +static inline void
    +rc_direct(lzma_range_encoder *rc,
    +		uint32_t value, uint32_t bit_count)
    +{
    +	do {
    +		rc->symbols[rc->count++]
    +				= RC_DIRECT_0 + ((value >> --bit_count) & 1);
    +	} while (bit_count != 0);
    +}
    +
    +
    +static inline void
    +rc_flush(lzma_range_encoder *rc)
    +{
    +	for (size_t i = 0; i < 5; ++i)
    +		rc->symbols[rc->count++] = RC_FLUSH;
    +}
    +
    +
    +static inline bool
    +rc_shift_low(lzma_range_encoder *rc,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	if ((uint32_t)(rc->low) < (uint32_t)(0xFF000000)
    +			|| (uint32_t)(rc->low >> 32) != 0) {
    +		do {
    +			if (*out_pos == out_size)
    +				return true;
    +
    +			out[*out_pos] = rc->cache + (uint8_t)(rc->low >> 32);
    +			++*out_pos;
    +			++rc->out_total;
    +			rc->cache = 0xFF;
    +
    +		} while (--rc->cache_size != 0);
    +
    +		rc->cache = (rc->low >> 24) & 0xFF;
    +	}
    +
    +	++rc->cache_size;
    +	rc->low = (rc->low & 0x00FFFFFF) << RC_SHIFT_BITS;
    +
    +	return false;
    +}
    +
    +
    +// NOTE: The last two arguments are uint64_t instead of size_t because in
    +// the dummy version these refer to the size of the whole range-encoded
    +// output stream, not just to the currently available output buffer space.
    +static inline bool
    +rc_shift_low_dummy(uint64_t *low, uint64_t *cache_size, uint8_t *cache,
    +		uint64_t *out_pos, uint64_t out_size)
    +{
    +	if ((uint32_t)(*low) < (uint32_t)(0xFF000000)
    +			|| (uint32_t)(*low >> 32) != 0) {
    +		do {
    +			if (*out_pos == out_size)
    +				return true;
    +
    +			++*out_pos;
    +			*cache = 0xFF;
    +
    +		} while (--*cache_size != 0);
    +
    +		*cache = (*low >> 24) & 0xFF;
    +	}
    +
    +	++*cache_size;
    +	*low = (*low & 0x00FFFFFF) << RC_SHIFT_BITS;
    +
    +	return false;
    +}
    +
    +
    +static inline bool
    +rc_encode(lzma_range_encoder *rc,
    +		uint8_t *out, size_t *out_pos, size_t out_size)
    +{
    +	assert(rc->count <= RC_SYMBOLS_MAX);
    +
    +	while (rc->pos < rc->count) {
    +		// Normalize
    +		if (rc->range < RC_TOP_VALUE) {
    +			if (rc_shift_low(rc, out, out_pos, out_size))
    +				return true;
    +
    +			rc->range <<= RC_SHIFT_BITS;
    +		}
    +
    +		// Encode a bit
    +		switch (rc->symbols[rc->pos]) {
    +		case RC_BIT_0: {
    +			probability prob = *rc->probs[rc->pos];
    +			rc->range = (rc->range >> RC_BIT_MODEL_TOTAL_BITS)
    +					* prob;
    +			prob += (RC_BIT_MODEL_TOTAL - prob) >> RC_MOVE_BITS;
    +			*rc->probs[rc->pos] = prob;
    +			break;
    +		}
    +
    +		case RC_BIT_1: {
    +			probability prob = *rc->probs[rc->pos];
    +			const uint32_t bound = prob * (rc->range
    +					>> RC_BIT_MODEL_TOTAL_BITS);
    +			rc->low += bound;
    +			rc->range -= bound;
    +			prob -= prob >> RC_MOVE_BITS;
    +			*rc->probs[rc->pos] = prob;
    +			break;
    +		}
    +
    +		case RC_DIRECT_0:
    +			rc->range >>= 1;
    +			break;
    +
    +		case RC_DIRECT_1:
    +			rc->range >>= 1;
    +			rc->low += rc->range;
    +			break;
    +
    +		case RC_FLUSH:
    +			// Prevent further normalizations.
    +			rc->range = UINT32_MAX;
    +
    +			// Flush the last five bytes (see rc_flush()).
    +			do {
    +				if (rc_shift_low(rc, out, out_pos, out_size))
    +					return true;
    +			} while (++rc->pos < rc->count);
    +
    +			// Reset the range encoder so we are ready to continue
    +			// encoding if we weren't finishing the stream.
    +			rc_reset(rc);
    +			return false;
    +
    +		default:
    +			assert(0);
    +			break;
    +		}
    +
    +		++rc->pos;
    +	}
    +
    +	rc->count = 0;
    +	rc->pos = 0;
    +
    +	return false;
    +}
    +
    +
    +static inline bool
    +rc_encode_dummy(const lzma_range_encoder *rc, uint64_t out_limit)
    +{
    +	assert(rc->count <= RC_SYMBOLS_MAX);
    +
    +	uint64_t low = rc->low;
    +	uint64_t cache_size = rc->cache_size;
    +	uint32_t range = rc->range;
    +	uint8_t cache = rc->cache;
    +	uint64_t out_pos = rc->out_total;
    +
    +	size_t pos = rc->pos;
    +
    +	while (true) {
    +		// Normalize
    +		if (range < RC_TOP_VALUE) {
    +			if (rc_shift_low_dummy(&low, &cache_size, &cache,
    +					&out_pos, out_limit))
    +				return true;
    +
    +			range <<= RC_SHIFT_BITS;
    +		}
    +
    +		// This check is here because the normalization above must
    +		// be done before flushing the last bytes.
    +		if (pos == rc->count)
    +			break;
    +
    +		// Encode a bit
    +		switch (rc->symbols[pos]) {
    +		case RC_BIT_0: {
    +			probability prob = *rc->probs[pos];
    +			range = (range >> RC_BIT_MODEL_TOTAL_BITS)
    +					* prob;
    +			break;
    +		}
    +
    +		case RC_BIT_1: {
    +			probability prob = *rc->probs[pos];
    +			const uint32_t bound = prob * (range
    +					>> RC_BIT_MODEL_TOTAL_BITS);
    +			low += bound;
    +			range -= bound;
    +			break;
    +		}
    +
    +		case RC_DIRECT_0:
    +			range >>= 1;
    +			break;
    +
    +		case RC_DIRECT_1:
    +			range >>= 1;
    +			low += range;
    +			break;
    +
    +		case RC_FLUSH:
    +		default:
    +			assert(0);
    +			break;
    +		}
    +
    +		++pos;
    +	}
    +
    +	// Flush the last bytes. This isn't in rc->symbols[] so we do
    +	// it after the above loop to take into account the size of
    +	// the flushing that will be done at the end of the stream.
    +	for (pos = 0; pos < 5; ++pos) {
    +		if (rc_shift_low_dummy(&low, &cache_size,
    +				&cache, &out_pos, out_limit))
    +			return true;
    +	}
    +
    +	return false;
    +}
    +
    +
    +static inline uint64_t
    +rc_pending(const lzma_range_encoder *rc)
    +{
    +	return rc->cache_size + 5 - 1;
    +}
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm.c
    new file mode 100644
    index 00000000000..58acb2d11ad
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm.c
    @@ -0,0 +1,74 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       arm.c
    +/// \brief      Filter for ARM binaries
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_private.h"
    +
    +
    +static size_t
    +arm_code(void *simple lzma_attribute((__unused__)),
    +		uint32_t now_pos, bool is_encoder,
    +		uint8_t *buffer, size_t size)
    +{
    +	size_t i;
    +	for (i = 0; i + 4 <= size; i += 4) {
    +		if (buffer[i + 3] == 0xEB) {
    +			uint32_t src = ((uint32_t)(buffer[i + 2]) << 16)
    +					| ((uint32_t)(buffer[i + 1]) << 8)
    +					| (uint32_t)(buffer[i + 0]);
    +			src <<= 2;
    +
    +			uint32_t dest;
    +			if (is_encoder)
    +				dest = now_pos + (uint32_t)(i) + 8 + src;
    +			else
    +				dest = src - (now_pos + (uint32_t)(i) + 8);
    +
    +			dest >>= 2;
    +			buffer[i + 2] = (dest >> 16);
    +			buffer[i + 1] = (dest >> 8);
    +			buffer[i + 0] = dest;
    +		}
    +	}
    +
    +	return i;
    +}
    +
    +
    +static lzma_ret
    +arm_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters, bool is_encoder)
    +{
    +	return lzma_simple_coder_init(next, allocator, filters,
    +			&arm_code, 0, 4, 4, is_encoder);
    +}
    +
    +
    +#ifdef HAVE_ENCODER_ARM
    +extern lzma_ret
    +lzma_simple_arm_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return arm_coder_init(next, allocator, filters, true);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_DECODER_ARM
    +extern lzma_ret
    +lzma_simple_arm_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return arm_coder_init(next, allocator, filters, false);
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm64.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm64.c
    new file mode 100644
    index 00000000000..16c2f565f73
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm64.c
    @@ -0,0 +1,136 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       arm64.c
    +/// \brief      Filter for ARM64 binaries
    +///
    +/// This converts ARM64 relative addresses in the BL and ADRP immediates
    +/// to absolute values to increase redundancy of ARM64 code.
    +///
    +/// Converting B or ADR instructions was also tested but it's not useful.
    +/// A majority of the jumps for the B instruction are very small (+/- 0xFF).
    +/// These are typical for loops and if-statements. Encoding them to their
    +/// absolute address reduces redundancy since many of the small relative
    +/// jump values are repeated, but very few of the absolute addresses are.
    +//
    +//  Authors:    Lasse Collin
    +//              Jia Tan
    +//              Igor Pavlov
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_private.h"
    +
    +
    +static size_t
    +arm64_code(void *simple lzma_attribute((__unused__)),
    +		uint32_t now_pos, bool is_encoder,
    +		uint8_t *buffer, size_t size)
    +{
    +	size_t i;
    +
    +	// Clang 14.0.6 on x86-64 makes this four times bigger and 40 % slower
    +	// with auto-vectorization that is enabled by default with -O2.
    +	// Such vectorization bloat happens with -O2 when targeting ARM64 too
    +	// but performance hasn't been tested.
    +#ifdef __clang__
    +#	pragma clang loop vectorize(disable)
    +#endif
    +	for (i = 0; i + 4 <= size; i += 4) {
    +		uint32_t pc = (uint32_t)(now_pos + i);
    +		uint32_t instr = read32le(buffer + i);
    +
    +		if ((instr >> 26) == 0x25) {
    +			// BL instruction:
    +			// The full 26-bit immediate is converted.
    +			// The range is +/-128 MiB.
    +			//
    +			// Using the full range helps quite a lot with
    +			// big executables. Smaller range would reduce false
    +			// positives in non-code sections of the input though
    +			// so this is a compromise that slightly favors big
    +			// files. With the full range, only six bits of the 32
    +			// need to match to trigger a conversion.
    +			const uint32_t src = instr;
    +			instr = 0x94000000;
    +
    +			pc >>= 2;
    +			if (!is_encoder)
    +				pc = 0U - pc;
    +
    +			instr |= (src + pc) & 0x03FFFFFF;
    +			write32le(buffer + i, instr);
    +
    +		} else if ((instr & 0x9F000000) == 0x90000000) {
    +			// ADRP instruction:
    +			// Only values in the range +/-512 MiB are converted.
    +			//
    +			// Using less than the full +/-4 GiB range reduces
    +			// false positives on non-code sections of the input
    +			// while being excellent for executables up to 512 MiB.
    +			// The positive effect of ADRP conversion is smaller
    +			// than that of BL but it also doesn't hurt so much in
    +			// non-code sections of input because, with +/-512 MiB
    +			// range, nine bits of 32 need to match to trigger a
    +			// conversion (two 10-bit match choices = 9 bits).
    +			const uint32_t src = ((instr >> 29) & 3)
    +					| ((instr >> 3) & 0x001FFFFC);
    +
    +			// With the addition only one branch is needed to
    +			// check the +/- range. This is usually false when
    +			// processing ARM64 code so branch prediction will
    +			// handle it well in terms of performance.
    +			//
    +			//if ((src & 0x001E0000) != 0
    +			// && (src & 0x001E0000) != 0x001E0000)
    +			if ((src + 0x00020000) & 0x001C0000)
    +				continue;
    +
    +			instr &= 0x9000001F;
    +
    +			pc >>= 12;
    +			if (!is_encoder)
    +				pc = 0U - pc;
    +
    +			const uint32_t dest = src + pc;
    +			instr |= (dest & 3) << 29;
    +			instr |= (dest & 0x0003FFFC) << 3;
    +			instr |= (0U - (dest & 0x00020000)) & 0x00E00000;
    +			write32le(buffer + i, instr);
    +		}
    +	}
    +
    +	return i;
    +}
    +
    +
    +static lzma_ret
    +arm64_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters, bool is_encoder)
    +{
    +	return lzma_simple_coder_init(next, allocator, filters,
    +			&arm64_code, 0, 4, 4, is_encoder);
    +}
    +
    +
    +#ifdef HAVE_ENCODER_ARM64
    +extern lzma_ret
    +lzma_simple_arm64_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return arm64_coder_init(next, allocator, filters, true);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_DECODER_ARM64
    +extern lzma_ret
    +lzma_simple_arm64_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return arm64_coder_init(next, allocator, filters, false);
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/armthumb.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/armthumb.c
    new file mode 100644
    index 00000000000..f1eeca9b80f
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/armthumb.c
    @@ -0,0 +1,79 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       armthumb.c
    +/// \brief      Filter for ARM-Thumb binaries
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_private.h"
    +
    +
    +static size_t
    +armthumb_code(void *simple lzma_attribute((__unused__)),
    +		uint32_t now_pos, bool is_encoder,
    +		uint8_t *buffer, size_t size)
    +{
    +	size_t i;
    +	for (i = 0; i + 4 <= size; i += 2) {
    +		if ((buffer[i + 1] & 0xF8) == 0xF0
    +				&& (buffer[i + 3] & 0xF8) == 0xF8) {
    +			uint32_t src = (((uint32_t)(buffer[i + 1]) & 7) << 19)
    +				| ((uint32_t)(buffer[i + 0]) << 11)
    +				| (((uint32_t)(buffer[i + 3]) & 7) << 8)
    +				| (uint32_t)(buffer[i + 2]);
    +
    +			src <<= 1;
    +
    +			uint32_t dest;
    +			if (is_encoder)
    +				dest = now_pos + (uint32_t)(i) + 4 + src;
    +			else
    +				dest = src - (now_pos + (uint32_t)(i) + 4);
    +
    +			dest >>= 1;
    +			buffer[i + 1] = 0xF0 | ((dest >> 19) & 0x7);
    +			buffer[i + 0] = (dest >> 11);
    +			buffer[i + 3] = 0xF8 | ((dest >> 8) & 0x7);
    +			buffer[i + 2] = (dest);
    +			i += 2;
    +		}
    +	}
    +
    +	return i;
    +}
    +
    +
    +static lzma_ret
    +armthumb_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters, bool is_encoder)
    +{
    +	return lzma_simple_coder_init(next, allocator, filters,
    +			&armthumb_code, 0, 4, 2, is_encoder);
    +}
    +
    +
    +#ifdef HAVE_ENCODER_ARMTHUMB
    +extern lzma_ret
    +lzma_simple_armthumb_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return armthumb_coder_init(next, allocator, filters, true);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_DECODER_ARMTHUMB
    +extern lzma_ret
    +lzma_simple_armthumb_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return armthumb_coder_init(next, allocator, filters, false);
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/ia64.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/ia64.c
    new file mode 100644
    index 00000000000..50250140997
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/ia64.c
    @@ -0,0 +1,115 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       ia64.c
    +/// \brief      Filter for IA64 (Itanium) binaries
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_private.h"
    +
    +
    +static size_t
    +ia64_code(void *simple lzma_attribute((__unused__)),
    +		uint32_t now_pos, bool is_encoder,
    +		uint8_t *buffer, size_t size)
    +{
    +	static const uint32_t BRANCH_TABLE[32] = {
    +		0, 0, 0, 0, 0, 0, 0, 0,
    +		0, 0, 0, 0, 0, 0, 0, 0,
    +		4, 4, 6, 6, 0, 0, 7, 7,
    +		4, 4, 0, 0, 4, 4, 0, 0
    +	};
    +
    +	size_t i;
    +	for (i = 0; i + 16 <= size; i += 16) {
    +		const uint32_t instr_template = buffer[i] & 0x1F;
    +		const uint32_t mask = BRANCH_TABLE[instr_template];
    +		uint32_t bit_pos = 5;
    +
    +		for (size_t slot = 0; slot < 3; ++slot, bit_pos += 41) {
    +			if (((mask >> slot) & 1) == 0)
    +				continue;
    +
    +			const size_t byte_pos = (bit_pos >> 3);
    +			const uint32_t bit_res = bit_pos & 0x7;
    +			uint64_t instruction = 0;
    +
    +			for (size_t j = 0; j < 6; ++j)
    +				instruction += (uint64_t)(
    +						buffer[i + j + byte_pos])
    +						<< (8 * j);
    +
    +			uint64_t inst_norm = instruction >> bit_res;
    +
    +			if (((inst_norm >> 37) & 0xF) == 0x5
    +					&& ((inst_norm >> 9) & 0x7) == 0
    +					/* &&  (inst_norm & 0x3F)== 0 */
    +					) {
    +				uint32_t src = (uint32_t)(
    +						(inst_norm >> 13) & 0xFFFFF);
    +				src |= ((inst_norm >> 36) & 1) << 20;
    +
    +				src <<= 4;
    +
    +				uint32_t dest;
    +				if (is_encoder)
    +					dest = now_pos + (uint32_t)(i) + src;
    +				else
    +					dest = src - (now_pos + (uint32_t)(i));
    +
    +				dest >>= 4;
    +
    +				inst_norm &= ~((uint64_t)(0x8FFFFF) << 13);
    +				inst_norm |= (uint64_t)(dest & 0xFFFFF) << 13;
    +				inst_norm |= (uint64_t)(dest & 0x100000)
    +						<< (36 - 20);
    +
    +				instruction &= (1U << bit_res) - 1;
    +				instruction |= (inst_norm << bit_res);
    +
    +				for (size_t j = 0; j < 6; j++)
    +					buffer[i + j + byte_pos] = (uint8_t)(
    +							instruction
    +							>> (8 * j));
    +			}
    +		}
    +	}
    +
    +	return i;
    +}
    +
    +
    +static lzma_ret
    +ia64_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters, bool is_encoder)
    +{
    +	return lzma_simple_coder_init(next, allocator, filters,
    +			&ia64_code, 0, 16, 16, is_encoder);
    +}
    +
    +
    +#ifdef HAVE_ENCODER_IA64
    +extern lzma_ret
    +lzma_simple_ia64_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return ia64_coder_init(next, allocator, filters, true);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_DECODER_IA64
    +extern lzma_ret
    +lzma_simple_ia64_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return ia64_coder_init(next, allocator, filters, false);
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/powerpc.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/powerpc.c
    new file mode 100644
    index 00000000000..ba6cfbef3ab
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/powerpc.c
    @@ -0,0 +1,79 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       powerpc.c
    +/// \brief      Filter for PowerPC (big endian) binaries
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_private.h"
    +
    +
    +static size_t
    +powerpc_code(void *simple lzma_attribute((__unused__)),
    +		uint32_t now_pos, bool is_encoder,
    +		uint8_t *buffer, size_t size)
    +{
    +	size_t i;
    +	for (i = 0; i + 4 <= size; i += 4) {
    +		// PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link)
    +		if ((buffer[i] >> 2) == 0x12
    +				&& ((buffer[i + 3] & 3) == 1)) {
    +
    +			const uint32_t src
    +				= (((uint32_t)(buffer[i + 0]) & 3) << 24)
    +				| ((uint32_t)(buffer[i + 1]) << 16)
    +				| ((uint32_t)(buffer[i + 2]) << 8)
    +				| ((uint32_t)(buffer[i + 3]) & ~UINT32_C(3));
    +
    +			uint32_t dest;
    +			if (is_encoder)
    +				dest = now_pos + (uint32_t)(i) + src;
    +			else
    +				dest = src - (now_pos + (uint32_t)(i));
    +
    +			buffer[i + 0] = 0x48 | ((dest >> 24) &  0x03);
    +			buffer[i + 1] = (dest >> 16);
    +			buffer[i + 2] = (dest >> 8);
    +			buffer[i + 3] &= 0x03;
    +			buffer[i + 3] |= dest;
    +		}
    +	}
    +
    +	return i;
    +}
    +
    +
    +static lzma_ret
    +powerpc_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters, bool is_encoder)
    +{
    +	return lzma_simple_coder_init(next, allocator, filters,
    +			&powerpc_code, 0, 4, 4, is_encoder);
    +}
    +
    +
    +#ifdef HAVE_ENCODER_POWERPC
    +extern lzma_ret
    +lzma_simple_powerpc_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return powerpc_coder_init(next, allocator, filters, true);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_DECODER_POWERPC
    +extern lzma_ret
    +lzma_simple_powerpc_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return powerpc_coder_init(next, allocator, filters, false);
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/riscv.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/riscv.c
    new file mode 100644
    index 00000000000..b18df8b637d
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/riscv.c
    @@ -0,0 +1,755 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       riscv.c
    +/// \brief      Filter for 32-bit/64-bit little/big endian RISC-V binaries
    +///
    +/// This converts program counter relative addresses in function calls
    +/// (JAL, AUIPC+JALR), address calculation of functions and global
    +/// variables (AUIPC+ADDI), loads (AUIPC+load), and stores (AUIPC+store).
    +///
    +/// For AUIPC+inst2 pairs, the paired instruction checking is fairly relaxed.
    +/// The paired instruction opcode must only have its lowest two bits set,
    +/// meaning it will convert any paired instruction that is not a 16-bit
    +/// compressed instruction. This was shown to be enough to keep the number
    +/// of false matches low while improving code size and speed.
    +//
    +//  Authors:    Lasse Collin
    +//              Jia Tan
    +//
    +//  Special thanks:
    +//
    +//    - Chien Wong  provided a few early versions of RISC-V
    +//      filter variants along with test files and benchmark results.
    +//
    +//    - Igor Pavlov helped a lot in the filter design, getting it both
    +//      faster and smaller. The implementation here is still independently
    +//      written, not based on LZMA SDK.
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +/*
    +
    +RISC-V filtering
    +================
    +
    +    RV32I and RV64I, possibly combined with extensions C, Zfh, F, D,
    +    and Q, are identical enough that the same filter works for both.
    +
    +    The instruction encoding is always little endian, even on systems
    +    with big endian data access. Thus the same filter works for both
    +    endiannesses.
    +
    +    The following instructions have program counter relative
    +    (pc-relative) behavior:
    +
    +JAL
    +---
    +
    +    JAL is used for function calls (including tail calls) and
    +    unconditional jumps within functions. Jumps within functions
    +    aren't useful to filter because the absolute addresses often
    +    appear only once or at most a few times. Tail calls and jumps
    +    within functions look the same to a simple filter so neither
    +    are filtered, that is, JAL x0 is ignored (the ABI name of the
    +    register x0 is "zero").
    +
    +    Almost all calls store the return address to register x1 (ra)
    +    or x5 (t0). To reduce false matches when the filter is applied
    +    to non-code data, only the JAL instructions that use x1 or x5
    +    are converted. JAL has pc-relative range of +/-1 MiB so longer
    +    calls and jumps need another method (AUIPC+JALR).
    +
    +C.J and C.JAL
    +-------------
    +
    +    C.J and C.JAL have pc-relative range of +/-2 KiB.
    +
    +    C.J is for tail calls and jumps within functions and isn't
    +    filtered for the reasons mentioned for JAL x0.
    +
    +    C.JAL is an RV32C-only instruction. Its encoding overlaps with
    +    RV64C-only C.ADDIW which is a common instruction. So if filtering
    +    C.JAL was useful (it wasn't tested) then a separate filter would
    +    be needed for RV32 and RV64. Also, false positives would be a
    +    significant problem when the filter is applied to non-code data
    +    because C.JAL needs only five bits to match. Thus, this filter
    +    doesn't modify C.JAL instructions.
    +
    +BEQ, BNE, BLT, BGE, BLTU, BGEU, C.BEQZ, and C.BNEZ
    +--------------------------------------------------
    +
    +    These are conditional branches with pc-relative range
    +    of +/-4 KiB (+/-256 B for C.*). The absolute addresses often
    +    appear only once and very short distances are the most common,
    +    so filtering these instructions would make compression worse.
    +
    +AUIPC with rd != x0
    +-------------------
    +
    +    AUIPC is paired with a second instruction (inst2) to do
    +    pc-relative jumps, calls, loads, stores, and for taking
    +    an address of a symbol. AUIPC has a 20-bit immediate and
    +    the possible inst2 choices have a 12-bit immediate.
    +
    +    AUIPC stores pc + 20-bit signed immediate to a register.
    +    The immediate encodes a multiple of 4 KiB so AUIPC itself
    +    has a pc-relative range of +/-2 GiB. AUIPC does *NOT* set
    +    the lowest 12 bits of the result to zero! This means that
    +    the 12-bit immediate in inst2 cannot just include the lowest
    +    12 bits of the absolute address as is; the immediate has to
    +    compensate for the lowest 12 bits that AUIPC copies from the
    +    program counter. This means that a good filter has to convert
    +    not only AUIPC but also the paired inst2.
    +
    +    A strict filter would focus on filtering the following
    +    AUIPC+inst2 pairs:
    +
    +      - AUIPC+JALR: Function calls, including tail calls.
    +
    +      - AUIPC+ADDI: Calculating the address of a function
    +        or a global variable.
    +
    +      - AUIPC+load/store from the base instruction sets
    +        (RV32I, RV64I) or from the floating point extensions
    +        Zfh, F, D, and Q:
    +          * RV32I: LB, LH, LW, LBU, LHU, SB, SH, SW
    +          * RV64I has also: LD, LWU, SD
    +          * Zfh: FLH, FSH
    +          * F: FLW, FSW
    +          * D: FLD, FSD
    +          * Q: FLQ, FSQ
    +
    +    NOTE: AUIPC+inst2 can only be a pair if AUIPC's rd specifies
    +    the same register as inst2's rs1.
    +
    +    Instead of strictly accepting only the above instructions as inst2,
    +    this filter uses a much simpler condition: the lowest two bits of
    +    inst2 must be set, that is, inst2 must not be a 16-bit compressed
    +    instruction. So this will accept all 32-bit and possible future
    +    extended instructions as a pair to AUIPC if the bits in AUIPC's
    +    rd [11:7] match the bits [19:15] in inst2 (the bits that I-type and
    +    S-type instructions use for rs1). Testing showed that this relaxed
    +    condition for inst2 did not consistently or significantly affect
    +    compression ratio but it reduced code size and improved speed.
    +
    +    Additionally, the paired instruction is always treated as an I-type
    +    instruction. The S-type instructions used by stores (SB, SH, SW,
    +    etc.) place the lowest 5 bits of the immediate in a different
    +    location than I-type instructions. AUIPC+store pairs are less
    +    common than other pairs, and testing showed that the extra
    +    code required to handle S-type instructions was not worth the
    +    compression ratio gained.
    +
    +    AUIPC+inst2 don't necessarily appear sequentially next to each
    +    other although very often they do. Especially AUIPC+JALR are
    +    sequential as that may allow instruction fusion in processors
    +    (and perhaps help branch prediction as a fused AUIPC+JALR is
    +    a direct branch while JALR alone is an indirect branch).
    +
    +    Clang 16 can generate code where AUIPC+inst2 is split:
    +
    +      - AUIPC is outside a loop and inst2 (load/store) is inside
    +        the loop. This way the AUIPC instruction needs to be
    +        executed only once.
    +
    +      - Load-modify-store may have AUIPC for the load and the same
    +        AUIPC-result is used for the store too. This may get combined
    +        with AUIPC being outside the loop.
    +
    +      - AUIPC is before a conditional branch and inst2 is hundreds
    +        of bytes away at the branch target.
    +
    +      - Inner and outer pair:
    +
    +            auipc   a1,0x2f
    +            auipc   a2,0x3d
    +            ld      a2,-500(a2)
    +            addi    a1,a1,-233
    +
    +      - Many split pairs with an untaken conditional branch between:
    +
    +            auipc   s9,0x1613   # Pair 1
    +            auipc   s4,0x1613   # Pair 2
    +            auipc   s6,0x1613   # Pair 3
    +            auipc   s10,0x1613  # Pair 4
    +            beqz    a5,a3baae
    +            ld      a0,0(a6)
    +            ld      a6,246(s9)  # Pair 1
    +            ld      a1,250(s4)  # Pair 2
    +            ld      a3,254(s6)  # Pair 3
    +            ld      a4,258(s10) # Pair 4
    +
    +    It's not possible to find all split pairs in a filter like this.
    +    At least in 2024, simple sequential pairs are 99 % of AUIPC uses
    +    so filtering only such pairs gives good results and makes the
    +    filter simpler. However, it's possible that future compilers will
    +    produce different code where sequential pairs aren't as common.
    +
    +    This filter doesn't convert AUIPC instructions alone because:
    +
    +    (1) The conversion would be off-by-one (or off-by-4096) half the
    +        time because the lowest 12 bits from inst2 (inst2_imm12)
    +        aren't known. We only know that the absolute address is
    +        pc + AUIPC_imm20 + [-2048, +2047] but there is no way to
    +        know the exact 4096-byte multiple (or 4096 * n + 2048):
    +        there are always two possibilities because AUIPC copies
    +        the 12 lowest bits from pc instead of zeroing them.
    +
    +        NOTE: The sign-extension of inst2_imm12 adds a tiny bit
    +        of extra complexity to AUIPC math in general but it's not
    +        the reason for this problem. The sign-extension only changes
    +        the relative position of the pc-relative 4096-byte window.
    +
    +    (2) Matching AUIPC instruction alone requires only seven bits.
    +        When the filter is applied to non-code data, that leads
    +        to many false positives which make compression worse.
    +        As long as most AUIPC+inst2 pairs appear as two consecutive
    +        instructions, converting only such pairs gives better results.
    +
    +    In assembly, AUIPC+inst2 tend to look like this:
    +
    +        # Call:
    +        auipc   ra, 0x12345
    +        jalr    ra, -42(ra)
    +
    +        # Tail call:
    +        auipc   t1, 0x12345
    +        jalr    zero, -42(t1)
    +
    +        # Getting the absolute address:
    +        auipc   a0, 0x12345
    +        addi    a0, a0, -42
    +
    +        # rd of inst2 isn't necessarily the same as rs1 even
    +        # in cases where there is no reason to preserve rs1.
    +        auipc   a0, 0x12345
    +        addi    a1, a0, -42
    +
    +    As of 2024, 16-bit instructions from the C extension don't
    +    appear as inst2. The RISC-V psABI doesn't list AUIPC+C.* as
    +    a linker relaxation type explicitly but it's not disallowed
    +    either. Usefulness is limited as most of the time the lowest
    +    12 bits won't fit in a C instruction. This filter doesn't
    +    support AUIPC+C.* combinations because this makes the filter
    +    simpler, there are no test files, and it hopefully will never
    +    be needed anyway.
    +
    +    (Compare AUIPC to ARM64 where ADRP does set the lowest 12 bits
    +    to zero. The paired instruction has the lowest 12 bits of the
    +    absolute address as is in a zero-extended immediate. Thus the
    +    ARM64 filter doesn't need to care about the instructions that
    +    are paired with ADRP. An off-by-4096 issue can still occur if
    +    the code section isn't aligned with the filter's start offset.
    +    It's not a problem with standalone ELF files but Windows PE
    +    files need start_offset=3072 for best results. Also, a .tar
    +    stores files with 512-byte alignment so most of the time it
    +    won't be the best for ARM64.)
    +
    +AUIPC with rd == x0
    +-------------------
    +
    +    AUIPC instructions with rd=x0 are reserved for HINTs in the base
    +    instruction set. Such AUIPC instructions are never filtered.
    +
    +    As of January 2024, it seems likely that AUIPC with rd=x0 will
    +    be used for landing pads (pseudoinstruction LPAD). LPAD is used
    +    to mark valid targets for indirect jumps (for JALR), for example,
    +    beginnings of functions. The 20-bit immediate in LPAD instruction
    +    is a label, not a pc-relative address. Thus it would be
    +    counterproductive to convert AUIPC instructions with rd=x0.
    +
    +    Often the next instruction after LPAD won't have rs1=x0 and thus
    +    the filtering would be skipped for that reason alone. However,
    +    it's not good to rely on this. For example, consider a function
    +    that begins like this:
    +
    +        int foo(int i)
    +        {
    +            if (i <= 234) {
    +                ...
    +            }
    +
    +    A compiler may generate something like this:
    +
    +        lpad    0x54321
    +        li      a5, 234
    +        bgt     a0, a5, .L2
    +
    +    Converting the pseudoinstructions to raw instructions:
    +
    +        auipc   x0, 0x54321
    +        addi    x15, x0, 234
    +        blt     x15, x10, .L2
    +
    +    In this case the filter would undesirably convert the AUIPC+ADDI
    +    pair if the filter didn't explicitly skip AUIPC instructions
    +    that have rd=x0.
    +
    +*/
    +
    +
    +#include "simple_private.h"
    +
    +
    +// This checks two conditions at once:
    +//    - AUIPC rd == inst2 rs1.
    +//    - inst2 opcode has the lowest two bits set.
    +//
    +// The 8 bit left shift aligns the rd of AUIPC with the rs1 of inst2.
    +// By XORing the registers, any non-zero value in those bits indicates the
    +// registers are not equal and thus not an AUIPC pair. Subtracting 3 from
    +// inst2 will zero out the first two opcode bits only when they are set.
    +// The mask tests if any of the register or opcode bits are set (and thus
    +// not an AUIPC pair).
    +//
    +// Alternative expression: (((((auipc) << 8) ^ (inst2)) & 0xF8003) != 3)
    +#define NOT_AUIPC_PAIR(auipc, inst2) \
    +	((((auipc) << 8) ^ ((inst2) - 3)) & 0xF8003)
    +
    +// This macro checks multiple conditions:
    +//   (1) AUIPC rd [11:7] == x2 (special rd value).
    +//   (2) AUIPC bits 12 and 13 set (the lowest two opcode bits of packed inst2).
    +//   (3) inst2_rs1 doesn't equal x0 or x2 because the opposite
    +//       conversion is only done when
    +//       auipc_rd != x0 &&
    +//       auipc_rd != x2 &&
    +//       auipc_rd == inst2_rs1.
    +//
    +// The left-hand side takes care of (1) and (2).
    +//   (a) The lowest 7 bits are already known to be AUIPC so subtracting 0x17
    +//       makes those bits zeros.
    +//   (b) If AUIPC rd equals x2, subtracting 0x100 makes bits [11:7] zeros.
    +//       If rd doesn't equal x2, then there will be at least one non-zero bit
    +//       and the next step (c) is irrelevant.
    +//   (c) If the lowest two opcode bits of the packed inst2 are set in [13:12],
    +//       then subtracting 0x3000 will make those bits zeros. Otherwise there
    +//       will be at least one non-zero bit.
    +//
    +// The shift by 18 removes the high bits from the final '>=' comparison and
    +// ensures that any non-zero result will be larger than any possible result
    +// from the right-hand side of the comparison. The cast ensures that the
    +// left-hand side didn't get promoted to a larger type than uint32_t.
    +//
    +// On the right-hand side, inst2_rs1 & 0x1D will be non-zero as long as
    +// inst2_rs1 is not x0 or x2.
    +//
    +// The final '>=' comparison will make the expression true if:
    +//   - The subtraction caused any bits to be set (special AUIPC rd value not
    +//     used or inst2 opcode bits not set). (non-zero >= non-zero or 0)
    +//   - The subtraction did not cause any bits to be set but inst2_rs1 was
    +//     x0 or x2. (0 >= 0)
    +#define NOT_SPECIAL_AUIPC(auipc, inst2_rs1) \
    +	((uint32_t)(((auipc) - 0x3117) << 18) >= ((inst2_rs1) & 0x1D))
    +
    +
    +// The encode and decode functions are split for this filter because of the
    +// AUIPC+inst2 filtering. This filter design allows a decoder-only
    +// implementation to be smaller than alternative designs.
    +
    +#ifdef HAVE_ENCODER_RISCV
    +static size_t
    +riscv_encode(void *simple lzma_attribute((__unused__)),
    +		uint32_t now_pos,
    +		bool is_encoder lzma_attribute((__unused__)),
    +		uint8_t *buffer, size_t size)
    +{
    +	// Avoid using i + 8 <= size in the loop condition.
    +	//
    +	// NOTE: If there is a JAL in the last six bytes of the stream, it
    +	// won't be converted. This is intentional to keep the code simpler.
    +	if (size < 8)
    +		return 0;
    +
    +	size -= 8;
    +
    +	size_t i;
    +
    +	// The loop is advanced by 2 bytes every iteration since the
    +	// instruction stream may include 16-bit instructions (C extension).
    +	for (i = 0; i <= size; i += 2) {
    +		uint32_t inst = buffer[i];
    +
    +		if (inst == 0xEF) {
    +			// JAL
    +			const uint32_t b1 = buffer[i + 1];
    +
    +			// Only filter rd=x1(ra) and rd=x5(t0).
    +			if ((b1 & 0x0D) != 0)
    +				continue;
    +
    +			// The 20-bit immediate is in four pieces.
    +			// The encoder stores it in big endian form
    +			// since it improves compression slightly.
    +			const uint32_t b2 = buffer[i + 2];
    +			const uint32_t b3 = buffer[i + 3];
    +			const uint32_t pc = now_pos + (uint32_t)i;
    +
    +// The following chart shows the highest three bytes of JAL, focusing on
    +// the 20-bit immediate field [31:12]. The first row of numbers is the
    +// bit position in a 32-bit little endian instruction. The second row of
    +// numbers shows the order of the immediate field in a J-type instruction.
    +// The last row is the bit number in each byte.
    +//
    +// To determine the amount to shift each bit, subtract the value in
    +// the last row from the value in the second last row. If the number
    +// is positive, shift left. If negative, shift right.
    +//
    +// For example, at the rightmost side of the chart, the bit 4 in b1 is
    +// the bit 12 of the address. Thus that bit needs to be shifted left
    +// by 12 - 4 = 8 bits to put it in the right place in the addr variable.
    +//
    +// NOTE: The immediate of a J-type instruction holds bits [20:1] of
    +// the address. The bit [0] is always 0 and not part of the immediate.
    +//
    +// |          b3             |          b2             |          b1         |
    +// | 31 30 29 28 27 26 25 24 | 23 22 21 20 19 18 17 16 | 15 14 13 12 x x x x |
    +// | 20 10  9  8  7  6  5  4 |  3  2  1 11 19 18 17 16 | 15 14 13 12 x x x x |
    +// |  7  6  5  4  3  2  1  0 |  7  6  5  4  3  2  1  0 |  7  6  5  4 x x x x |
    +
    +			uint32_t addr = ((b1 & 0xF0) << 8)
    +					| ((b2 & 0x0F) << 16)
    +					| ((b2 & 0x10) << 7)
    +					| ((b2 & 0xE0) >> 4)
    +					| ((b3 & 0x7F) << 4)
    +					| ((b3 & 0x80) << 13);
    +
    +			addr += pc;
    +
    +			buffer[i + 1] = (uint8_t)((b1 & 0x0F)
    +					| ((addr >> 13) & 0xF0));
    +
    +			buffer[i + 2] = (uint8_t)(addr >> 9);
    +			buffer[i + 3] = (uint8_t)(addr >> 1);
    +
    +			// The "-2" is included because the for-loop will
    +			// always increment by 2. In this case, we want to
    +			// skip an extra 2 bytes since we used 4 bytes
    +			// of input.
    +			i += 4 - 2;
    +
    +		} else if ((inst & 0x7F) == 0x17) {
    +			// AUIPC
    +			inst |= (uint32_t)buffer[i + 1] << 8;
    +			inst |= (uint32_t)buffer[i + 2] << 16;
    +			inst |= (uint32_t)buffer[i + 3] << 24;
    +
    +			// Branch based on AUIPC's rd. The bitmask test does
    +			// the same thing as this:
    +			//
    +			//     const uint32_t auipc_rd = (inst >> 7) & 0x1F;
    +			//     if (auipc_rd != 0 && auipc_rd != 2) {
    + 			if (inst & 0xE80) {
    +				// AUIPC's rd doesn't equal x0 or x2.
    +
    +				// Check if AUIPC+inst2 are a pair.
    +				uint32_t inst2 = read32le(buffer + i + 4);
    +
    +				if (NOT_AUIPC_PAIR(inst, inst2)) {
    +					// The NOT_AUIPC_PAIR macro allows
    +					// a false AUIPC+AUIPC pair if the
    +					// bits [19:15] (where rs1 would be)
    +					// in the second AUIPC match the rd
    +					// of the first AUIPC.
    +					//
    +					// We must skip enough forward so
    +					// that the first two bytes of the
    +					// second AUIPC cannot get converted.
    +					// Such a conversion could make the
    +					// current pair become a valid pair
    +					// which would desync the decoder.
    +					//
    +					// Skipping six bytes is enough even
    +					// though the above condition looks
    +					// at the lowest four bits of the
    +					// buffer[i + 6] too. This is safe
    +					// because this filter never changes
    +					// those bits if a conversion at
    +					// that position is done.
    +					i += 6 - 2;
    +					continue;
    +				}
    +
    +				// Convert AUIPC+inst2 to a special format:
    +				//
    +				//   - The lowest 7 bits [6:0] retain the
    +				//     AUIPC opcode.
    +				//
    +				//   - The rd [11:7] is set to x2(sp). x2 is
    +				//     used as the stack pointer so AUIPC with
    +				//     rd=x2 should be very rare in real-world
    +				//     executables.
    +				//
    +				//   - The remaining 20 bits [31:12] (that
    +				//     normally hold the pc-relative immediate)
    +				//     are used to store the lowest 20 bits of
    +				//     inst2. That is, the 12-bit immediate of
    +				//     inst2 is not included.
    +				//
    +				//   - The location of the original inst2 is
    +				//     used to store the 32-bit absolute
    +				//     address in big endian format. Compared
    +				//     to the 20+12-bit split encoding, this
    +				//     results in a longer uninterrupted
    +				//     sequence of identical common bytes
    +				//     when the same address is referred
    +				//     with different instruction pairs
    +				//     (like AUIPC+LD vs. AUIPC+ADDI) or
    +				//     when the occurrences of the same
    +				//     pair use different registers. When
    +				//     referring to adjacent memory locations
    +				//     (like function calls that go via the
    +				//     ELF PLT), in big endian order only the
    +				//     last 1-2 bytes differ; in little endian
    +				//     the differing 1-2 bytes would be in the
    +				//     middle of the 8-byte sequence.
    +				//
    +				// When reversing the transformation, the
    +				// original rd of AUIPC can be restored
    +				// from inst2's rs1 as they are required to
    +				// be the same.
    +
    +				// Arithmetic right shift makes sign extension
    +				// trivial but (1) it's implementation-defined
    +				// behavior (C99/C11/C23 6.5.7-p5) and so is
    +				// (2) casting unsigned to signed (6.3.1.3-p3).
    +				//
    +				// One can check for (1) with
    +				//
    +				//     if ((-1 >> 1) == -1) ...
    +				//
    +				// but (2) has to be checked from the
    +				// compiler docs. GCC promises that (1)
    +				// and (2) behave in the common expected
    +				// way and thus
    +				//
    +				//     addr += (uint32_t)(
    +				//             (int32_t)inst2 >> 20);
    +				//
    +				// does the same as the code below. But since
    +				// the 100 % portable way is only a few bytes
    +				// bigger code and there is no real speed
    +				// difference, let's just use that, especially
    +				// since the decoder doesn't need this at all.
    +				uint32_t addr = inst & 0xFFFFF000;
    +				addr += (inst2 >> 20)
    +						- ((inst2 >> 19) & 0x1000);
    +
    +				addr += now_pos + (uint32_t)i;
    +
    +				// Construct the first 32 bits:
    +				//   [6:0]    AUIPC opcode
    +				//   [11:7]   Special AUIPC rd = x2
    +				//   [31:12]  The lowest 20 bits of inst2
    +				inst = 0x17 | (2 << 7) | (inst2 << 12);
    +
    +				write32le(buffer + i, inst);
    +
    +				// The second 32 bits store the absolute
    +				// address in big endian order.
    +				write32be(buffer + i + 4, addr);
    +			} else {
    +				// AUIPC's rd equals x0 or x2.
    +				//
    +				// x0 indicates a landing pad (LPAD).
    +				// It's always skipped.
    +				//
    +				// AUIPC with rd == x2 is used for the special
    +				// format as explained above. When the input
    +				// contains a byte sequence that matches the
    +				// special format, "fake" decoding must be
    +				// done to keep the filter bijective (that
    +				// is, safe to apply on arbitrary data).
    +				//
    +				// See the "x0 or x2" section in riscv_decode()
    +				// for how the "real" decoding is done. The
    +				// "fake" decoding is a simplified version
    +				// of "real" decoding with the following
    +				// differences (these reduce code size of
    +				// the decoder):
    +				// (1) The lowest 12 bits aren't sign-extended.
    +				// (2) No address conversion is done.
    +				// (3) Big endian format isn't used (the fake
    +				//     address is in little endian order).
    +
    +				// Check if inst matches the special format.
    +				const uint32_t fake_rs1 = inst >> 27;
    +
    +				if (NOT_SPECIAL_AUIPC(inst, fake_rs1)) {
    +					i += 4 - 2;
    +					continue;
    +				}
    +
    +				const uint32_t fake_addr =
    +						read32le(buffer + i + 4);
    +
    +				// Construct the second 32 bits:
    +				//   [19:0]   Upper 20 bits from AUIPC
    +				//   [31:20]  The lowest 12 bits of fake_addr
    +				const uint32_t fake_inst2 = (inst >> 12)
    +						| (fake_addr << 20);
    +
    +				// Construct new first 32 bits from:
    +				//   [6:0]   AUIPC opcode
    +				//   [11:7]  Fake AUIPC rd = fake_rs1
    +				//   [31:12] The highest 20 bits of fake_addr
    +				inst = 0x17 | (fake_rs1 << 7)
    +					| (fake_addr & 0xFFFFF000);
    +
    +				write32le(buffer + i, inst);
    +				write32le(buffer + i + 4, fake_inst2);
    +			}
    +
    +			i += 8 - 2;
    +		}
    +	}
    +
    +	return i;
    +}
    +
    +
    +extern lzma_ret
    +lzma_simple_riscv_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return lzma_simple_coder_init(next, allocator, filters,
    +			&riscv_encode, 0, 8, 2, true);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_DECODER_RISCV
    +static size_t
    +riscv_decode(void *simple lzma_attribute((__unused__)),
    +		uint32_t now_pos,
    +		bool is_encoder lzma_attribute((__unused__)),
    +		uint8_t *buffer, size_t size)
    +{
    +	if (size < 8)
    +		return 0;
    +
    +	size -= 8;
    +
    +	size_t i;
    +	for (i = 0; i <= size; i += 2) {
    +		uint32_t inst = buffer[i];
    +
    +		if (inst == 0xEF) {
    +			// JAL
    +			const uint32_t b1 = buffer[i + 1];
    +
    +			// Only filter rd=x1(ra) and rd=x5(t0).
    +			if ((b1 & 0x0D) != 0)
    +				continue;
    +
    +			const uint32_t b2 = buffer[i + 2];
    +			const uint32_t b3 = buffer[i + 3];
    +			const uint32_t pc = now_pos + (uint32_t)i;
    +
    +// |          b3             |          b2             |          b1         |
    +// | 31 30 29 28 27 26 25 24 | 23 22 21 20 19 18 17 16 | 15 14 13 12 x x x x |
    +// | 20 10  9  8  7  6  5  4 |  3  2  1 11 19 18 17 16 | 15 14 13 12 x x x x |
    +// |  7  6  5  4  3  2  1  0 |  7  6  5  4  3  2  1  0 |  7  6  5  4 x x x x |
    +
    +			uint32_t addr = ((b1 & 0xF0) << 13)
    +					| (b2 << 9) | (b3 << 1);
    +
    +			addr -= pc;
    +
    +			buffer[i + 1] = (uint8_t)((b1 & 0x0F)
    +					| ((addr >> 8) & 0xF0));
    +
    +			buffer[i + 2] = (uint8_t)(((addr >> 16) & 0x0F)
    +					| ((addr >> 7) & 0x10)
    +					| ((addr << 4) & 0xE0));
    +
    +			buffer[i + 3] = (uint8_t)(((addr >> 4) & 0x7F)
    +					| ((addr >> 13) & 0x80));
    +
    +			i += 4 - 2;
    +
    +		} else if ((inst & 0x7F) == 0x17) {
    +			// AUIPC
    +			uint32_t inst2;
    +
    +			inst |= (uint32_t)buffer[i + 1] << 8;
    +			inst |= (uint32_t)buffer[i + 2] << 16;
    +			inst |= (uint32_t)buffer[i + 3] << 24;
    +
    +			if (inst & 0xE80) {
    +				// AUIPC's rd doesn't equal x0 or x2.
    +
    +				// Check if it is a "fake" AUIPC+inst2 pair.
    +				inst2 = read32le(buffer + i + 4);
    +
    +				if (NOT_AUIPC_PAIR(inst, inst2)) {
    +					i += 6 - 2;
    +					continue;
    +				}
    +
    +				// Decode (or more like re-encode) the "fake"
    +				// pair. The "fake" format doesn't do
    +				// sign-extension, address conversion, or
    +				// use big endian. (The use of little endian
    +				// allows sharing the write32le() calls in
    +				// the decoder to reduce code size when
    +				// unaligned access isn't supported.)
    +				uint32_t addr = inst & 0xFFFFF000;
    +				addr += inst2 >> 20;
    +
    +				inst = 0x17 | (2 << 7) | (inst2 << 12);
    +				inst2 = addr;
    +			} else {
    +				// AUIPC's rd equals x0 or x2.
    +
    +				// Check if inst matches the special format
    +				// used by the encoder.
    +				const uint32_t inst2_rs1 = inst >> 27;
    +
    +				if (NOT_SPECIAL_AUIPC(inst, inst2_rs1)) {
    +					i += 4 - 2;
    +					continue;
    +				}
    +
    +				// Decode the "real" pair.
    +				uint32_t addr = read32be(buffer + i + 4);
    +
    +				addr -= now_pos + (uint32_t)i;
    +
    +				// The second instruction:
    +				//   - Get the lowest 20 bits from inst.
    +				//   - Add the lowest 12 bits of the address
    +				//     as the immediate field.
    +				inst2 = (inst >> 12) | (addr << 20);
    +
    +				// AUIPC:
    +				//   - rd is the same as inst2_rs1.
    +				//   - The sign extension of the lowest 12 bits
    +				//     must be taken into account.
    +				inst = 0x17 | (inst2_rs1 << 7)
    +					| ((addr + 0x800) & 0xFFFFF000);
    +			}
    +
    +			// Both decoder branches write in little endian order.
    +			write32le(buffer + i, inst);
    +			write32le(buffer + i + 4, inst2);
    +
    +			i += 8 - 2;
    +		}
    +	}
    +
    +	return i;
    +}
    +
    +
    +extern lzma_ret
    +lzma_simple_riscv_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return lzma_simple_coder_init(next, allocator, filters,
    +			&riscv_decode, 0, 8, 2, false);
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.c
    new file mode 100644
    index 00000000000..5cbfa822704
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.c
    @@ -0,0 +1,291 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       simple_coder.c
    +/// \brief      Wrapper for simple filters
    +///
    +/// Simple filters don't change the size of the data i.e. number of bytes
    +/// in equals the number of bytes out.
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_private.h"
    +
    +
    +/// Copied or encodes/decodes more data to out[].
    +static lzma_ret
    +copy_or_code(lzma_simple_coder *coder, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	assert(!coder->end_was_reached);
    +
    +	if (coder->next.code == NULL) {
    +		lzma_bufcpy(in, in_pos, in_size, out, out_pos, out_size);
    +
    +		// Check if end of stream was reached.
    +		if (coder->is_encoder && action == LZMA_FINISH
    +				&& *in_pos == in_size)
    +			coder->end_was_reached = true;
    +
    +	} else {
    +		// Call the next coder in the chain to provide us some data.
    +		const lzma_ret ret = coder->next.code(
    +				coder->next.coder, allocator,
    +				in, in_pos, in_size,
    +				out, out_pos, out_size, action);
    +
    +		if (ret == LZMA_STREAM_END) {
    +			assert(!coder->is_encoder
    +					|| action == LZMA_FINISH);
    +			coder->end_was_reached = true;
    +
    +		} else if (ret != LZMA_OK) {
    +			return ret;
    +		}
    +	}
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static size_t
    +call_filter(lzma_simple_coder *coder, uint8_t *buffer, size_t size)
    +{
    +	const size_t filtered = coder->filter(coder->simple,
    +			coder->now_pos, coder->is_encoder,
    +			buffer, size);
    +	coder->now_pos += filtered;
    +	return filtered;
    +}
    +
    +
    +static lzma_ret
    +simple_code(void *coder_ptr, const lzma_allocator *allocator,
    +		const uint8_t *restrict in, size_t *restrict in_pos,
    +		size_t in_size, uint8_t *restrict out,
    +		size_t *restrict out_pos, size_t out_size, lzma_action action)
    +{
    +	lzma_simple_coder *coder = coder_ptr;
    +
    +	// TODO: Add partial support for LZMA_SYNC_FLUSH. We can support it
    +	// in cases when the filter is able to filter everything. With most
    +	// simple filters it can be done at offset that is a multiple of 2,
    +	// 4, or 16. With x86 filter, it needs good luck, and thus cannot
    +	// be made to work predictably.
    +	if (action == LZMA_SYNC_FLUSH)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	// Flush already filtered data from coder->buffer[] to out[].
    +	if (coder->pos < coder->filtered) {
    +		lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered,
    +				out, out_pos, out_size);
    +
    +		// If we couldn't flush all the filtered data, return to
    +		// application immediately.
    +		if (coder->pos < coder->filtered)
    +			return LZMA_OK;
    +
    +		if (coder->end_was_reached) {
    +			assert(coder->filtered == coder->size);
    +			return LZMA_STREAM_END;
    +		}
    +	}
    +
    +	// If we get here, there is no filtered data left in the buffer.
    +	coder->filtered = 0;
    +
    +	assert(!coder->end_was_reached);
    +
    +	// If there is more output space left than there is unfiltered data
    +	// in coder->buffer[], flush coder->buffer[] to out[], and copy/code
    +	// more data to out[] hopefully filling it completely. Then filter
    +	// the data in out[]. This step is where most of the data gets
    +	// filtered if the buffer sizes used by the application are reasonable.
    +	const size_t out_avail = out_size - *out_pos;
    +	const size_t buf_avail = coder->size - coder->pos;
    +	if (out_avail > buf_avail || buf_avail == 0) {
    +		// Store the old position so that we know from which byte
    +		// to start filtering.
    +		const size_t out_start = *out_pos;
    +
    +		// Flush data from coder->buffer[] to out[], but don't reset
    +		// coder->pos and coder->size yet. This way the coder can be
    +		// restarted if the next filter in the chain returns e.g.
    +		// LZMA_MEM_ERROR.
    +		//
    +		// Do the memcpy() conditionally because out can be NULL
    +		// (in which case buf_avail is always 0). Calling memcpy()
    +		// with a null-pointer is undefined even if the third
    +		// argument is 0.
    +		if (buf_avail > 0)
    +			memcpy(out + *out_pos, coder->buffer + coder->pos,
    +					buf_avail);
    +
    +		*out_pos += buf_avail;
    +
    +		// Copy/Encode/Decode more data to out[].
    +		{
    +			const lzma_ret ret = copy_or_code(coder, allocator,
    +					in, in_pos, in_size,
    +					out, out_pos, out_size, action);
    +			assert(ret != LZMA_STREAM_END);
    +			if (ret != LZMA_OK)
    +				return ret;
    +		}
    +
    +		// Filter out[] unless there is nothing to filter.
    +		// This way we avoid null pointer + 0 (undefined behavior)
    +		// when out == NULL.
    +		const size_t size = *out_pos - out_start;
    +		const size_t filtered = size == 0 ? 0 : call_filter(
    +				coder, out + out_start, size);
    +
    +		const size_t unfiltered = size - filtered;
    +		assert(unfiltered <= coder->allocated / 2);
    +
    +		// Now we can update coder->pos and coder->size, because
    +		// the next coder in the chain (if any) was successful.
    +		coder->pos = 0;
    +		coder->size = unfiltered;
    +
    +		if (coder->end_was_reached) {
    +			// The last byte has been copied to out[] already.
    +			// They are left as is.
    +			coder->size = 0;
    +
    +		} else if (unfiltered > 0) {
    +			// There is unfiltered data left in out[]. Copy it to
    +			// coder->buffer[] and rewind *out_pos appropriately.
    +			*out_pos -= unfiltered;
    +			memcpy(coder->buffer, out + *out_pos, unfiltered);
    +		}
    +	} else if (coder->pos > 0) {
    +		memmove(coder->buffer, coder->buffer + coder->pos, buf_avail);
    +		coder->size -= coder->pos;
    +		coder->pos = 0;
    +	}
    +
    +	assert(coder->pos == 0);
    +
    +	// If coder->buffer[] isn't empty, try to fill it by copying/decoding
    +	// more data. Then filter coder->buffer[] and copy the successfully
    +	// filtered data to out[]. It is probable, that some filtered and
    +	// unfiltered data will be left to coder->buffer[].
    +	if (coder->size > 0) {
    +		{
    +			const lzma_ret ret = copy_or_code(coder, allocator,
    +					in, in_pos, in_size,
    +					coder->buffer, &coder->size,
    +					coder->allocated, action);
    +			assert(ret != LZMA_STREAM_END);
    +			if (ret != LZMA_OK)
    +				return ret;
    +		}
    +
    +		coder->filtered = call_filter(
    +				coder, coder->buffer, coder->size);
    +
    +		// Everything is considered to be filtered if coder->buffer[]
    +		// contains the last bytes of the data.
    +		if (coder->end_was_reached)
    +			coder->filtered = coder->size;
    +
    +		// Flush as much as possible.
    +		lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered,
    +				out, out_pos, out_size);
    +	}
    +
    +	// Check if we got everything done.
    +	if (coder->end_was_reached && coder->pos == coder->size)
    +		return LZMA_STREAM_END;
    +
    +	return LZMA_OK;
    +}
    +
    +
    +static void
    +simple_coder_end(void *coder_ptr, const lzma_allocator *allocator)
    +{
    +	lzma_simple_coder *coder = coder_ptr;
    +	lzma_next_end(&coder->next, allocator);
    +	lzma_free(coder->simple, allocator);
    +	lzma_free(coder, allocator);
    +	return;
    +}
    +
    +
    +static lzma_ret
    +simple_coder_update(void *coder_ptr, const lzma_allocator *allocator,
    +		const lzma_filter *filters_null lzma_attribute((__unused__)),
    +		const lzma_filter *reversed_filters)
    +{
    +	lzma_simple_coder *coder = coder_ptr;
    +
    +	// No update support, just call the next filter in the chain.
    +	return lzma_next_filter_update(
    +			&coder->next, allocator, reversed_filters + 1);
    +}
    +
    +
    +extern lzma_ret
    +lzma_simple_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters,
    +		size_t (*filter)(void *simple, uint32_t now_pos,
    +			bool is_encoder, uint8_t *buffer, size_t size),
    +		size_t simple_size, size_t unfiltered_max,
    +		uint32_t alignment, bool is_encoder)
    +{
    +	// Allocate memory for the lzma_simple_coder structure if needed.
    +	lzma_simple_coder *coder = next->coder;
    +	if (coder == NULL) {
    +		// Here we allocate space also for the temporary buffer. We
    +		// need twice the size of unfiltered_max, because then it
    +		// is always possible to filter at least unfiltered_max bytes
    +		// more data in coder->buffer[] if it can be filled completely.
    +		coder = lzma_alloc(sizeof(lzma_simple_coder)
    +				+ 2 * unfiltered_max, allocator);
    +		if (coder == NULL)
    +			return LZMA_MEM_ERROR;
    +
    +		next->coder = coder;
    +		next->code = &simple_code;
    +		next->end = &simple_coder_end;
    +		next->update = &simple_coder_update;
    +
    +		coder->next = LZMA_NEXT_CODER_INIT;
    +		coder->filter = filter;
    +		coder->allocated = 2 * unfiltered_max;
    +
    +		// Allocate memory for filter-specific data structure.
    +		if (simple_size > 0) {
    +			coder->simple = lzma_alloc(simple_size, allocator);
    +			if (coder->simple == NULL)
    +				return LZMA_MEM_ERROR;
    +		} else {
    +			coder->simple = NULL;
    +		}
    +	}
    +
    +	if (filters[0].options != NULL) {
    +		const lzma_options_bcj *simple = filters[0].options;
    +		coder->now_pos = simple->start_offset;
    +		if (coder->now_pos & (alignment - 1))
    +			return LZMA_OPTIONS_ERROR;
    +	} else {
    +		coder->now_pos = 0;
    +	}
    +
    +	// Reset variables.
    +	coder->is_encoder = is_encoder;
    +	coder->end_was_reached = false;
    +	coder->pos = 0;
    +	coder->filtered = 0;
    +	coder->size = 0;
    +
    +	return lzma_next_filter_init(&coder->next, allocator, filters + 1);
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.h
    new file mode 100644
    index 00000000000..2b762d50071
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.h
    @@ -0,0 +1,89 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       simple_coder.h
    +/// \brief      Wrapper for simple filters
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_SIMPLE_CODER_H
    +#define LZMA_SIMPLE_CODER_H
    +
    +#include "common.h"
    +
    +
    +extern lzma_ret lzma_simple_x86_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_simple_x86_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +
    +extern lzma_ret lzma_simple_powerpc_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_simple_powerpc_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +
    +extern lzma_ret lzma_simple_ia64_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_simple_ia64_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +
    +extern lzma_ret lzma_simple_arm_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_simple_arm_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +
    +extern lzma_ret lzma_simple_armthumb_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_simple_armthumb_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +
    +extern lzma_ret lzma_simple_arm64_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_simple_arm64_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +
    +extern lzma_ret lzma_simple_sparc_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_simple_sparc_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +
    +extern lzma_ret lzma_simple_riscv_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +extern lzma_ret lzma_simple_riscv_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.c
    new file mode 100644
    index 00000000000..d9820ee8ed2
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.c
    @@ -0,0 +1,39 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       simple_decoder.c
    +/// \brief      Properties decoder for simple filters
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_decoder.h"
    +
    +
    +extern lzma_ret
    +lzma_simple_props_decode(void **options, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size)
    +{
    +	if (props_size == 0)
    +		return LZMA_OK;
    +
    +	if (props_size != 4)
    +		return LZMA_OPTIONS_ERROR;
    +
    +	lzma_options_bcj *opt = lzma_alloc(
    +			sizeof(lzma_options_bcj), allocator);
    +	if (opt == NULL)
    +		return LZMA_MEM_ERROR;
    +
    +	opt->start_offset = read32le(props);
    +
    +	// Don't leave an options structure allocated if start_offset is zero.
    +	if (opt->start_offset == 0)
    +		lzma_free(opt, allocator);
    +	else
    +		*options = opt;
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.h
    new file mode 100644
    index 00000000000..2ae87bb8632
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.h
    @@ -0,0 +1,21 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       simple_decoder.h
    +/// \brief      Properties decoder for simple filters
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_SIMPLE_DECODER_H
    +#define LZMA_SIMPLE_DECODER_H
    +
    +#include "simple_coder.h"
    +
    +extern lzma_ret lzma_simple_props_decode(
    +		void **options, const lzma_allocator *allocator,
    +		const uint8_t *props, size_t props_size);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.c
    new file mode 100644
    index 00000000000..d1f35096e2a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.c
    @@ -0,0 +1,37 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       simple_encoder.c
    +/// \brief      Properties encoder for simple filters
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_encoder.h"
    +
    +
    +extern lzma_ret
    +lzma_simple_props_size(uint32_t *size, const void *options)
    +{
    +	const lzma_options_bcj *const opt = options;
    +	*size = (opt == NULL || opt->start_offset == 0) ? 0 : 4;
    +	return LZMA_OK;
    +}
    +
    +
    +extern lzma_ret
    +lzma_simple_props_encode(const void *options, uint8_t *out)
    +{
    +	const lzma_options_bcj *const opt = options;
    +
    +	// The default start offset is zero, so we don't need to store any
    +	// options unless the start offset is non-zero.
    +	if (opt == NULL || opt->start_offset == 0)
    +		return LZMA_OK;
    +
    +	write32le(out, opt->start_offset);
    +
    +	return LZMA_OK;
    +}
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.h
    new file mode 100644
    index 00000000000..bf5edbb1c3f
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.h
    @@ -0,0 +1,22 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       simple_encoder.c
    +/// \brief      Properties encoder for simple filters
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_SIMPLE_ENCODER_H
    +#define LZMA_SIMPLE_ENCODER_H
    +
    +#include "simple_coder.h"
    +
    +
    +extern lzma_ret lzma_simple_props_size(uint32_t *size, const void *options);
    +
    +extern lzma_ret lzma_simple_props_encode(const void *options, uint8_t *out);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_private.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_private.h
    new file mode 100644
    index 00000000000..7aa360ff49e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_private.h
    @@ -0,0 +1,73 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       simple_private.h
    +/// \brief      Private definitions for so called simple filters
    +//
    +//  Author:     Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef LZMA_SIMPLE_PRIVATE_H
    +#define LZMA_SIMPLE_PRIVATE_H
    +
    +#include "simple_coder.h"
    +
    +
    +typedef struct {
    +	/// Next filter in the chain
    +	lzma_next_coder next;
    +
    +	/// True if the next coder in the chain has returned LZMA_STREAM_END.
    +	bool end_was_reached;
    +
    +	/// True if filter() should encode the data; false to decode.
    +	/// Currently all simple filters use the same function for encoding
    +	/// and decoding, because the difference between encoders and decoders
    +	/// is very small.
    +	bool is_encoder;
    +
    +	/// Pointer to filter-specific function, which does
    +	/// the actual filtering.
    +	size_t (*filter)(void *simple, uint32_t now_pos,
    +			bool is_encoder, uint8_t *buffer, size_t size);
    +
    +	/// Pointer to filter-specific data, or NULL if filter doesn't need
    +	/// any extra data.
    +	void *simple;
    +
    +	/// The lowest 32 bits of the current position in the data. Most
    +	/// filters need this to do conversions between absolute and relative
    +	/// addresses.
    +	uint32_t now_pos;
    +
    +	/// Size of the memory allocated for the buffer.
    +	size_t allocated;
    +
    +	/// Flushing position in the temporary buffer. buffer[pos] is the
    +	/// next byte to be copied to out[].
    +	size_t pos;
    +
    +	/// buffer[filtered] is the first unfiltered byte. When pos is smaller
    +	/// than filtered, there is unflushed filtered data in the buffer.
    +	size_t filtered;
    +
    +	/// Total number of bytes (both filtered and unfiltered) currently
    +	/// in the temporary buffer.
    +	size_t size;
    +
    +	/// Temporary buffer
    +	uint8_t buffer[];
    +} lzma_simple_coder;
    +
    +
    +extern lzma_ret lzma_simple_coder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters,
    +		size_t (*filter)(void *simple, uint32_t now_pos,
    +			bool is_encoder, uint8_t *buffer, size_t size),
    +		size_t simple_size, size_t unfiltered_max,
    +		uint32_t alignment, bool is_encoder);
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/sparc.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/sparc.c
    new file mode 100644
    index 00000000000..e8ad285a192
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/sparc.c
    @@ -0,0 +1,86 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       sparc.c
    +/// \brief      Filter for SPARC binaries
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_private.h"
    +
    +
    +static size_t
    +sparc_code(void *simple lzma_attribute((__unused__)),
    +		uint32_t now_pos, bool is_encoder,
    +		uint8_t *buffer, size_t size)
    +{
    +	size_t i;
    +	for (i = 0; i + 4 <= size; i += 4) {
    +
    +		if ((buffer[i] == 0x40 && (buffer[i + 1] & 0xC0) == 0x00)
    +				|| (buffer[i] == 0x7F
    +				&& (buffer[i + 1] & 0xC0) == 0xC0)) {
    +
    +			uint32_t src = ((uint32_t)buffer[i + 0] << 24)
    +					| ((uint32_t)buffer[i + 1] << 16)
    +					| ((uint32_t)buffer[i + 2] << 8)
    +					| ((uint32_t)buffer[i + 3]);
    +
    +			src <<= 2;
    +
    +			uint32_t dest;
    +			if (is_encoder)
    +				dest = now_pos + (uint32_t)(i) + src;
    +			else
    +				dest = src - (now_pos + (uint32_t)(i));
    +
    +			dest >>= 2;
    +
    +			dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF)
    +					| (dest & 0x3FFFFF)
    +					| 0x40000000;
    +
    +			buffer[i + 0] = (uint8_t)(dest >> 24);
    +			buffer[i + 1] = (uint8_t)(dest >> 16);
    +			buffer[i + 2] = (uint8_t)(dest >> 8);
    +			buffer[i + 3] = (uint8_t)(dest);
    +		}
    +	}
    +
    +	return i;
    +}
    +
    +
    +static lzma_ret
    +sparc_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters, bool is_encoder)
    +{
    +	return lzma_simple_coder_init(next, allocator, filters,
    +			&sparc_code, 0, 4, 4, is_encoder);
    +}
    +
    +
    +#ifdef HAVE_ENCODER_SPARC
    +extern lzma_ret
    +lzma_simple_sparc_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return sparc_coder_init(next, allocator, filters, true);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_DECODER_SPARC
    +extern lzma_ret
    +lzma_simple_sparc_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return sparc_coder_init(next, allocator, filters, false);
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/x86.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/x86.c
    new file mode 100644
    index 00000000000..f216231f2d1
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/x86.c
    @@ -0,0 +1,157 @@
    +// SPDX-License-Identifier: 0BSD
    +
    +///////////////////////////////////////////////////////////////////////////////
    +//
    +/// \file       x86.c
    +/// \brief      Filter for x86 binaries (BCJ filter)
    +///
    +//  Authors:    Igor Pavlov
    +//              Lasse Collin
    +//
    +///////////////////////////////////////////////////////////////////////////////
    +
    +#include "simple_private.h"
    +
    +
    +#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
    +
    +
    +typedef struct {
    +	uint32_t prev_mask;
    +	uint32_t prev_pos;
    +} lzma_simple_x86;
    +
    +
    +static size_t
    +x86_code(void *simple_ptr, uint32_t now_pos, bool is_encoder,
    +		uint8_t *buffer, size_t size)
    +{
    +	static const uint32_t MASK_TO_BIT_NUMBER[5] = { 0, 1, 2, 2, 3 };
    +
    +	lzma_simple_x86 *simple = simple_ptr;
    +	uint32_t prev_mask = simple->prev_mask;
    +	uint32_t prev_pos = simple->prev_pos;
    +
    +	if (size < 5)
    +		return 0;
    +
    +	if (now_pos - prev_pos > 5)
    +		prev_pos = now_pos - 5;
    +
    +	const size_t limit = size - 5;
    +	size_t buffer_pos = 0;
    +
    +	while (buffer_pos <= limit) {
    +		uint8_t b = buffer[buffer_pos];
    +		if (b != 0xE8 && b != 0xE9) {
    +			++buffer_pos;
    +			continue;
    +		}
    +
    +		const uint32_t offset = now_pos + (uint32_t)(buffer_pos)
    +				- prev_pos;
    +		prev_pos = now_pos + (uint32_t)(buffer_pos);
    +
    +		if (offset > 5) {
    +			prev_mask = 0;
    +		} else {
    +			for (uint32_t i = 0; i < offset; ++i) {
    +				prev_mask &= 0x77;
    +				prev_mask <<= 1;
    +			}
    +		}
    +
    +		b = buffer[buffer_pos + 4];
    +
    +		if (Test86MSByte(b) && (prev_mask >> 1) <= 4
    +			&& (prev_mask >> 1) != 3) {
    +
    +			uint32_t src = ((uint32_t)(b) << 24)
    +				| ((uint32_t)(buffer[buffer_pos + 3]) << 16)
    +				| ((uint32_t)(buffer[buffer_pos + 2]) << 8)
    +				| (buffer[buffer_pos + 1]);
    +
    +			uint32_t dest;
    +			while (true) {
    +				if (is_encoder)
    +					dest = src + (now_pos + (uint32_t)(
    +							buffer_pos) + 5);
    +				else
    +					dest = src - (now_pos + (uint32_t)(
    +							buffer_pos) + 5);
    +
    +				if (prev_mask == 0)
    +					break;
    +
    +				const uint32_t i = MASK_TO_BIT_NUMBER[
    +						prev_mask >> 1];
    +
    +				b = (uint8_t)(dest >> (24 - i * 8));
    +
    +				if (!Test86MSByte(b))
    +					break;
    +
    +				src = dest ^ ((1U << (32 - i * 8)) - 1);
    +			}
    +
    +			buffer[buffer_pos + 4]
    +					= (uint8_t)(~(((dest >> 24) & 1) - 1));
    +			buffer[buffer_pos + 3] = (uint8_t)(dest >> 16);
    +			buffer[buffer_pos + 2] = (uint8_t)(dest >> 8);
    +			buffer[buffer_pos + 1] = (uint8_t)(dest);
    +			buffer_pos += 5;
    +			prev_mask = 0;
    +
    +		} else {
    +			++buffer_pos;
    +			prev_mask |= 1;
    +			if (Test86MSByte(b))
    +				prev_mask |= 0x10;
    +		}
    +	}
    +
    +	simple->prev_mask = prev_mask;
    +	simple->prev_pos = prev_pos;
    +
    +	return buffer_pos;
    +}
    +
    +
    +static lzma_ret
    +x86_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    +		const lzma_filter_info *filters, bool is_encoder)
    +{
    +	const lzma_ret ret = lzma_simple_coder_init(next, allocator, filters,
    +			&x86_code, sizeof(lzma_simple_x86), 5, 1, is_encoder);
    +
    +	if (ret == LZMA_OK) {
    +		lzma_simple_coder *coder = next->coder;
    +		lzma_simple_x86 *simple = coder->simple;
    +		simple->prev_mask = 0;
    +		simple->prev_pos = (uint32_t)(-5);
    +	}
    +
    +	return ret;
    +}
    +
    +
    +#ifdef HAVE_ENCODER_X86
    +extern lzma_ret
    +lzma_simple_x86_encoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return x86_coder_init(next, allocator, filters, true);
    +}
    +#endif
    +
    +
    +#ifdef HAVE_DECODER_X86
    +extern lzma_ret
    +lzma_simple_x86_decoder_init(lzma_next_coder *next,
    +		const lzma_allocator *allocator,
    +		const lzma_filter_info *filters)
    +{
    +	return x86_coder_init(next, allocator, filters, false);
    +}
    +#endif
    diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/validate_map.sh b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/validate_map.sh
    new file mode 100644
    index 00000000000..dd1589d236e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/validate_map.sh
    @@ -0,0 +1,163 @@
    +#!/bin/sh
    +# SPDX-License-Identifier: 0BSD
    +
    +###############################################################################
    +#
    +# Check liblzma_*.map for certain types of errors.
    +#
    +# liblzma_generic.map is for FreeBSD and Solaris and possibly others
    +# except GNU/Linux.
    +#
    +# liblzma_linux.map is for GNU/Linux only. This and the matching extra code
    +# in the .c files make liblzma >= 5.2.7 compatible with binaries that were
    +# linked against ill-patched liblzma in RHEL/CentOS 7. By providing the
    +# compatibility in official XZ Utils release will hopefully prevent people
    +# from further copying the broken patch to other places when they want
    +# compatibility with binaries linked on RHEL/CentOS 7. The long version
    +# of the story:
    +#
    +#     RHEL/CentOS 7 shipped with 5.1.2alpha, including the threaded
    +#     encoder that is behind #ifdef LZMA_UNSTABLE in the API headers.
    +#     In 5.1.2alpha these symbols are under XZ_5.1.2alpha in liblzma.map.
    +#     API/ABI compatibility tracking isn't done between development
    +#     releases so newer releases didn't have XZ_5.1.2alpha anymore.
    +#
    +#     Later RHEL/CentOS 7 updated xz to 5.2.2 but they wanted to keep
    +#     the exported symbols compatible with 5.1.2alpha. After checking
    +#     the ABI changes it turned out that >= 5.2.0 ABI is backward
    +#     compatible with the threaded encoder functions from 5.1.2alpha
    +#     (but not vice versa as fixes and extensions to these functions
    +#     were made between 5.1.2alpha and 5.2.0).
    +#
    +#     In RHEL/CentOS 7, XZ Utils 5.2.2 was patched with
    +#     xz-5.2.2-compat-libs.patch to modify liblzma.map:
    +#
    +#       - XZ_5.1.2alpha was added with lzma_stream_encoder_mt and
    +#         lzma_stream_encoder_mt_memusage. This matched XZ Utils 5.1.2alpha.
    +#
    +#       - XZ_5.2 was replaced with XZ_5.2.2. It is clear that this was
    +#         an error; the intention was to keep using XZ_5.2 (XZ_5.2.2
    +#         has never been used in XZ Utils). So XZ_5.2.2 lists all
    +#         symbols that were listed under XZ_5.2 before the patch.
    +#         lzma_stream_encoder_mt and _mt_memusage are included too so
    +#         they are listed both here and under XZ_5.1.2alpha.
    +#
    +#     The patch didn't add any __asm__(".symver ...") lines to the .c
    +#     files. Thus the resulting liblzma.so exports the threaded encoder
    +#     functions under XZ_5.1.2alpha only. Listing the two functions
    +#     also under XZ_5.2.2 in liblzma.map has no effect without
    +#     matching .symver lines.
    +#
    +#     The lack of XZ_5.2 in RHEL/CentOS 7 means that binaries linked
    +#     against unpatched XZ Utils 5.2.x won't run on RHEL/CentOS 7.
    +#     This is unfortunate but this alone isn't too bad as the problem
    +#     is contained within RHEL/CentOS 7 and doesn't affect users
    +#     of other distributions. It could also be fixed internally in
    +#     RHEL/CentOS 7.
    +#
    +#     The second problem is more serious: In XZ Utils 5.2.2 the API
    +#     headers don't have #ifdef LZMA_UNSTABLE for obvious reasons.
    +#     This is true in RHEL/CentOS 7 version too. Thus now programs
    +#     using new APIs can be compiled without an extra #define. However,
    +#     the programs end up depending on symbol version XZ_5.1.2alpha
    +#     (and possibly also XZ_5.2.2) instead of XZ_5.2 as they would
    +#     with an unpatched XZ Utils 5.2.2. This means that such binaries
    +#     won't run on other distributions shipping XZ Utils >= 5.2.0 as
    +#     they don't provide XZ_5.1.2alpha or XZ_5.2.2; they only provide
    +#     XZ_5.2 (and XZ_5.0). (This includes RHEL/CentOS 8 as the patch
    +#     luckily isn't included there anymore with XZ Utils 5.2.4.)
    +#
    +#     Binaries built by RHEL/CentOS 7 users get distributed and then
    +#     people wonder why they don't run on some other distribution.
    +#     Seems that people have found out about the patch and been copying
    +#     it to some build scripts, seemingly curing the symptoms but
    +#     actually spreading the illness further and outside RHEL/CentOS 7.
    +#     Adding compatibility in an official XZ Utils release should work
    +#     as a vaccine against this ill patch and stop it from spreading.
    +#     The vaccine is kept GNU/Linux-only as other OSes should be immune
    +#     (hopefully it hasn't spread via some build script to other OSes).
    +#
    +# Author: Lasse Collin
    +#
    +###############################################################################
    +
    +LC_ALL=C
    +export LC_ALL
    +
    +STATUS=0
    +
    +cd "$(dirname "$0")"
    +
    +# Get the list of symbols that aren't defined in liblzma_generic.map.
    +SYMS=$(sed -n 's/^extern LZMA_API([^)]*) \([a-z0-9_]*\)(.*$/\1;/p' \
    +		api/lzma/*.h \
    +	| sort \
    +	| grep -Fve "$(sed '/[{}:*]/d;/^$/d;s/^	//' liblzma_generic.map)")
    +
    +# Check that there are no old alpha or beta versions listed.
    +VER=$(cd ../.. && sh build-aux/version.sh)
    +NAMES=
    +case $VER in
    +	*alpha | *beta)
    +		NAMES=$(sed -n 's/^.*XZ_\([^ ]*\)\(alpha\|beta\) .*$/\1\2/p' \
    +			liblzma_generic.map | grep -Fv "$VER")
    +		;;
    +esac
    +
    +# Check for duplicate lines. It can catch missing dependencies.
    +DUPS=$(sort liblzma_generic.map | sed '/^$/d;/^global:$/d' | uniq -d)
    +
    +# Check that liblzma_linux.map is in sync with liblzma_generic.map.
    +# The RHEL/CentOS 7 compatibility symbols are in a fixed location
    +# so it makes it easy to remove them for comparison with liblzma_generic.map.
    +#
    +# NOTE: Putting XZ_5.2 before the compatibility symbols XZ_5.1.2alpha
    +# and XZ_5.2.2 in liblzma_linux.map is important: If liblzma_linux.map is
    +# incorrectly used without #define HAVE_SYMBOL_VERSIONS_LINUX, only the first
    +# occurrence of each function name will be used from liblzma_linux.map;
    +# the rest are ignored by the linker. Thus having XZ_5.2 before the
    +# compatibility symbols means that @@XZ_5.2 will be used for the symbols
    +# listed under XZ_5.2 {...} and the same function names later in
    +# the file under XZ_5.1.2alpha {...} and XZ_5.2.2 {...} will be
    +# ignored (@XZ_5.1.2alpha or @XZ_5.2.2 won't be added at all when
    +# the #define HAVE_SYMBOL_VERSIONS_LINUX isn't used).
    +IN_SYNC=
    +if ! sed '111,125d' liblzma_linux.map \
    +		| cmp -s - liblzma_generic.map; then
    +	IN_SYNC=no
    +fi
    +
    +# Print error messages if needed.
    +if test -n "$SYMS$NAMES$DUPS$IN_SYNC"; then
    +	echo
    +	echo 'validate_map.sh found problems from liblzma_*.map:'
    +	echo
    +
    +	if test -n "$SYMS"; then
    +		echo 'liblzma_generic.map lacks the following symbols:'
    +		echo "$SYMS"
    +		echo
    +	fi
    +
    +	if test -n "$NAMES"; then
    +		echo 'Obsolete alpha or beta version names:'
    +		echo "$NAMES"
    +		echo
    +	fi
    +
    +	if test -n "$DUPS"; then
    +		echo 'Duplicate lines:'
    +		echo "$DUPS"
    +		echo
    +	fi
    +
    +	if test -n "$IN_SYNC"; then
    +		echo "liblzma_generic.map and liblzma_linux.map aren't in sync"
    +		echo
    +	fi
    +
    +	STATUS=1
    +fi
    +
    +# Exit status is 1 if problems were found, 0 otherwise.
    +exit "$STATUS"
    diff --git a/src/libs/3rdparty/karchive/AUTHORS b/src/libs/3rdparty/karchive/AUTHORS
    new file mode 100644
    index 00000000000..f6ec78707c6
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/AUTHORS
    @@ -0,0 +1,10 @@
    +Maintainers:
    +Mario Bensi 
    +David Faure 
    +
    +Many other contributors, see git log.
    +
    +For questions about this package, email kde-frameworks-devel@kde.org.
    +
    +For bug reports, please use https://bugs.kde.org
    +
    diff --git a/src/libs/3rdparty/karchive/CMakeLists.txt b/src/libs/3rdparty/karchive/CMakeLists.txt
    new file mode 100644
    index 00000000000..43b61a998f1
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/CMakeLists.txt
    @@ -0,0 +1,152 @@
    +cmake_minimum_required(VERSION 3.16)
    +
    +set(KF_VERSION "6.10.0") # handled by release scripts
    +project(KArchive VERSION ${KF_VERSION})
    +
    +include(FeatureSummary)
    +find_package(ECM 6.9.0  NO_MODULE)
    +set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
    +feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
    +
    +option(WITH_BZIP2 "Make bzip2 required" ON)
    +option(WITH_LIBLZMA "Make liblzma required" ON)
    +option(WITH_LIBZSTD "Make libzstd required" ON)
    +
    +set(PKGCONFIG_REQUIRED_TYPE "")
    +
    +if(WITH_BZIP2)
    +    set(BZIP2_PACKAGE_TYPE "REQUIRED")
    +else()
    +    set(BZIP2_PACKAGE_TYPE "RECOMMENDED")
    +endif()
    +
    +if(WITH_LIBLZMA)
    +    set(LIBLZMA_PACKAGE_TYPE "REQUIRED")
    +else()
    +    set(LIBLZMA_PACKAGE_TYPE "RECOMMENDED")
    +endif()
    +
    +if(WITH_LIBZSTD)
    +    set(PKGCONFIG_REQUIRED_TYPE "REQUIRED")
    +    set(LIBZSTD_REQUIRED_TYPE "REQUIRED")
    +else()
    +    set(LIBZSTD_REQUIRED_TYPE "")
    +endif()
    +
    +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
    +
    +include(KDEInstallDirs)
    +include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
    +include(KDECMakeSettings)
    +include(KDEGitCommitHooks)
    +
    +include(ECMGenerateExportHeader)
    +
    +set(REQUIRED_QT_VERSION 6.6.0)
    +find_package(Qt6Core ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
    +
    +find_package(ZLIB)
    +set_package_properties(ZLIB PROPERTIES
    +    URL "https://www.zlib.net"
    +    DESCRIPTION "Support for gzip compressed files and data streams"
    +    TYPE REQUIRED
    +    PURPOSE "Support for gzip compressed files and data streams"
    +)
    +
    +find_package(BZip2)
    +set_package_properties(BZip2 PROPERTIES
    +    URL "https://sourceware.org/bzip2/"
    +    DESCRIPTION "Support for BZip2 compressed files and data streams"
    +    TYPE ${BZIP2_PACKAGE_TYPE}
    +    PURPOSE "Support for BZip2 compressed files and data streams"
    +)
    +
    +find_package(LibLZMA)
    +set_package_properties(LibLZMA PROPERTIES
    +    URL "https://tukaani.org/xz/"
    +    DESCRIPTION "Support for xz compressed files and data streams"
    +    TYPE ${LIBLZMA_PACKAGE_TYPE}
    +    PURPOSE "Support for xz compressed files and data streams"
    +)
    +
    +
    +find_package(PkgConfig ${PKGCONFIG_REQUIRED_TYPE})
    +if (PkgConfig_FOUND)
    +    pkg_check_modules(LibZstd ${LIBZSTD_REQUIRED_TYPE} IMPORTED_TARGET "libzstd")
    +endif()
    +add_feature_info(LibZstd LibZstd_FOUND
    +                "Support for zstd compressed files and data streams"
    +)
    +
    +include(ECMSetupVersion)
    +include(ECMGenerateHeaders)
    +include(ECMQtDeclareLoggingCategory)
    +include(ECMAddQch)
    +include(ECMDeprecationSettings)
    +include(ECMPoQmTools)
    +
    +set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].")
    +
    +option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF)
    +add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)")
    +
    +set(karchive_version_header "${CMAKE_CURRENT_BINARY_DIR}/src/karchive_version.h")
    +ecm_setup_version(PROJECT
    +    VARIABLE_PREFIX KARCHIVE
    +    VERSION_HEADER "${karchive_version_header}"
    +    PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfigVersion.cmake"
    +    SOVERSION 6)
    +
    +ecm_set_disabled_deprecation_versions(
    +    QT 6.8
    +)
    +
    +
    +add_subdirectory(src)
    +if (BUILD_TESTING)
    +    add_subdirectory(autotests)
    +    add_subdirectory(tests)
    +endif()
    +
    +ecm_install_po_files_as_qm(poqm)
    +
    +# create a Config.cmake and a ConfigVersion.cmake file and install them
    +set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF6Archive")
    +
    +if (BUILD_QCH)
    +    ecm_install_qch_export(
    +        TARGETS KF6Archive_QCH
    +        FILE KF6ArchiveQchTargets.cmake
    +        DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
    +        COMPONENT Devel
    +    )
    +    set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF6ArchiveQchTargets.cmake\")")
    +endif()
    +
    +include(CMakePackageConfigHelpers)
    +
    +configure_package_config_file(
    +    "${CMAKE_CURRENT_SOURCE_DIR}/KF6ArchiveConfig.cmake.in"
    +    "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfig.cmake"
    +    INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
    +)
    +
    +install(FILES ${karchive_version_header}
    +        DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KArchive
    +        COMPONENT Devel)
    +
    +install(FILES
    +            "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfig.cmake"
    +            "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfigVersion.cmake"
    +        DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
    +        COMPONENT Devel)
    +
    +install(EXPORT KF6ArchiveTargets
    +        DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
    +        FILE KF6ArchiveTargets.cmake
    +        NAMESPACE KF6::)
    +
    +include(ECMFeatureSummary)
    +ecm_feature_summary(WHAT ALL   FATAL_ON_MISSING_REQUIRED_PACKAGES)
    +
    +kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT)
    diff --git a/src/libs/3rdparty/karchive/LICENSES/BSD-2-Clause.txt b/src/libs/3rdparty/karchive/LICENSES/BSD-2-Clause.txt
    new file mode 100644
    index 00000000000..2d2bab1127b
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/LICENSES/BSD-2-Clause.txt
    @@ -0,0 +1,22 @@
    +Copyright (c)  . All rights reserved.
    +
    +Redistribution and use in source and binary forms, with or without modification,
    +are permitted provided that the following conditions are met:
    +
    +1. Redistributions of source code must retain the above copyright notice,
    +this list of conditions and the following disclaimer.
    +
    +2. Redistributions in binary form must reproduce the above copyright notice,
    +this list of conditions and the following disclaimer in the documentation
    +and/or other materials provided with the distribution.
    +
    +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
    +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    diff --git a/src/libs/3rdparty/karchive/LICENSES/CC0-1.0.txt b/src/libs/3rdparty/karchive/LICENSES/CC0-1.0.txt
    new file mode 100644
    index 00000000000..0e259d42c99
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/LICENSES/CC0-1.0.txt
    @@ -0,0 +1,121 @@
    +Creative Commons Legal Code
    +
    +CC0 1.0 Universal
    +
    +    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
    +    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
    +    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
    +    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
    +    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
    +    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
    +    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
    +    HEREUNDER.
    +
    +Statement of Purpose
    +
    +The laws of most jurisdictions throughout the world automatically confer
    +exclusive Copyright and Related Rights (defined below) upon the creator
    +and subsequent owner(s) (each and all, an "owner") of an original work of
    +authorship and/or a database (each, a "Work").
    +
    +Certain owners wish to permanently relinquish those rights to a Work for
    +the purpose of contributing to a commons of creative, cultural and
    +scientific works ("Commons") that the public can reliably and without fear
    +of later claims of infringement build upon, modify, incorporate in other
    +works, reuse and redistribute as freely as possible in any form whatsoever
    +and for any purposes, including without limitation commercial purposes.
    +These owners may contribute to the Commons to promote the ideal of a free
    +culture and the further production of creative, cultural and scientific
    +works, or to gain reputation or greater distribution for their Work in
    +part through the use and efforts of others.
    +
    +For these and/or other purposes and motivations, and without any
    +expectation of additional consideration or compensation, the person
    +associating CC0 with a Work (the "Affirmer"), to the extent that he or she
    +is an owner of Copyright and Related Rights in the Work, voluntarily
    +elects to apply CC0 to the Work and publicly distribute the Work under its
    +terms, with knowledge of his or her Copyright and Related Rights in the
    +Work and the meaning and intended legal effect of CC0 on those rights.
    +
    +1. Copyright and Related Rights. A Work made available under CC0 may be
    +protected by copyright and related or neighboring rights ("Copyright and
    +Related Rights"). Copyright and Related Rights include, but are not
    +limited to, the following:
    +
    +  i. the right to reproduce, adapt, distribute, perform, display,
    +     communicate, and translate a Work;
    + ii. moral rights retained by the original author(s) and/or performer(s);
    +iii. publicity and privacy rights pertaining to a person's image or
    +     likeness depicted in a Work;
    + iv. rights protecting against unfair competition in regards to a Work,
    +     subject to the limitations in paragraph 4(a), below;
    +  v. rights protecting the extraction, dissemination, use and reuse of data
    +     in a Work;
    + vi. database rights (such as those arising under Directive 96/9/EC of the
    +     European Parliament and of the Council of 11 March 1996 on the legal
    +     protection of databases, and under any national implementation
    +     thereof, including any amended or successor version of such
    +     directive); and
    +vii. other similar, equivalent or corresponding rights throughout the
    +     world based on applicable law or treaty, and any national
    +     implementations thereof.
    +
    +2. Waiver. To the greatest extent permitted by, but not in contravention
    +of, applicable law, Affirmer hereby overtly, fully, permanently,
    +irrevocably and unconditionally waives, abandons, and surrenders all of
    +Affirmer's Copyright and Related Rights and associated claims and causes
    +of action, whether now known or unknown (including existing as well as
    +future claims and causes of action), in the Work (i) in all territories
    +worldwide, (ii) for the maximum duration provided by applicable law or
    +treaty (including future time extensions), (iii) in any current or future
    +medium and for any number of copies, and (iv) for any purpose whatsoever,
    +including without limitation commercial, advertising or promotional
    +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
    +member of the public at large and to the detriment of Affirmer's heirs and
    +successors, fully intending that such Waiver shall not be subject to
    +revocation, rescission, cancellation, termination, or any other legal or
    +equitable action to disrupt the quiet enjoyment of the Work by the public
    +as contemplated by Affirmer's express Statement of Purpose.
    +
    +3. Public License Fallback. Should any part of the Waiver for any reason
    +be judged legally invalid or ineffective under applicable law, then the
    +Waiver shall be preserved to the maximum extent permitted taking into
    +account Affirmer's express Statement of Purpose. In addition, to the
    +extent the Waiver is so judged Affirmer hereby grants to each affected
    +person a royalty-free, non transferable, non sublicensable, non exclusive,
    +irrevocable and unconditional license to exercise Affirmer's Copyright and
    +Related Rights in the Work (i) in all territories worldwide, (ii) for the
    +maximum duration provided by applicable law or treaty (including future
    +time extensions), (iii) in any current or future medium and for any number
    +of copies, and (iv) for any purpose whatsoever, including without
    +limitation commercial, advertising or promotional purposes (the
    +"License"). The License shall be deemed effective as of the date CC0 was
    +applied by Affirmer to the Work. Should any part of the License for any
    +reason be judged legally invalid or ineffective under applicable law, such
    +partial invalidity or ineffectiveness shall not invalidate the remainder
    +of the License, and in such case Affirmer hereby affirms that he or she
    +will not (i) exercise any of his or her remaining Copyright and Related
    +Rights in the Work or (ii) assert any associated claims and causes of
    +action with respect to the Work, in either case contrary to Affirmer's
    +express Statement of Purpose.
    +
    +4. Limitations and Disclaimers.
    +
    + a. No trademark or patent rights held by Affirmer are waived, abandoned,
    +    surrendered, licensed or otherwise affected by this document.
    + b. Affirmer offers the Work as-is and makes no representations or
    +    warranties of any kind concerning the Work, express, implied,
    +    statutory or otherwise, including without limitation warranties of
    +    title, merchantability, fitness for a particular purpose, non
    +    infringement, or the absence of latent or other defects, accuracy, or
    +    the present or absence of errors, whether or not discoverable, all to
    +    the greatest extent permissible under applicable law.
    + c. Affirmer disclaims responsibility for clearing rights of other persons
    +    that may apply to the Work or any use thereof, including without
    +    limitation any person's Copyright and Related Rights in the Work.
    +    Further, Affirmer disclaims responsibility for obtaining any necessary
    +    consents, permissions or other rights required for any use of the
    +    Work.
    + d. Affirmer understands and acknowledges that Creative Commons is not a
    +    party to this document and has no duty or obligation with respect to
    +    this CC0 or use of the Work.
    diff --git a/src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt b/src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt
    new file mode 100644
    index 00000000000..5c96471aafa
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt
    @@ -0,0 +1,446 @@
    +GNU LIBRARY GENERAL PUBLIC LICENSE
    +
    +Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc.
    +
    +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
    +
    +Everyone is permitted to copy and distribute verbatim copies of this license
    +document, but changing it is not allowed.
    +
    +[This is the first released version of the library GPL. It is numbered 2 because
    +it goes with version 2 of the ordinary GPL.]
    +
    +Preamble
    +
    +The licenses for most software are designed to take away your freedom to share
    +and change it. By contrast, the GNU General Public Licenses are intended to
    +guarantee your freedom to share and change free software--to make sure the
    +software is free for all its users.
    +
    +This license, the Library General Public License, applies to some specially
    +designated Free Software Foundation software, and to any other libraries whose
    +authors decide to use it. You can use it for your libraries, too.
    +
    +When we speak of free software, we are referring to freedom, not price. Our
    +General Public Licenses are designed to make sure that you have the freedom
    +to distribute copies of free software (and charge for this service if you
    +wish), that you receive source code or can get it if you want it, that you
    +can change the software or use pieces of it in new free programs; and that
    +you know you can do these things.
    +
    +To protect your rights, we need to make restrictions that forbid anyone to
    +deny you these rights or to ask you to surrender the rights. These restrictions
    +translate to certain responsibilities for you if you distribute copies of
    +the library, or if you modify it.
    +
    +For example, if you distribute copies of the library, whether gratis or for
    +a fee, you must give the recipients all the rights that we gave you. You must
    +make sure that they, too, receive or can get the source code. If you link
    +a program with the library, you must provide complete object files to the
    +recipients so that they can relink them with the library, after making changes
    +to the library and recompiling it. And you must show them these terms so they
    +know their rights.
    +
    +Our method of protecting your rights has two steps: (1) copyright the library,
    +and (2) offer you this license which gives you legal permission to copy, distribute
    +and/or modify the library.
    +
    +Also, for each distributor's protection, we want to make certain that everyone
    +understands that there is no warranty for this free library. If the library
    +is modified by someone else and passed on, we want its recipients to know
    +that what they have is not the original version, so that any problems introduced
    +by others will not reflect on the original authors' reputations.
    +
    +Finally, any free program is threatened constantly by software patents. We
    +wish to avoid the danger that companies distributing free software will individually
    +obtain patent licenses, thus in effect transforming the program into proprietary
    +software. To prevent this, we have made it clear that any patent must be licensed
    +for everyone's free use or not licensed at all.
    +
    +Most GNU software, including some libraries, is covered by the ordinary GNU
    +General Public License, which was designed for utility programs. This license,
    +the GNU Library General Public License, applies to certain designated libraries.
    +This license is quite different from the ordinary one; be sure to read it
    +in full, and don't assume that anything in it is the same as in the ordinary
    +license.
    +
    +The reason we have a separate public license for some libraries is that they
    +blur the distinction we usually make between modifying or adding to a program
    +and simply using it. Linking a program with a library, without changing the
    +library, is in some sense simply using the library, and is analogous to running
    +a utility program or application program. However, in a textual and legal
    +sense, the linked executable is a combined work, a derivative of the original
    +library, and the ordinary General Public License treats it as such.
    +
    +Because of this blurred distinction, using the ordinary General Public License
    +for libraries did not effectively promote software sharing, because most developers
    +did not use the libraries. We concluded that weaker conditions might promote
    +sharing better.
    +
    +However, unrestricted linking of non-free programs would deprive the users
    +of those programs of all benefit from the free status of the libraries themselves.
    +This Library General Public License is intended to permit developers of non-free
    +programs to use free libraries, while preserving your freedom as a user of
    +such programs to change the free libraries that are incorporated in them.
    +(We have not seen how to achieve this as regards changes in header files,
    +but we have achieved it as regards changes in the actual functions of the
    +Library.) The hope is that this will lead to faster development of free libraries.
    +
    +The precise terms and conditions for copying, distribution and modification
    +follow. Pay close attention to the difference between a "work based on the
    +library" and a "work that uses the library". The former contains code derived
    +from the library, while the latter only works together with the library.
    +
    +Note that it is possible for a library to be covered by the ordinary General
    +Public License rather than by this special one.
    +
    +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    +
    +0. This License Agreement applies to any software library which contains a
    +notice placed by the copyright holder or other authorized party saying it
    +may be distributed under the terms of this Library General Public License
    +(also called "this License"). Each licensee is addressed as "you".
    +
    +A "library" means a collection of software functions and/or data prepared
    +so as to be conveniently linked with application programs (which use some
    +of those functions and data) to form executables.
    +
    +The "Library", below, refers to any such software library or work which has
    +been distributed under these terms. A "work based on the Library" means either
    +the Library or any derivative work under copyright law: that is to say, a
    +work containing the Library or a portion of it, either verbatim or with modifications
    +and/or translated straightforwardly into another language. (Hereinafter, translation
    +is included without limitation in the term "modification".)
    +
    +"Source code" for a work means the preferred form of the work for making modifications
    +to it. For a library, complete source code means all the source code for all
    +modules it contains, plus any associated interface definition files, plus
    +the scripts used to control compilation and installation of the library.
    +
    +Activities other than copying, distribution and modification are not covered
    +by this License; they are outside its scope. The act of running a program
    +using the Library is not restricted, and output from such a program is covered
    +only if its contents constitute a work based on the Library (independent of
    +the use of the Library in a tool for writing it). Whether that is true depends
    +on what the Library does and what the program that uses the Library does.
    +
    +1. You may copy and distribute verbatim copies of the Library's complete source
    +code as you receive it, in any medium, provided that you conspicuously and
    +appropriately publish on each copy an appropriate copyright notice and disclaimer
    +of warranty; keep intact all the notices that refer to this License and to
    +the absence of any warranty; and distribute a copy of this License along with
    +the Library.
    +
    +You may charge a fee for the physical act of transferring a copy, and you
    +may at your option offer warranty protection in exchange for a fee.
    +
    +2. You may modify your copy or copies of the Library or any portion of it,
    +thus forming a work based on the Library, and copy and distribute such modifications
    +or work under the terms of Section 1 above, provided that you also meet all
    +of these conditions:
    +
    +      a) The modified work must itself be a software library.
    +
    +b) You must cause the files modified to carry prominent notices stating that
    +you changed the files and the date of any change.
    +
    +c) You must cause the whole of the work to be licensed at no charge to all
    +third parties under the terms of this License.
    +
    +d) If a facility in the modified Library refers to a function or a table of
    +data to be supplied by an application program that uses the facility, other
    +than as an argument passed when the facility is invoked, then you must make
    +a good faith effort to ensure that, in the event an application does not supply
    +such function or table, the facility still operates, and performs whatever
    +part of its purpose remains meaningful.
    +
    +(For example, a function in a library to compute square roots has a purpose
    +that is entirely well-defined independent of the application. Therefore, Subsection
    +2d requires that any application-supplied function or table used by this function
    +must be optional: if the application does not supply it, the square root function
    +must still compute square roots.)
    +
    +These requirements apply to the modified work as a whole. If identifiable
    +sections of that work are not derived from the Library, and can be reasonably
    +considered independent and separate works in themselves, then this License,
    +and its terms, do not apply to those sections when you distribute them as
    +separate works. But when you distribute the same sections as part of a whole
    +which is a work based on the Library, the distribution of the whole must be
    +on the terms of this License, whose permissions for other licensees extend
    +to the entire whole, and thus to each and every part regardless of who wrote
    +it.
    +
    +Thus, it is not the intent of this section to claim rights or contest your
    +rights to work written entirely by you; rather, the intent is to exercise
    +the right to control the distribution of derivative or collective works based
    +on the Library.
    +
    +In addition, mere aggregation of another work not based on the Library with
    +the Library (or with a work based on the Library) on a volume of a storage
    +or distribution medium does not bring the other work under the scope of this
    +License.
    +
    +3. You may opt to apply the terms of the ordinary GNU General Public License
    +instead of this License to a given copy of the Library. To do this, you must
    +alter all the notices that refer to this License, so that they refer to the
    +ordinary GNU General Public License, version 2, instead of to this License.
    +(If a newer version than version 2 of the ordinary GNU General Public License
    +has appeared, then you can specify that version instead if you wish.) Do not
    +make any other change in these notices.
    +
    +Once this change is made in a given copy, it is irreversible for that copy,
    +so the ordinary GNU General Public License applies to all subsequent copies
    +and derivative works made from that copy.
    +
    +This option is useful when you wish to copy part of the code of the Library
    +into a program that is not a library.
    +
    +4. You may copy and distribute the Library (or a portion or derivative of
    +it, under Section 2) in object code or executable form under the terms of
    +Sections 1 and 2 above provided that you accompany it with the complete corresponding
    +machine-readable source code, which must be distributed under the terms of
    +Sections 1 and 2 above on a medium customarily used for software interchange.
    +
    +If distribution of object code is made by offering access to copy from a designated
    +place, then offering equivalent access to copy the source code from the same
    +place satisfies the requirement to distribute the source code, even though
    +third parties are not compelled to copy the source along with the object code.
    +
    +5. A program that contains no derivative of any portion of the Library, but
    +is designed to work with the Library by being compiled or linked with it,
    +is called a "work that uses the Library". Such a work, in isolation, is not
    +a derivative work of the Library, and therefore falls outside the scope of
    +this License.
    +
    +However, linking a "work that uses the Library" with the Library creates an
    +executable that is a derivative of the Library (because it contains portions
    +of the Library), rather than a "work that uses the library". The executable
    +is therefore covered by this License. Section 6 states terms for distribution
    +of such executables.
    +
    +When a "work that uses the Library" uses material from a header file that
    +is part of the Library, the object code for the work may be a derivative work
    +of the Library even though the source code is not. Whether this is true is
    +especially significant if the work can be linked without the Library, or if
    +the work is itself a library. The threshold for this to be true is not precisely
    +defined by law.
    +
    +If such an object file uses only numerical parameters, data structure layouts
    +and accessors, and small macros and small inline functions (ten lines or less
    +in length), then the use of the object file is unrestricted, regardless of
    +whether it is legally a derivative work. (Executables containing this object
    +code plus portions of the Library will still fall under Section 6.)
    +
    +Otherwise, if the work is a derivative of the Library, you may distribute
    +the object code for the work under the terms of Section 6. Any executables
    +containing that work also fall under Section 6, whether or not they are linked
    +directly with the Library itself.
    +
    +6. As an exception to the Sections above, you may also compile or link a "work
    +that uses the Library" with the Library to produce a work containing portions
    +of the Library, and distribute that work under terms of your choice, provided
    +that the terms permit modification of the work for the customer's own use
    +and reverse engineering for debugging such modifications.
    +
    +You must give prominent notice with each copy of the work that the Library
    +is used in it and that the Library and its use are covered by this License.
    +You must supply a copy of this License. If the work during execution displays
    +copyright notices, you must include the copyright notice for the Library among
    +them, as well as a reference directing the user to the copy of this License.
    +Also, you must do one of these things:
    +
    +a) Accompany the work with the complete corresponding machine-readable source
    +code for the Library including whatever changes were used in the work (which
    +must be distributed under Sections 1 and 2 above); and, if the work is an
    +executable linked with the Library, with the complete machine-readable "work
    +that uses the Library", as object code and/or source code, so that the user
    +can modify the Library and then relink to produce a modified executable containing
    +the modified Library. (It is understood that the user who changes the contents
    +of definitions files in the Library will not necessarily be able to recompile
    +the application to use the modified definitions.)
    +
    +b) Accompany the work with a written offer, valid for at least three years,
    +to give the same user the materials specified in Subsection 6a, above, for
    +a charge no more than the cost of performing this distribution.
    +
    +c) If distribution of the work is made by offering access to copy from a designated
    +place, offer equivalent access to copy the above specified materials from
    +the same place.
    +
    +d) Verify that the user has already received a copy of these materials or
    +that you have already sent this user a copy.
    +
    +For an executable, the required form of the "work that uses the Library" must
    +include any data and utility programs needed for reproducing the executable
    +from it. However, as a special exception, the source code distributed need
    +not include anything that is normally distributed (in either source or binary
    +form) with the major components (compiler, kernel, and so on) of the operating
    +system on which the executable runs, unless that component itself accompanies
    +the executable.
    +
    +It may happen that this requirement contradicts the license restrictions of
    +other proprietary libraries that do not normally accompany the operating system.
    +Such a contradiction means you cannot use both them and the Library together
    +in an executable that you distribute.
    +
    +7. You may place library facilities that are a work based on the Library side-by-side
    +in a single library together with other library facilities not covered by
    +this License, and distribute such a combined library, provided that the separate
    +distribution of the work based on the Library and of the other library facilities
    +is otherwise permitted, and provided that you do these two things:
    +
    +a) Accompany the combined library with a copy of the same work based on the
    +Library, uncombined with any other library facilities. This must be distributed
    +under the terms of the Sections above.
    +
    +b) Give prominent notice with the combined library of the fact that part of
    +it is a work based on the Library, and explaining where to find the accompanying
    +uncombined form of the same work.
    +
    +8. You may not copy, modify, sublicense, link with, or distribute the Library
    +except as expressly provided under this License. Any attempt otherwise to
    +copy, modify, sublicense, link with, or distribute the Library is void, and
    +will automatically terminate your rights under this License. However, parties
    +who have received copies, or rights, from you under this License will not
    +have their licenses terminated so long as such parties remain in full compliance.
    +
    +9. You are not required to accept this License, since you have not signed
    +it. However, nothing else grants you permission to modify or distribute the
    +Library or its derivative works. These actions are prohibited by law if you
    +do not accept this License. Therefore, by modifying or distributing the Library
    +(or any work based on the Library), you indicate your acceptance of this License
    +to do so, and all its terms and conditions for copying, distributing or modifying
    +the Library or works based on it.
    +
    +10. Each time you redistribute the Library (or any work based on the Library),
    +the recipient automatically receives a license from the original licensor
    +to copy, distribute, link with or modify the Library subject to these terms
    +and conditions. You may not impose any further restrictions on the recipients'
    +exercise of the rights granted herein. You are not responsible for enforcing
    +compliance by third parties to this License.
    +
    +11. If, as a consequence of a court judgment or allegation of patent infringement
    +or for any other reason (not limited to patent issues), conditions are imposed
    +on you (whether by court order, agreement or otherwise) that contradict the
    +conditions of this License, they do not excuse you from the conditions of
    +this License. If you cannot distribute so as to satisfy simultaneously your
    +obligations under this License and any other pertinent obligations, then as
    +a consequence you may not distribute the Library at all. For example, if a
    +patent license would not permit royalty-free redistribution of the Library
    +by all those who receive copies directly or indirectly through you, then the
    +only way you could satisfy both it and this License would be to refrain entirely
    +from distribution of the Library.
    +
    +If any portion of this section is held invalid or unenforceable under any
    +particular circumstance, the balance of the section is intended to apply,
    +and the section as a whole is intended to apply in other circumstances.
    +
    +It is not the purpose of this section to induce you to infringe any patents
    +or other property right claims or to contest validity of any such claims;
    +this section has the sole purpose of protecting the integrity of the free
    +software distribution system which is implemented by public license practices.
    +Many people have made generous contributions to the wide range of software
    +distributed through that system in reliance on consistent application of that
    +system; it is up to the author/donor to decide if he or she is willing to
    +distribute software through any other system and a licensee cannot impose
    +that choice.
    +
    +This section is intended to make thoroughly clear what is believed to be a
    +consequence of the rest of this License.
    +
    +12. If the distribution and/or use of the Library is restricted in certain
    +countries either by patents or by copyrighted interfaces, the original copyright
    +holder who places the Library under this License may add an explicit geographical
    +distribution limitation excluding those countries, so that distribution is
    +permitted only in or among countries not thus excluded. In such case, this
    +License incorporates the limitation as if written in the body of this License.
    +
    +13. The Free Software Foundation may publish revised and/or new versions of
    +the Library General Public License from time to time. Such new versions will
    +be similar in spirit to the present version, but may differ in detail to address
    +new problems or concerns.
    +
    +Each version is given a distinguishing version number. If the Library specifies
    +a version number of this License which applies to it and "any later version",
    +you have the option of following the terms and conditions either of that version
    +or of any later version published by the Free Software Foundation. If the
    +Library does not specify a license version number, you may choose any version
    +ever published by the Free Software Foundation.
    +
    +14. If you wish to incorporate parts of the Library into other free programs
    +whose distribution conditions are incompatible with these, write to the author
    +to ask for permission. For software which is copyrighted by the Free Software
    +Foundation, write to the Free Software Foundation; we sometimes make exceptions
    +for this. Our decision will be guided by the two goals of preserving the free
    +status of all derivatives of our free software and of promoting the sharing
    +and reuse of software generally.
    +
    +   NO WARRANTY
    +
    +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
    +THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
    +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY
    +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
    +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
    +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
    +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
    +
    +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
    +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
    +THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
    +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE
    +OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
    +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES
    +OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH
    +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
    +END OF TERMS AND CONDITIONS
    +
    +How to Apply These Terms to Your New Libraries
    +
    +If you develop a new library, and you want it to be of the greatest possible
    +use to the public, we recommend making it free software that everyone can
    +redistribute and change. You can do so by permitting redistribution under
    +these terms (or, alternatively, under the terms of the ordinary General Public
    +License).
    +
    +To apply these terms, attach the following notices to the library. It is safest
    +to attach them to the start of each source file to most effectively convey
    +the exclusion of warranty; and each file should have at least the "copyright"
    +line and a pointer to where the full notice is found.
    +
    +one line to give the library's name and an idea of what it does.
    +
    +Copyright (C) year name of author
    +
    +This library is free software; you can redistribute it and/or modify it under
    +the terms of the GNU Library General Public License as published by the Free
    +Software Foundation; either version 2 of the License, or (at your option)
    +any later version.
    +
    +This library is distributed in the hope that it will be useful, but WITHOUT
    +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    +FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
    +details.
    +
    +You should have received a copy of the GNU Library General Public License
    +along with this library; if not, write to the Free Software Foundation, Inc.,
    +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
    +
    +Also add information on how to contact you by electronic and paper mail.
    +
    +You should also get your employer (if you work as a programmer) or your school,
    +if any, to sign a "copyright disclaimer" for the library, if necessary. Here
    +is a sample; alter the names:
    +
    +Yoyodyne, Inc., hereby disclaims all copyright interest in
    +
    +the library `Frob' (a library for tweaking knobs) written
    +
    +by James Random Hacker.
    +
    +signature of Ty Coon, 1 April 1990
    +
    +Ty Coon, President of Vice
    +
    +That's all there is to it!
    diff --git a/src/libs/3rdparty/karchive/README.md b/src/libs/3rdparty/karchive/README.md
    new file mode 100644
    index 00000000000..6caf60dc454
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/README.md
    @@ -0,0 +1,33 @@
    +# KArchive
    +
    +Reading, creating, and manipulating file archives
    +
    +## Introduction
    +
    +KArchive provides classes for easy reading, creation and manipulation of
    +"archive" formats like ZIP and TAR.
    +
    +It also provides transparent compression and decompression of data, like the
    +GZip format, via a subclass of QIODevice.
    +
    +## Usage
    +
    +If you want to read and write compressed data, just create an instance of
    +KCompressionDevice and write to or read from that.
    +
    +If you want to read and write archive formats, create an instance of the
    +appropriate subclass of KArchive (eg: K7Zip for 7-Zip files).  You may need to
    +combine this with usage of KCompressionDevice (see the API documentation for the
    +relevant KArchive subclass for details).
    +
    +## Changes for Qt Creator
    +
    +* Stripped everything but src folder
    +* Created simplified and qtc'ified CMakeLists.txt
    +* Removed config-compression.h (defines moved to CMakeLists.txt)
    +* Replaced QMutableListIterator usages 
    +  ([upstream](https://invent.kde.org/frameworks/karchive/-/merge_requests/82))
    +* Added "progress" parameter to KArchive::copyTo
    +  ([upstream](https://invent.kde.org/frameworks/karchive/-/merge_requests/84))
    +* Added "Fix" to KTar to workaround mime database changes in Qt 6.8.0
    +  ([upstream](https://invent.kde.org/frameworks/karchive/-/merge_requests/83))
    diff --git a/src/libs/3rdparty/karchive/src/k7zip.cpp b/src/libs/3rdparty/karchive/src/k7zip.cpp
    new file mode 100644
    index 00000000000..03ee383aa11
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/k7zip.cpp
    @@ -0,0 +1,3028 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2011 Mario Bensi 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "k7zip.h"
    +#include "karchive_p.h"
    +#include "loggingcategory.h"
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "kcompressiondevice.h"
    +#include "klimitediodevice_p.h"
    +#include 
    +#include 
    +
    +#include "zlib.h"
    +#include 
    +#include  // time()
    +
    +#ifndef QT_STAT_LNK
    +#define QT_STAT_LNK 0120000
    +#endif // QT_STAT_LNK
    +
    +////////////////////////////////////////////////////////////////////////
    +/////////////////////////// K7Zip //////////////////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +
    +#define BUFFER_SIZE 8 * 1024
    +
    +static const unsigned char k7zip_signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
    +// static const unsigned char XZ_HEADER_MAGIC[6] = { 0xFD, '7', 'z', 'X', 'Z', 0x00 };
    +
    +/* clang-format off */
    +static QChar GetUi16(const char *p, quint64 offset)
    +{
    +    return QChar(static_cast(p[offset + 0])
    +                 | (static_cast(p[1]) << 8));
    +}
    +
    +static quint32 GetUi32(const char *p, quint64 offset)
    +{
    +    return (static_cast(p[offset + 0])
    +            | (static_cast(p[offset + 1]) << 8)
    +            | (static_cast(p[offset + 2]) << 16)
    +            | (static_cast(p[offset + 3]) << 24));
    +}
    +
    +static quint64 GetUi64(const char *p, quint64 offset)
    +{
    +    return (GetUi32(p, offset)
    +            | (static_cast(GetUi32(p, offset + 4)) << 32));
    +}
    +
    +static quint32 lzma2_dic_size_from_prop(int p)
    +{
    +    return ((static_cast(2) | (p & 1)) << ((p / 2) + 11));
    +}
    +
    +/* clang-format on*/
    +
    +#define FILE_ATTRIBUTE_READONLY 1
    +#define FILE_ATTRIBUTE_HIDDEN 2
    +#define FILE_ATTRIBUTE_SYSTEM 4
    +#define FILE_ATTRIBUTE_DIRECTORY 16
    +#define FILE_ATTRIBUTE_ARCHIVE 32
    +#define FILE_ATTRIBUTE_DEVICE 64
    +#define FILE_ATTRIBUTE_NORMAL 128
    +#define FILE_ATTRIBUTE_TEMPORARY 256
    +#define FILE_ATTRIBUTE_SPARSE_FILE 512
    +#define FILE_ATTRIBUTE_REPARSE_POINT 1024
    +#define FILE_ATTRIBUTE_COMPRESSED 2048
    +#define FILE_ATTRIBUTE_OFFLINE 0x1000
    +#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
    +#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */
    +
    +enum HeaderType {
    +    kEnd,
    +
    +    kHeader,
    +
    +    kArchiveProperties,
    +
    +    kAdditionalStreamsInfo,
    +    kMainStreamsInfo,
    +    kFilesInfo,
    +
    +    kPackInfo,
    +    kUnpackInfo,
    +    kSubStreamsInfo,
    +
    +    kSize,
    +    kCRC,
    +
    +    kFolder,
    +
    +    kCodersUnpackSize,
    +    kNumUnpackStream,
    +
    +    kEmptyStream,
    +    kEmptyFile,
    +    kAnti,
    +
    +    kName,
    +    kCTime,
    +    kATime,
    +    kMTime,
    +    kAttributes,
    +    kComment,
    +
    +    kEncodedHeader,
    +
    +    kStartPos,
    +    kDummy,
    +};
    +
    +// Method ID
    +// static const quint64 k_Copy = 0x00;
    +// static const quint64 k_Delta = 0x03;
    +// static const quint64 k_x86 = 0x04; //BCJ
    +// static const quint64 k_PPC = 0x05; // BIG Endian
    +// static const quint64 k_IA64 = 0x06;
    +// static const quint64 k_ARM = 0x07; // little Endian
    +// static const quint64 k_ARM_Thumb = 0x08; // little Endian
    +// static const quint64 k_SPARC = 0x09;
    +static const quint64 k_LZMA2 = 0x21;
    +// static const quint64 k_Swap2 = 0x020302;
    +// static const quint64 k_Swap4 = 0x020304;
    +static const quint64 k_LZMA = 0x030101;
    +static const quint64 k_BCJ = 0x03030103;
    +static const quint64 k_BCJ2 = 0x0303011B;
    +// static const quint64 k_7zPPC = 0x03030205;
    +// static const quint64 k_Alpha = 0x03030301;
    +// static const quint64 k_7zIA64 = 0x03030401;
    +// static const quint64 k_7zARM = 0x03030501;
    +// static const quint64 k_M68 = 0x03030605; //Big Endian
    +// static const quint64 k_ARMT = 0x03030701;
    +// static const quint64 k_7zSPARC = 0x03030805;
    +static const quint64 k_PPMD = 0x030401;
    +// static const quint64 k_Experimental = 0x037F01;
    +// static const quint64 k_Shrink = 0x040101;
    +// static const quint64 k_Implode = 0x040106;
    +// static const quint64 k_Deflate = 0x040108;
    +// static const quint64 k_Deflate64 = 0x040109;
    +// static const quint64 k_Imploding = 0x040110;
    +// static const quint64 k_Jpeg = 0x040160;
    +// static const quint64 k_WavPack = 0x040161;
    +// static const quint64 k_PPMd = 0x040162;
    +// static const quint64 k_wzAES = 0x040163;
    +static const quint64 k_BZip2 = 0x040202;
    +// static const quint64 k_Rar15 = 0x040301;
    +// static const quint64 k_Rar20 = 0x040302;
    +// static const quint64 k_Rar29 = 0x040303;
    +// static const quint64 k_Arj = 0x040401; //1 2 3
    +// static const quint64 k_Arj4 = 0x040402;
    +// static const quint64 k_Z = 0x0405;
    +// static const quint64 k_Lzh = 0x0406;
    +// static const quint64 k_Cab = 0x0408;
    +// static const quint64 k_DeflateNSIS = 0x040901;
    +// static const quint64 k_Bzip2NSIS = 0x040902;
    +static const quint64 k_AES = 0x06F10701;
    +
    +/**
    + * A K7ZipFileEntry represents a file in a 7zip archive.
    + */
    +class K7ZipFileEntry : public KArchiveFile
    +{
    +public:
    +    K7ZipFileEntry(K7Zip *zip,
    +                   const QString &name,
    +                   int access,
    +                   const QDateTime &date,
    +                   const QString &user,
    +                   const QString &group,
    +                   const QString &symlink,
    +                   qint64 pos,
    +                   qint64 size,
    +                   const QByteArray &data);
    +
    +    ~K7ZipFileEntry() override;
    +
    +    /**
    +     * @return the content of this file.
    +     * Call data() with care (only once per file), this data isn't cached.
    +     */
    +    QByteArray data() const override;
    +
    +    /**
    +     * This method returns QIODevice (internal class: KLimitedIODevice)
    +     * on top of the underlying QIODevice. This is obviously for reading only.
    +     *
    +     * WARNING: Note that the ownership of the device is being transferred to the caller,
    +     * who will have to delete it.
    +     *
    +     * The returned device auto-opens (in readonly mode), no need to open it.
    +     * @return the QIODevice of the file
    +     */
    +    QIODevice *createDevice() const override;
    +
    +private:
    +    const QByteArray m_data;
    +    QBuffer *m_buffer;
    +};
    +
    +K7ZipFileEntry::K7ZipFileEntry(K7Zip *zip,
    +                               const QString &name,
    +                               int access,
    +                               const QDateTime &date,
    +                               const QString &user,
    +                               const QString &group,
    +                               const QString &symlink,
    +                               qint64 pos,
    +                               qint64 size,
    +                               const QByteArray &data)
    +    : KArchiveFile(zip, name, access, date, user, group, symlink, pos, size)
    +    , m_data(data)
    +    , m_buffer(new QBuffer)
    +{
    +    m_buffer->setData(m_data);
    +    m_buffer->open(QIODevice::ReadOnly);
    +}
    +
    +K7ZipFileEntry::~K7ZipFileEntry()
    +{
    +    delete m_buffer;
    +}
    +
    +QByteArray K7ZipFileEntry::data() const
    +{
    +    return m_data.mid(position(), size());
    +}
    +
    +QIODevice *K7ZipFileEntry::createDevice() const
    +{
    +    return new KLimitedIODevice(m_buffer, position(), size());
    +}
    +
    +class FileInfo
    +{
    +public:
    +    FileInfo()
    +        : size(0)
    +        , attributes(0)
    +        , crc(0)
    +        , attribDefined(false)
    +        , crcDefined(false)
    +        , hasStream(false)
    +        , isDir(false)
    +    {
    +    }
    +
    +    QString path;
    +    quint64 size;
    +    quint32 attributes;
    +    quint32 crc;
    +    bool attribDefined;
    +    bool crcDefined;
    +    bool hasStream;
    +    bool isDir;
    +};
    +
    +class Folder
    +{
    +public:
    +    class FolderInfo
    +    {
    +    public:
    +        FolderInfo()
    +            : numInStreams(0)
    +            , numOutStreams(0)
    +            , methodID(0)
    +        {
    +        }
    +
    +        bool isSimpleCoder() const
    +        {
    +            return (numInStreams == 1) && (numOutStreams == 1);
    +        }
    +
    +        int numInStreams;
    +        int numOutStreams;
    +        QList properties;
    +        quint64 methodID;
    +    };
    +
    +    Folder()
    +        : unpackCRCDefined(false)
    +        , unpackCRC(0)
    +    {
    +    }
    +
    +    ~Folder()
    +    {
    +        qDeleteAll(folderInfos);
    +    }
    +
    +    Q_DISABLE_COPY(Folder)
    +
    +    quint64 getUnpackSize() const
    +    {
    +        if (unpackSizes.isEmpty()) {
    +            return 0;
    +        }
    +        for (int i = unpackSizes.size() - 1; i >= 0; i--) {
    +            if (findBindPairForOutStream(i) < 0) {
    +                return unpackSizes.at(i);
    +            }
    +        }
    +        return 0;
    +    }
    +
    +    int getNumOutStreams() const
    +    {
    +        int result = 0;
    +        for (int i = 0; i < folderInfos.size(); i++) {
    +            result += folderInfos.at(i)->numOutStreams;
    +        }
    +        return result;
    +    }
    +
    +    quint32 getCoderInStreamIndex(quint32 coderIndex) const
    +    {
    +        quint32 streamIndex = 0;
    +        for (quint32 i = 0; i < coderIndex; i++) {
    +            streamIndex += folderInfos.at(i)->numInStreams;
    +        }
    +        return streamIndex;
    +    }
    +
    +    quint32 getCoderOutStreamIndex(quint32 coderIndex) const
    +    {
    +        quint32 streamIndex = 0;
    +        for (quint32 i = 0; i < coderIndex; i++) {
    +            streamIndex += folderInfos.at(i)->numOutStreams;
    +        }
    +        return streamIndex;
    +    }
    +
    +    int findBindPairForInStream(size_t inStreamIndex) const
    +    {
    +        for (int i = 0; i < inIndexes.size(); i++) {
    +            if (inIndexes[i] == inStreamIndex) {
    +                return i;
    +            }
    +        }
    +        return -1;
    +    }
    +
    +    int findBindPairForOutStream(size_t outStreamIndex) const
    +    {
    +        for (int i = 0; i < outIndexes.size(); i++) {
    +            if (outIndexes[i] == outStreamIndex) {
    +                return i;
    +            }
    +        }
    +        return -1;
    +    }
    +
    +    int findPackStreamArrayIndex(size_t inStreamIndex) const
    +    {
    +        for (int i = 0; i < packedStreams.size(); i++) {
    +            if (packedStreams[i] == inStreamIndex) {
    +                return i;
    +            }
    +        }
    +        return -1;
    +    }
    +
    +    void findInStream(quint32 streamIndex, quint32 &coderIndex, quint32 &coderStreamIndex) const
    +    {
    +        for (coderIndex = 0; coderIndex < (quint32)folderInfos.size(); coderIndex++) {
    +            quint32 curSize = folderInfos[coderIndex]->numInStreams;
    +            if (streamIndex < curSize) {
    +                coderStreamIndex = streamIndex;
    +                return;
    +            }
    +            streamIndex -= curSize;
    +        }
    +    }
    +
    +    void findOutStream(quint32 streamIndex, quint32 &coderIndex, quint32 &coderStreamIndex) const
    +    {
    +        for (coderIndex = 0; coderIndex < (quint32)folderInfos.size(); coderIndex++) {
    +            quint32 curSize = folderInfos[coderIndex]->numOutStreams;
    +            if (streamIndex < curSize) {
    +                coderStreamIndex = streamIndex;
    +                return;
    +            }
    +            streamIndex -= curSize;
    +        }
    +    }
    +
    +    bool isEncrypted() const
    +    {
    +        for (int i = folderInfos.size() - 1; i >= 0; i--) {
    +            if (folderInfos.at(i)->methodID == k_AES) {
    +                return true;
    +            }
    +        }
    +        return false;
    +    }
    +
    +    // bool CheckStructure() const;
    +
    +    bool unpackCRCDefined;
    +    quint32 unpackCRC;
    +    QList folderInfos;
    +    QList inIndexes;
    +    QList outIndexes;
    +    QList packedStreams;
    +    QList unpackSizes;
    +};
    +
    +class Q_DECL_HIDDEN K7Zip::K7ZipPrivate
    +{
    +public:
    +    K7ZipPrivate(K7Zip *parent)
    +        : q(parent)
    +        , packPos(0)
    +        , numPackStreams(0)
    +        , buffer(nullptr)
    +        , pos(0)
    +        , end(0)
    +        , headerSize(0)
    +        , countSize(0)
    +        , m_currentFile(nullptr)
    +    {
    +    }
    +
    +    ~K7ZipPrivate()
    +    {
    +        qDeleteAll(folders);
    +        qDeleteAll(fileInfos);
    +    }
    +
    +    K7Zip *q;
    +
    +    QList packCRCsDefined;
    +    QList packCRCs;
    +    QList numUnpackStreamsInFolders;
    +
    +    QList folders;
    +    QList fileInfos;
    +    // File information
    +    QList cTimesDefined;
    +    QList cTimes;
    +    QList aTimesDefined;
    +    QList aTimes;
    +    QList mTimesDefined;
    +    QList mTimes;
    +    QList startPositionsDefined;
    +    QList startPositions;
    +    QList fileInfoPopIDs;
    +
    +    quint64 packPos;
    +    quint64 numPackStreams;
    +    QList packSizes;
    +    QList unpackSizes;
    +    QList digestsDefined;
    +    QList digests;
    +
    +    QList isAnti;
    +
    +    const char *buffer;
    +    quint64 pos;
    +    quint64 end;
    +    quint64 headerSize;
    +    quint64 countSize;
    +
    +    // Write
    +    QByteArray header;
    +    QByteArray outData; // Store data in this buffer before compress and write in archive.
    +    K7ZipFileEntry *m_currentFile;
    +    QList m_entryList;
    +
    +    void clear()
    +    {
    +        packCRCsDefined.clear();
    +        packCRCs.clear();
    +        numUnpackStreamsInFolders.clear();
    +        qDeleteAll(folders);
    +        folders.clear();
    +        qDeleteAll(fileInfos);
    +        fileInfos.clear();
    +        cTimesDefined.clear();
    +        cTimes.clear();
    +        aTimesDefined.clear();
    +        aTimes.clear();
    +        mTimesDefined.clear();
    +        mTimes.clear();
    +        startPositionsDefined.clear();
    +        startPositions.clear();
    +        fileInfoPopIDs.clear();
    +        packSizes.clear();
    +        unpackSizes.clear();
    +        digestsDefined.clear();
    +        digests.clear();
    +        isAnti.clear();
    +
    +        buffer = nullptr;
    +        pos = 0;
    +        end = 0;
    +        headerSize = 0;
    +        countSize = 0;
    +    }
    +
    +    // Read
    +    int readByte();
    +    quint32 readUInt32();
    +    quint64 readUInt64();
    +    quint64 readNumber();
    +    QString readString();
    +    void readHashDigests(int numItems, QList &digestsDefined, QList &digests);
    +    void readBoolVector(int numItems, QList &v);
    +    void readBoolVector2(int numItems, QList &v);
    +    void skipData(int size);
    +    bool findAttribute(int attribute);
    +    bool readUInt64DefVector(int numFiles, QList &values, QList &defined);
    +
    +    Folder *folderItem();
    +    bool readMainStreamsInfo();
    +    bool readPackInfo();
    +    bool readUnpackInfo();
    +    bool readSubStreamsInfo();
    +    QByteArray readAndDecodePackedStreams(bool readMainStreamInfo = true);
    +
    +    // Write
    +    void createItemsFromEntities(const KArchiveDirectory *, const QString &, QByteArray &);
    +    void writeByte(unsigned char b);
    +    void writeNumber(quint64 value);
    +    void writeBoolVector(const QList &boolVector);
    +    void writeUInt32(quint32 value);
    +    void writeUInt64(quint64 value);
    +    void writeHashDigests(const QList &digestsDefined, const QList &digests);
    +    void writeAlignedBoolHeader(const QList &v, int numDefined, int type, unsigned itemSize);
    +    void writeUInt64DefVector(const QList &v, const QList &defined, int type);
    +    void writeFolder(const Folder *folder);
    +    void writePackInfo(quint64 dataOffset, QList &packedSizes, QList &packedCRCsDefined, QList &packedCRCs);
    +    void writeUnpackInfo(const QList &folderItems);
    +    void writeSubStreamsInfo(const QList &unpackSizes, const QList &digestsDefined, const QList &digests);
    +    void writeHeader(quint64 &headerOffset);
    +    void writeSignature();
    +    void writeStartHeader(const quint64 nextHeaderSize, const quint32 nextHeaderCRC, const quint64 nextHeaderOffset);
    +    QByteArray encodeStream(QList &packSizes, QList &folds);
    +};
    +
    +K7Zip::K7Zip(const QString &fileName)
    +    : KArchive(fileName)
    +    , d(new K7ZipPrivate(this))
    +{
    +}
    +
    +K7Zip::K7Zip(QIODevice *dev)
    +    : KArchive(dev)
    +    , d(new K7ZipPrivate(this))
    +{
    +    Q_ASSERT(dev);
    +}
    +
    +K7Zip::~K7Zip()
    +{
    +    if (isOpen()) {
    +        close();
    +    }
    +
    +    delete d;
    +}
    +
    +int K7Zip::K7ZipPrivate::readByte()
    +{
    +    if (!buffer || pos + 1 > end) {
    +        return -1;
    +    }
    +    return buffer[pos++];
    +}
    +
    +quint32 K7Zip::K7ZipPrivate::readUInt32()
    +{
    +    if (!buffer || (quint64)(pos + 4) > end) {
    +        qCDebug(KArchiveLog) << "error size";
    +        return 0;
    +    }
    +
    +    quint32 res = GetUi32(buffer, pos);
    +    pos += 4;
    +    return res;
    +}
    +
    +quint64 K7Zip::K7ZipPrivate::readUInt64()
    +{
    +    if (!buffer || (quint64)(pos + 8) > end) {
    +        qCDebug(KArchiveLog) << "error size";
    +        return 0;
    +    }
    +
    +    quint64 res = GetUi64(buffer, pos);
    +    pos += 8;
    +    return res;
    +}
    +
    +quint64 K7Zip::K7ZipPrivate::readNumber()
    +{
    +    if (!buffer || (quint64)(pos + 8) > end) {
    +        return 0;
    +    }
    +
    +    unsigned char firstByte = buffer[pos++];
    +    unsigned char mask = 0x80;
    +    quint64 value = 0;
    +    for (int i = 0; i < 8; i++) {
    +        if ((firstByte & mask) == 0) {
    +            quint64 highPart = firstByte & (mask - 1);
    +            value += (highPart << (i * 8));
    +            return value;
    +        }
    +        value |= ((unsigned char)buffer[pos++] << (8 * i));
    +        mask >>= 1;
    +    }
    +    return value;
    +}
    +
    +QString K7Zip::K7ZipPrivate::readString()
    +{
    +    if (!buffer) {
    +        return QString();
    +    }
    +
    +    const char *buf = buffer + pos;
    +    size_t rem = (end - pos) / 2 * 2;
    +    {
    +        size_t i;
    +        for (i = 0; i < rem; i += 2) {
    +            if (buf[i] == 0 && buf[i + 1] == 0) {
    +                break;
    +            }
    +        }
    +        if (i == rem) {
    +            qCDebug(KArchiveLog) << "read string error";
    +            return QString();
    +        }
    +        rem = i;
    +    }
    +
    +    int len = (int)(rem / 2);
    +    if (len < 0 || (size_t)len * 2 != rem) {
    +        qCDebug(KArchiveLog) << "read string unsupported";
    +        return QString();
    +    }
    +
    +    QString p;
    +    for (int i = 0; i < len; i++, buf += 2) {
    +        p += GetUi16(buf, 0);
    +    }
    +
    +    pos += rem + 2;
    +    return p;
    +}
    +
    +void K7Zip::K7ZipPrivate::skipData(int size)
    +{
    +    if (!buffer || pos + size > end) {
    +        return;
    +    }
    +    pos += size;
    +}
    +
    +bool K7Zip::K7ZipPrivate::findAttribute(int attribute)
    +{
    +    if (!buffer) {
    +        return false;
    +    }
    +
    +    for (;;) {
    +        int type = readByte();
    +        if (type == attribute) {
    +            return true;
    +        }
    +        if (type == kEnd) {
    +            return false;
    +        }
    +        skipData(readNumber());
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::readBoolVector(int numItems, QList &v)
    +{
    +    if (!buffer) {
    +        return;
    +    }
    +
    +    unsigned char b = 0;
    +    unsigned char mask = 0;
    +    for (int i = 0; i < numItems; i++) {
    +        if (mask == 0) {
    +            b = readByte();
    +            mask = 0x80;
    +        }
    +        v.append((b & mask) != 0);
    +        mask >>= 1;
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::readBoolVector2(int numItems, QList &v)
    +{
    +    if (!buffer) {
    +        return;
    +    }
    +
    +    int allAreDefined = readByte();
    +    if (allAreDefined == 0) {
    +        readBoolVector(numItems, v);
    +        return;
    +    }
    +
    +    for (int i = 0; i < numItems; i++) {
    +        v.append(true);
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::readHashDigests(int numItems, QList &digestsDefined, QList &digests)
    +{
    +    if (!buffer) {
    +        return;
    +    }
    +
    +    readBoolVector2(numItems, digestsDefined);
    +    for (int i = 0; i < numItems; i++) {
    +        quint32 crc = 0;
    +        if (digestsDefined[i]) {
    +            crc = GetUi32(buffer, pos);
    +            pos += 4;
    +        }
    +        digests.append(crc);
    +    }
    +}
    +
    +Folder *K7Zip::K7ZipPrivate::folderItem()
    +{
    +    if (!buffer) {
    +        return nullptr;
    +    }
    +
    +    Folder *folder = new Folder;
    +    int numCoders = readNumber();
    +
    +    quint64 numInStreamsTotal = 0;
    +    quint64 numOutStreamsTotal = 0;
    +    for (int i = 0; i < numCoders; ++i) {
    +        // BYTE
    +        //    {
    +        //      0:3 CodecIdSize
    +        //      4:  Is Complex Coder
    +        //      5:  There Are Attributes
    +        //      6:  Reserved
    +        //      7:  There are more alternative methods. (Not used
    +        //      anymore, must be 0).
    +        //    }
    +        unsigned char coderInfo = readByte();
    +        int codecIdSize = (coderInfo & 0xF);
    +        if (codecIdSize > 8) {
    +            qCDebug(KArchiveLog) << "unsupported codec id size";
    +            delete folder;
    +            return nullptr;
    +        }
    +        Folder::FolderInfo *info = new Folder::FolderInfo();
    +        std::unique_ptr codecID(new unsigned char[codecIdSize]);
    +        for (int i = 0; i < codecIdSize; ++i) {
    +            codecID[i] = readByte();
    +        }
    +
    +        int id = 0;
    +        for (int j = 0; j < codecIdSize; j++) {
    +            id |= codecID[codecIdSize - 1 - j] << (8 * j);
    +        }
    +        info->methodID = id;
    +
    +        // if (Is Complex Coder)
    +        if ((coderInfo & 0x10) != 0) {
    +            info->numInStreams = readNumber();
    +            info->numOutStreams = readNumber();
    +        } else {
    +            info->numInStreams = 1;
    +            info->numOutStreams = 1;
    +        }
    +
    +        // if (There Are Attributes)
    +        if ((coderInfo & 0x20) != 0) {
    +            int propertiesSize = readNumber();
    +            for (int i = 0; i < propertiesSize; ++i) {
    +                info->properties.append(readByte());
    +            }
    +        }
    +
    +        if ((coderInfo & 0x80) != 0) {
    +            qCDebug(KArchiveLog) << "unsupported";
    +            delete info;
    +            delete folder;
    +            return nullptr;
    +        }
    +
    +        numInStreamsTotal += info->numInStreams;
    +        numOutStreamsTotal += info->numOutStreams;
    +        folder->folderInfos.append(info);
    +    }
    +
    +    int numBindPairs = numOutStreamsTotal - 1;
    +    for (int i = 0; i < numBindPairs; i++) {
    +        folder->inIndexes.append(readNumber());
    +        folder->outIndexes.append(readNumber());
    +    }
    +
    +    int numPackedStreams = numInStreamsTotal - numBindPairs;
    +    if (numPackedStreams > 1) {
    +        for (int i = 0; i < numPackedStreams; ++i) {
    +            folder->packedStreams.append(readNumber());
    +        }
    +    } else {
    +        if (numPackedStreams == 1) {
    +            for (quint64 i = 0; i < numInStreamsTotal; i++) {
    +                if (folder->findBindPairForInStream(i) < 0) {
    +                    folder->packedStreams.append(i);
    +                    break;
    +                }
    +            }
    +            if (folder->packedStreams.size() != 1) {
    +                delete folder;
    +                return nullptr;
    +            }
    +        }
    +    }
    +    return folder;
    +}
    +
    +bool K7Zip::K7ZipPrivate::readUInt64DefVector(int numFiles, QList &values, QList &defined)
    +{
    +    if (!buffer) {
    +        return false;
    +    }
    +
    +    readBoolVector2(numFiles, defined);
    +
    +    int external = readByte();
    +    if (external != 0) {
    +        int dataIndex = readNumber();
    +        if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
    +            qCDebug(KArchiveLog) << "wrong data index";
    +            return false;
    +        }
    +
    +        // TODO : go to the new index
    +    }
    +
    +    for (int i = 0; i < numFiles; i++) {
    +        quint64 t = 0;
    +        if (defined[i]) {
    +            t = readUInt64();
    +        }
    +        values.append(t);
    +    }
    +    return true;
    +}
    +
    +bool K7Zip::K7ZipPrivate::readPackInfo()
    +{
    +    if (!buffer) {
    +        return false;
    +    }
    +
    +    packPos = readNumber();
    +    numPackStreams = readNumber();
    +    packSizes.clear();
    +
    +    packCRCsDefined.clear();
    +    packCRCs.clear();
    +
    +    if (!findAttribute(kSize)) {
    +        qCDebug(KArchiveLog) << "kSize not found";
    +        return false;
    +    }
    +
    +    for (quint64 i = 0; i < numPackStreams; ++i) {
    +        packSizes.append(readNumber());
    +    }
    +
    +    for (;;) {
    +        int type = readByte();
    +        if (type == kEnd) {
    +            break;
    +        }
    +        if (type == kCRC) {
    +            readHashDigests(numPackStreams, packCRCsDefined, packCRCs);
    +            continue;
    +        }
    +        skipData(readNumber());
    +    }
    +
    +    if (packCRCs.isEmpty()) {
    +        for (quint64 i = 0; i < numPackStreams; ++i) {
    +            packCRCsDefined.append(false);
    +            packCRCs.append(0);
    +        }
    +    }
    +    return true;
    +}
    +
    +bool K7Zip::K7ZipPrivate::readUnpackInfo()
    +{
    +    if (!buffer) {
    +        return false;
    +    }
    +
    +    if (!findAttribute(kFolder)) {
    +        qCDebug(KArchiveLog) << "kFolder not found";
    +        return false;
    +    }
    +
    +    int numFolders = readNumber();
    +    qDeleteAll(folders);
    +    folders.clear();
    +    int external = readByte();
    +    switch (external) {
    +    case 0: {
    +        for (int i = 0; i < numFolders; ++i) {
    +            folders.append(folderItem());
    +        }
    +        break;
    +    }
    +    case 1: {
    +        int dataIndex = readNumber();
    +        if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
    +            qCDebug(KArchiveLog) << "wrong data index";
    +        }
    +        // TODO : go to the new index
    +        break;
    +    }
    +    default:
    +        qCDebug(KArchiveLog) << "external error";
    +        return false;
    +    }
    +
    +    if (!findAttribute(kCodersUnpackSize)) {
    +        qCDebug(KArchiveLog) << "kCodersUnpackSize not found";
    +        return false;
    +    }
    +
    +    for (int i = 0; i < numFolders; ++i) {
    +        Folder *folder = folders.at(i);
    +        int numOutStreams = folder->getNumOutStreams();
    +        for (int j = 0; j < numOutStreams; ++j) {
    +            folder->unpackSizes.append(readNumber());
    +        }
    +    }
    +
    +    for (;;) {
    +        int type = readByte();
    +        if (type == kEnd) {
    +            break;
    +        }
    +        if (type == kCRC) {
    +            QList crcsDefined;
    +            QList crcs;
    +            readHashDigests(numFolders, crcsDefined, crcs);
    +            for (int i = 0; i < numFolders; i++) {
    +                Folder *folder = folders.at(i);
    +                folder->unpackCRCDefined = crcsDefined[i];
    +                folder->unpackCRC = crcs[i];
    +            }
    +            continue;
    +        }
    +        skipData(readNumber());
    +    }
    +    return true;
    +}
    +
    +bool K7Zip::K7ZipPrivate::readSubStreamsInfo()
    +{
    +    if (!buffer) {
    +        return false;
    +    }
    +
    +    numUnpackStreamsInFolders.clear();
    +
    +    int type;
    +    for (;;) {
    +        type = readByte();
    +        if (type == kNumUnpackStream) {
    +            for (int i = 0; i < folders.size(); i++) {
    +                numUnpackStreamsInFolders.append(readNumber());
    +            }
    +            continue;
    +        }
    +        if (type == kCRC || type == kSize) {
    +            break;
    +        }
    +        if (type == kEnd) {
    +            break;
    +        }
    +        skipData(readNumber());
    +    }
    +
    +    if (numUnpackStreamsInFolders.isEmpty()) {
    +        for (int i = 0; i < folders.size(); i++) {
    +            numUnpackStreamsInFolders.append(1);
    +        }
    +    }
    +
    +    for (int i = 0; i < numUnpackStreamsInFolders.size(); i++) {
    +        quint64 numSubstreams = numUnpackStreamsInFolders.at(i);
    +        if (numSubstreams == 0) {
    +            continue;
    +        }
    +        quint64 sum = 0;
    +        for (quint64 j = 1; j < numSubstreams; j++) {
    +            if (type == kSize) {
    +                int size = readNumber();
    +                unpackSizes.append(size);
    +                sum += size;
    +            }
    +        }
    +        unpackSizes.append(folders.at(i)->getUnpackSize() - sum);
    +    }
    +
    +    if (type == kSize) {
    +        type = readByte();
    +    }
    +
    +    int numDigests = 0;
    +    int numDigestsTotal = 0;
    +    for (int i = 0; i < folders.size(); i++) {
    +        quint64 numSubstreams = numUnpackStreamsInFolders.at(i);
    +        if (numSubstreams != 1 || !folders.at(i)->unpackCRCDefined) {
    +            numDigests += numSubstreams;
    +        }
    +        numDigestsTotal += numSubstreams;
    +    }
    +
    +    for (;;) {
    +        if (type == kCRC) {
    +            QList digestsDefined2;
    +            QList digests2;
    +            readHashDigests(numDigests, digestsDefined2, digests2);
    +            int digestIndex = 0;
    +            for (int i = 0; i < folders.size(); i++) {
    +                quint64 numSubstreams = numUnpackStreamsInFolders.at(i);
    +                const Folder *folder = folders.at(i);
    +                if (numSubstreams == 1 && folder->unpackCRCDefined) {
    +                    digestsDefined.append(true);
    +                    digests.append(folder->unpackCRC);
    +                } else {
    +                    for (quint64 j = 0; j < numSubstreams; j++, digestIndex++) {
    +                        digestsDefined.append(digestsDefined2[digestIndex]);
    +                        digests.append(digests2[digestIndex]);
    +                    }
    +                }
    +            }
    +        } else if (type == kEnd) {
    +            if (digestsDefined.isEmpty()) {
    +                for (int i = 0; i < numDigestsTotal; i++) {
    +                    digestsDefined.append(false);
    +                    digests.append(0);
    +                }
    +            }
    +
    +            break;
    +        } else {
    +            skipData(readNumber());
    +        }
    +
    +        type = readByte();
    +    }
    +    return true;
    +}
    +
    +#define TICKSPERSEC 10000000
    +#define TICKSPERMSEC 10000
    +#define SECSPERDAY 86400
    +#define SECSPERHOUR 3600
    +#define SECSPERMIN 60
    +#define EPOCHWEEKDAY 1 /* Jan 1, 1601 was Monday */
    +#define DAYSPERWEEK 7
    +#define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
    +#define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
    +#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
    +#define SECS_1601_TO_1970 ((369 * 365 + 89) * (unsigned long long)SECSPERDAY)
    +
    +static uint toTimeT(const long long liTime)
    +{
    +    long long time = liTime / TICKSPERSEC;
    +
    +    /* The native version of RtlTimeToTimeFields does not take leap seconds
    +     * into account */
    +
    +    /* Split the time into days and seconds within the day */
    +    long int days = time / SECSPERDAY;
    +    int secondsInDay = time % SECSPERDAY;
    +
    +    /* compute time of day */
    +    short hour = (short)(secondsInDay / SECSPERHOUR);
    +    secondsInDay = secondsInDay % SECSPERHOUR;
    +    short minute = (short)(secondsInDay / SECSPERMIN);
    +    short second = (short)(secondsInDay % SECSPERMIN);
    +
    +    /* compute year, month and day of month. */
    +    long int cleaps = (3 * ((4 * days + 1227) / DAYSPERQUADRICENTENNIUM) + 3) / 4;
    +    days += 28188 + cleaps;
    +    long int years = (20 * days - 2442) / (5 * DAYSPERNORMALQUADRENNIUM);
    +    long int yearday = days - (years * DAYSPERNORMALQUADRENNIUM) / 4;
    +    long int months = (64 * yearday) / 1959;
    +    /* the result is based on a year starting on March.
    +     * To convert take 12 from January and February and
    +     * increase the year by one. */
    +
    +    short month;
    +    short year;
    +    if (months < 14) {
    +        month = (short)(months - 1);
    +        year = (short)(years + 1524);
    +    } else {
    +        month = (short)(months - 13);
    +        year = (short)(years + 1525);
    +    }
    +    /* calculation of day of month is based on the wonderful
    +     * sequence of INT( n * 30.6): it reproduces the·
    +     * 31-30-31-30-31-31 month lengths exactly for small n's */
    +    short day = (short)(yearday - (1959 * months) / 64);
    +
    +    QDateTime t(QDate(year, month, day), QTime(hour, minute, second));
    +    t.setTimeZone(QTimeZone::utc());
    +    return t.toSecsSinceEpoch();
    +}
    +
    +long long rtlSecondsSince1970ToSpecTime(quint32 seconds)
    +{
    +    long long secs = seconds * (long long)TICKSPERSEC + TICKS_1601_TO_1970;
    +    return secs;
    +}
    +
    +bool K7Zip::K7ZipPrivate::readMainStreamsInfo()
    +{
    +    if (!buffer) {
    +        return false;
    +    }
    +
    +    quint32 type;
    +    for (;;) {
    +        type = readByte();
    +        if (type > ((quint32)1 << 30)) {
    +            qCDebug(KArchiveLog) << "type error";
    +            return false;
    +        }
    +        switch (type) {
    +        case kEnd:
    +            return true;
    +        case kPackInfo: {
    +            if (!readPackInfo()) {
    +                qCDebug(KArchiveLog) << "error during read pack information";
    +                return false;
    +            }
    +            break;
    +        }
    +        case kUnpackInfo: {
    +            if (!readUnpackInfo()) {
    +                qCDebug(KArchiveLog) << "error during read pack information";
    +                return false;
    +            }
    +            break;
    +        }
    +        case kSubStreamsInfo: {
    +            if (!readSubStreamsInfo()) {
    +                qCDebug(KArchiveLog) << "error during read substreams information";
    +                return false;
    +            }
    +            break;
    +        }
    +        default:
    +            qCDebug(KArchiveLog) << "Wrong type";
    +            return false;
    +        }
    +    }
    +
    +    qCDebug(KArchiveLog) << "should not reach";
    +    return false;
    +}
    +
    +static bool getInStream(const Folder *folder, quint32 streamIndex, int &seqInStream, quint32 &coderIndex)
    +{
    +    for (int i = 0; i < folder->packedStreams.size(); i++) {
    +        if (folder->packedStreams[i] == streamIndex) {
    +            seqInStream = i;
    +            return true;
    +        }
    +    }
    +
    +    int binderIndex = folder->findBindPairForInStream(streamIndex);
    +    if (binderIndex < 0) {
    +        return false;
    +    }
    +
    +    quint32 coderStreamIndex;
    +    folder->findOutStream(folder->outIndexes[binderIndex], coderIndex, coderStreamIndex);
    +
    +    quint32 startIndex = folder->getCoderInStreamIndex(coderIndex);
    +
    +    if (folder->folderInfos[coderIndex]->numInStreams > 1) {
    +        return false;
    +    }
    +
    +    for (int i = 0; i < (int)folder->folderInfos[coderIndex]->numInStreams; i++) {
    +        getInStream(folder, startIndex + i, seqInStream, coderIndex);
    +    }
    +
    +    return true;
    +}
    +
    +static bool getOutStream(const Folder *folder, quint32 streamIndex, int &seqOutStream)
    +{
    +    QList outStreams;
    +    quint32 outStreamIndex = 0;
    +    for (int i = 0; i < folder->folderInfos.size(); i++) {
    +        const Folder::FolderInfo *coderInfo = folder->folderInfos.at(i);
    +
    +        for (int j = 0; j < coderInfo->numOutStreams; j++, outStreamIndex++) {
    +            if (folder->findBindPairForOutStream(outStreamIndex) < 0) {
    +                outStreams.append(outStreamIndex);
    +            }
    +        }
    +    }
    +
    +    for (int i = 0; i < outStreams.size(); i++) {
    +        if (outStreams[i] == streamIndex) {
    +            seqOutStream = i;
    +            return true;
    +        }
    +    }
    +
    +    int binderIndex = folder->findBindPairForOutStream(streamIndex);
    +    if (binderIndex < 0) {
    +        return false;
    +    }
    +
    +    quint32 coderIndex;
    +    quint32 coderStreamIndex;
    +    folder->findInStream(folder->inIndexes[binderIndex], coderIndex, coderStreamIndex);
    +
    +    quint32 startIndex = folder->getCoderOutStreamIndex(coderIndex);
    +
    +    if (folder->folderInfos[coderIndex]->numOutStreams > 1) {
    +        return false;
    +    }
    +
    +    for (int i = 0; i < (int)folder->folderInfos[coderIndex]->numOutStreams; i++) {
    +        getOutStream(folder, startIndex + i, seqOutStream);
    +    }
    +
    +    return true;
    +}
    +
    +const int kNumTopBits = 24;
    +const quint32 kTopValue = (1 << kNumTopBits);
    +
    +class RangeDecoder
    +{
    +    int pos;
    +
    +public:
    +    QByteArray stream;
    +    quint32 range;
    +    quint32 code;
    +
    +    RangeDecoder(const QByteArray &s)
    +        : pos(0)
    +        , stream(s)
    +        , range(0xFFFFFFFF)
    +        , code(0)
    +    {
    +        for (int i = 0; i < 5; i++) {
    +            code = (code << 8) | readByte();
    +        }
    +    }
    +
    +    unsigned char readByte()
    +    {
    +        if (pos >= stream.size()) {
    +            return 0;
    +        }
    +        return stream[pos++];
    +    }
    +
    +    void normalize()
    +    {
    +        while (range < kTopValue) {
    +            code = (code << 8) | readByte();
    +            range <<= 8;
    +        }
    +    }
    +
    +    quint32 getThreshold(quint32 total)
    +    {
    +        return (code) / (range /= total);
    +    }
    +
    +    void decode(quint32 start, quint32 size)
    +    {
    +        code -= start * range;
    +        range *= size;
    +        normalize();
    +    }
    +
    +    quint32 decodeDirectBits(int numTotalBits)
    +    {
    +        quint32 r = range;
    +        quint32 c = code;
    +        quint32 result = 0;
    +        for (int i = numTotalBits; i != 0; i--) {
    +            r >>= 1;
    +            quint32 t = (c - r) >> 31;
    +            c -= r & (t - 1);
    +            result = (result << 1) | (1 - t);
    +
    +            if (r < kTopValue) {
    +                c = (c << 8) | readByte();
    +                r <<= 8;
    +            }
    +        }
    +        range = r;
    +        code = c;
    +        return result;
    +    }
    +
    +    quint32 DecodeBit(quint32 size0, quint32 numTotalBits)
    +    {
    +        quint32 newBound = (range >> numTotalBits) * size0;
    +        quint32 symbol;
    +        if (code < newBound) {
    +            symbol = 0;
    +            range = newBound;
    +        } else {
    +            symbol = 1;
    +            code -= newBound;
    +            range -= newBound;
    +        }
    +        normalize();
    +        return symbol;
    +    }
    +};
    +
    +const int kNumBitModelTotalBits = 11;
    +const quint32 kBitModelTotal = (1 << kNumBitModelTotalBits);
    +
    +template
    +class CBitModel
    +{
    +public:
    +    quint32 prob;
    +    void updateModel(quint32 symbol)
    +    {
    +        if (symbol == 0) {
    +            prob += (kBitModelTotal - prob) >> numMoveBits;
    +        } else {
    +            prob -= (prob) >> numMoveBits;
    +        }
    +    }
    +
    +    void init()
    +    {
    +        prob = kBitModelTotal / 2;
    +    }
    +};
    +
    +template
    +class CBitDecoder : public CBitModel
    +{
    +public:
    +    quint32 decode(RangeDecoder *decoder)
    +    {
    +        quint32 newBound = (decoder->range >> kNumBitModelTotalBits) * this->prob;
    +        if (decoder->code < newBound) {
    +            decoder->range = newBound;
    +            this->prob += (kBitModelTotal - this->prob) >> numMoveBits;
    +            if (decoder->range < kTopValue) {
    +                decoder->code = (decoder->code << 8) | decoder->readByte();
    +                decoder->range <<= 8;
    +            }
    +            return 0;
    +        } else {
    +            decoder->range -= newBound;
    +            decoder->code -= newBound;
    +            this->prob -= (this->prob) >> numMoveBits;
    +            if (decoder->range < kTopValue) {
    +                decoder->code = (decoder->code << 8) | decoder->readByte();
    +                decoder->range <<= 8;
    +            }
    +            return 1;
    +        }
    +    }
    +};
    +
    +inline bool isJcc(unsigned char b0, unsigned char b1)
    +{
    +    return (b0 == 0x0F && (b1 & 0xF0) == 0x80);
    +}
    +inline bool isJ(unsigned char b0, unsigned char b1)
    +{
    +    return ((b1 & 0xFE) == 0xE8 || isJcc(b0, b1));
    +}
    +inline unsigned getIndex(unsigned char b0, unsigned char b1)
    +{
    +    return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257));
    +}
    +
    +const int kNumMoveBits = 5;
    +
    +static QByteArray decodeBCJ2(const QByteArray &mainStream, const QByteArray &callStream, const QByteArray &jumpStream, const QByteArray &rangeBuffer)
    +{
    +    unsigned char prevByte = 0;
    +    QByteArray outStream;
    +    int mainStreamPos = 0;
    +    int callStreamPos = 0;
    +    int jumpStreamPos = 0;
    +
    +    RangeDecoder rangeDecoder(rangeBuffer);
    +
    +    QList> statusDecoder(256 + 2);
    +
    +    for (int i = 0; i < 256 + 2; i++) {
    +        statusDecoder[i].init();
    +    }
    +
    +    for (;;) {
    +        quint32 i;
    +        unsigned char b = 0;
    +        const quint32 kBurstSize = (1 << 18);
    +        for (i = 0; i < kBurstSize; i++) {
    +            if (mainStreamPos == mainStream.size()) {
    +                return outStream;
    +            }
    +
    +            b = mainStream[mainStreamPos++];
    +            outStream.append(b);
    +
    +            if (isJ(prevByte, b)) {
    +                break;
    +            }
    +            prevByte = b;
    +        }
    +
    +        if (i == kBurstSize) {
    +            continue;
    +        }
    +
    +        unsigned index = getIndex(prevByte, b);
    +        if (statusDecoder[index].decode(&rangeDecoder) == 1) {
    +            if (b == 0xE8) {
    +                if (callStreamPos + 4 > callStream.size()) {
    +                    return QByteArray();
    +                }
    +            } else {
    +                if (jumpStreamPos + 4 > jumpStream.size()) {
    +                    return QByteArray();
    +                }
    +            }
    +            quint32 src = 0;
    +            for (int i = 0; i < 4; i++) {
    +                unsigned char b0;
    +                if (b == 0xE8) {
    +                    b0 = callStream[callStreamPos++];
    +                } else {
    +                    b0 = jumpStream[jumpStreamPos++];
    +                }
    +                src <<= 8;
    +                src |= ((quint32)b0);
    +            }
    +
    +            quint32 dest = src - (quint32(outStream.size()) + 4);
    +            outStream.append((unsigned char)(dest));
    +            outStream.append((unsigned char)(dest >> 8));
    +            outStream.append((unsigned char)(dest >> 16));
    +            outStream.append((unsigned char)(dest >> 24));
    +            prevByte = (unsigned char)(dest >> 24);
    +        } else {
    +            prevByte = b;
    +        }
    +    }
    +}
    +
    +QByteArray K7Zip::K7ZipPrivate::readAndDecodePackedStreams(bool readMainStreamInfo)
    +{
    +    if (!buffer) {
    +        return QByteArray();
    +    }
    +
    +    if (readMainStreamInfo) {
    +        readMainStreamsInfo();
    +    }
    +
    +    QByteArray inflatedData;
    +
    +    quint64 startPos = 32 + packPos;
    +    for (int i = 0; i < folders.size(); i++) {
    +        const Folder *folder = folders.at(i);
    +        quint64 unpackSize64 = folder->getUnpackSize();
    +        size_t unpackSize = (size_t)unpackSize64;
    +        if (unpackSize != unpackSize64) {
    +            qCDebug(KArchiveLog) << "unsupported";
    +            return inflatedData;
    +        }
    +
    +        // Find main coder
    +        quint32 mainCoderIndex = 0;
    +        QList outStreamIndexed;
    +        int outStreamIndex = 0;
    +        for (int j = 0; j < folder->folderInfos.size(); j++) {
    +            const Folder::FolderInfo *info = folder->folderInfos[j];
    +            for (int k = 0; k < info->numOutStreams; k++, outStreamIndex++) {
    +                if (folder->findBindPairForOutStream(outStreamIndex) < 0) {
    +                    outStreamIndexed.append(outStreamIndex);
    +                    break;
    +                }
    +            }
    +        }
    +
    +        quint32 temp = 0;
    +        if (!outStreamIndexed.isEmpty()) {
    +            folder->findOutStream(outStreamIndexed[0], mainCoderIndex, temp);
    +        }
    +
    +        quint32 startInIndex = folder->getCoderInStreamIndex(mainCoderIndex);
    +        quint32 startOutIndex = folder->getCoderOutStreamIndex(mainCoderIndex);
    +
    +        Folder::FolderInfo *mainCoder = folder->folderInfos[mainCoderIndex];
    +
    +        QList seqInStreams;
    +        QList coderIndexes;
    +        seqInStreams.reserve(mainCoder->numInStreams);
    +        coderIndexes.reserve(mainCoder->numInStreams);
    +        for (int j = 0; j < (int)mainCoder->numInStreams; j++) {
    +            int seqInStream;
    +            quint32 coderIndex;
    +            getInStream(folder, startInIndex + j, seqInStream, coderIndex);
    +            seqInStreams.append(seqInStream);
    +            coderIndexes.append(coderIndex);
    +        }
    +
    +        QList seqOutStreams;
    +        seqOutStreams.reserve(mainCoder->numOutStreams);
    +        for (int j = 0; j < (int)mainCoder->numOutStreams; j++) {
    +            int seqOutStream;
    +            getOutStream(folder, startOutIndex + j, seqOutStream);
    +            seqOutStreams.append(seqOutStream);
    +        }
    +
    +        QList datas;
    +        for (int j = 0; j < (int)mainCoder->numInStreams; j++) {
    +            quint64 size = packSizes[j + i];
    +            std::unique_ptr encodedBuffer(new char[size]);
    +            QIODevice *dev = q->device();
    +            dev->seek(startPos);
    +            quint64 n = dev->read(encodedBuffer.get(), size);
    +            if (n != size) {
    +                qCDebug(KArchiveLog) << "Failed read next size, should read " << size << ", read " << n;
    +                return inflatedData;
    +            }
    +            QByteArray deflatedData(encodedBuffer.get(), size);
    +            datas.append(deflatedData);
    +            startPos += size;
    +            pos += size;
    +            headerSize += size;
    +        }
    +
    +        QList inflatedDatas;
    +        QByteArray deflatedData;
    +        for (int j = 0; j < seqInStreams.size(); ++j) {
    +            Folder::FolderInfo *coder = nullptr;
    +            if ((quint32)j != mainCoderIndex) {
    +                coder = folder->folderInfos[coderIndexes[j]];
    +            } else {
    +                coder = folder->folderInfos[mainCoderIndex];
    +            }
    +
    +            deflatedData = datas[seqInStreams[j]];
    +
    +            KFilterBase *filter = nullptr;
    +
    +            switch (coder->methodID) {
    +            case k_LZMA:
    +                filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::Xz);
    +                if (!filter) {
    +                    qCDebug(KArchiveLog) << "filter not found";
    +                    return QByteArray();
    +                }
    +                static_cast(filter)->init(QIODevice::ReadOnly, KXzFilter::LZMA, coder->properties);
    +                break;
    +            case k_LZMA2:
    +                filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::Xz);
    +                if (!filter) {
    +                    qCDebug(KArchiveLog) << "filter not found";
    +                    return QByteArray();
    +                }
    +                static_cast(filter)->init(QIODevice::ReadOnly, KXzFilter::LZMA2, coder->properties);
    +                break;
    +            case k_PPMD: {
    +                /*if (coder->properties.size() == 5) {
    +                    //Byte order = *(const Byte *)coder.Props;
    +                    qint32 dicSize = ((unsigned char)coder->properties[1]        |
    +                                     (((unsigned char)coder->properties[2]) <<  8) |
    +                                     (((unsigned char)coder->properties[3]) << 16) |
    +                                     (((unsigned char)coder->properties[4]) << 24));
    +                }*/
    +                break;
    +            }
    +            case k_AES:
    +                if (coder->properties.size() >= 1) {
    +                    // const Byte *data = (const Byte *)coder.Props;
    +                    // Byte firstByte = *data++;
    +                    // UInt32 numCyclesPower = firstByte & 0x3F;
    +                }
    +                break;
    +            case k_BCJ:
    +                filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::Xz);
    +                if (!filter) {
    +                    qCDebug(KArchiveLog) << "filter not found";
    +                    return QByteArray();
    +                }
    +                static_cast(filter)->init(QIODevice::ReadOnly, KXzFilter::BCJ, coder->properties);
    +                break;
    +            case k_BCJ2: {
    +                QByteArray bcj2 = decodeBCJ2(inflatedDatas[0], inflatedDatas[1], inflatedDatas[2], deflatedData);
    +                inflatedDatas.clear();
    +                inflatedDatas.append(bcj2);
    +                break;
    +            }
    +            case k_BZip2:
    +                filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::BZip2);
    +                if (!filter) {
    +                    qCDebug(KArchiveLog) << "filter not found";
    +                    return QByteArray();
    +                }
    +                filter->init(QIODevice::ReadOnly);
    +                break;
    +            }
    +
    +            if (coder->methodID == k_BCJ2) {
    +                continue;
    +            }
    +
    +            if (!filter) {
    +                return QByteArray();
    +            }
    +
    +            filter->setInBuffer(deflatedData.data(), deflatedData.size());
    +
    +            QByteArray outBuffer;
    +            // reserve memory
    +            outBuffer.resize(unpackSize);
    +
    +            KFilterBase::Result result = KFilterBase::Ok;
    +            QByteArray inflatedDataTmp;
    +            while (result != KFilterBase::End && result != KFilterBase::Error && !filter->inBufferEmpty()) {
    +                filter->setOutBuffer(outBuffer.data(), outBuffer.size());
    +                result = filter->uncompress();
    +                if (result == KFilterBase::Error) {
    +                    qCDebug(KArchiveLog) << " decode error";
    +                    filter->terminate();
    +                    delete filter;
    +                    return QByteArray();
    +                }
    +                int uncompressedBytes = outBuffer.size() - filter->outBufferAvailable();
    +
    +                // append the uncompressed data to inflate buffer
    +                inflatedDataTmp.append(outBuffer.data(), uncompressedBytes);
    +
    +                if (result == KFilterBase::End) {
    +                    // qCDebug(KArchiveLog) << "Finished unpacking";
    +                    break; // Finished.
    +                }
    +            }
    +
    +            if (result != KFilterBase::End && !filter->inBufferEmpty()) {
    +                qCDebug(KArchiveLog) << "decode failed result" << result;
    +                filter->terminate();
    +                delete filter;
    +                return QByteArray();
    +            }
    +
    +            filter->terminate();
    +            delete filter;
    +
    +            inflatedDatas.append(inflatedDataTmp);
    +        }
    +
    +        QByteArray inflated;
    +        for (const QByteArray &data : std::as_const(inflatedDatas)) {
    +            inflated.append(data);
    +        }
    +
    +        inflatedDatas.clear();
    +
    +        if (folder->unpackCRCDefined) {
    +            if ((size_t)inflated.size() < unpackSize) {
    +                qCDebug(KArchiveLog) << "wrong crc size data";
    +                return QByteArray();
    +            }
    +            quint32 crc = crc32(0, (Bytef *)(inflated.data()), unpackSize);
    +            if (crc != folder->unpackCRC) {
    +                qCDebug(KArchiveLog) << "wrong crc";
    +                return QByteArray();
    +            }
    +        }
    +
    +        inflatedData.append(inflated);
    +    }
    +
    +    return inflatedData;
    +}
    +
    +///////////////// Write ////////////////////
    +
    +void K7Zip::K7ZipPrivate::createItemsFromEntities(const KArchiveDirectory *dir, const QString &path, QByteArray &data)
    +{
    +    const QStringList l = dir->entries();
    +    QStringList::ConstIterator it = l.begin();
    +    for (; it != l.end(); ++it) {
    +        const KArchiveEntry *entry = dir->entry((*it));
    +
    +        FileInfo *fileInfo = new FileInfo;
    +        fileInfo->attribDefined = true;
    +
    +        fileInfo->path = path + entry->name();
    +        mTimesDefined.append(true);
    +        mTimes.append(rtlSecondsSince1970ToSpecTime(entry->date().toSecsSinceEpoch()));
    +
    +        if (entry->isFile()) {
    +            const K7ZipFileEntry *fileEntry = static_cast(entry);
    +
    +            fileInfo->attributes = FILE_ATTRIBUTE_ARCHIVE;
    +            fileInfo->attributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((entry->permissions() & 0xFFFF) << 16);
    +            fileInfo->size = fileEntry->size();
    +            QString symLink = fileEntry->symLinkTarget();
    +            if (fileInfo->size > 0) {
    +                fileInfo->hasStream = true;
    +                data.append(outData.mid(fileEntry->position(), fileEntry->size()));
    +                unpackSizes.append(fileInfo->size);
    +            } else if (!symLink.isEmpty()) {
    +                fileInfo->hasStream = true;
    +                data.append(symLink.toUtf8());
    +                unpackSizes.append(symLink.size());
    +            }
    +            fileInfos.append(fileInfo);
    +        } else if (entry->isDirectory()) {
    +            fileInfo->attributes = FILE_ATTRIBUTE_DIRECTORY;
    +            fileInfo->attributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((entry->permissions() & 0xFFFF) << 16);
    +            fileInfo->isDir = true;
    +            fileInfos.append(fileInfo);
    +            createItemsFromEntities((KArchiveDirectory *)entry, path + (*it) + QLatin1Char('/'), data);
    +        }
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::writeByte(unsigned char b)
    +{
    +    header.append(b);
    +    countSize++;
    +}
    +
    +void K7Zip::K7ZipPrivate::writeNumber(quint64 value)
    +{
    +    int firstByte = 0;
    +    short mask = 0x80;
    +    int i;
    +    for (i = 0; i < 8; i++) {
    +        if (value < ((quint64(1) << (7 * (i + 1))))) {
    +            firstByte |= (int)(value >> (8 * i));
    +            break;
    +        }
    +        firstByte |= mask;
    +        mask >>= 1;
    +    }
    +    writeByte(firstByte);
    +    for (; i > 0; i--) {
    +        writeByte((int)value);
    +        value >>= 8;
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::writeBoolVector(const QList &boolVector)
    +{
    +    int b = 0;
    +    short mask = 0x80;
    +    for (int i = 0; i < boolVector.size(); i++) {
    +        if (boolVector[i]) {
    +            b |= mask;
    +        }
    +        mask >>= 1;
    +        if (mask == 0) {
    +            writeByte(b);
    +            mask = 0x80;
    +            b = 0;
    +        }
    +    }
    +    if (mask != 0x80) {
    +        writeByte(b);
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::writeUInt32(quint32 value)
    +{
    +    for (int i = 0; i < 4; i++) {
    +        writeByte((unsigned char)value);
    +        value >>= 8;
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::writeUInt64(quint64 value)
    +{
    +    for (int i = 0; i < 8; i++) {
    +        writeByte((unsigned char)value);
    +        value >>= 8;
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::writeAlignedBoolHeader(const QList &v, int numDefined, int type, unsigned itemSize)
    +{
    +    const unsigned bvSize = (numDefined == v.size()) ? 0 : ((unsigned)v.size() + 7) / 8;
    +    const quint64 dataSize = (quint64)numDefined * itemSize + bvSize + 2;
    +    // SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
    +
    +    writeByte(type);
    +    writeNumber(dataSize);
    +    if (numDefined == v.size()) {
    +        writeByte(1);
    +    } else {
    +        writeByte(0);
    +        writeBoolVector(v);
    +    }
    +    writeByte(0);
    +}
    +
    +void K7Zip::K7ZipPrivate::writeUInt64DefVector(const QList &v, const QList &defined, int type)
    +{
    +    int numDefined = 0;
    +
    +    for (int i = 0; i < defined.size(); i++) {
    +        if (defined[i]) {
    +            numDefined++;
    +        }
    +    }
    +
    +    if (numDefined == 0) {
    +        return;
    +    }
    +
    +    writeAlignedBoolHeader(defined, numDefined, type, 8);
    +
    +    for (int i = 0; i < defined.size(); i++) {
    +        if (defined[i]) {
    +            writeUInt64(v[i]);
    +        }
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::writeHashDigests(const QList &digestsDefined, const QList &digests)
    +{
    +    int numDefined = 0;
    +    int i;
    +    for (i = 0; i < digestsDefined.size(); i++) {
    +        if (digestsDefined[i]) {
    +            numDefined++;
    +        }
    +    }
    +
    +    if (numDefined == 0) {
    +        return;
    +    }
    +
    +    writeByte(kCRC);
    +    if (numDefined == digestsDefined.size()) {
    +        writeByte(1);
    +    } else {
    +        writeByte(0);
    +        writeBoolVector(digestsDefined);
    +    }
    +
    +    for (i = 0; i < digests.size(); i++) {
    +        if (digestsDefined[i]) {
    +            writeUInt32(digests[i]);
    +        }
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::writePackInfo(quint64 dataOffset, QList &packedSizes, QList &packedCRCsDefined, QList &packedCRCs)
    +{
    +    if (packedSizes.isEmpty()) {
    +        return;
    +    }
    +    writeByte(kPackInfo);
    +    writeNumber(dataOffset);
    +    writeNumber(packedSizes.size());
    +    writeByte(kSize);
    +
    +    for (int i = 0; i < packedSizes.size(); i++) {
    +        writeNumber(packedSizes[i]);
    +    }
    +
    +    writeHashDigests(packedCRCsDefined, packedCRCs);
    +
    +    writeByte(kEnd);
    +}
    +
    +void K7Zip::K7ZipPrivate::writeFolder(const Folder *folder)
    +{
    +    writeNumber(folder->folderInfos.size());
    +    for (int i = 0; i < folder->folderInfos.size(); i++) {
    +        const Folder::FolderInfo *info = folder->folderInfos.at(i);
    +        {
    +            size_t propsSize = info->properties.size();
    +
    +            quint64 id = info->methodID;
    +            size_t idSize;
    +            for (idSize = 1; idSize < sizeof(id); idSize++) {
    +                if ((id >> (8 * idSize)) == 0) {
    +                    break;
    +                }
    +            }
    +
    +            int longID[15];
    +            for (int t = idSize - 1; t >= 0; t--, id >>= 8) {
    +                longID[t] = (int)(id & 0xFF);
    +            }
    +
    +            int b;
    +            b = (int)(idSize & 0xF);
    +            bool isComplex = !info->isSimpleCoder();
    +            b |= (isComplex ? 0x10 : 0);
    +            b |= ((propsSize != 0) ? 0x20 : 0);
    +
    +            writeByte(b);
    +            for (size_t j = 0; j < idSize; ++j) {
    +                writeByte(longID[j]);
    +            }
    +
    +            if (isComplex) {
    +                writeNumber(info->numInStreams);
    +                writeNumber(info->numOutStreams);
    +            }
    +
    +            if (propsSize == 0) {
    +                continue;
    +            }
    +
    +            writeNumber(propsSize);
    +            for (size_t j = 0; j < propsSize; ++j) {
    +                writeByte(info->properties[j]);
    +            }
    +        }
    +    }
    +
    +    for (int i = 0; i < folder->inIndexes.size(); i++) {
    +        writeNumber(folder->inIndexes[i]);
    +        writeNumber(folder->outIndexes[i]);
    +    }
    +
    +    if (folder->packedStreams.size() > 1) {
    +        for (int i = 0; i < folder->packedStreams.size(); i++) {
    +            writeNumber(folder->packedStreams[i]);
    +        }
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::writeUnpackInfo(const QList &folderItems)
    +{
    +    if (folderItems.isEmpty()) {
    +        return;
    +    }
    +
    +    writeByte(kUnpackInfo);
    +
    +    writeByte(kFolder);
    +    writeNumber(folderItems.size());
    +    {
    +        writeByte(0);
    +        for (int i = 0; i < folderItems.size(); i++) {
    +            writeFolder(folderItems[i]);
    +        }
    +    }
    +
    +    writeByte(kCodersUnpackSize);
    +    int i;
    +    for (i = 0; i < folderItems.size(); i++) {
    +        const Folder *folder = folderItems[i];
    +        for (int j = 0; j < folder->unpackSizes.size(); j++) {
    +            writeNumber(folder->unpackSizes.at(j));
    +        }
    +    }
    +
    +    QList unpackCRCsDefined;
    +    QList unpackCRCs;
    +    unpackCRCsDefined.reserve(folderItems.size());
    +    unpackCRCs.reserve(folderItems.size());
    +    for (i = 0; i < folderItems.size(); i++) {
    +        const Folder *folder = folderItems[i];
    +        unpackCRCsDefined.append(folder->unpackCRCDefined);
    +        unpackCRCs.append(folder->unpackCRC);
    +    }
    +    writeHashDigests(unpackCRCsDefined, unpackCRCs);
    +
    +    writeByte(kEnd);
    +}
    +
    +void K7Zip::K7ZipPrivate::writeSubStreamsInfo(const QList &unpackSizes, const QList &digestsDefined, const QList &digests)
    +{
    +    writeByte(kSubStreamsInfo);
    +
    +    for (int i = 0; i < numUnpackStreamsInFolders.size(); i++) {
    +        if (numUnpackStreamsInFolders.at(i) != 1) {
    +            writeByte(kNumUnpackStream);
    +            for (int j = 0; j < numUnpackStreamsInFolders.size(); j++) {
    +                writeNumber(numUnpackStreamsInFolders.at(j));
    +            }
    +            break;
    +        }
    +    }
    +
    +    bool needFlag = true;
    +    int index = 0;
    +    for (int i = 0; i < numUnpackStreamsInFolders.size(); i++) {
    +        for (quint32 j = 0; j < numUnpackStreamsInFolders.at(i); j++) {
    +            if (j + 1 != numUnpackStreamsInFolders.at(i)) {
    +                if (needFlag) {
    +                    writeByte(kSize);
    +                }
    +                needFlag = false;
    +                writeNumber(unpackSizes[index]);
    +            }
    +            index++;
    +        }
    +    }
    +
    +    QList digestsDefined2;
    +    QList digests2;
    +
    +    int digestIndex = 0;
    +    for (int i = 0; i < folders.size(); i++) {
    +        int numSubStreams = (int)numUnpackStreamsInFolders.at(i);
    +        if (numSubStreams == 1 && folders.at(i)->unpackCRCDefined) {
    +            digestIndex++;
    +        } else {
    +            for (int j = 0; j < numSubStreams; j++, digestIndex++) {
    +                digestsDefined2.append(digestsDefined[digestIndex]);
    +                digests2.append(digests[digestIndex]);
    +            }
    +        }
    +    }
    +    writeHashDigests(digestsDefined2, digests2);
    +    writeByte(kEnd);
    +}
    +
    +QByteArray K7Zip::K7ZipPrivate::encodeStream(QList &packSizes, QList &folds)
    +{
    +    Folder *folder = new Folder;
    +    folder->unpackCRCDefined = true;
    +    folder->unpackCRC = crc32(0, (Bytef *)(header.data()), header.size());
    +    folder->unpackSizes.append(header.size());
    +
    +    Folder::FolderInfo *info = new Folder::FolderInfo();
    +    info->numInStreams = 1;
    +    info->numOutStreams = 1;
    +    info->methodID = k_LZMA2;
    +
    +    quint32 dictSize = header.size();
    +    const quint32 kMinReduceSize = (1 << 16);
    +    if (dictSize < kMinReduceSize) {
    +        dictSize = kMinReduceSize;
    +    }
    +
    +    int dict;
    +    for (dict = 0; dict < 40; dict++) {
    +        if (dictSize <= lzma2_dic_size_from_prop(dict)) {
    +            break;
    +        }
    +    }
    +
    +    info->properties.append(dict);
    +    folder->folderInfos.append(info);
    +
    +    folds.append(folder);
    +
    +    // compress data
    +    QByteArray encodedData;
    +    if (!header.isEmpty()) {
    +        QByteArray enc;
    +        QBuffer inBuffer(&enc);
    +
    +        KCompressionDevice flt(&inBuffer, false, KCompressionDevice::Xz);
    +        flt.open(QIODevice::WriteOnly);
    +
    +        KFilterBase *filter = flt.filterBase();
    +
    +        static_cast(filter)->init(QIODevice::WriteOnly, KXzFilter::LZMA2, info->properties);
    +
    +        const int ret = flt.write(header);
    +        if (ret != header.size()) {
    +            qCDebug(KArchiveLog) << "write error write " << ret << "expected" << header.size();
    +            return encodedData;
    +        }
    +
    +        flt.close();
    +        encodedData = inBuffer.data();
    +    }
    +
    +    packSizes.append(encodedData.size());
    +    return encodedData;
    +}
    +
    +void K7Zip::K7ZipPrivate::writeHeader(quint64 &headerOffset)
    +{
    +    quint64 packedSize = 0;
    +    for (int i = 0; i < packSizes.size(); ++i) {
    +        packedSize += packSizes[i];
    +    }
    +
    +    headerOffset = packedSize;
    +
    +    writeByte(kHeader);
    +
    +    // Archive Properties
    +
    +    if (!folders.isEmpty()) {
    +        writeByte(kMainStreamsInfo);
    +        writePackInfo(0, packSizes, packCRCsDefined, packCRCs);
    +
    +        writeUnpackInfo(folders);
    +
    +        QList unpackFileSizes;
    +        QList digestsDefined;
    +        QList digests;
    +        for (int i = 0; i < fileInfos.size(); i++) {
    +            const FileInfo *file = fileInfos.at(i);
    +            if (!file->hasStream) {
    +                continue;
    +            }
    +            unpackFileSizes.append(file->size);
    +            digestsDefined.append(file->crcDefined);
    +            digests.append(file->crc);
    +        }
    +
    +        writeSubStreamsInfo(unpackSizes, digestsDefined, digests);
    +        writeByte(kEnd);
    +    }
    +
    +    if (fileInfos.isEmpty()) {
    +        writeByte(kEnd);
    +        return;
    +    }
    +
    +    writeByte(kFilesInfo);
    +    writeNumber(fileInfos.size());
    +
    +    {
    +        /* ---------- Empty Streams ---------- */
    +        QList emptyStreamVector;
    +        int numEmptyStreams = 0;
    +        for (int i = 0; i < fileInfos.size(); i++) {
    +            if (fileInfos.at(i)->hasStream) {
    +                emptyStreamVector.append(false);
    +            } else {
    +                emptyStreamVector.append(true);
    +                numEmptyStreams++;
    +            }
    +        }
    +
    +        if (numEmptyStreams > 0) {
    +            writeByte(kEmptyStream);
    +            writeNumber(((unsigned)emptyStreamVector.size() + 7) / 8);
    +            writeBoolVector(emptyStreamVector);
    +
    +            QList emptyFileVector;
    +            QList antiVector;
    +            int numEmptyFiles = 0;
    +            int numAntiItems = 0;
    +            for (int i = 0; i < fileInfos.size(); i++) {
    +                const FileInfo *file = fileInfos.at(i);
    +                if (!file->hasStream) {
    +                    emptyFileVector.append(!file->isDir);
    +                    if (!file->isDir) {
    +                        numEmptyFiles++;
    +                        bool isAnti = (i < this->isAnti.size() && this->isAnti[i]);
    +                        antiVector.append(isAnti);
    +                        if (isAnti) {
    +                            numAntiItems++;
    +                        }
    +                    }
    +                }
    +            }
    +
    +            if (numEmptyFiles > 0) {
    +                writeByte(kEmptyFile);
    +                writeNumber(((unsigned)emptyFileVector.size() + 7) / 8);
    +                writeBoolVector(emptyFileVector);
    +            }
    +
    +            if (numAntiItems > 0) {
    +                writeByte(kAnti);
    +                writeNumber(((unsigned)antiVector.size() + 7) / 8);
    +                writeBoolVector(antiVector);
    +            }
    +        }
    +    }
    +
    +    {
    +        /* ---------- Names ---------- */
    +
    +        int numDefined = 0;
    +        size_t namesDataSize = 0;
    +        for (int i = 0; i < fileInfos.size(); i++) {
    +            const QString &name = fileInfos.at(i)->path;
    +            if (!name.isEmpty()) {
    +                numDefined++;
    +                namesDataSize += (name.length() + 1) * 2;
    +            }
    +        }
    +
    +        if (numDefined > 0) {
    +            namesDataSize++;
    +            // SkipAlign(2 + GetBigNumberSize(namesDataSize), 2);
    +
    +            writeByte(kName);
    +            writeNumber(namesDataSize);
    +            writeByte(0);
    +            for (int i = 0; i < fileInfos.size(); i++) {
    +                const QString &name = fileInfos.at(i)->path;
    +                for (int t = 0; t < name.length(); t++) {
    +                    wchar_t c = name[t].toLatin1();
    +                    writeByte((unsigned char)c);
    +                    writeByte((unsigned char)(c >> 8));
    +                }
    +                // End of string
    +                writeByte(0);
    +                writeByte(0);
    +            }
    +        }
    +    }
    +
    +    writeUInt64DefVector(mTimes, mTimesDefined, kMTime);
    +
    +    writeUInt64DefVector(startPositions, startPositionsDefined, kStartPos);
    +
    +    {
    +        /* ---------- Write Attrib ---------- */
    +        QList boolVector;
    +        int numDefined = 0;
    +        boolVector.reserve(fileInfos.size());
    +        for (int i = 0; i < fileInfos.size(); i++) {
    +            bool defined = fileInfos.at(i)->attribDefined;
    +            boolVector.append(defined);
    +            if (defined) {
    +                numDefined++;
    +            }
    +        }
    +
    +        if (numDefined > 0) {
    +            writeAlignedBoolHeader(boolVector, numDefined, kAttributes, 4);
    +            for (int i = 0; i < fileInfos.size(); i++) {
    +                const FileInfo *file = fileInfos.at(i);
    +                if (file->attribDefined) {
    +                    writeUInt32(file->attributes);
    +                }
    +            }
    +        }
    +    }
    +
    +    writeByte(kEnd); // for files
    +    writeByte(kEnd); // for headers*/
    +}
    +
    +static void setUInt32(unsigned char *p, quint32 d)
    +{
    +    for (int i = 0; i < 4; i++, d >>= 8) {
    +        p[i] = (unsigned)d;
    +    }
    +}
    +
    +static void setUInt64(unsigned char *p, quint64 d)
    +{
    +    for (int i = 0; i < 8; i++, d >>= 8) {
    +        p[i] = (unsigned char)d;
    +    }
    +}
    +
    +void K7Zip::K7ZipPrivate::writeStartHeader(const quint64 nextHeaderSize, const quint32 nextHeaderCRC, const quint64 nextHeaderOffset)
    +{
    +    unsigned char buf[24];
    +    setUInt64(buf + 4, nextHeaderOffset);
    +    setUInt64(buf + 12, nextHeaderSize);
    +    setUInt32(buf + 20, nextHeaderCRC);
    +    setUInt32(buf, crc32(0, (Bytef *)(buf + 4), 20));
    +    q->device()->write((char *)buf, 24);
    +}
    +
    +void K7Zip::K7ZipPrivate::writeSignature()
    +{
    +    unsigned char buf[8];
    +    memcpy(buf, k7zip_signature, 6);
    +    buf[6] = 0 /*kMajorVersion*/;
    +    buf[7] = 3;
    +    q->device()->write((char *)buf, 8);
    +}
    +
    +bool K7Zip::openArchive(QIODevice::OpenMode mode)
    +{
    +    if (!(mode & QIODevice::ReadOnly)) {
    +        return true;
    +    }
    +
    +    QIODevice *dev = device();
    +
    +    if (!dev) {
    +        setErrorString(tr("Could not get underlying device"));
    +        return false;
    +    }
    +
    +    char header[32];
    +    // check signature
    +    qint64 n = dev->read(header, 32);
    +    if (n != 32) {
    +        setErrorString(tr("Read header failed"));
    +        return false;
    +    }
    +
    +    for (int i = 0; i < 6; ++i) {
    +        if ((unsigned char)header[i] != k7zip_signature[i]) {
    +            setErrorString(tr("Check signature failed"));
    +            return false;
    +        }
    +    }
    +
    +    // get Archive Version
    +    int major = header[6];
    +    int minor = header[7];
    +
    +    /*if (major > 0 || minor > 2) {
    +        qCDebug(KArchiveLog) << "wrong archive version";
    +        return false;
    +    }*/
    +
    +    // get Start Header CRC
    +    quint32 startHeaderCRC = GetUi32(header, 8);
    +    quint64 nextHeaderOffset = GetUi64(header, 12);
    +    quint64 nextHeaderSize = GetUi64(header, 20);
    +    quint32 nextHeaderCRC = GetUi32(header, 28);
    +
    +    quint32 crc = crc32(0, (Bytef *)(header + 0xC), 20);
    +
    +    if (crc != startHeaderCRC) {
    +        setErrorString(tr("Bad CRC"));
    +        return false;
    +    }
    +
    +    if (nextHeaderSize == 0) {
    +        return true;
    +    }
    +
    +    if (nextHeaderSize > (quint64)0xFFFFFFFF) {
    +        setErrorString(tr("Next header size is too big"));
    +        return false;
    +    }
    +
    +    if ((qint64)nextHeaderOffset < 0) {
    +        setErrorString(tr("Next header size is less than zero"));
    +        return false;
    +    }
    +
    +    dev->seek(nextHeaderOffset + 32);
    +
    +    QByteArray inBuffer;
    +    inBuffer.resize(nextHeaderSize);
    +
    +    n = dev->read(inBuffer.data(), inBuffer.size());
    +    if (n != (qint64)nextHeaderSize) {
    +        setErrorString(tr("Failed read next header size; should read %1, read %2").arg(nextHeaderSize).arg(n));
    +        return false;
    +    }
    +    d->buffer = inBuffer.data();
    +    d->end = nextHeaderSize;
    +
    +    d->headerSize = 32 + nextHeaderSize;
    +    // int physSize = 32 + nextHeaderSize + nextHeaderOffset;
    +
    +    crc = crc32(0, (Bytef *)(d->buffer), (quint32)nextHeaderSize);
    +
    +    if (crc != nextHeaderCRC) {
    +        setErrorString(tr("Bad next header CRC"));
    +        return false;
    +    }
    +
    +    int type = d->readByte();
    +    QByteArray decodedData;
    +    if (type != kHeader) {
    +        if (type != kEncodedHeader) {
    +            setErrorString(tr("Error in header"));
    +            return false;
    +        }
    +
    +        decodedData = d->readAndDecodePackedStreams();
    +
    +        int external = d->readByte();
    +        if (external != 0) {
    +            int dataIndex = (int)d->readNumber();
    +            if (dataIndex < 0) {
    +                // qCDebug(KArchiveLog) << "dataIndex error";
    +            }
    +            d->buffer = decodedData.constData();
    +            d->pos = 0;
    +            d->end = decodedData.size();
    +        }
    +
    +        type = d->readByte();
    +        if (type != kHeader) {
    +            setErrorString(tr("Wrong header type"));
    +            return false;
    +        }
    +    }
    +    // read header
    +
    +    type = d->readByte();
    +
    +    if (type == kArchiveProperties) {
    +        // TODO : implement this part
    +        setErrorString(tr("Not implemented"));
    +        return false;
    +    }
    +
    +    if (type == kAdditionalStreamsInfo) {
    +        // TODO : implement this part
    +        setErrorString(tr("Not implemented"));
    +        return false;
    +    }
    +
    +    if (type == kMainStreamsInfo) {
    +        if (!d->readMainStreamsInfo()) {
    +            setErrorString(tr("Error while reading main streams information"));
    +            return false;
    +        }
    +        type = d->readByte();
    +    } else {
    +        for (int i = 0; i < d->folders.size(); ++i) {
    +            Folder *folder = d->folders.at(i);
    +            d->unpackSizes.append(folder->getUnpackSize());
    +            d->digestsDefined.append(folder->unpackCRCDefined);
    +            d->digests.append(folder->unpackCRC);
    +        }
    +    }
    +
    +    if (type == kEnd) {
    +        return true;
    +    }
    +
    +    if (type != kFilesInfo) {
    +        setErrorString(tr("Error while reading header"));
    +        return false;
    +    }
    +
    +    // read files info
    +    int numFiles = d->readNumber();
    +    for (int i = 0; i < numFiles; ++i) {
    +        d->fileInfos.append(new FileInfo);
    +    }
    +
    +    QList emptyStreamVector;
    +    QList emptyFileVector;
    +    QList antiFileVector;
    +    int numEmptyStreams = 0;
    +
    +    for (;;) {
    +        quint64 type = d->readByte();
    +        if (type == kEnd) {
    +            break;
    +        }
    +
    +        quint64 size = d->readNumber();
    +
    +        size_t ppp = d->pos;
    +
    +        bool addPropIdToList = true;
    +        bool isKnownType = true;
    +
    +        if (type > ((quint32)1 << 30)) {
    +            isKnownType = false;
    +        } else {
    +            switch (type) {
    +            case kEmptyStream: {
    +                d->readBoolVector(numFiles, emptyStreamVector);
    +                for (int i = 0; i < emptyStreamVector.size(); ++i) {
    +                    if (emptyStreamVector[i]) {
    +                        numEmptyStreams++;
    +                    }
    +                }
    +
    +                break;
    +            }
    +            case kEmptyFile:
    +                d->readBoolVector(numEmptyStreams, emptyFileVector);
    +                break;
    +            case kAnti:
    +                d->readBoolVector(numEmptyStreams, antiFileVector);
    +                break;
    +            case kCTime:
    +                if (!d->readUInt64DefVector(numFiles, d->cTimes, d->cTimesDefined)) {
    +                    return false;
    +                }
    +                break;
    +            case kATime:
    +                if (!d->readUInt64DefVector(numFiles, d->aTimes, d->aTimesDefined)) {
    +                    return false;
    +                }
    +                break;
    +            case kMTime:
    +                if (!d->readUInt64DefVector(numFiles, d->mTimes, d->mTimesDefined)) {
    +                    setErrorString(tr("Error reading modification time"));
    +                    return false;
    +                }
    +                break;
    +            case kName: {
    +                int external = d->readByte();
    +                if (external != 0) {
    +                    int dataIndex = d->readNumber();
    +                    if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
    +                        qCDebug(KArchiveLog) << "wrong data index";
    +                    }
    +
    +                    // TODO : go to the new index
    +                }
    +
    +                QString name;
    +                for (int i = 0; i < numFiles; i++) {
    +                    name = d->readString();
    +                    d->fileInfos.at(i)->path = name;
    +                }
    +                break;
    +            }
    +            case kAttributes: {
    +                QList attributesAreDefined;
    +                d->readBoolVector2(numFiles, attributesAreDefined);
    +                int external = d->readByte();
    +                if (external != 0) {
    +                    int dataIndex = d->readNumber();
    +                    if (dataIndex < 0) {
    +                        qCDebug(KArchiveLog) << "wrong data index";
    +                    }
    +
    +                    // TODO : go to the new index
    +                }
    +
    +                for (int i = 0; i < numFiles; i++) {
    +                    FileInfo *fileInfo = d->fileInfos.at(i);
    +                    fileInfo->attribDefined = attributesAreDefined[i];
    +                    if (fileInfo->attribDefined) {
    +                        fileInfo->attributes = d->readUInt32();
    +                    }
    +                }
    +                break;
    +            }
    +            case kStartPos:
    +                if (!d->readUInt64DefVector(numFiles, d->startPositions, d->startPositionsDefined)) {
    +                    setErrorString(tr("Error reading MTime"));
    +                    return false;
    +                }
    +                break;
    +            case kDummy: {
    +                for (quint64 i = 0; i < size; i++) {
    +                    if (d->readByte() != 0) {
    +                        setErrorString(tr("Invalid"));
    +                        return false;
    +                    }
    +                }
    +                addPropIdToList = false;
    +                break;
    +            }
    +            default:
    +                addPropIdToList = isKnownType = false;
    +            }
    +        }
    +
    +        if (isKnownType) {
    +            if (addPropIdToList) {
    +                d->fileInfoPopIDs.append(type);
    +            }
    +        } else {
    +            d->skipData(d->readNumber());
    +        }
    +
    +        bool checkRecordsSize = (major > 0 || minor > 2);
    +        if (checkRecordsSize && d->pos - ppp != size) {
    +            setErrorString(tr("Read size failed "
    +                              "(checkRecordsSize: %1, d->pos - ppp: %2, size: %3)")
    +                               .arg(checkRecordsSize)
    +                               .arg(d->pos - ppp)
    +                               .arg(size));
    +            return false;
    +        }
    +    }
    +
    +    int emptyFileIndex = 0;
    +    int sizeIndex = 0;
    +
    +    int numAntiItems = 0;
    +
    +    if (emptyStreamVector.isEmpty()) {
    +        emptyStreamVector.fill(false, numFiles);
    +    }
    +
    +    if (antiFileVector.isEmpty()) {
    +        antiFileVector.fill(false, numEmptyStreams);
    +    }
    +    if (emptyFileVector.isEmpty()) {
    +        emptyFileVector.fill(false, numEmptyStreams);
    +    }
    +
    +    for (int i = 0; i < numEmptyStreams; i++) {
    +        if (antiFileVector[i]) {
    +            numAntiItems++;
    +        }
    +    }
    +
    +    d->outData = d->readAndDecodePackedStreams(false);
    +
    +    int oldPos = 0;
    +    for (int i = 0; i < numFiles; i++) {
    +        FileInfo *fileInfo = d->fileInfos.at(i);
    +        bool isAnti;
    +        fileInfo->hasStream = !emptyStreamVector[i];
    +        if (fileInfo->hasStream) {
    +            fileInfo->isDir = false;
    +            isAnti = false;
    +            fileInfo->size = d->unpackSizes[sizeIndex];
    +            fileInfo->crc = d->digests[sizeIndex];
    +            fileInfo->crcDefined = d->digestsDefined[sizeIndex];
    +            sizeIndex++;
    +        } else {
    +            fileInfo->isDir = !emptyFileVector[emptyFileIndex];
    +            isAnti = antiFileVector[emptyFileIndex];
    +            emptyFileIndex++;
    +            fileInfo->size = 0;
    +            fileInfo->crcDefined = false;
    +        }
    +        if (numAntiItems != 0) {
    +            d->isAnti.append(isAnti);
    +        }
    +
    +        int access;
    +        bool symlink = false;
    +        if (fileInfo->attributes & FILE_ATTRIBUTE_UNIX_EXTENSION) {
    +            access = fileInfo->attributes >> 16;
    +            if ((access & QT_STAT_MASK) == QT_STAT_LNK) {
    +                symlink = true;
    +            }
    +        } else {
    +            if (fileInfo->isDir) {
    +                access = S_IFDIR | 0755;
    +            } else {
    +                access = 0100644;
    +            }
    +        }
    +
    +        qint64 pos = 0;
    +        if (!fileInfo->isDir) {
    +            pos = oldPos;
    +            oldPos += fileInfo->size;
    +        }
    +
    +        KArchiveEntry *e;
    +        QString entryName;
    +        int index = fileInfo->path.lastIndexOf(QLatin1Char('/'));
    +        if (index == -1) {
    +            entryName = fileInfo->path;
    +        } else {
    +            entryName = fileInfo->path.mid(index + 1);
    +        }
    +        Q_ASSERT(!entryName.isEmpty());
    +
    +        QDateTime mTime;
    +        if (d->mTimesDefined.size() > i && d->mTimesDefined[i]) {
    +            mTime = KArchivePrivate::time_tToDateTime(toTimeT(d->mTimes[i]));
    +        } else {
    +            mTime = KArchivePrivate::time_tToDateTime(time(nullptr));
    +        }
    +
    +        if (fileInfo->isDir) {
    +            QString path = QDir::cleanPath(fileInfo->path);
    +            const KArchiveEntry *ent = rootDir()->entry(path);
    +            if (ent && ent->isDirectory()) {
    +                e = nullptr;
    +            } else {
    +                e = new KArchiveDirectory(this, entryName, access, mTime, rootDir()->user(), rootDir()->group(), QString() /*symlink*/);
    +            }
    +        } else {
    +            if (!symlink) {
    +                e = new K7ZipFileEntry(this,
    +                                       entryName,
    +                                       access,
    +                                       mTime,
    +                                       rootDir()->user(),
    +                                       rootDir()->group(),
    +                                       QString() /*symlink*/,
    +                                       pos,
    +                                       fileInfo->size,
    +                                       d->outData);
    +            } else {
    +                QString target = QFile::decodeName(d->outData.mid(pos, fileInfo->size));
    +                e = new K7ZipFileEntry(this, entryName, access, mTime, rootDir()->user(), rootDir()->group(), target, 0, 0, nullptr);
    +            }
    +        }
    +
    +        if (e) {
    +            if (index == -1) {
    +                rootDir()->addEntry(e);
    +            } else {
    +                QString path = QDir::cleanPath(fileInfo->path.left(index));
    +                KArchiveDirectory *d = findOrCreate(path);
    +                d->addEntry(e);
    +            }
    +        }
    +    }
    +
    +    return true;
    +}
    +
    +bool K7Zip::closeArchive()
    +{
    +    // Unnecessary check (already checked by KArchive::close())
    +    if (!isOpen()) {
    +        // qCWarning(KArchiveLog) << "You must open the file before close it\n";
    +        return false;
    +    }
    +
    +    if ((mode() == QIODevice::ReadOnly)) {
    +        return true;
    +    }
    +
    +    d->clear();
    +
    +    Folder *folder = new Folder();
    +
    +    folder->unpackSizes.clear();
    +    folder->unpackSizes.append(d->outData.size());
    +
    +    Folder::FolderInfo *info = new Folder::FolderInfo();
    +
    +    info->numInStreams = 1;
    +    info->numOutStreams = 1;
    +    info->methodID = k_LZMA2;
    +
    +    quint32 dictSize = d->outData.size();
    +
    +    const quint32 kMinReduceSize = (1 << 16);
    +    if (dictSize < kMinReduceSize) {
    +        dictSize = kMinReduceSize;
    +    }
    +
    +    // k_LZMA2 method
    +    int dict;
    +    for (dict = 0; dict < 40; dict++) {
    +        if (dictSize <= lzma2_dic_size_from_prop(dict)) {
    +            break;
    +        }
    +    }
    +    info->properties.append(dict);
    +
    +    folder->folderInfos.append(info);
    +    d->folders.append(folder);
    +
    +    const KArchiveDirectory *dir = directory();
    +    QByteArray data;
    +    d->createItemsFromEntities(dir, QString(), data);
    +    d->outData = data;
    +
    +    folder->unpackCRCDefined = true;
    +    folder->unpackCRC = crc32(0, (Bytef *)(d->outData.data()), d->outData.size());
    +
    +    // compress data
    +    QByteArray encodedData;
    +    if (!d->outData.isEmpty()) {
    +        QByteArray enc;
    +        QBuffer inBuffer(&enc);
    +
    +        KCompressionDevice flt(&inBuffer, false, KCompressionDevice::Xz);
    +        flt.open(QIODevice::WriteOnly);
    +
    +        KFilterBase *filter = flt.filterBase();
    +
    +        static_cast(filter)->init(QIODevice::WriteOnly, KXzFilter::LZMA2, info->properties);
    +
    +        const int ret = flt.write(d->outData);
    +        if (ret != d->outData.size()) {
    +            setErrorString(tr("Write error"));
    +            return false;
    +        }
    +
    +        flt.close();
    +        encodedData = inBuffer.data();
    +    }
    +
    +    d->packSizes.append(encodedData.size());
    +
    +    int numUnpackStream = 0;
    +    for (int i = 0; i < d->fileInfos.size(); ++i) {
    +        if (d->fileInfos.at(i)->hasStream) {
    +            numUnpackStream++;
    +        }
    +    }
    +    d->numUnpackStreamsInFolders.append(numUnpackStream);
    +
    +    quint64 headerOffset;
    +    d->writeHeader(headerOffset);
    +
    +    // Encode Header
    +    QByteArray encodedStream;
    +    {
    +        QList packSizes;
    +        QList folders;
    +        encodedStream = d->encodeStream(packSizes, folders);
    +
    +        if (folders.isEmpty()) {
    +            // FIXME Not sure why this is an error. Come up with a better message
    +            setErrorString(tr("Failed while encoding header"));
    +            return false;
    +        }
    +
    +        d->header.clear();
    +
    +        d->writeByte(kEncodedHeader);
    +        QList emptyDefined;
    +        QList emptyCrcs;
    +        d->writePackInfo(headerOffset, packSizes, emptyDefined, emptyCrcs);
    +        d->writeUnpackInfo(folders);
    +        d->writeByte(kEnd);
    +        for (int i = 0; i < packSizes.size(); i++) {
    +            headerOffset += packSizes.at(i);
    +        }
    +        qDeleteAll(folders);
    +    }
    +    // end encode header
    +
    +    quint64 nextHeaderSize = d->header.size();
    +    quint32 nextHeaderCRC = crc32(0, (Bytef *)(d->header.data()), d->header.size());
    +    quint64 nextHeaderOffset = headerOffset;
    +
    +    device()->seek(0);
    +    d->writeSignature();
    +    d->writeStartHeader(nextHeaderSize, nextHeaderCRC, nextHeaderOffset);
    +    device()->write(encodedData.data(), encodedData.size());
    +    device()->write(encodedStream.data(), encodedStream.size());
    +    device()->write(d->header.data(), d->header.size());
    +
    +    return true;
    +}
    +
    +bool K7Zip::doFinishWriting(qint64 size)
    +{
    +    d->m_currentFile->setSize(size);
    +    d->m_currentFile = nullptr;
    +
    +    return true;
    +}
    +
    +bool K7Zip::doWriteData(const char *data, qint64 size)
    +{
    +    if (!d->m_currentFile) {
    +        setErrorString(tr("No file currently selected"));
    +        return false;
    +    }
    +
    +    if (d->m_currentFile->position() == d->outData.size()) {
    +        d->outData.append(data, size);
    +    } else {
    +        d->outData.remove(d->m_currentFile->position(), d->m_currentFile->size());
    +        d->outData.insert(d->m_currentFile->position(), data, size);
    +    }
    +
    +    return true;
    +}
    +
    +bool K7Zip::doPrepareWriting(const QString &name,
    +                             const QString &user,
    +                             const QString &group,
    +                             qint64 /*size*/,
    +                             mode_t perm,
    +                             const QDateTime & /*atime*/,
    +                             const QDateTime &mtime,
    +                             const QDateTime & /*ctime*/)
    +{
    +    if (!isOpen()) {
    +        setErrorString(tr("Application error: 7-Zip file must be open before being written into"));
    +        qCWarning(KArchiveLog) << "doPrepareWriting failed: !isOpen()";
    +        return false;
    +    }
    +
    +    if (!(mode() & QIODevice::WriteOnly)) {
    +        setErrorString(tr("Application error: attempted to write into non-writable 7-Zip file"));
    +        qCWarning(KArchiveLog) << "doPrepareWriting failed: !(mode() & QIODevice::WriteOnly)";
    +        return false;
    +    }
    +
    +    // Find or create parent dir
    +    KArchiveDirectory *parentDir = rootDir();
    +    // QString fileName( name );
    +    // In some files we can find dir/./file => call cleanPath
    +    QString fileName(QDir::cleanPath(name));
    +    int i = name.lastIndexOf(QLatin1Char('/'));
    +    if (i != -1) {
    +        QString dir = name.left(i);
    +        fileName = name.mid(i + 1);
    +        parentDir = findOrCreate(dir);
    +    }
    +
    +    // test if the entry already exist
    +    const KArchiveEntry *entry = parentDir->entry(fileName);
    +    if (!entry) {
    +        K7ZipFileEntry *e =
    +            new K7ZipFileEntry(this, fileName, perm, mtime, user, group, QString() /*symlink*/, d->outData.size(), 0 /*unknown yet*/, d->outData);
    +        if (!parentDir->addEntryV2(e)) {
    +            return false;
    +        }
    +        d->m_entryList << e;
    +        d->m_currentFile = e;
    +    } else {
    +        // TODO : find and replace in m_entryList
    +        // d->m_currentFile = static_cast(entry);
    +    }
    +
    +    return true;
    +}
    +
    +bool K7Zip::doWriteDir(const QString &name,
    +                       const QString &user,
    +                       const QString &group,
    +                       mode_t perm,
    +                       const QDateTime & /*atime*/,
    +                       const QDateTime &mtime,
    +                       const QDateTime & /*ctime*/)
    +{
    +    if (!isOpen()) {
    +        setErrorString(tr("Application error: 7-Zip file must be open before being written into"));
    +        qCWarning(KArchiveLog) << "doWriteDir failed: !isOpen()";
    +        return false;
    +    }
    +
    +    if (!(mode() & QIODevice::WriteOnly)) {
    +        // qCWarning(KArchiveLog) << "You must open the tar file for writing\n";
    +        return false;
    +    }
    +
    +    // In some tar files we can find dir/./ => call cleanPath
    +    QString dirName(QDir::cleanPath(name));
    +
    +    // Remove trailing '/'
    +    if (dirName.endsWith(QLatin1Char('/'))) {
    +        dirName.remove(dirName.size() - 1, 1);
    +    }
    +
    +    KArchiveDirectory *parentDir = rootDir();
    +    int i = dirName.lastIndexOf(QLatin1Char('/'));
    +    if (i != -1) {
    +        QString dir = name.left(i);
    +        dirName = name.mid(i + 1);
    +        parentDir = findOrCreate(dir);
    +    }
    +
    +    KArchiveDirectory *e = new KArchiveDirectory(this, dirName, perm, mtime, user, group, QString() /*symlink*/);
    +    parentDir->addEntry(e);
    +
    +    return true;
    +}
    +
    +bool K7Zip::doWriteSymLink(const QString &name,
    +                           const QString &target,
    +                           const QString &user,
    +                           const QString &group,
    +                           mode_t perm,
    +                           const QDateTime & /*atime*/,
    +                           const QDateTime &mtime,
    +                           const QDateTime & /*ctime*/)
    +{
    +    if (!isOpen()) {
    +        setErrorString(tr("Application error: 7-Zip file must be open before being written into"));
    +        qCWarning(KArchiveLog) << "doWriteSymLink failed: !isOpen()";
    +        return false;
    +    }
    +
    +    if (!(mode() & QIODevice::WriteOnly)) {
    +        setErrorString(tr("Application error: attempted to write into non-writable 7-Zip file"));
    +        qCWarning(KArchiveLog) << "doWriteSymLink failed: !(mode() & QIODevice::WriteOnly)";
    +        return false;
    +    }
    +
    +    // Find or create parent dir
    +    KArchiveDirectory *parentDir = rootDir();
    +    // In some files we can find dir/./file => call cleanPath
    +    QString fileName(QDir::cleanPath(name));
    +    int i = name.lastIndexOf(QLatin1Char('/'));
    +    if (i != -1) {
    +        QString dir = name.left(i);
    +        fileName = name.mid(i + 1);
    +        parentDir = findOrCreate(dir);
    +    }
    +    QByteArray encodedTarget = QFile::encodeName(target);
    +
    +    K7ZipFileEntry *e = new K7ZipFileEntry(this, fileName, perm, mtime, user, group, target, 0, 0, nullptr);
    +    d->outData.append(encodedTarget);
    +
    +    if (!parentDir->addEntryV2(e)) {
    +        return false;
    +    }
    +
    +    d->m_entryList << e;
    +
    +    return true;
    +}
    +
    +void K7Zip::virtual_hook(int id, void *data)
    +{
    +    KArchive::virtual_hook(id, data);
    +}
    diff --git a/src/libs/3rdparty/karchive/src/k7zip.h b/src/libs/3rdparty/karchive/src/k7zip.h
    new file mode 100644
    index 00000000000..b065e4ccb3b
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/k7zip.h
    @@ -0,0 +1,100 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2011 Mario Bensi 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef K7ZIP_H
    +#define K7ZIP_H
    +
    +#include "karchive.h"
    +
    +/**
    + * @class K7Zip k7zip.h K7Zip
    + *
    + * A class for reading / writing p7zip archives.
    + *
    + * @author Mario Bensi
    + */
    +class KARCHIVE_EXPORT K7Zip : public KArchive
    +{
    +    Q_DECLARE_TR_FUNCTIONS(K7Zip)
    +
    +public:
    +    /**
    +     * Creates an instance that operates on the given filename
    +     * using the compression filter associated to given mimetype.
    +     *
    +     * @param filename is a local path (e.g. "/home/user/myfile.7z")
    +     */
    +    explicit K7Zip(const QString &filename);
    +
    +    /**
    +     * Creates an instance that operates on the given device.
    +     * The device can be compressed (KCompressionDevice) or not (QFile, etc.).
    +     * @warning Do not assume that giving a QFile here will decompress the file,
    +     * in case it's compressed!
    +     * @param dev the device to read from. If the source is compressed, the
    +     * QIODevice must take care of decompression
    +     */
    +    explicit K7Zip(QIODevice *dev);
    +
    +    /**
    +     * If the archive is still opened, then it will be
    +     * closed automatically by the destructor.
    +     */
    +    ~K7Zip() override;
    +
    +protected:
    +    /// Reimplemented from KArchive
    +    bool doWriteSymLink(
    +        const QString &name,
    +        const QString &target,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +    /// Reimplemented from KArchive
    +    bool doWriteDir(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +    /// Reimplemented from KArchive
    +    bool doPrepareWriting(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        qint64 size,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +    /// Reimplemented from KArchive
    +    bool doFinishWriting(qint64 size) override;
    +
    +    /// Reimplemented from KArchive
    +    bool doWriteData(const char *data, qint64 size) override;
    +
    +    /**
    +     * Opens the archive for reading.
    +     * Parses the directory listing of the archive
    +     * and creates the KArchiveDirectory/KArchiveFile entries.
    +     * @param mode the mode of the file
    +     */
    +    bool openArchive(QIODevice::OpenMode mode) override;
    +    bool closeArchive() override;
    +
    +protected:
    +    void virtual_hook(int id, void *data) override;
    +
    +private:
    +    class K7ZipPrivate;
    +    K7ZipPrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kar.cpp b/src/libs/3rdparty/karchive/src/kar.cpp
    new file mode 100644
    index 00000000000..5bbe3de9312
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kar.cpp
    @@ -0,0 +1,195 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2002 Laurence Anderson 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "kar.h"
    +#include "karchive_p.h"
    +#include "loggingcategory.h"
    +
    +#include 
    +#include 
    +
    +#include 
    +
    +#include "kcompressiondevice.h"
    +//#include "klimitediodevice_p.h"
    +
    +// As documented in QByteArray
    +static constexpr int kMaxQByteArraySize = std::numeric_limits::max() - 32;
    +
    +////////////////////////////////////////////////////////////////////////
    +/////////////////////////// KAr ///////////////////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +
    +class Q_DECL_HIDDEN KAr::KArPrivate
    +{
    +public:
    +    KArPrivate()
    +    {
    +    }
    +};
    +
    +KAr::KAr(const QString &filename)
    +    : KArchive(filename)
    +    , d(new KArPrivate)
    +{
    +}
    +
    +KAr::KAr(QIODevice *dev)
    +    : KArchive(dev)
    +    , d(new KArPrivate)
    +{
    +}
    +
    +KAr::~KAr()
    +{
    +    if (isOpen()) {
    +        close();
    +    }
    +    delete d;
    +}
    +
    +bool KAr::doPrepareWriting(const QString &, const QString &, const QString &, qint64, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
    +{
    +    setErrorString(tr("Cannot write to AR file"));
    +    qCWarning(KArchiveLog) << "doPrepareWriting not implemented for KAr";
    +    return false;
    +}
    +
    +bool KAr::doFinishWriting(qint64)
    +{
    +    setErrorString(tr("Cannot write to AR file"));
    +    qCWarning(KArchiveLog) << "doFinishWriting not implemented for KAr";
    +    return false;
    +}
    +
    +bool KAr::doWriteDir(const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
    +{
    +    setErrorString(tr("Cannot write to AR file"));
    +    qCWarning(KArchiveLog) << "doWriteDir not implemented for KAr";
    +    return false;
    +}
    +
    +bool KAr::doWriteSymLink(const QString &, const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
    +{
    +    setErrorString(tr("Cannot write to AR file"));
    +    qCWarning(KArchiveLog) << "doWriteSymLink not implemented for KAr";
    +    return false;
    +}
    +
    +bool KAr::openArchive(QIODevice::OpenMode mode)
    +{
    +    // Open archive
    +
    +    if (mode == QIODevice::WriteOnly) {
    +        return true;
    +    }
    +    if (mode != QIODevice::ReadOnly && mode != QIODevice::ReadWrite) {
    +        setErrorString(tr("Unsupported mode %1").arg(mode));
    +        return false;
    +    }
    +
    +    QIODevice *dev = device();
    +    if (!dev) {
    +        return false;
    +    }
    +
    +    QByteArray magic = dev->read(7);
    +    if (magic != "!") {
    +        setErrorString(tr("Invalid main magic"));
    +        return false;
    +    }
    +
    +    QByteArray ar_longnames;
    +    while (!dev->atEnd()) {
    +        QByteArray ar_header;
    +        ar_header.resize(60);
    +
    +        dev->seek(dev->pos() + (2 - (dev->pos() % 2)) % 2); // Ar headers are padded to byte boundary
    +
    +        if (dev->read(ar_header.data(), 60) != 60) { // Read ar header
    +            qCWarning(KArchiveLog) << "Couldn't read header";
    +            return true; // Probably EOF / trailing junk
    +        }
    +
    +        if (!ar_header.endsWith("`\n")) { // Check header magic // krazy:exclude=strings
    +            setErrorString(tr("Invalid magic"));
    +            return false;
    +        }
    +
    +        QByteArray name = ar_header.mid(0, 16); // Process header
    +        const int date = ar_header.mid(16, 12).trimmed().toInt();
    +        // const int uid = ar_header.mid( 28, 6 ).trimmed().toInt();
    +        // const int gid = ar_header.mid( 34, 6 ).trimmed().toInt();
    +        const int mode = ar_header.mid(40, 8).trimmed().toInt(nullptr, 8);
    +        const qint64 size = ar_header.mid(48, 10).trimmed().toInt();
    +        if (size < 0 || size > kMaxQByteArraySize) {
    +            setErrorString(tr("Invalid size"));
    +            return false;
    +        }
    +
    +        bool skip_entry = false; // Deal with special entries
    +        if (name.mid(0, 1) == "/") {
    +            if (name.mid(1, 1) == "/") { // Longfilename table entry
    +                ar_longnames.resize(size);
    +                // Read the table. Note that the QByteArray will contain NUL characters after each entry.
    +                dev->read(ar_longnames.data(), size);
    +                skip_entry = true;
    +                qCDebug(KArchiveLog) << "Read in longnames entry";
    +            } else if (name.mid(1, 1) == " ") { // Symbol table entry
    +                qCDebug(KArchiveLog) << "Skipped symbol entry";
    +                dev->seek(dev->pos() + size);
    +                skip_entry = true;
    +            } else { // Longfilename, look it up in the table
    +                const int ar_longnamesIndex = name.mid(1, 15).trimmed().toInt();
    +                qCDebug(KArchiveLog) << "Longfilename #" << ar_longnamesIndex;
    +                if (ar_longnames.isEmpty()) {
    +                    setErrorString(tr("Invalid longfilename reference"));
    +                    return false;
    +                }
    +                if (ar_longnamesIndex < 0 || ar_longnamesIndex >= ar_longnames.size()) {
    +                    setErrorString(tr("Invalid longfilename position reference"));
    +                    return false;
    +                }
    +                name = QByteArray(ar_longnames.constData() + ar_longnamesIndex);
    +                name.truncate(name.indexOf('/'));
    +            }
    +        }
    +        if (skip_entry) {
    +            continue;
    +        }
    +
    +        // Process filename
    +        name = name.trimmed();
    +        name.replace('/', QByteArray());
    +        qCDebug(KArchiveLog) << "Filename: " << name << " Size: " << size;
    +
    +        KArchiveEntry *entry = new KArchiveFile(this,
    +                                                QString::fromLocal8Bit(name.constData()),
    +                                                mode,
    +                                                KArchivePrivate::time_tToDateTime(date),
    +                                                rootDir()->user(),
    +                                                rootDir()->group(),
    +                                                /*symlink*/ QString(),
    +                                                dev->pos(),
    +                                                size);
    +        rootDir()->addEntry(entry); // Ar files don't support directories, so everything in root
    +
    +        dev->seek(dev->pos() + size); // Skip contents
    +    }
    +
    +    return true;
    +}
    +
    +bool KAr::closeArchive()
    +{
    +    // Close the archive
    +    return true;
    +}
    +
    +void KAr::virtual_hook(int id, void *data)
    +{
    +    KArchive::virtual_hook(id, data);
    +}
    diff --git a/src/libs/3rdparty/karchive/src/kar.h b/src/libs/3rdparty/karchive/src/kar.h
    new file mode 100644
    index 00000000000..17e5b1abbc7
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kar.h
    @@ -0,0 +1,106 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2002 Laurence Anderson 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef KAR_H
    +#define KAR_H
    +
    +#include "karchive.h"
    +
    +/**
    + * @class KAr kar.h KAr
    + *
    + * KAr is a class for reading archives in ar format. Writing
    + * is not supported. Reading archives that contain files bigger than
    + * INT_MAX - 32 bytes is not supported.
    + * @short A class for reading ar archives.
    + * @author Laurence Anderson 
    + */
    +class KARCHIVE_EXPORT KAr : public KArchive
    +{
    +    Q_DECLARE_TR_FUNCTIONS(KAr)
    +
    +public:
    +    /**
    +     * Creates an instance that operates on the given filename.
    +     *
    +     * @param filename is a local path (e.g. "/home/holger/myfile.ar")
    +     */
    +    explicit KAr(const QString &filename);
    +
    +    /**
    +     * Creates an instance that operates on the given device.
    +     * The device can be compressed (KCompressionDevice) or not (QFile, etc.).
    +     * @param dev the device to read from
    +     */
    +    explicit KAr(QIODevice *dev);
    +
    +    /**
    +     * If the ar file is still opened, then it will be
    +     * closed automatically by the destructor.
    +     */
    +    ~KAr() override;
    +
    +protected:
    +    /*
    +     * Writing is not supported by this class, will always fail.
    +     * @return always false
    +     */
    +    bool doPrepareWriting(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        qint64 size,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +
    +    /*
    +     * Writing is not supported by this class, will always fail.
    +     * @return always false
    +     */
    +    bool doFinishWriting(qint64 size) override;
    +
    +    /*
    +     * Writing is not supported by this class, will always fail.
    +     * @return always false
    +     */
    +    bool doWriteDir(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +
    +    bool doWriteSymLink(
    +        const QString &name,
    +        const QString &target,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +
    +    /**
    +     * Opens the archive for reading.
    +     * Parses the directory listing of the archive
    +     * and creates the KArchiveDirectory/KArchiveFile entries.
    +     *
    +     */
    +    bool openArchive(QIODevice::OpenMode mode) override;
    +    bool closeArchive() override;
    +
    +protected:
    +    void virtual_hook(int id, void *data) override;
    +
    +private:
    +    class KArPrivate;
    +    KArPrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/karchive.cpp b/src/libs/3rdparty/karchive/src/karchive.cpp
    new file mode 100644
    index 00000000000..2a3e7b38348
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/karchive.cpp
    @@ -0,0 +1,1062 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +   SPDX-FileCopyrightText: 2003 Leo Savernik 
    +
    +   Moved from ktar.cpp by Roberto Teixeira 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "karchive.h"
    +#include "karchive_p.h"
    +#include "klimitediodevice_p.h"
    +#include "loggingcategory.h"
    +
    +#include  // QT_STATBUF, QT_LSTAT
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include 
    +#include 
    +#include 
    +
    +#include 
    +
    +#ifdef Q_OS_UNIX
    +#include 
    +#include  // PATH_MAX
    +#include 
    +#include 
    +#endif
    +#ifdef Q_OS_WIN
    +#include  // DWORD, GetUserNameW
    +#endif // Q_OS_WIN
    +
    +#if defined(Q_OS_UNIX)
    +#define STAT_METHOD QT_LSTAT
    +#else
    +#define STAT_METHOD QT_STAT
    +#endif
    +
    +////////////////////////////////////////////////////////////////////////
    +/////////////////// KArchiveDirectoryPrivate ///////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +
    +class KArchiveDirectoryPrivate
    +{
    +public:
    +    KArchiveDirectoryPrivate(KArchiveDirectory *parent)
    +        : q(parent)
    +    {
    +    }
    +
    +    ~KArchiveDirectoryPrivate()
    +    {
    +        qDeleteAll(entries);
    +    }
    +
    +    KArchiveDirectoryPrivate(const KArchiveDirectoryPrivate &) = delete;
    +    KArchiveDirectoryPrivate &operator=(const KArchiveDirectoryPrivate &) = delete;
    +
    +    static KArchiveDirectoryPrivate *get(KArchiveDirectory *directory)
    +    {
    +        return directory->d;
    +    }
    +
    +    // Returns in containingDirectory the directory that actually contains the returned entry
    +    const KArchiveEntry *entry(const QString &_name, KArchiveDirectory **containingDirectory) const
    +    {
    +        *containingDirectory = q;
    +
    +        QString name = QDir::cleanPath(_name);
    +        int pos = name.indexOf(QLatin1Char('/'));
    +        if (pos == 0) { // absolute path (see also KArchive::findOrCreate)
    +            if (name.length() > 1) {
    +                name = name.mid(1); // remove leading slash
    +                pos = name.indexOf(QLatin1Char('/')); // look again
    +            } else { // "/"
    +                return q;
    +            }
    +        }
    +        // trailing slash ? -> remove
    +        if (pos != -1 && pos == name.length() - 1) {
    +            name = name.left(pos);
    +            pos = name.indexOf(QLatin1Char('/')); // look again
    +        }
    +        if (pos != -1) {
    +            const QString left = name.left(pos);
    +            const QString right = name.mid(pos + 1);
    +
    +            // qCDebug(KArchiveLog) << "left=" << left << "right=" << right;
    +
    +            KArchiveEntry *e = entries.value(left);
    +            if (!e || !e->isDirectory()) {
    +                return nullptr;
    +            }
    +            *containingDirectory = static_cast(e);
    +            return (*containingDirectory)->d->entry(right, containingDirectory);
    +        }
    +
    +        return entries.value(name);
    +    }
    +
    +    KArchiveDirectory *q;
    +    QHash entries;
    +};
    +
    +////////////////////////////////////////////////////////////////////////
    +/////////////////////////// KArchive ///////////////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +
    +KArchive::KArchive(const QString &fileName)
    +    : d(new KArchivePrivate(this))
    +{
    +    if (fileName.isEmpty()) {
    +        qCWarning(KArchiveLog) << "KArchive: No file name specified";
    +    }
    +    d->fileName = fileName;
    +    // This constructor leaves the device set to 0.
    +    // This is for the use of QSaveFile, see open().
    +}
    +
    +KArchive::KArchive(QIODevice *dev)
    +    : d(new KArchivePrivate(this))
    +{
    +    if (!dev) {
    +        qCWarning(KArchiveLog) << "KArchive: Null device specified";
    +    }
    +    d->dev = dev;
    +}
    +
    +KArchive::~KArchive()
    +{
    +    Q_ASSERT(!isOpen()); // the derived class destructor must have closed already
    +    delete d;
    +}
    +
    +bool KArchive::open(QIODevice::OpenMode mode)
    +{
    +    Q_ASSERT(mode != QIODevice::NotOpen);
    +
    +    if (isOpen()) {
    +        close();
    +    }
    +
    +    if (!d->fileName.isEmpty()) {
    +        Q_ASSERT(!d->dev);
    +        if (!createDevice(mode)) {
    +            return false;
    +        }
    +    }
    +
    +    if (!d->dev) {
    +        setErrorString(tr("No filename or device was specified"));
    +        return false;
    +    }
    +
    +    if (!d->dev->isOpen() && !d->dev->open(mode)) {
    +        setErrorString(tr("Could not open device in mode %1").arg(mode));
    +        return false;
    +    }
    +
    +    d->mode = mode;
    +
    +    Q_ASSERT(!d->rootDir);
    +    d->rootDir = nullptr;
    +
    +    return openArchive(mode);
    +}
    +
    +bool KArchive::createDevice(QIODevice::OpenMode mode)
    +{
    +    switch (mode) {
    +    case QIODevice::WriteOnly:
    +        if (!d->fileName.isEmpty()) {
    +            // The use of QSaveFile can't be done in the ctor (no mode known yet)
    +            // qCDebug(KArchiveLog) << "Writing to a file using QSaveFile";
    +            d->saveFile = new QSaveFile(d->fileName);
    +#ifdef Q_OS_ANDROID
    +            // we cannot rename on to Android content: URLs
    +            if (d->fileName.startsWith(QLatin1String("content://"))) {
    +                d->saveFile->setDirectWriteFallback(true);
    +            }
    +#endif
    +            if (!d->saveFile->open(QIODevice::WriteOnly)) {
    +                setErrorString(tr("QSaveFile creation for %1 failed: %2").arg(d->fileName, d->saveFile->errorString()));
    +
    +                delete d->saveFile;
    +                d->saveFile = nullptr;
    +                return false;
    +            }
    +            d->dev = d->saveFile;
    +            Q_ASSERT(d->dev);
    +        }
    +        break;
    +    case QIODevice::ReadOnly:
    +    case QIODevice::ReadWrite:
    +        // ReadWrite mode still uses QFile for now; we'd need to copy to the tempfile, in fact.
    +        if (!d->fileName.isEmpty()) {
    +            d->dev = new QFile(d->fileName);
    +            d->deviceOwned = true;
    +        }
    +        break; // continued below
    +    default:
    +        setErrorString(tr("Unsupported mode %1").arg(d->mode));
    +        return false;
    +    }
    +    return true;
    +}
    +
    +bool KArchive::close()
    +{
    +    if (!isOpen()) {
    +        setErrorString(tr("Archive already closed"));
    +        return false; // already closed (return false or true? arguable...)
    +    }
    +
    +    // moved by holger to allow kzip to write the zip central dir
    +    // to the file in closeArchive()
    +    // DF: added d->dev so that we skip closeArchive if saving aborted.
    +    bool closeSucceeded = true;
    +    if (d->dev) {
    +        closeSucceeded = closeArchive();
    +        if (d->mode == QIODevice::WriteOnly && !closeSucceeded) {
    +            d->abortWriting();
    +        }
    +    }
    +
    +    if (d->dev && d->dev != d->saveFile) {
    +        d->dev->close();
    +    }
    +
    +    // if d->saveFile is not null then it is equal to d->dev.
    +    if (d->saveFile) {
    +        closeSucceeded = d->saveFile->commit();
    +        delete d->saveFile;
    +        d->saveFile = nullptr;
    +    }
    +    if (d->deviceOwned) {
    +        delete d->dev; // we created it ourselves in open()
    +    }
    +
    +    delete d->rootDir;
    +    d->rootDir = nullptr;
    +    d->mode = QIODevice::NotOpen;
    +    d->dev = nullptr;
    +    return closeSucceeded;
    +}
    +
    +QString KArchive::errorString() const
    +{
    +    return d->errorStr;
    +}
    +
    +const KArchiveDirectory *KArchive::directory() const
    +{
    +    // rootDir isn't const so that parsing-on-demand is possible
    +    return const_cast(this)->rootDir();
    +}
    +
    +bool KArchive::addLocalFile(const QString &fileName, const QString &destName)
    +{
    +    QFileInfo fileInfo(fileName);
    +    if (!fileInfo.isFile() && !fileInfo.isSymLink()) {
    +        setErrorString(tr("%1 doesn't exist or is not a regular file.").arg(fileName));
    +        return false;
    +    }
    +
    +    QT_STATBUF fi;
    +    if (STAT_METHOD(QFile::encodeName(fileName).constData(), &fi) == -1) {
    +        setErrorString(tr("Failed accessing the file %1 for adding to the archive. The error was: %2").arg(fileName).arg(QLatin1String{strerror(errno)}));
    +        return false;
    +    }
    +
    +    if (fileInfo.isSymLink()) {
    +        QString symLinkTarget;
    +        // Do NOT use fileInfo.symLinkTarget() for unix symlinks!
    +        // It returns the -full- path to the target, while we want the target string "as is".
    +#if defined(Q_OS_UNIX) && !defined(Q_OS_OS2EMX)
    +        const QByteArray encodedFileName = QFile::encodeName(fileName);
    +        QByteArray s;
    +#if defined(PATH_MAX)
    +        s.resize(PATH_MAX + 1);
    +#else
    +        int path_max = pathconf(encodedFileName.data(), _PC_PATH_MAX);
    +        if (path_max <= 0) {
    +            path_max = 4096;
    +        }
    +        s.resize(path_max);
    +#endif
    +        int len = readlink(encodedFileName.data(), s.data(), s.size() - 1);
    +        if (len >= 0) {
    +            s[len] = '\0';
    +            symLinkTarget = QFile::decodeName(s.constData());
    +        }
    +#endif
    +        if (symLinkTarget.isEmpty()) { // Mac or Windows
    +            symLinkTarget = fileInfo.symLinkTarget();
    +        }
    +        return writeSymLink(destName,
    +                            symLinkTarget,
    +                            fileInfo.owner(),
    +                            fileInfo.group(),
    +                            fi.st_mode,
    +                            fileInfo.lastRead(),
    +                            fileInfo.lastModified(),
    +                            fileInfo.birthTime());
    +    } /*end if*/
    +
    +    qint64 size = fileInfo.size();
    +
    +    // the file must be opened before prepareWriting is called, otherwise
    +    // if the opening fails, no content will follow the already written
    +    // header and the tar file is incorrect
    +    QFile file(fileName);
    +    if (!file.open(QIODevice::ReadOnly)) {
    +        setErrorString(tr("Couldn't open file %1: %2").arg(fileName, file.errorString()));
    +        return false;
    +    }
    +
    +    if (!prepareWriting(destName, fileInfo.owner(), fileInfo.group(), size, fi.st_mode, fileInfo.lastRead(), fileInfo.lastModified(), fileInfo.birthTime())) {
    +        // qCWarning(KArchiveLog) << " prepareWriting" << destName << "failed";
    +        return false;
    +    }
    +
    +    // Read and write data in chunks to minimize memory usage
    +    QByteArray array;
    +    array.resize(int(qMin(qint64(1024 * 1024), size)));
    +    qint64 n;
    +    qint64 total = 0;
    +    while ((n = file.read(array.data(), array.size())) > 0) {
    +        if (!writeData(array.data(), n)) {
    +            // qCWarning(KArchiveLog) << "writeData failed";
    +            return false;
    +        }
    +        total += n;
    +    }
    +    Q_ASSERT(total == size);
    +
    +    if (!finishWriting(size)) {
    +        // qCWarning(KArchiveLog) << "finishWriting failed";
    +        return false;
    +    }
    +    return true;
    +}
    +
    +bool KArchive::addLocalDirectory(const QString &path, const QString &destName)
    +{
    +    QDir dir(path);
    +    if (!dir.exists()) {
    +        setErrorString(tr("Directory %1 does not exist").arg(path));
    +        return false;
    +    }
    +    dir.setFilter(dir.filter() | QDir::Hidden);
    +    const QStringList files = dir.entryList();
    +    for (const QString &file : files) {
    +        if (file != QLatin1String(".") && file != QLatin1String("..")) {
    +            const QString fileName = path + QLatin1Char('/') + file;
    +            //            qCDebug(KArchiveLog) << "storing " << fileName;
    +            const QString dest = destName.isEmpty() ? file : (destName + QLatin1Char('/') + file);
    +            QFileInfo fileInfo(fileName);
    +
    +            if (fileInfo.isFile() || fileInfo.isSymLink()) {
    +                addLocalFile(fileName, dest);
    +            } else if (fileInfo.isDir()) {
    +                // Write directory, so that empty dirs are preserved (and permissions written out, etc.)
    +                int perms = 0;
    +                QT_STATBUF fi;
    +                if (STAT_METHOD(QFile::encodeName(fileName).constData(), &fi) != -1) {
    +                    perms = fi.st_mode;
    +                }
    +                writeDir(dest, fileInfo.owner(), fileInfo.group(), perms, fileInfo.lastRead(), fileInfo.lastModified(), fileInfo.birthTime());
    +                // Recurse
    +                addLocalDirectory(fileName, dest);
    +            }
    +            // We omit sockets
    +        }
    +    }
    +    return true;
    +}
    +
    +bool KArchive::writeFile(const QString &name,
    +                         QByteArrayView data,
    +                         mode_t perm,
    +                         const QString &user,
    +                         const QString &group,
    +                         const QDateTime &atime,
    +                         const QDateTime &mtime,
    +                         const QDateTime &ctime)
    +{
    +    const qint64 size = data.size();
    +    if (!prepareWriting(name, user, group, size, perm, atime, mtime, ctime)) {
    +        // qCWarning(KArchiveLog) << "prepareWriting failed";
    +        return false;
    +    }
    +
    +    // Write data
    +    // Note: if data is null, don't call write, it would terminate the KCompressionDevice
    +    if (data.constData() && size && !writeData(data.constData(), size)) {
    +        // qCWarning(KArchiveLog) << "writeData failed";
    +        return false;
    +    }
    +
    +    if (!finishWriting(size)) {
    +        // qCWarning(KArchiveLog) << "finishWriting failed";
    +        return false;
    +    }
    +    return true;
    +}
    +
    +bool KArchive::writeData(const char *data, qint64 size)
    +{
    +    return doWriteData(data, size);
    +}
    +
    +bool KArchive::writeData(QByteArrayView data)
    +{
    +    return doWriteData(data.constData(), data.size());
    +}
    +
    +bool KArchive::doWriteData(const char *data, qint64 size)
    +{
    +    bool ok = device()->write(data, size) == size;
    +    if (!ok) {
    +        setErrorString(tr("Writing failed: %1").arg(device()->errorString()));
    +        d->abortWriting();
    +    }
    +    return ok;
    +}
    +
    +// The writeDir -> doWriteDir pattern allows to avoid propagating the default
    +// values into all virtual methods of subclasses, and it allows more extensibility:
    +// if a new argument is needed, we can add a writeDir overload which stores the
    +// additional argument in the d pointer, and doWriteDir reimplementations can fetch
    +// it from there.
    +
    +bool KArchive::writeDir(const QString &name,
    +                        const QString &user,
    +                        const QString &group,
    +                        mode_t perm,
    +                        const QDateTime &atime,
    +                        const QDateTime &mtime,
    +                        const QDateTime &ctime)
    +{
    +    return doWriteDir(name, user, group, perm | 040000, atime, mtime, ctime);
    +}
    +
    +bool KArchive::writeSymLink(const QString &name,
    +                            const QString &target,
    +                            const QString &user,
    +                            const QString &group,
    +                            mode_t perm,
    +                            const QDateTime &atime,
    +                            const QDateTime &mtime,
    +                            const QDateTime &ctime)
    +{
    +    return doWriteSymLink(name, target, user, group, perm, atime, mtime, ctime);
    +}
    +
    +bool KArchive::prepareWriting(const QString &name,
    +                              const QString &user,
    +                              const QString &group,
    +                              qint64 size,
    +                              mode_t perm,
    +                              const QDateTime &atime,
    +                              const QDateTime &mtime,
    +                              const QDateTime &ctime)
    +{
    +    bool ok = doPrepareWriting(name, user, group, size, perm, atime, mtime, ctime);
    +    if (!ok) {
    +        d->abortWriting();
    +    }
    +    return ok;
    +}
    +
    +bool KArchive::finishWriting(qint64 size)
    +{
    +    return doFinishWriting(size);
    +}
    +
    +void KArchive::setErrorString(const QString &errorStr)
    +{
    +    d->errorStr = errorStr;
    +}
    +
    +static QString getCurrentUserName()
    +{
    +#if defined(Q_OS_UNIX)
    +    struct passwd *pw = getpwuid(getuid());
    +    return pw ? QFile::decodeName(pw->pw_name) : QString::number(getuid());
    +#elif defined(Q_OS_WIN)
    +    wchar_t buffer[255];
    +    DWORD size = 255;
    +    bool ok = GetUserNameW(buffer, &size);
    +    if (!ok) {
    +        return QString();
    +    }
    +    return QString::fromWCharArray(buffer);
    +#else
    +    return QString();
    +#endif
    +}
    +
    +static QString getCurrentGroupName()
    +{
    +#if defined(Q_OS_UNIX)
    +    struct group *grp = getgrgid(getgid());
    +    return grp ? QFile::decodeName(grp->gr_name) : QString::number(getgid());
    +#elif defined(Q_OS_WIN)
    +    return QString();
    +#else
    +    return QString();
    +#endif
    +}
    +
    +KArchiveDirectory *KArchive::rootDir()
    +{
    +    if (!d->rootDir) {
    +        // qCDebug(KArchiveLog) << "Making root dir ";
    +        QString username = ::getCurrentUserName();
    +        QString groupname = ::getCurrentGroupName();
    +
    +        d->rootDir = new KArchiveDirectory(this, QStringLiteral("/"), int(0777 + S_IFDIR), QDateTime(), username, groupname, QString());
    +    }
    +    return d->rootDir;
    +}
    +
    +KArchiveDirectory *KArchive::findOrCreate(const QString &path)
    +{
    +    return d->findOrCreate(path, 0 /*recursionCounter*/);
    +}
    +
    +KArchiveDirectory *KArchivePrivate::findOrCreate(const QString &path, int recursionCounter)
    +{
    +    // Check we're not in a path that is ultra deep, this is most probably fine since PATH_MAX on Linux
    +    // is defined as 4096, so even on /a/a/a/a/a/a 2500 recursions puts us over that limit
    +    // an ultra deep recursion will make us crash due to not enough stack. Tests show that 1MB stack
    +    // (default on Linux seems to be 8MB) gives us up to around 4000 recursions
    +    if (recursionCounter > 2500) {
    +        qCWarning(KArchiveLog) << "path recursion limit exceeded, bailing out";
    +        return nullptr;
    +    }
    +    // qCDebug(KArchiveLog) << path;
    +    if (path.isEmpty() || path == QLatin1String("/") || path == QLatin1String(".")) { // root dir => found
    +        // qCDebug(KArchiveLog) << "returning rootdir";
    +        return q->rootDir();
    +    }
    +    // Important note : for tar files containing absolute paths
    +    // (i.e. beginning with "/"), this means the leading "/" will
    +    // be removed (no KDirectory for it), which is exactly the way
    +    // the "tar" program works (though it displays a warning about it)
    +    // See also KArchiveDirectory::entry().
    +
    +    // Already created ? => found
    +    KArchiveDirectory *existingEntryParentDirectory;
    +    const KArchiveEntry *existingEntry = KArchiveDirectoryPrivate::get(q->rootDir())->entry(path, &existingEntryParentDirectory);
    +    if (existingEntry) {
    +        if (existingEntry->isDirectory())
    +        // qCDebug(KArchiveLog) << "found it";
    +        {
    +            const KArchiveDirectory *dir = static_cast(existingEntry);
    +            return const_cast(dir);
    +        } else {
    +            const KArchiveFile *file = static_cast(existingEntry);
    +            if (file->size() > 0) {
    +                qCWarning(KArchiveLog) << path << "is normal file, but there are file paths in the archive assuming it is a directory, bailing out";
    +                return nullptr;
    +            }
    +
    +            qCDebug(KArchiveLog) << path << " is an empty file, assuming it is actually a directory and replacing";
    +            KArchiveEntry *myEntry = const_cast(existingEntry);
    +            existingEntryParentDirectory->removeEntry(myEntry);
    +            delete myEntry;
    +        }
    +    }
    +
    +    // Otherwise go up and try again
    +    int pos = path.lastIndexOf(QLatin1Char('/'));
    +    KArchiveDirectory *parent;
    +    QString dirname;
    +    if (pos == -1) { // no more slash => create in root dir
    +        parent = q->rootDir();
    +        dirname = path;
    +    } else {
    +        QString left = path.left(pos);
    +        dirname = path.mid(pos + 1);
    +        parent = findOrCreate(left, recursionCounter + 1); // recursive call... until we find an existing dir.
    +    }
    +
    +    if (!parent) {
    +        return nullptr;
    +    }
    +
    +    // qCDebug(KArchiveLog) << "found parent " << parent->name() << " adding " << dirname << " to ensure " << path;
    +    // Found -> add the missing piece
    +    KArchiveDirectory *e = new KArchiveDirectory(q, dirname, rootDir->permissions(), rootDir->date(), rootDir->user(), rootDir->group(), QString());
    +    if (parent->addEntryV2(e)) {
    +        return e; // now a directory to  exists
    +    } else {
    +        return nullptr;
    +    }
    +}
    +
    +void KArchive::setDevice(QIODevice *dev)
    +{
    +    if (d->deviceOwned) {
    +        delete d->dev;
    +    }
    +    d->dev = dev;
    +    d->deviceOwned = false;
    +}
    +
    +void KArchive::setRootDir(KArchiveDirectory *rootDir)
    +{
    +    Q_ASSERT(!d->rootDir); // Call setRootDir only once during parsing please ;)
    +    delete d->rootDir; // but if it happens, don't leak
    +    d->rootDir = rootDir;
    +}
    +
    +QIODevice::OpenMode KArchive::mode() const
    +{
    +    return d->mode;
    +}
    +
    +QIODevice *KArchive::device() const
    +{
    +    return d->dev;
    +}
    +
    +bool KArchive::isOpen() const
    +{
    +    return d->mode != QIODevice::NotOpen;
    +}
    +
    +QString KArchive::fileName() const
    +{
    +    return d->fileName;
    +}
    +
    +void KArchivePrivate::abortWriting()
    +{
    +    if (saveFile) {
    +        saveFile->cancelWriting();
    +        delete saveFile;
    +        saveFile = nullptr;
    +        dev = nullptr;
    +    }
    +}
    +
    +// this is a hacky wrapper to check if time_t value is invalid
    +QDateTime KArchivePrivate::time_tToDateTime(uint time_t)
    +{
    +    if (time_t == uint(-1)) {
    +        return QDateTime();
    +    }
    +    return QDateTime::fromSecsSinceEpoch(time_t);
    +}
    +
    +////////////////////////////////////////////////////////////////////////
    +/////////////////////// KArchiveEntry //////////////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +
    +class KArchiveEntryPrivate
    +{
    +public:
    +    KArchiveEntryPrivate(KArchive *_archive,
    +                         const QString &_name,
    +                         int _access,
    +                         const QDateTime &_date,
    +                         const QString &_user,
    +                         const QString &_group,
    +                         const QString &_symlink)
    +        : name(_name)
    +        , date(_date)
    +        , access(_access)
    +        , user(_user)
    +        , group(_group)
    +        , symlink(_symlink)
    +        , archive(_archive)
    +    {
    +    }
    +    QString name;
    +    QDateTime date;
    +    mode_t access;
    +    QString user;
    +    QString group;
    +    QString symlink;
    +    KArchive *archive;
    +};
    +
    +KArchiveEntry::KArchiveEntry(KArchive *t,
    +                             const QString &name,
    +                             int access,
    +                             const QDateTime &date,
    +                             const QString &user,
    +                             const QString &group,
    +                             const QString &symlink)
    +    : d(new KArchiveEntryPrivate(t, name, access, date, user, group, symlink))
    +{
    +}
    +
    +KArchiveEntry::~KArchiveEntry()
    +{
    +    delete d;
    +}
    +
    +QDateTime KArchiveEntry::date() const
    +{
    +    return d->date;
    +}
    +
    +QString KArchiveEntry::name() const
    +{
    +    return d->name;
    +}
    +
    +mode_t KArchiveEntry::permissions() const
    +{
    +    return d->access;
    +}
    +
    +QString KArchiveEntry::user() const
    +{
    +    return d->user;
    +}
    +
    +QString KArchiveEntry::group() const
    +{
    +    return d->group;
    +}
    +
    +QString KArchiveEntry::symLinkTarget() const
    +{
    +    return d->symlink;
    +}
    +
    +bool KArchiveEntry::isFile() const
    +{
    +    return false;
    +}
    +
    +bool KArchiveEntry::isDirectory() const
    +{
    +    return false;
    +}
    +
    +KArchive *KArchiveEntry::archive() const
    +{
    +    return d->archive;
    +}
    +
    +////////////////////////////////////////////////////////////////////////
    +/////////////////////// KArchiveFile ///////////////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +
    +class KArchiveFilePrivate
    +{
    +public:
    +    KArchiveFilePrivate(qint64 _pos, qint64 _size)
    +        : pos(_pos)
    +        , size(_size)
    +    {
    +    }
    +    qint64 pos;
    +    qint64 size;
    +};
    +
    +KArchiveFile::KArchiveFile(KArchive *t,
    +                           const QString &name,
    +                           int access,
    +                           const QDateTime &date,
    +                           const QString &user,
    +                           const QString &group,
    +                           const QString &symlink,
    +                           qint64 pos,
    +                           qint64 size)
    +    : KArchiveEntry(t, name, access, date, user, group, symlink)
    +    , d(new KArchiveFilePrivate(pos, size))
    +{
    +}
    +
    +KArchiveFile::~KArchiveFile()
    +{
    +    delete d;
    +}
    +
    +qint64 KArchiveFile::position() const
    +{
    +    return d->pos;
    +}
    +
    +qint64 KArchiveFile::size() const
    +{
    +    return d->size;
    +}
    +
    +void KArchiveFile::setSize(qint64 s)
    +{
    +    d->size = s;
    +}
    +
    +QByteArray KArchiveFile::data() const
    +{
    +    bool ok = archive()->device()->seek(d->pos);
    +    if (!ok) {
    +        // qCWarning(KArchiveLog) << "Failed to sync to" << d->pos << "to read" << name();
    +    }
    +
    +    // Read content
    +    QByteArray arr;
    +    if (d->size) {
    +        arr = archive()->device()->read(d->size);
    +        Q_ASSERT(arr.size() == d->size);
    +    }
    +    return arr;
    +}
    +
    +QIODevice *KArchiveFile::createDevice() const
    +{
    +    return new KLimitedIODevice(archive()->device(), d->pos, d->size);
    +}
    +
    +bool KArchiveFile::isFile() const
    +{
    +    return true;
    +}
    +
    +static QFileDevice::Permissions withExecutablePerms(QFileDevice::Permissions filePerms, mode_t perms)
    +{
    +    if (perms & 01) {
    +        filePerms |= QFileDevice::ExeOther;
    +    }
    +
    +    if (perms & 010) {
    +        filePerms |= QFileDevice::ExeGroup;
    +    }
    +
    +    if (perms & 0100) {
    +        filePerms |= QFileDevice::ExeOwner;
    +    }
    +
    +    return filePerms;
    +}
    +
    +bool KArchiveFile::copyTo(const QString &dest) const
    +{
    +    QFile f(dest + QLatin1Char('/') + name());
    +    if (f.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
    +        QIODevice *inputDev = createDevice();
    +        if (!inputDev) {
    +            f.remove();
    +            return false;
    +        }
    +
    +        // Read and write data in chunks to minimize memory usage
    +        const qint64 chunkSize = 1024 * 1024;
    +        qint64 remainingSize = d->size;
    +        QByteArray array;
    +        array.resize(int(qMin(chunkSize, remainingSize)));
    +
    +        while (remainingSize > 0) {
    +            const qint64 currentChunkSize = qMin(chunkSize, remainingSize);
    +            const qint64 n = inputDev->read(array.data(), currentChunkSize);
    +            Q_UNUSED(n) // except in Q_ASSERT
    +            Q_ASSERT(n == currentChunkSize);
    +            f.write(array.data(), currentChunkSize);
    +            remainingSize -= currentChunkSize;
    +        }
    +        f.setPermissions(withExecutablePerms(f.permissions(), permissions()));
    +        f.close();
    +
    +        delete inputDev;
    +        return true;
    +    }
    +    return false;
    +}
    +
    +////////////////////////////////////////////////////////////////////////
    +//////////////////////// KArchiveDirectory /////////////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +
    +KArchiveDirectory::KArchiveDirectory(KArchive *t,
    +                                     const QString &name,
    +                                     int access,
    +                                     const QDateTime &date,
    +                                     const QString &user,
    +                                     const QString &group,
    +                                     const QString &symlink)
    +    : KArchiveEntry(t, name, access, date, user, group, symlink)
    +    , d(new KArchiveDirectoryPrivate(this))
    +{
    +}
    +
    +KArchiveDirectory::~KArchiveDirectory()
    +{
    +    delete d;
    +}
    +
    +QStringList KArchiveDirectory::entries() const
    +{
    +    return d->entries.keys();
    +}
    +
    +const KArchiveEntry *KArchiveDirectory::entry(const QString &_name) const
    +{
    +    KArchiveDirectory *dummy;
    +    return d->entry(_name, &dummy);
    +}
    +
    +const KArchiveFile *KArchiveDirectory::file(const QString &name) const
    +{
    +    const KArchiveEntry *e = entry(name);
    +    if (e && e->isFile()) {
    +        return static_cast(e);
    +    }
    +    return nullptr;
    +}
    +
    +void KArchiveDirectory::addEntry(KArchiveEntry *entry)
    +{
    +    addEntryV2(entry);
    +}
    +
    +bool KArchiveDirectory::addEntryV2(KArchiveEntry *entry)
    +{
    +    if (d->entries.value(entry->name())) {
    +        qCWarning(KArchiveLog) << "directory " << name() << "has entry" << entry->name() << "already";
    +        delete entry;
    +        return false;
    +    }
    +    d->entries.insert(entry->name(), entry);
    +    return true;
    +}
    +
    +void KArchiveDirectory::removeEntry(KArchiveEntry *entry)
    +{
    +    if (!entry) {
    +        return;
    +    }
    +
    +    QHash::Iterator it = d->entries.find(entry->name());
    +    // nothing removed?
    +    if (it == d->entries.end()) {
    +        qCWarning(KArchiveLog) << "directory " << name() << "has no entry with name " << entry->name();
    +        return;
    +    }
    +    if (it.value() != entry) {
    +        qCWarning(KArchiveLog) << "directory " << name() << "has another entry for name " << entry->name();
    +        return;
    +    }
    +    d->entries.erase(it);
    +}
    +
    +bool KArchiveDirectory::isDirectory() const
    +{
    +    return true;
    +}
    +
    +static bool sortByPosition(const KArchiveFile *file1, const KArchiveFile *file2)
    +{
    +    return file1->position() < file2->position();
    +}
    +
    +bool KArchiveDirectory::copyTo(const QString &dest, bool recursiveCopy) const
    +{
    +    QDir root;
    +    const QString destDir(QDir(dest).absolutePath()); // get directory path without any "." or ".."
    +
    +    QList fileList;
    +    QMap fileToDir;
    +
    +    // placeholders for iterated items
    +    QStack dirStack;
    +    QStack dirNameStack;
    +
    +    dirStack.push(this); // init stack at current directory
    +    dirNameStack.push(destDir); // ... with given path
    +    do {
    +        const KArchiveDirectory *curDir = dirStack.pop();
    +
    +        // extract only to specified folder if it is located within archive's extraction folder
    +        // otherwise put file under root position in extraction folder
    +        QString curDirName = dirNameStack.pop();
    +        if (!QDir(curDirName).absolutePath().startsWith(destDir)) {
    +            qCWarning(KArchiveLog) << "Attempted export into folder" << curDirName << "which is outside of the extraction root folder" << destDir << "."
    +                                   << "Changing export of contained files to extraction root folder.";
    +            curDirName = destDir;
    +        }
    +
    +        if (!root.mkpath(curDirName)) {
    +            return false;
    +        }
    +
    +        const QStringList dirEntries = curDir->entries();
    +        for (QStringList::const_iterator it = dirEntries.begin(); it != dirEntries.end(); ++it) {
    +            const KArchiveEntry *curEntry = curDir->entry(*it);
    +            if (!curEntry->symLinkTarget().isEmpty()) {
    +                QString linkName = curDirName + QLatin1Char('/') + curEntry->name();
    +                // To create a valid link on Windows, linkName must have a .lnk file extension.
    +#ifdef Q_OS_WIN
    +                if (!linkName.endsWith(QLatin1String(".lnk"))) {
    +                    linkName += QLatin1String(".lnk");
    +                }
    +#endif
    +                QFile symLinkTarget(curEntry->symLinkTarget());
    +                if (!symLinkTarget.link(linkName)) {
    +                    // qCDebug(KArchiveLog) << "symlink(" << curEntry->symLinkTarget() << ',' << linkName << ") failed:" << strerror(errno);
    +                }
    +            } else {
    +                if (curEntry->isFile()) {
    +                    const KArchiveFile *curFile = dynamic_cast(curEntry);
    +                    if (curFile) {
    +                        fileList.append(curFile);
    +                        fileToDir.insert(curFile->position(), curDirName);
    +                    }
    +                }
    +
    +                if (curEntry->isDirectory() && recursiveCopy) {
    +                    const KArchiveDirectory *ad = dynamic_cast(curEntry);
    +                    if (ad) {
    +                        dirStack.push(ad);
    +                        dirNameStack.push(curDirName + QLatin1Char('/') + curEntry->name());
    +                    }
    +                }
    +            }
    +        }
    +    } while (!dirStack.isEmpty());
    +
    +    std::sort(fileList.begin(), fileList.end(), sortByPosition); // sort on d->pos, so we have a linear access
    +
    +    for (QList::const_iterator it = fileList.constBegin(), end = fileList.constEnd(); it != end; ++it) {
    +        const KArchiveFile *f = *it;
    +        qint64 pos = f->position();
    +        if (!f->copyTo(fileToDir[pos])) {
    +            return false;
    +        }
    +    }
    +    return true;
    +}
    +
    +void KArchive::virtual_hook(int, void *)
    +{
    +    /*BASE::virtual_hook( id, data )*/;
    +}
    +
    +void KArchiveEntry::virtual_hook(int, void *)
    +{
    +    /*BASE::virtual_hook( id, data );*/
    +}
    +
    +void KArchiveFile::virtual_hook(int id, void *data)
    +{
    +    KArchiveEntry::virtual_hook(id, data);
    +}
    +
    +void KArchiveDirectory::virtual_hook(int id, void *data)
    +{
    +    KArchiveEntry::virtual_hook(id, data);
    +}
    diff --git a/src/libs/3rdparty/karchive/src/karchive.h b/src/libs/3rdparty/karchive/src/karchive.h
    new file mode 100644
    index 00000000000..8d490304546
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/karchive.h
    @@ -0,0 +1,433 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +   SPDX-FileCopyrightText: 2003 Leo Savernik 
    +
    +   Moved from ktar.h by Roberto Teixeira 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef KARCHIVE_H
    +#define KARCHIVE_H
    +
    +#include 
    +#include 
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "karchive_export.h"
    +
    +#ifdef Q_OS_WIN
    +#include  // mode_t
    +#endif
    +
    +class KArchiveDirectory;
    +class KArchiveFile;
    +
    +class KArchivePrivate;
    +/**
    + * @class KArchive karchive.h KArchive
    + *
    + * KArchive is a base class for reading and writing archives.
    + * @short generic class for reading/writing archives
    + * @author David Faure 
    + */
    +class KARCHIVE_EXPORT KArchive
    +{
    +    Q_DECLARE_TR_FUNCTIONS(KArchive)
    +
    +protected:
    +    /**
    +     * Base constructor (protected since this is a pure virtual class).
    +     * @param fileName is a local path (e.g. "/tmp/myfile.ext"),
    +     * from which the archive will be read from, or into which the archive
    +     * will be written, depending on the mode given to open().
    +     */
    +    explicit KArchive(const QString &fileName);
    +
    +    /**
    +     * Base constructor (protected since this is a pure virtual class).
    +     * @param dev the I/O device where the archive reads its data
    +     * Note that this can be a file, but also a data buffer, a compression filter, etc.
    +     * For a file in writing mode it is better to use the other constructor
    +     * though, to benefit from the use of QSaveFile when saving.
    +     */
    +    explicit KArchive(QIODevice *dev);
    +
    +public:
    +    virtual ~KArchive();
    +
    +    /**
    +     * Opens the archive for reading or writing.
    +     * Inherited classes might want to reimplement openArchive instead.
    +     * @param mode may be QIODevice::ReadOnly or QIODevice::WriteOnly
    +     * @see close
    +     */
    +    virtual bool open(QIODevice::OpenMode mode);
    +
    +    /**
    +     * Closes the archive.
    +     * Inherited classes might want to reimplement closeArchive instead.
    +     *
    +     * @return true if close succeeded without problems
    +     * @see open
    +     */
    +    virtual bool close();
    +
    +    /**
    +     * Returns a description of the last error
    +     * @since 5.29
    +     */
    +    QString errorString() const;
    +
    +    /**
    +     * Checks whether the archive is open.
    +     * @return true if the archive is opened
    +     */
    +    bool isOpen() const;
    +
    +    /**
    +     * Returns the mode in which the archive was opened
    +     * @return the mode in which the archive was opened (QIODevice::ReadOnly or QIODevice::WriteOnly)
    +     * @see open()
    +     */
    +    QIODevice::OpenMode mode() const;
    +
    +    /**
    +     * The underlying device.
    +     * @return the underlying device.
    +     */
    +    QIODevice *device() const;
    +
    +    /**
    +     * The name of the archive file, as passed to the constructor that takes a
    +     * fileName, or an empty string if you used the QIODevice constructor.
    +     * @return the name of the file, or QString() if unknown
    +     */
    +    QString fileName() const;
    +
    +    /**
    +     * If an archive is opened for reading, then the contents
    +     * of the archive can be accessed via this function.
    +     * @return the directory of the archive
    +     */
    +    const KArchiveDirectory *directory() const;
    +
    +    /**
    +     * Writes a local file into the archive. The main difference with writeFile,
    +     * is that this method minimizes memory usage, by not loading the whole file
    +     * into memory in one go.
    +     *
    +     * If @p fileName is a symbolic link, it will be written as is, i.e.
    +     * it will not be resolved before.
    +     * @param fileName full path to an existing local file, to be added to the archive.
    +     * @param destName the resulting name (or relative path) of the file in the archive.
    +     */
    +    bool addLocalFile(const QString &fileName, const QString &destName);
    +
    +    /**
    +     * Writes a local directory into the archive, including all its contents, recursively.
    +     * Calls addLocalFile for each file to be added.
    +     *
    +     * It will also add a @p path that is a symbolic link to a
    +     * directory. The symbolic link will be dereferenced and the content of the
    +     * directory it is pointing to added recursively. However, symbolic links
    +     * *under* @p path will be stored as is.
    +     * @param path full path to an existing local directory, to be added to the archive.
    +     * @param destName the resulting name (or relative path) of the file in the archive.
    +     */
    +    bool addLocalDirectory(const QString &path, const QString &destName);
    +
    +    /**
    +     * If an archive is opened for writing then you can add new directories
    +     * using this function. KArchive won't write one directory twice.
    +     *
    +     * This method also allows some file metadata to be set.
    +     * However, depending on the archive type not all metadata might be regarded.
    +     *
    +     * @param name the name of the directory
    +     * @param user the user that owns the directory
    +     * @param group the group that owns the directory
    +     * @param perm permissions of the directory
    +     * @param atime time the file was last accessed
    +     * @param mtime modification time of the file
    +     * @param ctime time of last status change
    +     */
    +    bool writeDir(const QString &name,
    +                  const QString &user = QString(),
    +                  const QString &group = QString(),
    +                  mode_t perm = 040755,
    +                  const QDateTime &atime = QDateTime(),
    +                  const QDateTime &mtime = QDateTime(),
    +                  const QDateTime &ctime = QDateTime());
    +
    +    /**
    +     * Writes a symbolic link to the archive if supported.
    +     * The archive must be opened for writing.
    +     *
    +     * @param name name of symbolic link
    +     * @param target target of symbolic link
    +     * @param user the user that owns the directory
    +     * @param group the group that owns the directory
    +     * @param perm permissions of the directory
    +     * @param atime time the file was last accessed
    +     * @param mtime modification time of the file
    +     * @param ctime time of last status change
    +     */
    +    bool writeSymLink(const QString &name,
    +                      const QString &target,
    +                      const QString &user = QString(),
    +                      const QString &group = QString(),
    +                      mode_t perm = 0120755,
    +                      const QDateTime &atime = QDateTime(),
    +                      const QDateTime &mtime = QDateTime(),
    +                      const QDateTime &ctime = QDateTime());
    +
    +    /**
    +     * Writes a new file into the archive.
    +     *
    +     * The archive must be opened for writing first.
    +     *
    +     * The necessary parent directories are created automatically
    +     * if needed. For instance, writing "mydir/test1" does not
    +     * require creating the directory "mydir" first.
    +     *
    +     * This method also allows some file metadata to be
    +     * set. However, depending on the archive type not all metadata might be
    +     * written out.
    +     *
    +     * @param name the name of the file
    +     * @param data the data to write
    +     * @param perm permissions of the file
    +     * @param user the user that owns the file
    +     * @param group the group that owns the file
    +     * @param atime time the file was last accessed
    +     * @param mtime modification time of the file
    +     * @param ctime time of last status change
    +     * @since 6.0
    +     */
    +    bool writeFile(const QString &name,
    +                   QByteArrayView data,
    +                   mode_t perm = 0100644,
    +                   const QString &user = QString(),
    +                   const QString &group = QString(),
    +                   const QDateTime &atime = QDateTime(),
    +                   const QDateTime &mtime = QDateTime(),
    +                   const QDateTime &ctime = QDateTime());
    +
    +    /**
    +     * Here's another way of writing a file into an archive:
    +     * Call prepareWriting(), then call writeData()
    +     * as many times as wanted then call finishWriting( totalSize ).
    +     * For tar.gz files, you need to know the size before hand, it is needed in the header!
    +     * For zip files, size isn't used.
    +     *
    +     * This method also allows some file metadata to be
    +     * set. However, depending on the archive type not all metadata might be
    +     * regarded.
    +     * @param name the name of the file
    +     * @param user the user that owns the file
    +     * @param group the group that owns the file
    +     * @param size the size of the file
    +     * @param perm permissions of the file
    +     * @param atime time the file was last accessed
    +     * @param mtime modification time of the file
    +     * @param ctime time of last status change
    +     */
    +    bool prepareWriting(const QString &name,
    +                        const QString &user,
    +                        const QString &group,
    +                        qint64 size,
    +                        mode_t perm = 0100644,
    +                        const QDateTime &atime = QDateTime(),
    +                        const QDateTime &mtime = QDateTime(),
    +                        const QDateTime &ctime = QDateTime());
    +
    +    /**
    +     * Write data into the current file - to be called after calling prepareWriting
    +     * @param data a pointer to the data
    +     * @param size the size of the chunk
    +     * @return @c true if successful, @c false otherwise
    +     */
    +    bool writeData(const char *data, qint64 size);
    +
    +    /**
    +     * Overload for writeData(const char *, qint64);
    +     * @since 6.0
    +     */
    +    bool writeData(QByteArrayView data);
    +
    +    /**
    +     * Call finishWriting after writing the data.
    +     * @param size the size of the file
    +     * @see prepareWriting()
    +     */
    +    bool finishWriting(qint64 size);
    +
    +protected:
    +    /**
    +     * Opens an archive for reading or writing.
    +     * Called by open.
    +     * @param mode may be QIODevice::ReadOnly or QIODevice::WriteOnly
    +     */
    +    virtual bool openArchive(QIODevice::OpenMode mode) = 0;
    +
    +    /**
    +     * Closes the archive.
    +     * Called by close.
    +     */
    +    virtual bool closeArchive() = 0;
    +
    +    /**
    +     * Sets error description
    +     * @param errorStr error description
    +     * @since 5.29
    +     */
    +    void setErrorString(const QString &errorStr);
    +
    +    /**
    +     * Retrieves or create the root directory.
    +     * The default implementation assumes that openArchive() did the parsing,
    +     * so it creates a dummy rootdir if none was set (write mode, or no '/' in the archive).
    +     * Reimplement this to provide parsing/listing on demand.
    +     * @return the root directory
    +     */
    +    virtual KArchiveDirectory *rootDir();
    +
    +    /**
    +     * Write a directory to the archive.
    +     * This virtual method must be implemented by subclasses.
    +     *
    +     * Depending on the archive type not all metadata might be used.
    +     *
    +     * @param name the name of the directory
    +     * @param user the user that owns the directory
    +     * @param group the group that owns the directory
    +     * @param perm permissions of the directory. Use 040755 if you don't have any other information.
    +     * @param atime time the file was last accessed
    +     * @param mtime modification time of the file
    +     * @param ctime time of last status change
    +     * @see writeDir
    +     */
    +    virtual bool doWriteDir(const QString &name,
    +                            const QString &user,
    +                            const QString &group,
    +                            mode_t perm,
    +                            const QDateTime &atime,
    +                            const QDateTime &mtime,
    +                            const QDateTime &ctime) = 0;
    +
    +    /**
    +     * Writes a symbolic link to the archive.
    +     * This virtual method must be implemented by subclasses.
    +     *
    +     * @param name name of symbolic link
    +     * @param target target of symbolic link
    +     * @param user the user that owns the directory
    +     * @param group the group that owns the directory
    +     * @param perm permissions of the directory
    +     * @param atime time the file was last accessed
    +     * @param mtime modification time of the file
    +     * @param ctime time of last status change
    +     * @see writeSymLink
    +     */
    +    virtual bool doWriteSymLink(const QString &name,
    +                                const QString &target,
    +                                const QString &user,
    +                                const QString &group,
    +                                mode_t perm,
    +                                const QDateTime &atime,
    +                                const QDateTime &mtime,
    +                                const QDateTime &ctime) = 0;
    +
    +    /**
    +     * This virtual method must be implemented by subclasses.
    +     *
    +     * Depending on the archive type not all metadata might be used.
    +     *
    +     * @param name the name of the file
    +     * @param user the user that owns the file
    +     * @param group the group that owns the file
    +     * @param size the size of the file
    +     * @param perm permissions of the file. Use 0100644 if you don't have any more specific permissions to set.
    +     * @param atime time the file was last accessed
    +     * @param mtime modification time of the file
    +     * @param ctime time of last status change
    +     * @see prepareWriting
    +     */
    +    virtual bool doPrepareWriting(const QString &name,
    +                                  const QString &user,
    +                                  const QString &group,
    +                                  qint64 size,
    +                                  mode_t perm,
    +                                  const QDateTime &atime,
    +                                  const QDateTime &mtime,
    +                                  const QDateTime &ctime) = 0;
    +
    +    /**
    +     * Write data into the current file.
    +     * Called by writeData.
    +     *
    +     * @param data a pointer to the data
    +     * @param size the size of the chunk
    +     * @return @c true if successful, @c false otherwise
    +     * @see writeData
    +     * @since 6.0
    +     */
    +    virtual bool doWriteData(const char *data, qint64 size);
    +
    +    /**
    +     * Called after writing the data.
    +     * This virtual method must be implemented by subclasses.
    +     *
    +     * @param size the size of the file
    +     * @see finishWriting()
    +     */
    +    virtual bool doFinishWriting(qint64 size) = 0;
    +
    +    /**
    +     * Ensures that @p path exists, create otherwise.
    +     * This handles e.g. tar files missing directory entries, like mico-2.3.0.tar.gz :)
    +     * @param path the path of the directory
    +     * @return the directory with the given @p path
    +     */
    +    KArchiveDirectory *findOrCreate(const QString &path);
    +
    +    /**
    +     * Can be reimplemented in order to change the creation of the device
    +     * (when using the fileName constructor). By default this method uses
    +     * QSaveFile when saving, and a simple QFile on reading.
    +     * This method is called by open().
    +     */
    +    virtual bool createDevice(QIODevice::OpenMode mode);
    +
    +    /**
    +     * Can be called by derived classes in order to set the underlying device.
    +     * Note that KArchive will -not- own the device, it must be deleted by the derived class.
    +     */
    +    void setDevice(QIODevice *dev);
    +
    +    /**
    +     * Derived classes call setRootDir from openArchive,
    +     * to set the root directory after parsing an existing archive.
    +     */
    +    void setRootDir(KArchiveDirectory *rootDir);
    +
    +protected:
    +    virtual void virtual_hook(int id, void *data);
    +
    +private:
    +    friend class KArchivePrivate;
    +    KArchivePrivate *const d;
    +};
    +
    +// for source compat
    +#include "karchivedirectory.h"
    +#include "karchivefile.h"
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/karchive_export.h b/src/libs/3rdparty/karchive/src/karchive_export.h
    new file mode 100644
    index 00000000000..0e1d27afc8a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/karchive_export.h
    @@ -0,0 +1,14 @@
    +// Copyright (C) 2024 The Qt Company Ltd.
    +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
    +
    +#pragma once
    +
    +#include 
    +
    +#ifndef KARCHIVE_EXPORT
    +#ifdef KARCHIVE_LIBRARY
    +#define KARCHIVE_EXPORT Q_DECL_EXPORT
    +#else
    +#define KARCHIVE_EXPORT Q_DECL_IMPORT
    +#endif
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/karchive_p.h b/src/libs/3rdparty/karchive/src/karchive_p.h
    new file mode 100644
    index 00000000000..0a83def8cb9
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/karchive_p.h
    @@ -0,0 +1,59 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +   SPDX-FileCopyrightText: 2003 Leo Savernik 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#ifndef KARCHIVE_P_H
    +#define KARCHIVE_P_H
    +
    +#include "karchive.h"
    +
    +#include 
    +
    +class KArchivePrivate
    +{
    +    Q_DECLARE_TR_FUNCTIONS(KArchivePrivate)
    +
    +public:
    +    KArchivePrivate(KArchive *parent)
    +        : q(parent)
    +    {
    +    }
    +    ~KArchivePrivate()
    +    {
    +        if (deviceOwned) {
    +            delete dev; // we created it ourselves in open()
    +            dev = nullptr;
    +        }
    +
    +        delete saveFile;
    +        delete rootDir;
    +    }
    +
    +    KArchivePrivate(const KArchivePrivate &) = delete;
    +    KArchivePrivate &operator=(const KArchivePrivate &) = delete;
    +
    +    static bool hasRootDir(KArchive *archive)
    +    {
    +        return archive->d->rootDir;
    +    }
    +
    +    void abortWriting();
    +
    +    static QDateTime time_tToDateTime(uint time_t);
    +
    +    KArchiveDirectory *findOrCreate(const QString &path, int recursionCounter);
    +
    +    KArchive *q = nullptr;
    +    KArchiveDirectory *rootDir = nullptr;
    +    QSaveFile *saveFile = nullptr;
    +    QIODevice *dev = nullptr;
    +    QString fileName;
    +    QIODevice::OpenMode mode = QIODevice::NotOpen;
    +    bool deviceOwned = false; // if true, we (KArchive) own dev and must delete it
    +    QString errorStr{tr("Unknown error")};
    +};
    +
    +#endif // KARCHIVE_P_H
    diff --git a/src/libs/3rdparty/karchive/src/karchivedirectory.h b/src/libs/3rdparty/karchive/src/karchivedirectory.h
    new file mode 100644
    index 00000000000..9a45b9ad71e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/karchivedirectory.h
    @@ -0,0 +1,131 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +   SPDX-FileCopyrightText: 2003 Leo Savernik 
    +
    +   Moved from ktar.h by Roberto Teixeira 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef KARCHIVEDIRECTORY_H
    +#define KARCHIVEDIRECTORY_H
    +
    +#include 
    +#include 
    +
    +#include 
    +#include 
    +#include 
    +
    +#include "karchiveentry.h"
    +
    +class KArchiveDirectoryPrivate;
    +class KArchiveFile;
    +/**
    + * @class KArchiveDirectory karchivedirectory.h KArchiveDirectory
    + *
    + * Represents a directory entry in a KArchive.
    + * @short A directory in an archive.
    + *
    + * @see KArchive
    + * @see KArchiveFile
    + */
    +class KARCHIVE_EXPORT KArchiveDirectory : public KArchiveEntry
    +{
    +public:
    +    /**
    +     * Creates a new directory entry.
    +     * @param archive the entries archive
    +     * @param name the name of the entry
    +     * @param access the permissions in unix format
    +     * @param date the date (in seconds since 1970)
    +     * @param user the user that owns the entry
    +     * @param group the group that owns the entry
    +     * @param symlink the symlink, or QString()
    +     */
    +    KArchiveDirectory(
    +        KArchive *archive,
    +        const QString &name,
    +        int access,
    +        const QDateTime &date,
    +        const QString &user,
    +        const QString &group,
    +        const QString &symlink);
    +
    +    ~KArchiveDirectory() override;
    +
    +    /**
    +     * Returns a list of sub-entries.
    +     * Note that the list is not sorted, it's even in random order (due to using a hashtable).
    +     * Use sort() on the result to sort the list by filename.
    +     *
    +     * @return the names of all entries in this directory (filenames, no path).
    +     */
    +    QStringList entries() const;
    +
    +    /**
    +     * Returns the entry in the archive with the given name.
    +     * The entry could be a file or a directory, use isFile() to find out which one it is.
    +     * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
    +     * @return a pointer to the entry in the directory, or a null pointer if there is no such entry.
    +     */
    +    const KArchiveEntry *entry(const QString &name) const;
    +
    +    /**
    +     * Returns the file entry in the archive with the given name.
    +     * If the entry exists and is a file, a KArchiveFile is returned.
    +     * Otherwise, a null pointer is returned.
    +     * This is a convenience method for entry(), when we know the entry is expected to be a file.
    +     *
    +     * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
    +     * @return a pointer to the file entry in the directory, or a null pointer if there is no such file entry.
    +     * @since 5.3
    +     */
    +    const KArchiveFile *file(const QString &name) const;
    +
    +    /**
    +     * @internal
    +     * Adds a new entry to the directory.
    +     * Note: this can delete the entry if another one with the same name is already present
    +     */
    +    void addEntry(KArchiveEntry *); // KF6 TODO: return bool
    +
    +    /**
    +     * @internal
    +     * Adds a new entry to the directory.
    +     * @return whether the entry was added or not. Non added entries are deleted
    +     */
    +    bool addEntryV2(KArchiveEntry *); // KF6 TODO: merge with the one above
    +
    +    /**
    +     * @internal
    +     * Removes an entry from the directory.
    +     */
    +    void removeEntry(KArchiveEntry *); // KF6 TODO: return bool since it can fail
    +
    +    /**
    +     * Checks whether this entry is a directory.
    +     * @return true, since this entry is a directory
    +     */
    +    bool isDirectory() const override;
    +
    +    /**
    +     * Extracts all entries in this archive directory to the directory
    +     * @p dest.
    +     * @param dest the directory to extract to
    +     * @param recursive if set to true, subdirectories are extracted as well
    +     * @return true on success, false if the directory (dest + '/' + name()) couldn't be created
    +     */
    +    bool copyTo(
    +        const QString &dest,
    +        bool recursive = true,
    +        std::function progress = nullptr) const;
    +
    +protected:
    +    void virtual_hook(int id, void *data) override;
    +
    +private:
    +    friend class KArchiveDirectoryPrivate;
    +    KArchiveDirectoryPrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/karchiveentry.h b/src/libs/3rdparty/karchive/src/karchiveentry.h
    new file mode 100644
    index 00000000000..c18bf685cda
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/karchiveentry.h
    @@ -0,0 +1,111 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +   SPDX-FileCopyrightText: 2003 Leo Savernik 
    +
    +   Moved from ktar.h by Roberto Teixeira 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef KARCHIVEENTRY_H
    +#define KARCHIVEENTRY_H
    +
    +#include 
    +#include 
    +
    +#include "karchive_export.h"
    +
    +#include 
    +#include 
    +
    +#ifdef Q_OS_WIN
    +#include  // mode_t
    +#endif
    +
    +class KArchiveDirectory;
    +class KArchiveFile;
    +class KArchive;
    +
    +class KArchiveEntryPrivate;
    +/**
    + * @class KArchiveEntry karchiveentry.h KArchiveEntry
    + *
    + * A base class for entries in an KArchive.
    + * @short Base class for the archive-file's directory structure.
    + *
    + * @see KArchiveFile
    + * @see KArchiveDirectory
    + */
    +class KARCHIVE_EXPORT KArchiveEntry
    +{
    +public:
    +    /**
    +     * Creates a new entry.
    +     * @param archive the entries archive
    +     * @param name the name of the entry
    +     * @param access the permissions in unix format
    +     * @param date the date (in seconds since 1970)
    +     * @param user the user that owns the entry
    +     * @param group the group that owns the entry
    +     * @param symlink the symlink, or QString()
    +     */
    +    KArchiveEntry(KArchive *archive, const QString &name, int access, const QDateTime &date, const QString &user, const QString &group, const QString &symlink);
    +
    +    virtual ~KArchiveEntry();
    +
    +    /**
    +     * Creation date of the file.
    +     * @return the creation date
    +     */
    +    QDateTime date() const;
    +
    +    /**
    +     * Name of the file without path.
    +     * @return the file name without path
    +     */
    +    QString name() const;
    +    /**
    +     * The permissions and mode flags as returned by the stat() function
    +     * in st_mode.
    +     * @return the permissions
    +     */
    +    mode_t permissions() const;
    +    /**
    +     * User who created the file.
    +     * @return the owner of the file
    +     */
    +    QString user() const;
    +    /**
    +     * Group of the user who created the file.
    +     * @return the group of the file
    +     */
    +    QString group() const;
    +
    +    /**
    +     * Symlink if there is one.
    +     * @return the symlink, or QString()
    +     */
    +    QString symLinkTarget() const;
    +
    +    /**
    +     * Checks whether the entry is a file.
    +     * @return true if this entry is a file
    +     */
    +    virtual bool isFile() const;
    +
    +    /**
    +     * Checks whether the entry is a directory.
    +     * @return true if this entry is a directory
    +     */
    +    virtual bool isDirectory() const;
    +
    +protected:
    +    KArchive *archive() const;
    +
    +protected:
    +    virtual void virtual_hook(int id, void *data);
    +
    +private:
    +    KArchiveEntryPrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/karchivefile.h b/src/libs/3rdparty/karchive/src/karchivefile.h
    new file mode 100644
    index 00000000000..fae0d584897
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/karchivefile.h
    @@ -0,0 +1,110 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +   SPDX-FileCopyrightText: 2003 Leo Savernik 
    +
    +   Moved from ktar.h by Roberto Teixeira 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef KARCHIVEFILE_H
    +#define KARCHIVEFILE_H
    +
    +#include "karchiveentry.h"
    +
    +class KArchiveFilePrivate;
    +/**
    + * @class KArchiveFile karchivefile.h KArchiveFile
    + *
    + * Represents a file entry in a KArchive.
    + * @short A file in an archive.
    + *
    + * @see KArchive
    + * @see KArchiveDirectory
    + */
    +class KARCHIVE_EXPORT KArchiveFile : public KArchiveEntry
    +{
    +public:
    +    /**
    +     * Creates a new file entry. Do not call this, KArchive takes care of it.
    +     * @param archive the entries archive
    +     * @param name the name of the entry
    +     * @param access the permissions in unix format
    +     * @param date the date (in seconds since 1970)
    +     * @param user the user that owns the entry
    +     * @param group the group that owns the entry
    +     * @param symlink the symlink, or QString()
    +     * @param pos the position of the file in the directory
    +     * @param size the size of the file
    +     */
    +    KArchiveFile(
    +        KArchive *archive,
    +        const QString &name,
    +        int access,
    +        const QDateTime &date,
    +        const QString &user,
    +        const QString &group,
    +        const QString &symlink,
    +        qint64 pos,
    +        qint64 size);
    +
    +    /**
    +     * Destructor. Do not call this, KArchive takes care of it.
    +     */
    +    ~KArchiveFile() override;
    +
    +    /**
    +     * Position of the data in the [uncompressed] archive.
    +     * @return the position of the file
    +     */
    +    qint64 position() const;
    +    /**
    +     * Size of the data.
    +     * @return the size of the file
    +     */
    +    qint64 size() const;
    +    /**
    +     * Set size of data, usually after writing the file.
    +     * @param s the new size of the file
    +     */
    +    void setSize(qint64 s);
    +
    +    /**
    +     * Returns the data of the file.
    +     * Call data() with care (only once per file), this data isn't cached.
    +     * @return the content of this file.
    +     */
    +    virtual QByteArray data() const;
    +
    +    /**
    +     * This method returns QIODevice (internal class: KLimitedIODevice)
    +     * on top of the underlying QIODevice. This is obviously for reading only.
    +     *
    +     * WARNING: Note that the ownership of the device is being transferred to the caller,
    +     * who will have to delete it.
    +     *
    +     * The returned device auto-opens (in readonly mode), no need to open it.
    +     * @return the QIODevice of the file
    +     */
    +    virtual QIODevice *createDevice() const;
    +
    +    /**
    +     * Checks whether this entry is a file.
    +     * @return true, since this entry is a file
    +     */
    +    bool isFile() const override;
    +
    +    /**
    +     * Extracts the file to the directory @p dest
    +     * @param dest the directory to extract to
    +     * @return true on success, false if the file (dest + '/' + name()) couldn't be created
    +     */
    +    bool copyTo(const QString &dest) const;
    +
    +protected:
    +    void virtual_hook(int id, void *data) override;
    +
    +private:
    +    KArchiveFilePrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kbzip2filter.cpp b/src/libs/3rdparty/karchive/src/kbzip2filter.cpp
    new file mode 100644
    index 00000000000..67532b640cd
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kbzip2filter.cpp
    @@ -0,0 +1,198 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "kbzip2filter.h"
    +#include "loggingcategory.h"
    +
    +#if HAVE_BZIP2_SUPPORT
    +
    +// we don't need that
    +#define BZ_NO_STDIO
    +extern "C" {
    +#include 
    +}
    +
    +#if NEED_BZ2_PREFIX
    +#define bzDecompressInit(x, y, z) BZ2_bzDecompressInit(x, y, z)
    +#define bzDecompressEnd(x) BZ2_bzDecompressEnd(x)
    +#define bzCompressEnd(x) BZ2_bzCompressEnd(x)
    +#define bzDecompress(x) BZ2_bzDecompress(x)
    +#define bzCompress(x, y) BZ2_bzCompress(x, y)
    +#define bzCompressInit(x, y, z, a) BZ2_bzCompressInit(x, y, z, a);
    +#endif
    +
    +#include 
    +
    +#include 
    +
    +// For docu on this, see /usr/doc/bzip2-0.9.5d/bzip2-0.9.5d/manual_3.html
    +
    +class Q_DECL_HIDDEN KBzip2Filter::Private
    +{
    +public:
    +    Private()
    +        : isInitialized(false)
    +    {
    +        memset(&zStream, 0, sizeof(zStream));
    +        mode = 0;
    +    }
    +
    +    bz_stream zStream;
    +    int mode;
    +    bool isInitialized;
    +};
    +
    +KBzip2Filter::KBzip2Filter()
    +    : d(new Private)
    +{
    +}
    +
    +KBzip2Filter::~KBzip2Filter()
    +{
    +    delete d;
    +}
    +
    +bool KBzip2Filter::init(int mode)
    +{
    +    if (d->isInitialized) {
    +        terminate();
    +    }
    +
    +    d->zStream.next_in = nullptr;
    +    d->zStream.avail_in = 0;
    +    if (mode == QIODevice::ReadOnly) {
    +        const int result = bzDecompressInit(&d->zStream, 0, 0);
    +        if (result != BZ_OK) {
    +            // qCDebug(KArchiveLog) << "bzDecompressInit returned " << result;
    +            return false;
    +        }
    +    } else if (mode == QIODevice::WriteOnly) {
    +        const int result = bzCompressInit(&d->zStream, 5, 0, 0);
    +        if (result != BZ_OK) {
    +            // qCDebug(KArchiveLog) << "bzDecompressInit returned " << result;
    +            return false;
    +        }
    +    } else {
    +        // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
    +        return false;
    +    }
    +    d->mode = mode;
    +    d->isInitialized = true;
    +    return true;
    +}
    +
    +int KBzip2Filter::mode() const
    +{
    +    return d->mode;
    +}
    +
    +bool KBzip2Filter::terminate()
    +{
    +    if (d->mode == QIODevice::ReadOnly) {
    +        const int result = bzDecompressEnd(&d->zStream);
    +        if (result != BZ_OK) {
    +            // qCDebug(KArchiveLog) << "bzDecompressEnd returned " << result;
    +            return false;
    +        }
    +    } else if (d->mode == QIODevice::WriteOnly) {
    +        const int result = bzCompressEnd(&d->zStream);
    +        if (result != BZ_OK) {
    +            // qCDebug(KArchiveLog) << "bzCompressEnd returned " << result;
    +            return false;
    +        }
    +    } else {
    +        // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
    +        return false;
    +    }
    +    d->isInitialized = false;
    +    return true;
    +}
    +
    +void KBzip2Filter::reset()
    +{
    +    // bzip2 doesn't seem to have a reset call...
    +    terminate();
    +    init(d->mode);
    +}
    +
    +void KBzip2Filter::setOutBuffer(char *data, uint maxlen)
    +{
    +    d->zStream.avail_out = maxlen;
    +    d->zStream.next_out = data;
    +}
    +
    +void KBzip2Filter::setInBuffer(const char *data, unsigned int size)
    +{
    +    d->zStream.avail_in = size;
    +    d->zStream.next_in = const_cast(data);
    +}
    +
    +int KBzip2Filter::inBufferAvailable() const
    +{
    +    return d->zStream.avail_in;
    +}
    +
    +int KBzip2Filter::outBufferAvailable() const
    +{
    +    return d->zStream.avail_out;
    +}
    +
    +KBzip2Filter::Result KBzip2Filter::uncompress()
    +{
    +    // qCDebug(KArchiveLog) << "Calling bzDecompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
    +    int result = bzDecompress(&d->zStream);
    +    if (result < BZ_OK) {
    +        bzDecompressEnd(&d->zStream);
    +    }
    +
    +    switch (result) {
    +    case BZ_OK:
    +        return KFilterBase::Ok;
    +    case BZ_STREAM_END:
    +        return KFilterBase::End;
    +    case BZ_MEM_ERROR:
    +        qCWarning(KArchiveLog) << "bzDecompress error, insufficient memory";
    +        break;
    +    case BZ_DATA_ERROR:
    +        qCWarning(KArchiveLog) << "bzDecompress error, data integrity error";
    +        break;
    +    case BZ_DATA_ERROR_MAGIC:
    +        qCWarning(KArchiveLog) << "bzDecompress error, stream does not start with the right magic bytes";
    +        break;
    +    case BZ_PARAM_ERROR:
    +        qCWarning(KArchiveLog) << "bzDecompress error, parameter error";
    +        break;
    +    default:
    +        qCWarning(KArchiveLog) << "bzDecompress error, returned:" << result;
    +        break;
    +    }
    +    return KFilterBase::Error;
    +}
    +
    +KBzip2Filter::Result KBzip2Filter::compress(bool finish)
    +{
    +    // qCDebug(KArchiveLog) << "Calling bzCompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
    +    int result = bzCompress(&d->zStream, finish ? BZ_FINISH : BZ_RUN);
    +
    +    switch (result) {
    +    case BZ_OK:
    +    case BZ_FLUSH_OK:
    +    case BZ_RUN_OK:
    +    case BZ_FINISH_OK:
    +        return KFilterBase::Ok;
    +        break;
    +    case BZ_STREAM_END:
    +        // qCDebug(KArchiveLog) << "  bzCompress returned " << result;
    +        return KFilterBase::End;
    +        break;
    +    default:
    +        // qCDebug(KArchiveLog) << "  bzCompress returned " << result;
    +        return KFilterBase::Error;
    +        break;
    +    }
    +}
    +
    +#endif /* HAVE_BZIP2_SUPPORT */
    diff --git a/src/libs/3rdparty/karchive/src/kbzip2filter.h b/src/libs/3rdparty/karchive/src/kbzip2filter.h
    new file mode 100644
    index 00000000000..2aca8ebaaaa
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kbzip2filter.h
    @@ -0,0 +1,47 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#ifndef __kbzip2filter__h
    +#define __kbzip2filter__h
    +
    +#if HAVE_BZIP2_SUPPORT
    +
    +#include "kfilterbase.h"
    +
    +/**
    + * Internal class used by KCompressionDevice
    + * @internal
    + */
    +class KBzip2Filter : public KFilterBase
    +{
    +public:
    +    KBzip2Filter();
    +    ~KBzip2Filter() override;
    +
    +    bool init(int) override;
    +    int mode() const override;
    +    bool terminate() override;
    +    void reset() override;
    +    bool readHeader() override
    +    {
    +        return true; // bzip2 handles it by itself ! Cool !
    +    }
    +    bool writeHeader(const QByteArray &) override { return true; }
    +    void setOutBuffer(char *data, uint maxlen) override;
    +    void setInBuffer(const char *data, uint size) override;
    +    int inBufferAvailable() const override;
    +    int outBufferAvailable() const override;
    +    Result uncompress() override;
    +    Result compress(bool finish) override;
    +
    +private:
    +    class Private;
    +    Private *const d;
    +};
    +
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp b/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp
    new file mode 100644
    index 00000000000..56f2f47bef3
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp
    @@ -0,0 +1,519 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000 David Faure 
    +   SPDX-FileCopyrightText: 2011 Mario Bensi 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "kcompressiondevice.h"
    +#include "kcompressiondevice_p.h"
    +#include "kfilterbase.h"
    +#include "loggingcategory.h"
    +#include "kgzipfilter.h"
    +#include "knonefilter.h"
    +
    +#include "config-compression.h"
    +
    +#if HAVE_BZIP2_SUPPORT
    +#include "kbzip2filter.h"
    +#endif
    +#if HAVE_XZ_SUPPORT
    +#include "kxzfilter.h"
    +#endif
    +#if HAVE_ZSTD_SUPPORT
    +#include "kzstdfilter.h"
    +#endif
    +
    +#include 
    +#include 
    +#include 
    +
    +#include 
    +#include  // for EOF
    +#include 
    +
    +class KCompressionDevicePrivate
    +{
    +public:
    +    KCompressionDevicePrivate(KCompressionDevice *qq)
    +        : bNeedHeader(true)
    +        , bSkipHeaders(false)
    +        , bOpenedUnderlyingDevice(false)
    +        , type(KCompressionDevice::None)
    +        , errorCode(QFileDevice::NoError)
    +        , deviceReadPos(0)
    +        , q(qq)
    +    {
    +    }
    +
    +    void propagateErrorCode();
    +
    +    bool bNeedHeader;
    +    bool bSkipHeaders;
    +    bool bOpenedUnderlyingDevice;
    +    QByteArray buffer; // Used as 'input buffer' when reading, as 'output buffer' when writing
    +    QByteArray origFileName;
    +    KFilterBase::Result result;
    +    KFilterBase *filter;
    +    KCompressionDevice::CompressionType type;
    +    QFileDevice::FileError errorCode;
    +    qint64 deviceReadPos;
    +    KCompressionDevice *q;
    +};
    +
    +void KCompressionDevicePrivate::propagateErrorCode()
    +{
    +    QIODevice *dev = filter->device();
    +    if (QFileDevice *fileDev = qobject_cast(dev)) {
    +        if (fileDev->error() != QFileDevice::NoError) {
    +            errorCode = fileDev->error();
    +            q->setErrorString(dev->errorString());
    +        }
    +    }
    +    // ... we have no generic way to propagate errors from other kinds of iodevices. Sucks, heh? :(
    +}
    +
    +static KCompressionDevice::CompressionType findCompressionByFileName(const QString &fileName)
    +{
    +    if (fileName.endsWith(QLatin1String(".gz"), Qt::CaseInsensitive)) {
    +        return KCompressionDevice::GZip;
    +    }
    +#if HAVE_BZIP2_SUPPORT
    +    if (fileName.endsWith(QLatin1String(".bz2"), Qt::CaseInsensitive)) {
    +        return KCompressionDevice::BZip2;
    +    }
    +#endif
    +#if HAVE_XZ_SUPPORT
    +    if (fileName.endsWith(QLatin1String(".lzma"), Qt::CaseInsensitive) || fileName.endsWith(QLatin1String(".xz"), Qt::CaseInsensitive)) {
    +        return KCompressionDevice::Xz;
    +    }
    +#endif
    +#if HAVE_ZSTD_SUPPORT
    +    if (fileName.endsWith(QLatin1String(".zst"), Qt::CaseInsensitive)) {
    +        return KCompressionDevice::Zstd;
    +    }
    +#endif
    +    else {
    +        // not a warning, since this is called often with other MIME types (see #88574)...
    +        // maybe we can avoid that though?
    +        // qCDebug(KArchiveLog) << "findCompressionByFileName : no compression found for " << fileName;
    +    }
    +
    +    return KCompressionDevice::None;
    +}
    +
    +KCompressionDevice::CompressionType KCompressionDevice::compressionTypeForMimeType(const QString &mimeType)
    +{
    +    if (mimeType == QLatin1String("application/gzip") //
    +        || mimeType == QLatin1String("application/x-gzip") // legacy name, kept for compatibility
    +    ) {
    +        return KCompressionDevice::GZip;
    +    }
    +#if HAVE_BZIP2_SUPPORT
    +    if (mimeType == QLatin1String("application/x-bzip") //
    +        || mimeType == QLatin1String("application/x-bzip2") // old name, kept for compatibility
    +    ) {
    +        return KCompressionDevice::BZip2;
    +    }
    +#endif
    +#if HAVE_XZ_SUPPORT
    +    if (mimeType == QLatin1String("application/x-lzma") // legacy name, still used
    +        || mimeType == QLatin1String("application/x-xz") // current naming
    +    ) {
    +        return KCompressionDevice::Xz;
    +    }
    +#endif
    +#if HAVE_ZSTD_SUPPORT
    +    if (mimeType == QLatin1String("application/zstd")) {
    +        return KCompressionDevice::Zstd;
    +    }
    +#endif
    +    QMimeDatabase db;
    +    const QMimeType mime = db.mimeTypeForName(mimeType);
    +    if (mime.isValid()) {
    +        // use legacy MIME type for now, see comment in impl. of KTar(const QString &, const QString &_mimetype)
    +        if (mime.inherits(QStringLiteral("application/x-gzip"))) {
    +            return KCompressionDevice::GZip;
    +        }
    +#if HAVE_BZIP2_SUPPORT
    +        if (mime.inherits(QStringLiteral("application/x-bzip"))) {
    +            return KCompressionDevice::BZip2;
    +        }
    +#endif
    +#if HAVE_XZ_SUPPORT
    +        if (mime.inherits(QStringLiteral("application/x-lzma"))) {
    +            return KCompressionDevice::Xz;
    +        }
    +
    +        if (mime.inherits(QStringLiteral("application/x-xz"))) {
    +            return KCompressionDevice::Xz;
    +        }
    +#endif
    +    }
    +
    +    // not a warning, since this is called often with other MIME types (see #88574)...
    +    // maybe we can avoid that though?
    +    // qCDebug(KArchiveLog) << "no compression found for" << mimeType;
    +    return KCompressionDevice::None;
    +}
    +
    +KFilterBase *KCompressionDevice::filterForCompressionType(KCompressionDevice::CompressionType type)
    +{
    +    switch (type) {
    +    case KCompressionDevice::GZip:
    +        return new KGzipFilter;
    +    case KCompressionDevice::BZip2:
    +#if HAVE_BZIP2_SUPPORT
    +        return new KBzip2Filter;
    +#else
    +        return nullptr;
    +#endif
    +    case KCompressionDevice::Xz:
    +#if HAVE_XZ_SUPPORT
    +        return new KXzFilter;
    +#else
    +        return nullptr;
    +#endif
    +    case KCompressionDevice::None:
    +        return new KNoneFilter;
    +    case KCompressionDevice::Zstd:
    +#if HAVE_ZSTD_SUPPORT
    +        return new KZstdFilter;
    +#else
    +        return nullptr;
    +#endif
    +    }
    +    return nullptr;
    +}
    +
    +KCompressionDevice::KCompressionDevice(QIODevice *inputDevice, bool autoDeleteInputDevice, CompressionType type)
    +    : d(new KCompressionDevicePrivate(this))
    +{
    +    assert(inputDevice);
    +    d->filter = filterForCompressionType(type);
    +    if (d->filter) {
    +        d->type = type;
    +        d->filter->setDevice(inputDevice, autoDeleteInputDevice);
    +    }
    +}
    +
    +KCompressionDevice::KCompressionDevice(const QString &fileName, CompressionType type)
    +    : d(new KCompressionDevicePrivate(this))
    +{
    +    QFile *f = new QFile(fileName);
    +    d->filter = filterForCompressionType(type);
    +    if (d->filter) {
    +        d->type = type;
    +        d->filter->setDevice(f, true);
    +    } else {
    +        delete f;
    +    }
    +}
    +
    +KCompressionDevice::KCompressionDevice(const QString &fileName)
    +    : KCompressionDevice(fileName, findCompressionByFileName(fileName))
    +{
    +}
    +
    +KCompressionDevice::~KCompressionDevice()
    +{
    +    if (isOpen()) {
    +        close();
    +    }
    +    delete d->filter;
    +    delete d;
    +}
    +
    +KCompressionDevice::CompressionType KCompressionDevice::compressionType() const
    +{
    +    return d->type;
    +}
    +
    +bool KCompressionDevice::open(QIODevice::OpenMode mode)
    +{
    +    if (isOpen()) {
    +        // qCWarning(KArchiveLog) << "KCompressionDevice::open: device is already open";
    +        return true; // QFile returns false, but well, the device -is- open...
    +    }
    +    if (!d->filter) {
    +        return false;
    +    }
    +    d->bOpenedUnderlyingDevice = false;
    +    // qCDebug(KArchiveLog) << mode;
    +    if (mode == QIODevice::ReadOnly) {
    +        d->buffer.resize(0);
    +    } else {
    +        d->buffer.resize(BUFFER_SIZE);
    +        d->filter->setOutBuffer(d->buffer.data(), d->buffer.size());
    +    }
    +    if (!d->filter->device()->isOpen()) {
    +        if (!d->filter->device()->open(mode)) {
    +            // qCWarning(KArchiveLog) << "KCompressionDevice::open: Couldn't open underlying device";
    +            d->propagateErrorCode();
    +            return false;
    +        }
    +        d->bOpenedUnderlyingDevice = true;
    +    }
    +    d->bNeedHeader = !d->bSkipHeaders;
    +    d->filter->setFilterFlags(d->bSkipHeaders ? KFilterBase::NoHeaders : KFilterBase::WithHeaders);
    +    if (!d->filter->init(mode & ~QIODevice::Truncate)) {
    +        return false;
    +    }
    +    d->result = KFilterBase::Ok;
    +    setOpenMode(mode);
    +    return true;
    +}
    +
    +void KCompressionDevice::close()
    +{
    +    if (!isOpen()) {
    +        return;
    +    }
    +    if (d->filter->mode() == QIODevice::WriteOnly && d->errorCode == QFileDevice::NoError) {
    +        write(nullptr, 0); // finish writing
    +    }
    +    // qCDebug(KArchiveLog) << "Calling terminate().";
    +
    +    if (!d->filter->terminate()) {
    +        // qCWarning(KArchiveLog) << "KCompressionDevice::close: terminate returned an error";
    +        d->errorCode = QFileDevice::UnspecifiedError;
    +    }
    +    if (d->bOpenedUnderlyingDevice) {
    +        QIODevice *dev = d->filter->device();
    +        dev->close();
    +        d->propagateErrorCode();
    +    }
    +    setOpenMode(QIODevice::NotOpen);
    +}
    +
    +QFileDevice::FileError KCompressionDevice::error() const
    +{
    +    return d->errorCode;
    +}
    +
    +bool KCompressionDevice::seek(qint64 pos)
    +{
    +    if (d->deviceReadPos == pos) {
    +        return QIODevice::seek(pos);
    +    }
    +
    +    // qCDebug(KArchiveLog) << "seek(" << pos << ") called, current pos=" << QIODevice::pos();
    +
    +    Q_ASSERT(d->filter->mode() == QIODevice::ReadOnly);
    +
    +    if (pos == 0) {
    +        if (!QIODevice::seek(pos)) {
    +            return false;
    +        }
    +
    +        // We can forget about the cached data
    +        d->bNeedHeader = !d->bSkipHeaders;
    +        d->result = KFilterBase::Ok;
    +        d->filter->setInBuffer(nullptr, 0);
    +        d->filter->reset();
    +        d->deviceReadPos = 0;
    +        return d->filter->device()->reset();
    +    }
    +
    +    qint64 bytesToRead;
    +    if (d->deviceReadPos < pos) { // we can start from here
    +        bytesToRead = pos - d->deviceReadPos;
    +        // Since we're going to do a read() below
    +        // we need to reset the internal QIODevice pos to the real position we are
    +        // so that after read() we are indeed pointing to the pos seek
    +        // asked us to be in
    +        if (!QIODevice::seek(d->deviceReadPos)) {
    +            return false;
    +        }
    +    } else {
    +        // we have to start from 0 ! Ugly and slow, but better than the previous
    +        // solution (KTarGz was allocating everything into memory)
    +        if (!seek(0)) { // recursive
    +            return false;
    +        }
    +        bytesToRead = pos;
    +    }
    +
    +    // qCDebug(KArchiveLog) << "reading " << bytesToRead << " dummy bytes";
    +    QByteArray dummy(qMin(bytesToRead, qint64(SEEK_BUFFER_SIZE)), 0);
    +    while (bytesToRead > 0) {
    +        const qint64 bytesToReadThisTime = qMin(bytesToRead, qint64(dummy.size()));
    +        const bool result = (read(dummy.data(), bytesToReadThisTime) == bytesToReadThisTime);
    +        if (!result) {
    +            return false;
    +        }
    +        bytesToRead -= bytesToReadThisTime;
    +    }
    +    return true;
    +}
    +
    +bool KCompressionDevice::atEnd() const
    +{
    +    return (d->type == KCompressionDevice::None || d->result == KFilterBase::End) //
    +        && QIODevice::atEnd() // take QIODevice's internal buffer into account
    +        && d->filter->device()->atEnd();
    +}
    +
    +qint64 KCompressionDevice::readData(char *data, qint64 maxlen)
    +{
    +    Q_ASSERT(d->filter->mode() == QIODevice::ReadOnly);
    +    // qCDebug(KArchiveLog) << "maxlen=" << maxlen;
    +    KFilterBase *filter = d->filter;
    +
    +    uint dataReceived = 0;
    +
    +    // We came to the end of the stream
    +    if (d->result == KFilterBase::End) {
    +        return dataReceived;
    +    }
    +
    +    // If we had an error, return -1.
    +    if (d->result != KFilterBase::Ok) {
    +        return -1;
    +    }
    +
    +    qint64 availOut = maxlen;
    +    filter->setOutBuffer(data, maxlen);
    +
    +    while (dataReceived < maxlen) {
    +        if (filter->inBufferEmpty()) {
    +            // Not sure about the best size to set there.
    +            // For sure, it should be bigger than the header size (see comment in readHeader)
    +            d->buffer.resize(BUFFER_SIZE);
    +            // Request data from underlying device
    +            int size = filter->device()->read(d->buffer.data(), d->buffer.size());
    +            // qCDebug(KArchiveLog) << "got" << size << "bytes from device";
    +            if (size) {
    +                filter->setInBuffer(d->buffer.data(), size);
    +            } else {
    +                // Not enough data available in underlying device for now
    +                break;
    +            }
    +        }
    +        if (d->bNeedHeader) {
    +            (void)filter->readHeader();
    +            d->bNeedHeader = false;
    +        }
    +
    +        d->result = filter->uncompress();
    +
    +        if (d->result == KFilterBase::Error) {
    +            // qCWarning(KArchiveLog) << "KCompressionDevice: Error when uncompressing data";
    +            break;
    +        }
    +
    +        // We got that much data since the last time we went here
    +        uint outReceived = availOut - filter->outBufferAvailable();
    +        // qCDebug(KArchiveLog) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived;
    +        if (availOut < uint(filter->outBufferAvailable())) {
    +            // qCWarning(KArchiveLog) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !";
    +        }
    +
    +        dataReceived += outReceived;
    +        data += outReceived;
    +        availOut = maxlen - dataReceived;
    +        if (d->result == KFilterBase::End) {
    +            // We're actually at the end, no more data to check
    +            if (filter->device()->atEnd()) {
    +                break;
    +            }
    +
    +            // Still not done, re-init and try again
    +            filter->init(filter->mode());
    +        }
    +        filter->setOutBuffer(data, availOut);
    +    }
    +
    +    d->deviceReadPos += dataReceived;
    +    return dataReceived;
    +}
    +
    +qint64 KCompressionDevice::writeData(const char *data /*0 to finish*/, qint64 len)
    +{
    +    KFilterBase *filter = d->filter;
    +    Q_ASSERT(filter->mode() == QIODevice::WriteOnly);
    +    // If we had an error, return 0.
    +    if (d->result != KFilterBase::Ok) {
    +        return 0;
    +    }
    +
    +    bool finish = (data == nullptr);
    +    if (!finish) {
    +        filter->setInBuffer(data, len);
    +        if (d->bNeedHeader) {
    +            (void)filter->writeHeader(d->origFileName);
    +            d->bNeedHeader = false;
    +        }
    +    }
    +
    +    uint dataWritten = 0;
    +    uint availIn = len;
    +    while (dataWritten < len || finish) {
    +        d->result = filter->compress(finish);
    +
    +        if (d->result == KFilterBase::Error) {
    +            // qCWarning(KArchiveLog) << "KCompressionDevice: Error when compressing data";
    +            // What to do ?
    +            break;
    +        }
    +
    +        // Wrote everything ?
    +        if (filter->inBufferEmpty() || (d->result == KFilterBase::End)) {
    +            // We got that much data since the last time we went here
    +            uint wrote = availIn - filter->inBufferAvailable();
    +
    +            // qCDebug(KArchiveLog) << " Wrote everything for now. avail_in=" << filter->inBufferAvailable() << "result=" << d->result << "wrote=" << wrote;
    +
    +            // Move on in the input buffer
    +            data += wrote;
    +            dataWritten += wrote;
    +
    +            availIn = len - dataWritten;
    +            // qCDebug(KArchiveLog) << " availIn=" << availIn << "dataWritten=" << dataWritten << "pos=" << pos();
    +            if (availIn > 0) {
    +                filter->setInBuffer(data, availIn);
    +            }
    +        }
    +
    +        if (filter->outBufferFull() || (d->result == KFilterBase::End) || finish) {
    +            // qCDebug(KArchiveLog) << " writing to underlying. avail_out=" << filter->outBufferAvailable();
    +            int towrite = d->buffer.size() - filter->outBufferAvailable();
    +            if (towrite > 0) {
    +                // Write compressed data to underlying device
    +                int size = filter->device()->write(d->buffer.data(), towrite);
    +                if (size != towrite) {
    +                    // qCWarning(KArchiveLog) << "KCompressionDevice::write. Could only write " << size << " out of " << towrite << " bytes";
    +                    d->errorCode = QFileDevice::WriteError;
    +                    setErrorString(tr("Could not write. Partition full?"));
    +                    return 0; // indicate an error
    +                }
    +                // qCDebug(KArchiveLog) << " wrote " << size << " bytes";
    +            }
    +            if (d->result == KFilterBase::End) {
    +                Q_ASSERT(finish); // hopefully we don't get end before finishing
    +                break;
    +            }
    +            d->buffer.resize(BUFFER_SIZE);
    +            filter->setOutBuffer(d->buffer.data(), d->buffer.size());
    +        }
    +    }
    +
    +    return dataWritten;
    +}
    +
    +void KCompressionDevice::setOrigFileName(const QByteArray &fileName)
    +{
    +    d->origFileName = fileName;
    +}
    +
    +void KCompressionDevice::setSkipHeaders()
    +{
    +    d->bSkipHeaders = true;
    +}
    +
    +KFilterBase *KCompressionDevice::filterBase()
    +{
    +    return d->filter;
    +}
    +
    +#include "moc_kcompressiondevice.cpp"
    diff --git a/src/libs/3rdparty/karchive/src/kcompressiondevice.h b/src/libs/3rdparty/karchive/src/kcompressiondevice.h
    new file mode 100644
    index 00000000000..218f2d51234
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kcompressiondevice.h
    @@ -0,0 +1,146 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000 David Faure 
    +   SPDX-FileCopyrightText: 2011 Mario Bensi 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef __kcompressiondevice_h
    +#define __kcompressiondevice_h
    +
    +#include "karchive_export.h"
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +class KCompressionDevicePrivate;
    +
    +class KFilterBase;
    +
    +/**
    + * @class KCompressionDevice kcompressiondevice.h KCompressionDevice
    + *
    + * A class for reading and writing compressed data onto a device
    + * (e.g. file, but other usages are possible, like a buffer or a socket).
    + *
    + * Use this class to read/write compressed files.
    + */
    +
    +class KARCHIVE_EXPORT KCompressionDevice : public QIODevice // KF6 TODO: consider inheriting from QFileDevice, so apps can use error() generically ?
    +{
    +    Q_OBJECT
    +public:
    +    enum CompressionType {
    +        GZip,
    +        BZip2,
    +        Xz,
    +        None,
    +        Zstd, ///< @since 5.82
    +    };
    +
    +    /**
    +     * Constructs a KCompressionDevice for a given CompressionType (e.g. GZip, BZip2 etc.).
    +     * @param inputDevice input device.
    +     * @param autoDeleteInputDevice if true, @p inputDevice will be deleted automatically
    +     * @param type the CompressionType to use.
    +     */
    +    KCompressionDevice(QIODevice *inputDevice, bool autoDeleteInputDevice, CompressionType type);
    +
    +    /**
    +     * Constructs a KCompressionDevice for a given CompressionType (e.g. GZip, BZip2 etc.).
    +     * @param fileName the name of the file to filter.
    +     * @param type the CompressionType to use.
    +     */
    +    KCompressionDevice(const QString &fileName, CompressionType type);
    +
    +    /**
    +     * Constructs a KCompressionDevice for a given @p fileName.
    +     * @param fileName the name of the file to filter.
    +     * @since 5.85
    +     */
    +    explicit KCompressionDevice(const QString &fileName);
    +
    +    /**
    +     * Destructs the KCompressionDevice.
    +     * Calls close() if the filter device is still open.
    +     */
    +    ~KCompressionDevice() override;
    +
    +    /**
    +     * The compression actually used by this device.
    +     * If the support for the compression requested in the constructor
    +     * is not available, then the device will use None.
    +     */
    +    CompressionType compressionType() const;
    +
    +    /**
    +     * Open for reading or writing.
    +     */
    +    bool open(QIODevice::OpenMode mode) override;
    +
    +    /**
    +     * Close after reading or writing.
    +     */
    +    void close() override;
    +
    +    /**
    +     * For writing gzip compressed files only:
    +     * set the name of the original file, to be used in the gzip header.
    +     * @param fileName the name of the original file
    +     */
    +    void setOrigFileName(const QByteArray &fileName);
    +
    +    /**
    +     * Call this let this device skip the gzip headers when reading/writing.
    +     * This way KCompressionDevice (with gzip filter) can be used as a direct wrapper
    +     * around zlib - this is used by KZip.
    +     */
    +    void setSkipHeaders();
    +
    +    /**
    +     * That one can be quite slow, when going back. Use with care.
    +     */
    +    bool seek(qint64) override;
    +
    +    bool atEnd() const override;
    +
    +    /**
    +     * Call this to create the appropriate filter for the CompressionType
    +     * named @p type.
    +     * @param type the type of the compression filter
    +     * @return the filter for the @p type, or 0 if not found
    +     */
    +    static KFilterBase *filterForCompressionType(CompressionType type);
    +
    +    /**
    +     * Returns the compression type for the given MIME type, if possible. Otherwise returns None.
    +     * This handles simple cases like application/gzip, but also application/x-compressed-tar, and inheritance.
    +     * @since 5.85
    +     */
    +    static CompressionType compressionTypeForMimeType(const QString &mimetype);
    +
    +    /**
    +     * Returns the error code from the last failing operation.
    +     * This is especially useful after calling close(), which unfortunately returns void
    +     * (see https://bugreports.qt.io/browse/QTBUG-70033), to see if the flushing done by close
    +     * was able to write all the data to disk.
    +     */
    +    QFileDevice::FileError error() const;
    +
    +protected:
    +    friend class K7Zip;
    +
    +    qint64 readData(char *data, qint64 maxlen) override;
    +    qint64 writeData(const char *data, qint64 len) override;
    +
    +    KFilterBase *filterBase();
    +
    +private:
    +    friend KCompressionDevicePrivate;
    +    KCompressionDevicePrivate *const d;
    +};
    +
    +Q_DECLARE_METATYPE(KCompressionDevice::CompressionType)
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kcompressiondevice_p.h b/src/libs/3rdparty/karchive/src/kcompressiondevice_p.h
    new file mode 100644
    index 00000000000..dda5f98276e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kcompressiondevice_p.h
    @@ -0,0 +1,13 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000 David Faure 
    +   SPDX-FileCopyrightText: 2011 Mario Bensi 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef __kcompressiondevice_p_h
    +#define __kcompressiondevice_p_h
    +
    +#define BUFFER_SIZE 8 * 1024
    +#define SEEK_BUFFER_SIZE 3 * BUFFER_SIZE
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kfilterbase.cpp b/src/libs/3rdparty/karchive/src/kfilterbase.cpp
    new file mode 100644
    index 00000000000..dc7bea840e7
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kfilterbase.cpp
    @@ -0,0 +1,81 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "kfilterbase.h"
    +
    +#include 
    +
    +class KFilterBasePrivate
    +{
    +public:
    +    KFilterBasePrivate()
    +        : m_flags(KFilterBase::WithHeaders)
    +        , m_dev(nullptr)
    +        , m_bAutoDel(false)
    +    {
    +    }
    +    KFilterBase::FilterFlags m_flags;
    +    QIODevice *m_dev;
    +    bool m_bAutoDel;
    +};
    +
    +KFilterBase::KFilterBase()
    +    : d(new KFilterBasePrivate)
    +{
    +}
    +
    +KFilterBase::~KFilterBase()
    +{
    +    if (d->m_bAutoDel) {
    +        delete d->m_dev;
    +    }
    +    delete d;
    +}
    +
    +void KFilterBase::setDevice(QIODevice *dev, bool autodelete)
    +{
    +    d->m_dev = dev;
    +    d->m_bAutoDel = autodelete;
    +}
    +
    +QIODevice *KFilterBase::device()
    +{
    +    return d->m_dev;
    +}
    +
    +bool KFilterBase::inBufferEmpty() const
    +{
    +    return inBufferAvailable() == 0;
    +}
    +
    +bool KFilterBase::outBufferFull() const
    +{
    +    return outBufferAvailable() == 0;
    +}
    +
    +bool KFilterBase::terminate()
    +{
    +    return true;
    +}
    +
    +void KFilterBase::reset()
    +{
    +}
    +
    +void KFilterBase::setFilterFlags(FilterFlags flags)
    +{
    +    d->m_flags = flags;
    +}
    +
    +KFilterBase::FilterFlags KFilterBase::filterFlags() const
    +{
    +    return d->m_flags;
    +}
    +
    +void KFilterBase::virtual_hook(int, void *)
    +{
    +    /*BASE::virtual_hook( id, data );*/
    +}
    diff --git a/src/libs/3rdparty/karchive/src/kfilterbase.h b/src/libs/3rdparty/karchive/src/kfilterbase.h
    new file mode 100644
    index 00000000000..bf0e7883700
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kfilterbase.h
    @@ -0,0 +1,109 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#ifndef __kfilterbase__h
    +#define __kfilterbase__h
    +
    +#include "karchive_export.h"
    +
    +#include 
    +#include 
    +class KFilterBasePrivate;
    +
    +class QIODevice;
    +
    +/**
    + * @class KFilterBase kfilterbase.h KFilterBase
    + *
    + * This is the base class for compression filters
    + * such as gzip and bzip2. It's pretty much internal.
    + * Don't use directly, use KCompressionDevice instead.
    + * @internal
    + */
    +class KARCHIVE_EXPORT KFilterBase
    +{
    +public:
    +    KFilterBase();
    +    virtual ~KFilterBase();
    +
    +    /**
    +     * Sets the device on which the filter will work
    +     * @param dev the device on which the filter will work
    +     * @param autodelete if true, @p dev is deleted when the filter is deleted
    +     */
    +    void setDevice(QIODevice *dev, bool autodelete = false);
    +    // Note that this isn't in the constructor, because of KLibFactory::create,
    +    // but it should be called before using the filterbase !
    +
    +    /**
    +     * Returns the device on which the filter will work.
    +     * @returns the device on which the filter will work
    +     */
    +    QIODevice *device();
    +    /** \internal */
    +    virtual bool init(int mode) = 0;
    +    /** \internal */
    +    virtual int mode() const = 0;
    +    /** \internal */
    +    virtual bool terminate();
    +    /** \internal */
    +    virtual void reset();
    +    /** \internal */
    +    virtual bool readHeader() = 0;
    +    /** \internal */
    +    virtual bool writeHeader(const QByteArray &filename) = 0;
    +    /** \internal */
    +    virtual void setOutBuffer(char *data, uint maxlen) = 0;
    +    /** \internal */
    +    virtual void setInBuffer(const char *data, uint size) = 0;
    +    /** \internal */
    +    virtual bool inBufferEmpty() const;
    +    /** \internal */
    +    virtual int inBufferAvailable() const = 0;
    +    /** \internal */
    +    virtual bool outBufferFull() const;
    +    /** \internal */
    +    virtual int outBufferAvailable() const = 0;
    +
    +    /** \internal */
    +    enum Result {
    +        Ok,
    +        End,
    +        Error,
    +    };
    +    /** \internal */
    +    virtual Result uncompress() = 0;
    +    /** \internal */
    +    virtual Result compress(bool finish) = 0;
    +
    +    /**
    +     * \internal
    +     * \since 4.3
    +     */
    +    enum FilterFlags {
    +        NoHeaders = 0,
    +        WithHeaders = 1,
    +        ZlibHeaders = 2, // only use for gzip compression
    +    };
    +    /**
    +     * \internal
    +     * \since 4.3
    +     */
    +    void setFilterFlags(FilterFlags flags);
    +    FilterFlags filterFlags() const;
    +
    +protected:
    +    /** Virtual hook, used to add new "virtual" functions while maintaining
    +        binary compatibility. Unused in this class.
    +    */
    +    virtual void virtual_hook(int id, void *data);
    +
    +private:
    +    Q_DISABLE_COPY(KFilterBase)
    +    KFilterBasePrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kgzipfilter.cpp b/src/libs/3rdparty/karchive/src/kgzipfilter.cpp
    new file mode 100644
    index 00000000000..c7623f7ba57
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kgzipfilter.cpp
    @@ -0,0 +1,366 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "kgzipfilter.h"
    +#include "loggingcategory.h"
    +
    +#include 
    +#include 
    +
    +#include 
    +#include 
    +
    +/* gzip flag byte */
    +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
    +
    +// #define DEBUG_GZIP
    +
    +class Q_DECL_HIDDEN KGzipFilter::Private
    +{
    +public:
    +    Private()
    +        : headerWritten(false)
    +        , footerWritten(false)
    +        , compressed(false)
    +        , mode(0)
    +        , crc(0)
    +        , isInitialized(false)
    +    {
    +        zStream.zalloc = static_cast(nullptr);
    +        zStream.zfree = static_cast(nullptr);
    +        zStream.opaque = static_cast(nullptr);
    +    }
    +
    +    z_stream zStream;
    +    bool headerWritten;
    +    bool footerWritten;
    +    bool compressed;
    +    int mode;
    +    ulong crc;
    +    bool isInitialized;
    +};
    +
    +KGzipFilter::KGzipFilter()
    +    : d(new Private)
    +{
    +}
    +
    +KGzipFilter::~KGzipFilter()
    +{
    +    delete d;
    +}
    +
    +bool KGzipFilter::init(int mode)
    +{
    +    switch (filterFlags()) {
    +    case NoHeaders:
    +        return init(mode, RawDeflate);
    +    case WithHeaders:
    +        return init(mode, GZipHeader);
    +    case ZlibHeaders:
    +        return init(mode, ZlibHeader);
    +    }
    +    return false;
    +}
    +
    +bool KGzipFilter::init(int mode, Flag flag)
    +{
    +    if (d->isInitialized) {
    +        terminate();
    +    }
    +    d->zStream.next_in = Z_NULL;
    +    d->zStream.avail_in = 0;
    +    if (mode == QIODevice::ReadOnly) {
    +        const int windowBits = (flag == RawDeflate) ? -MAX_WBITS /*no zlib header*/
    +            : (flag == GZipHeader)                  ? MAX_WBITS + 32 /* auto-detect and eat gzip header */
    +                                                    : MAX_WBITS /*zlib header*/;
    +        const int result = inflateInit2(&d->zStream, windowBits);
    +        if (result != Z_OK) {
    +            // qCDebug(KArchiveLog) << "inflateInit2 returned " << result;
    +            return false;
    +        }
    +    } else if (mode == QIODevice::WriteOnly) {
    +        int result = deflateInit2(&d->zStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); // same here
    +        if (result != Z_OK) {
    +            // qCDebug(KArchiveLog) << "deflateInit returned " << result;
    +            return false;
    +        }
    +    } else {
    +        // qCWarning(KArchiveLog) << "KGzipFilter: Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
    +        return false;
    +    }
    +    d->mode = mode;
    +    d->compressed = true;
    +    d->headerWritten = false;
    +    d->footerWritten = false;
    +    d->isInitialized = true;
    +    return true;
    +}
    +
    +int KGzipFilter::mode() const
    +{
    +    return d->mode;
    +}
    +
    +bool KGzipFilter::terminate()
    +{
    +    if (d->mode == QIODevice::ReadOnly) {
    +        int result = inflateEnd(&d->zStream);
    +        if (result != Z_OK) {
    +            // qCDebug(KArchiveLog) << "inflateEnd returned " << result;
    +            return false;
    +        }
    +    } else if (d->mode == QIODevice::WriteOnly) {
    +        int result = deflateEnd(&d->zStream);
    +        if (result != Z_OK) {
    +            // qCDebug(KArchiveLog) << "deflateEnd returned " << result;
    +            return false;
    +        }
    +    }
    +    d->isInitialized = false;
    +    return true;
    +}
    +
    +void KGzipFilter::reset()
    +{
    +    if (d->mode == QIODevice::ReadOnly) {
    +        int result = inflateReset(&d->zStream);
    +        if (result != Z_OK) {
    +            // qCDebug(KArchiveLog) << "inflateReset returned " << result;
    +            // TODO return false
    +        }
    +    } else if (d->mode == QIODevice::WriteOnly) {
    +        int result = deflateReset(&d->zStream);
    +        if (result != Z_OK) {
    +            // qCDebug(KArchiveLog) << "deflateReset returned " << result;
    +            // TODO return false
    +        }
    +        d->headerWritten = false;
    +        d->footerWritten = false;
    +    }
    +}
    +
    +bool KGzipFilter::readHeader()
    +{
    +    // We now rely on zlib to read the full header (see the MAX_WBITS + 32 in init).
    +    // We just use this method to check if the data is actually compressed.
    +
    +#ifdef DEBUG_GZIP
    +    qCDebug(KArchiveLog) << "avail=" << d->zStream.avail_in;
    +#endif
    +    // Assume not compressed until we see a gzip header
    +    d->compressed = false;
    +    const Bytef *p = d->zStream.next_in;
    +    int i = d->zStream.avail_in;
    +    if ((i -= 10) < 0) {
    +        return false; // Need at least 10 bytes
    +    }
    +#ifdef DEBUG_GZIP
    +    qCDebug(KArchiveLog) << "first byte is " << QString::number(*p, 16);
    +#endif
    +    if (*p++ != 0x1f) {
    +        return false; // GZip magic
    +    }
    +#ifdef DEBUG_GZIP
    +    qCDebug(KArchiveLog) << "second byte is " << QString::number(*p, 16);
    +#endif
    +    if (*p++ != 0x8b) {
    +        return false;
    +    }
    +
    +    d->compressed = true;
    +#ifdef DEBUG_GZIP
    +    qCDebug(KArchiveLog) << "header OK";
    +#endif
    +    return true;
    +}
    +
    +/* Output a 16 bit value, lsb first */
    +#define put_short(w)                                                                                                                                           \
    +    *p++ = uchar((w)&0xff);                                                                                                                                    \
    +    *p++ = uchar(ushort(w) >> 8);
    +
    +/* Output a 32 bit value to the bit stream, lsb first */
    +#define put_long(n)                                                                                                                                            \
    +    put_short((n)&0xffff);                                                                                                                                     \
    +    put_short((ulong(n)) >> 16);
    +
    +bool KGzipFilter::writeHeader(const QByteArray &fileName)
    +{
    +    Bytef *p = d->zStream.next_out;
    +    int i = d->zStream.avail_out;
    +    *p++ = 0x1f;
    +    *p++ = 0x8b;
    +    *p++ = Z_DEFLATED;
    +    *p++ = ORIG_NAME;
    +    put_long(time(nullptr)); // Modification time (in unix format)
    +    *p++ = 0; // Extra flags (2=max compress, 4=fastest compress)
    +    *p++ = 3; // Unix
    +
    +    uint len = fileName.length();
    +    for (uint j = 0; j < len; ++j) {
    +        *p++ = fileName[j];
    +    }
    +    *p++ = 0;
    +    int headerSize = p - d->zStream.next_out;
    +    i -= headerSize;
    +    Q_ASSERT(i > 0);
    +    d->crc = crc32(0L, nullptr, 0);
    +    d->zStream.next_out = p;
    +    d->zStream.avail_out = i;
    +    d->headerWritten = true;
    +    return true;
    +}
    +
    +void KGzipFilter::writeFooter()
    +{
    +    Q_ASSERT(d->headerWritten);
    +    Q_ASSERT(!d->footerWritten);
    +    Bytef *p = d->zStream.next_out;
    +    int i = d->zStream.avail_out;
    +    // qCDebug(KArchiveLog) << "avail_out=" << i << "writing CRC=" << QString::number(d->crc, 16) << "at p=" << p;
    +    put_long(d->crc);
    +    // qCDebug(KArchiveLog) << "writing totalin=" << d->zStream.total_in << "at p=" << p;
    +    put_long(d->zStream.total_in);
    +    i -= p - d->zStream.next_out;
    +    d->zStream.next_out = p;
    +    d->zStream.avail_out = i;
    +    d->footerWritten = true;
    +}
    +
    +void KGzipFilter::setOutBuffer(char *data, uint maxlen)
    +{
    +    d->zStream.avail_out = maxlen;
    +    d->zStream.next_out = reinterpret_cast(data);
    +}
    +void KGzipFilter::setInBuffer(const char *data, uint size)
    +{
    +#ifdef DEBUG_GZIP
    +    qCDebug(KArchiveLog) << "avail_in=" << size;
    +#endif
    +    d->zStream.avail_in = size;
    +    d->zStream.next_in = reinterpret_cast(const_cast(data));
    +}
    +int KGzipFilter::inBufferAvailable() const
    +{
    +    return d->zStream.avail_in;
    +}
    +int KGzipFilter::outBufferAvailable() const
    +{
    +    return d->zStream.avail_out;
    +}
    +
    +KGzipFilter::Result KGzipFilter::uncompress_noop()
    +{
    +    // I'm not sure that we really need support for that (uncompressed streams),
    +    // but why not, it can't hurt to have it. One case I can think of is someone
    +    // naming a tar file "blah.tar.gz" :-)
    +    if (d->zStream.avail_in > 0) {
    +        int n = (d->zStream.avail_in < d->zStream.avail_out) ? d->zStream.avail_in : d->zStream.avail_out;
    +        memcpy(d->zStream.next_out, d->zStream.next_in, n);
    +        d->zStream.avail_out -= n;
    +        d->zStream.next_in += n;
    +        d->zStream.avail_in -= n;
    +        return KFilterBase::Ok;
    +    } else {
    +        return KFilterBase::End;
    +    }
    +}
    +
    +KGzipFilter::Result KGzipFilter::uncompress()
    +{
    +#ifndef NDEBUG
    +    if (d->mode == 0) {
    +        // qCWarning(KArchiveLog) << "mode==0; KGzipFilter::init was not called!";
    +        return KFilterBase::Error;
    +    } else if (d->mode == QIODevice::WriteOnly) {
    +        // qCWarning(KArchiveLog) << "uncompress called but the filter was opened for writing!";
    +        return KFilterBase::Error;
    +    }
    +    Q_ASSERT(d->mode == QIODevice::ReadOnly);
    +#endif
    +
    +    if (!d->compressed) {
    +        return uncompress_noop();
    +    }
    +
    +#ifdef DEBUG_GZIP
    +    qCDebug(KArchiveLog) << "Calling inflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
    +    qCDebug(KArchiveLog) << "    next_in=" << d->zStream.next_in;
    +#endif
    +
    +    while (d->zStream.avail_in > 0) {
    +        int result = inflate(&d->zStream, Z_SYNC_FLUSH);
    +
    +#ifdef DEBUG_GZIP
    +        qCDebug(KArchiveLog) << " -> inflate returned " << result;
    +        qCDebug(KArchiveLog) << " now avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
    +        qCDebug(KArchiveLog) << "     next_in=" << d->zStream.next_in;
    +#endif
    +
    +        if (result == Z_OK) {
    +            return KFilterBase::Ok;
    +        }
    +
    +        // We can't handle any other results
    +        if (result != Z_STREAM_END) {
    +            return KFilterBase::Error;
    +        }
    +
    +        // It really was the end
    +        if (d->zStream.avail_in == 0) {
    +            return KFilterBase::End;
    +        }
    +
    +        // Store before resetting
    +        Bytef *data = d->zStream.next_in; // This is increased appropriately by zlib beforehand
    +        uInt size = d->zStream.avail_in;
    +
    +        // Reset the stream, if that fails we assume we're at the end
    +        if (!init(d->mode)) {
    +            return KFilterBase::End;
    +        }
    +
    +        // Reset the data to where we left off
    +        d->zStream.next_in = data;
    +        d->zStream.avail_in = size;
    +    }
    +
    +    return KFilterBase::End;
    +}
    +
    +KGzipFilter::Result KGzipFilter::compress(bool finish)
    +{
    +    Q_ASSERT(d->compressed);
    +    Q_ASSERT(d->mode == QIODevice::WriteOnly);
    +
    +    const Bytef *p = d->zStream.next_in;
    +    ulong len = d->zStream.avail_in;
    +#ifdef DEBUG_GZIP
    +    qCDebug(KArchiveLog) << "  calling deflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
    +#endif
    +    const int result = deflate(&d->zStream, finish ? Z_FINISH : Z_NO_FLUSH);
    +    if (result != Z_OK && result != Z_STREAM_END) {
    +        // qCDebug(KArchiveLog) << "  deflate returned " << result;
    +    }
    +    if (d->headerWritten) {
    +        // qCDebug(KArchiveLog) << "Computing CRC for the next " << len - d->zStream.avail_in << " bytes";
    +        d->crc = crc32(d->crc, p, len - d->zStream.avail_in);
    +    }
    +    KGzipFilter::Result callerResult = result == Z_OK ? KFilterBase::Ok : (Z_STREAM_END ? KFilterBase::End : KFilterBase::Error);
    +
    +    if (result == Z_STREAM_END && d->headerWritten && !d->footerWritten) {
    +        if (d->zStream.avail_out >= 8 /*footer size*/) {
    +            // qCDebug(KArchiveLog) << "finished, write footer";
    +            writeFooter();
    +        } else {
    +            // No room to write the footer (#157706/#188415), we'll have to do it on the next pass.
    +            // qCDebug(KArchiveLog) << "finished, but no room for footer yet";
    +            callerResult = KFilterBase::Ok;
    +        }
    +    }
    +    return callerResult;
    +}
    diff --git a/src/libs/3rdparty/karchive/src/kgzipfilter.h b/src/libs/3rdparty/karchive/src/kgzipfilter.h
    new file mode 100644
    index 00000000000..05e84d86f53
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kgzipfilter.h
    @@ -0,0 +1,59 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000, 2009 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#ifndef __kgzipfilter__h
    +#define __kgzipfilter__h
    +
    +#include "kfilterbase.h"
    +
    +/**
    + * Internal class used by KCompressionDevice
    + *
    + * This header is not installed.
    + *
    + * @internal
    + */
    +class KGzipFilter : public KFilterBase
    +{
    +public:
    +    KGzipFilter();
    +    ~KGzipFilter() override;
    +
    +    bool init(int mode) override;
    +
    +    // The top of zlib.h explains it: there are three cases.
    +    // - Raw deflate, no header (e.g. inside a ZIP file)
    +    // - Thin zlib header (1) (which is normally what HTTP calls "deflate" (2))
    +    // - Gzip header, implemented here by readHeader
    +    //
    +    // (1) as written out by compress()/compress2()
    +    // (2) see https://www.zlib.net/zlib_faq.html#faq39
    +    enum Flag {
    +        RawDeflate = 0, // raw deflate data
    +        ZlibHeader = 1, // zlib headers (HTTP deflate)
    +        GZipHeader = 2,
    +    };
    +    bool init(int mode, Flag flag); // for direct users of KGzipFilter
    +    int mode() const override;
    +    bool terminate() override;
    +    void reset() override;
    +    bool readHeader() override; // this is about the GZIP header
    +    bool writeHeader(const QByteArray &fileName) override;
    +    void writeFooter();
    +    void setOutBuffer(char *data, uint maxlen) override;
    +    void setInBuffer(const char *data, uint size) override;
    +    int inBufferAvailable() const override;
    +    int outBufferAvailable() const override;
    +    Result uncompress() override;
    +    Result compress(bool finish) override;
    +
    +private:
    +    Result uncompress_noop();
    +    class Private;
    +    Private *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/klimitediodevice.cpp b/src/libs/3rdparty/karchive/src/klimitediodevice.cpp
    new file mode 100644
    index 00000000000..d8b35b0257a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/klimitediodevice.cpp
    @@ -0,0 +1,73 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2001, 2002, 2007 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "klimitediodevice_p.h"
    +#include "loggingcategory.h"
    +
    +KLimitedIODevice::KLimitedIODevice(QIODevice *dev, qint64 start, qint64 length)
    +    : m_dev(dev)
    +    , m_start(start)
    +    , m_length(length)
    +{
    +    // qCDebug(KArchiveLog) << "start=" << start << "length=" << length;
    +    open(QIODevice::ReadOnly); // krazy:exclude=syscalls
    +}
    +
    +bool KLimitedIODevice::open(QIODevice::OpenMode m)
    +{
    +    // qCDebug(KArchiveLog) << "m=" << m;
    +    if (m & QIODevice::ReadOnly) {
    +        /*bool ok = false;
    +          if ( m_dev->isOpen() )
    +          ok = ( m_dev->mode() == QIODevice::ReadOnly );
    +          else
    +          ok = m_dev->open( m );
    +          if ( ok )*/
    +        m_dev->seek(m_start); // No concurrent access !
    +    } else {
    +        // qCWarning(KArchiveLog) << "KLimitedIODevice::open only supports QIODevice::ReadOnly!";
    +    }
    +    setOpenMode(QIODevice::ReadOnly);
    +    return true;
    +}
    +
    +void KLimitedIODevice::close()
    +{
    +}
    +
    +qint64 KLimitedIODevice::size() const
    +{
    +    return m_length;
    +}
    +
    +qint64 KLimitedIODevice::readData(char *data, qint64 maxlen)
    +{
    +    maxlen = qMin(maxlen, m_length - pos()); // Apply upper limit
    +    return m_dev->read(data, maxlen);
    +}
    +
    +bool KLimitedIODevice::seek(qint64 pos)
    +{
    +    Q_ASSERT(pos <= m_length);
    +    pos = qMin(pos, m_length); // Apply upper limit
    +    bool ret = m_dev->seek(m_start + pos);
    +    if (ret) {
    +        QIODevice::seek(pos);
    +    }
    +    return ret;
    +}
    +
    +qint64 KLimitedIODevice::bytesAvailable() const
    +{
    +    return QIODevice::bytesAvailable();
    +}
    +
    +bool KLimitedIODevice::isSequential() const
    +{
    +    return m_dev->isSequential();
    +}
    +
    +#include "moc_klimitediodevice_p.cpp"
    diff --git a/src/libs/3rdparty/karchive/src/klimitediodevice_p.h b/src/libs/3rdparty/karchive/src/klimitediodevice_p.h
    new file mode 100644
    index 00000000000..ca5db975d36
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/klimitediodevice_p.h
    @@ -0,0 +1,58 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2001, 2002, 2007 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#ifndef klimitediodevice_p_h
    +#define klimitediodevice_p_h
    +
    +#include 
    +#include 
    +/**
    + * A readonly device that reads from an underlying device
    + * from a given point to another (e.g. to give access to a single
    + * file inside an archive).
    + * @author David Faure 
    + * @internal - used by KArchive
    + */
    +class KLimitedIODevice : public QIODevice
    +{
    +    Q_OBJECT
    +public:
    +    /**
    +     * Creates a new KLimitedIODevice.
    +     * @param dev the underlying device, opened or not
    +     * This device itself auto-opens (in readonly mode), no need to open it.
    +     * @param start where to start reading (position in bytes)
    +     * @param length the length of the data to read (in bytes)
    +     */
    +    KLimitedIODevice(QIODevice *dev, qint64 start, qint64 length);
    +    ~KLimitedIODevice() override
    +    {
    +    }
    +
    +    bool isSequential() const override;
    +
    +    bool open(QIODevice::OpenMode m) override;
    +    void close() override;
    +
    +    qint64 size() const override;
    +
    +    qint64 readData(char *data, qint64 maxlen) override;
    +    qint64 writeData(const char *, qint64) override
    +    {
    +        return -1; // unsupported
    +    }
    +
    +    // virtual qint64 pos() const { return m_dev->pos() - m_start; }
    +    bool seek(qint64 pos) override;
    +    qint64 bytesAvailable() const override;
    +
    +private:
    +    QIODevice *m_dev;
    +    qint64 m_start;
    +    qint64 m_length;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/knonefilter.cpp b/src/libs/3rdparty/karchive/src/knonefilter.cpp
    new file mode 100644
    index 00000000000..b0fd8328dfc
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/knonefilter.cpp
    @@ -0,0 +1,127 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2011 Mario Bensi 
    +
    +   Based on kbzip2filter:
    +   SPDX-FileCopyrightText: 2000, 2009 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "knonefilter.h"
    +
    +#include 
    +
    +class Q_DECL_HIDDEN KNoneFilter::Private
    +{
    +public:
    +    Private()
    +        : mode(0)
    +        , avail_out(0)
    +        , avail_in(0)
    +        , next_in(nullptr)
    +        , next_out(nullptr)
    +    {
    +    }
    +
    +    int mode;
    +    int avail_out;
    +    int avail_in;
    +    const char *next_in;
    +    char *next_out;
    +};
    +
    +KNoneFilter::KNoneFilter()
    +    : d(new Private)
    +{
    +}
    +
    +KNoneFilter::~KNoneFilter()
    +{
    +    delete d;
    +}
    +
    +bool KNoneFilter::init(int mode)
    +{
    +    d->mode = mode;
    +    return true;
    +}
    +
    +int KNoneFilter::mode() const
    +{
    +    return d->mode;
    +}
    +
    +bool KNoneFilter::terminate()
    +{
    +    return true;
    +}
    +
    +void KNoneFilter::reset()
    +{
    +}
    +
    +bool KNoneFilter::readHeader()
    +{
    +    return true;
    +}
    +
    +bool KNoneFilter::writeHeader(const QByteArray & /*fileName*/)
    +{
    +    return true;
    +}
    +
    +void KNoneFilter::setOutBuffer(char *data, uint maxlen)
    +{
    +    d->avail_out = maxlen;
    +    d->next_out = data;
    +}
    +
    +void KNoneFilter::setInBuffer(const char *data, uint size)
    +{
    +    d->next_in = data;
    +    d->avail_in = size;
    +}
    +
    +int KNoneFilter::inBufferAvailable() const
    +{
    +    return d->avail_in;
    +}
    +
    +int KNoneFilter::outBufferAvailable() const
    +{
    +    return d->avail_out;
    +}
    +
    +KNoneFilter::Result KNoneFilter::uncompress()
    +{
    +#ifndef NDEBUG
    +    if (d->mode != QIODevice::ReadOnly) {
    +        return KFilterBase::Error;
    +    }
    +#endif
    +    return copyData();
    +}
    +
    +KNoneFilter::Result KNoneFilter::compress(bool finish)
    +{
    +    Q_ASSERT(d->mode == QIODevice::WriteOnly);
    +    Q_UNUSED(finish);
    +
    +    return copyData();
    +}
    +
    +KNoneFilter::Result KNoneFilter::copyData()
    +{
    +    Q_ASSERT(d->avail_out > 0);
    +    if (d->avail_in > 0) {
    +        const int n = qMin(d->avail_in, d->avail_out);
    +        memcpy(d->next_out, d->next_in, n);
    +        d->avail_out -= n;
    +        d->next_in += n;
    +        d->next_out += n;
    +        d->avail_in -= n;
    +        return KFilterBase::Ok;
    +    } else {
    +        return KFilterBase::End;
    +    }
    +}
    diff --git a/src/libs/3rdparty/karchive/src/knonefilter.h b/src/libs/3rdparty/karchive/src/knonefilter.h
    new file mode 100644
    index 00000000000..ce3da48ca95
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/knonefilter.h
    @@ -0,0 +1,48 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2011 Mario Bensi 
    +
    +   Based on kbzip2filter:
    +   SPDX-FileCopyrightText: 2000, 2009 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#ifndef __knonefilter__h
    +#define __knonefilter__h
    +
    +#include "kfilterbase.h"
    +
    +/**
    + * Internal class used by KCompressionDevice
    + *
    + * This header is not installed.
    + *
    + * @internal
    + */
    +class KNoneFilter : public KFilterBase
    +{
    +public:
    +    KNoneFilter();
    +    ~KNoneFilter() override;
    +
    +    bool init(int mode) override;
    +    int mode() const override;
    +    bool terminate() override;
    +    void reset() override;
    +    bool readHeader() override; // this is about the GZIP header
    +    bool writeHeader(const QByteArray &fileName) override;
    +    void setOutBuffer(char *data, uint maxlen) override;
    +    void setInBuffer(const char *data, uint size) override;
    +    int inBufferAvailable() const override;
    +    int outBufferAvailable() const override;
    +    Result uncompress() override;
    +    Result compress(bool finish) override;
    +
    +private:
    +    Result copyData();
    +
    +    class Private;
    +    Private *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/krcc.cpp b/src/libs/3rdparty/karchive/src/krcc.cpp
    new file mode 100644
    index 00000000000..e5eef4508a5
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/krcc.cpp
    @@ -0,0 +1,162 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2014 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "krcc.h"
    +#include "karchive_p.h"
    +#include "loggingcategory.h"
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +class Q_DECL_HIDDEN KRcc::KRccPrivate
    +{
    +public:
    +    KRccPrivate()
    +    {
    +    }
    +    void createEntries(const QDir &dir, KArchiveDirectory *parentDir, KRcc *q);
    +
    +    QString m_prefix; // '/' + uuid
    +};
    +
    +/**
    + * A KRccFileEntry represents a file in a rcc archive.
    + */
    +class KRccFileEntry : public KArchiveFile
    +{
    +public:
    +    KRccFileEntry(KArchive *archive,
    +                  const QString &name,
    +                  int access,
    +                  const QDateTime &date,
    +                  const QString &user,
    +                  const QString &group,
    +                  qint64 size,
    +                  const QString &resourcePath)
    +        : KArchiveFile(archive, name, access, date, user, group, QString(), 0, size)
    +        , m_resourcePath(resourcePath)
    +    {
    +    }
    +
    +    QByteArray data() const override
    +    {
    +        QFile f(m_resourcePath);
    +        if (f.open(QIODevice::ReadOnly)) {
    +            return f.readAll();
    +        }
    +        qCWarning(KArchiveLog) << "Couldn't open" << m_resourcePath;
    +        return QByteArray();
    +    }
    +    QIODevice *createDevice() const override
    +    {
    +        return new QFile(m_resourcePath);
    +    }
    +
    +private:
    +    QString m_resourcePath;
    +};
    +
    +KRcc::KRcc(const QString &filename)
    +    : KArchive(filename)
    +    , d(new KRccPrivate)
    +{
    +}
    +
    +KRcc::~KRcc()
    +{
    +    if (isOpen()) {
    +        close();
    +    }
    +    delete d;
    +}
    +
    +bool KRcc::doPrepareWriting(const QString &, const QString &, const QString &, qint64, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
    +{
    +    setErrorString(tr("Cannot write to RCC file"));
    +    qCWarning(KArchiveLog) << "doPrepareWriting not implemented for KRcc";
    +    return false;
    +}
    +
    +bool KRcc::doFinishWriting(qint64)
    +{
    +    setErrorString(tr("Cannot write to RCC file"));
    +    qCWarning(KArchiveLog) << "doFinishWriting not implemented for KRcc";
    +    return false;
    +}
    +
    +bool KRcc::doWriteDir(const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
    +{
    +    setErrorString(tr("Cannot write to RCC file"));
    +    qCWarning(KArchiveLog) << "doWriteDir not implemented for KRcc";
    +    return false;
    +}
    +
    +bool KRcc::doWriteSymLink(const QString &, const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
    +{
    +    setErrorString(tr("Cannot write to RCC file"));
    +    qCWarning(KArchiveLog) << "doWriteSymLink not implemented for KRcc";
    +    return false;
    +}
    +
    +bool KRcc::openArchive(QIODevice::OpenMode mode)
    +{
    +    // Open archive
    +
    +    if (mode == QIODevice::WriteOnly) {
    +        return true;
    +    }
    +    if (mode != QIODevice::ReadOnly && mode != QIODevice::ReadWrite) {
    +        setErrorString(tr("Unsupported mode %1").arg(mode));
    +        return false;
    +    }
    +
    +    QUuid uuid = QUuid::createUuid();
    +    d->m_prefix = QLatin1Char('/') + uuid.toString();
    +    if (!QResource::registerResource(fileName(), d->m_prefix)) {
    +        setErrorString(tr("Failed to register resource %1 under prefix %2").arg(fileName(), d->m_prefix));
    +        return false;
    +    }
    +
    +    QDir dir(QLatin1Char(':') + d->m_prefix);
    +    d->createEntries(dir, rootDir(), this);
    +    return true;
    +}
    +
    +void KRcc::KRccPrivate::createEntries(const QDir &dir, KArchiveDirectory *parentDir, KRcc *q)
    +{
    +    for (const QString &fileName : dir.entryList()) {
    +        const QString entryPath = dir.path() + QLatin1Char('/') + fileName;
    +        const QFileInfo info(entryPath);
    +        if (info.isFile()) {
    +            KArchiveEntry *entry = new KRccFileEntry(q, fileName, 0444, info.lastModified(), parentDir->user(), parentDir->group(), info.size(), entryPath);
    +            parentDir->addEntry(entry);
    +        } else {
    +            KArchiveDirectory *entry =
    +                new KArchiveDirectory(q, fileName, 0555, info.lastModified(), parentDir->user(), parentDir->group(), /*symlink*/ QString());
    +            if (parentDir->addEntryV2(entry)) {
    +                createEntries(QDir(entryPath), entry, q);
    +            }
    +        }
    +    }
    +}
    +
    +bool KRcc::closeArchive()
    +{
    +    // Close the archive
    +    QResource::unregisterResource(fileName(), d->m_prefix);
    +    // ignore errors
    +    return true;
    +}
    +
    +void KRcc::virtual_hook(int id, void *data)
    +{
    +    KArchive::virtual_hook(id, data);
    +}
    diff --git a/src/libs/3rdparty/karchive/src/krcc.h b/src/libs/3rdparty/karchive/src/krcc.h
    new file mode 100644
    index 00000000000..1c1bfd67971
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/krcc.h
    @@ -0,0 +1,103 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2014 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef KRCC_H
    +#define KRCC_H
    +
    +#include "karchive.h"
    +
    +/**
    + * KRcc is a class for reading dynamic binary resources created by Qt's rcc tool
    + * from a .qrc file and the files it points to.
    + *
    + * Writing is not supported.
    + * @short A class for reading rcc resources.
    + * @since 5.3
    + */
    +class KARCHIVE_EXPORT KRcc : public KArchive
    +{
    +    Q_DECLARE_TR_FUNCTIONS(KRcc)
    +
    +public:
    +    /**
    +     * Creates an instance that operates on the given filename.
    +     *
    +     * @param filename is a local path (e.g. "/home/holger/myfile.rcc")
    +     */
    +    explicit KRcc(const QString &filename);
    +
    +    /**
    +     * If the rcc file is still opened, then it will be
    +     * closed automatically by the destructor.
    +     */
    +    ~KRcc() override;
    +
    +protected:
    +    /*
    +     * Writing is not supported by this class, will always fail.
    +     * @return always false
    +     */
    +    bool doPrepareWriting(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        qint64 size,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +
    +    /*
    +     * Writing is not supported by this class, will always fail.
    +     * @return always false
    +     */
    +    bool doFinishWriting(qint64 size) override;
    +
    +    /*
    +     * Writing is not supported by this class, will always fail.
    +     * @return always false
    +     */
    +    bool doWriteDir(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +
    +    /*
    +     * Writing is not supported by this class, will always fail.
    +     * @return always false
    +     */
    +    bool doWriteSymLink(
    +        const QString &name,
    +        const QString &target,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +
    +    /**
    +     * Registers the .rcc resource in the QResource system under a unique identifier,
    +     * then lists that, and creates the KArchiveFile/KArchiveDirectory entries.
    +     */
    +    bool openArchive(QIODevice::OpenMode mode) override;
    +    /**
    +     * Unregisters the .rcc resource from the QResource system.
    +     */
    +    bool closeArchive() override;
    +
    +protected:
    +    void virtual_hook(int id, void *data) override;
    +
    +private:
    +    class KRccPrivate;
    +    KRccPrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/ktar.cpp b/src/libs/3rdparty/karchive/src/ktar.cpp
    new file mode 100644
    index 00000000000..0ea6313b931
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/ktar.cpp
    @@ -0,0 +1,975 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000 David Faure 
    +   SPDX-FileCopyrightText: 2003 Leo Savernik 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "ktar.h"
    +#include "karchive_p.h"
    +#include "kcompressiondevice.h"
    +#include "kfilterbase.h"
    +#include "loggingcategory.h"
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include 
    +#include  // strtol
    +
    +////////////////////////////////////////////////////////////////////////
    +/////////////////////////// KTar ///////////////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +
    +// Mime types of known filters
    +static const char application_bzip[] = "application/x-bzip";
    +static const char application_lzma[] = "application/x-lzma";
    +static const char application_xz[] = "application/x-xz";
    +static const char application_zstd[] = "application/zstd";
    +
    +/* clang-format off */
    +namespace MimeType
    +{
    +QString application_gzip()     { return QStringLiteral("application/gzip"); }
    +QString application_gzip_old() { return QStringLiteral("application/x-gzip"); }
    +}
    +/* clang-format on */
    +
    +class Q_DECL_HIDDEN KTar::KTarPrivate
    +{
    +public:
    +    KTarPrivate(KTar *parent)
    +        : q(parent)
    +        , tarEnd(0)
    +        , tmpFile(nullptr)
    +        , compressionDevice(nullptr)
    +    {
    +    }
    +
    +    KTar *q;
    +    QStringList dirList;
    +    qint64 tarEnd;
    +    QTemporaryFile *tmpFile;
    +    QString mimetype;
    +    QByteArray origFileName;
    +    KCompressionDevice *compressionDevice;
    +
    +    bool fillTempFile(const QString &fileName);
    +    bool writeBackTempFile(const QString &fileName);
    +    void fillBuffer(char *buffer, const char *mode, qint64 size, const QDateTime &mtime, char typeflag, const char *uname, const char *gname);
    +    void writeLonglink(char *buffer, const QByteArray &name, char typeflag, const char *uname, const char *gname);
    +    qint64 readRawHeader(char *buffer);
    +    bool readLonglink(char *buffer, QByteArray &longlink);
    +    qint64 readHeader(char *buffer, QString &name, QString &symlink);
    +};
    +
    +KTar::KTar(const QString &fileName, const QString &_mimetype)
    +    : KArchive(fileName)
    +    , d(new KTarPrivate(this))
    +{
    +    // shared-mime-info < 1.1 does not know about application/gzip.
    +    // While Qt has optionally a copy of shared-mime-info (1.10 for 5.15.0),
    +    // it uses the system one if it exists.
    +    // Once shared-mime-info 1.1 is required or can be assumed on all targeted
    +    // platforms (right now RHEL/CentOS 6 as target of appimage-based apps
    +    // bundling also karchive does not meet this requirement)
    +    // switch to use the new application/gzip id instead when interacting with QMimeDatabase
    +    // For now: map new name to legacy name and use that
    +    d->mimetype = (_mimetype == MimeType::application_gzip()) ? MimeType::application_gzip_old() : _mimetype;
    +}
    +
    +KTar::KTar(QIODevice *dev)
    +    : KArchive(dev)
    +    , d(new KTarPrivate(this))
    +{
    +}
    +
    +// Only called when a filename was given
    +bool KTar::createDevice(QIODevice::OpenMode mode)
    +{
    +    if (d->mimetype.isEmpty()) {
    +        // Find out mimetype manually
    +
    +        QMimeDatabase db;
    +        QMimeType mime;
    +        if (mode != QIODevice::WriteOnly && QFile::exists(fileName())) {
    +            // Give priority to file contents: if someone renames a .tar.bz2 to .tar.gz,
    +            // we can still do the right thing here.
    +            QFile f(fileName());
    +            if (f.open(QIODevice::ReadOnly)) {
    +                mime = db.mimeTypeForData(&f);
    +            }
    +            if (!mime.isValid()) {
    +                // Unable to determine mimetype from contents, get it from file name
    +                mime = db.mimeTypeForFile(fileName(), QMimeDatabase::MatchExtension);
    +            }
    +        } else {
    +            mime = db.mimeTypeForFile(fileName(), QMimeDatabase::MatchExtension);
    +        }
    +
    +        // qCDebug(KArchiveLog) << mode << mime->name();
    +
    +        if (mime.inherits(QStringLiteral("application/x-compressed-tar")) || mime.inherits(MimeType::application_gzip_old())) {
    +            // gzipped tar file (with possibly invalid file name), ask for gzip filter
    +            d->mimetype = MimeType::application_gzip_old();
    +        } else if (mime.inherits(QStringLiteral("application/x-bzip-compressed-tar")) || mime.inherits(QStringLiteral("application/x-bzip2-compressed-tar"))
    +                   || mime.inherits(QStringLiteral("application/x-bzip2")) || mime.inherits(QString::fromLatin1(application_bzip))) {
    +            // bzipped2 tar file (with possibly invalid file name), ask for bz2 filter
    +            d->mimetype = QString::fromLatin1(application_bzip);
    +        } else if (mime.inherits(QStringLiteral("application/x-lzma-compressed-tar")) || mime.inherits(QString::fromLatin1(application_lzma))) {
    +            // lzma compressed tar file (with possibly invalid file name), ask for xz filter
    +            d->mimetype = QString::fromLatin1(application_lzma);
    +        } else if (mime.inherits(QStringLiteral("application/x-xz-compressed-tar")) || mime.inherits(QString::fromLatin1(application_xz))) {
    +            // xz compressed tar file (with possibly invalid name), ask for xz filter
    +            d->mimetype = QString::fromLatin1(application_xz);
    +        } else if (mime.inherits(QStringLiteral("application/x-zstd-compressed-tar")) || mime.inherits(QString::fromLatin1(application_zstd))) {
    +            // zstd compressed tar file (with possibly invalid name), ask for zstd filter
    +            d->mimetype = QString::fromLatin1(application_zstd);
    +        }
    +    }
    +
    +    if (d->mimetype == QLatin1String("application/x-tar")) {
    +        return KArchive::createDevice(mode);
    +    } else if (mode == QIODevice::WriteOnly) {
    +        if (!KArchive::createDevice(mode)) {
    +            return false;
    +        }
    +        if (!d->mimetype.isEmpty()) {
    +            // Create a compression filter on top of the QSaveFile device that KArchive created.
    +            // qCDebug(KArchiveLog) << "creating KCompressionDevice for" << d->mimetype;
    +            KCompressionDevice::CompressionType type = KCompressionDevice::compressionTypeForMimeType(d->mimetype);
    +            d->compressionDevice = new KCompressionDevice(device(), false, type);
    +            setDevice(d->compressionDevice);
    +        }
    +        return true;
    +    } else {
    +        // The compression filters are very slow with random access.
    +        // So instead of applying the filter to the device,
    +        // the file is completely extracted instead,
    +        // and we work on the extracted tar file.
    +        // This improves the extraction speed by the archive KIO worker supporting the tar protocol dramatically,
    +        // if the archive file contains many files.
    +        // This is because the archive KIO worker extracts one file after the other and normally
    +        // has to walk through the decompression filter each time.
    +        // Which is in fact nearly as slow as a complete decompression for each file.
    +
    +        Q_ASSERT(!d->tmpFile);
    +        d->tmpFile = new QTemporaryFile();
    +        d->tmpFile->setFileTemplate(QDir::tempPath() + QLatin1Char('/') + QLatin1String("ktar-XXXXXX.tar"));
    +        d->tmpFile->open();
    +        // qCDebug(KArchiveLog) << "creating tempfile:" << d->tmpFile->fileName();
    +
    +        setDevice(d->tmpFile);
    +        return true;
    +    }
    +}
    +
    +KTar::~KTar()
    +{
    +    // mjarrett: Closes to prevent ~KArchive from aborting w/o device
    +    if (isOpen()) {
    +        close();
    +    }
    +
    +    delete d->tmpFile;
    +    delete d->compressionDevice;
    +    delete d;
    +}
    +
    +void KTar::setOrigFileName(const QByteArray &fileName)
    +{
    +    if (!isOpen() || !(mode() & QIODevice::WriteOnly)) {
    +        // qCWarning(KArchiveLog) << "KTar::setOrigFileName: File must be opened for writing first.\n";
    +        return;
    +    }
    +    d->origFileName = fileName;
    +}
    +
    +qint64 KTar::KTarPrivate::readRawHeader(char *buffer)
    +{
    +    // Read header
    +    qint64 n = q->device()->read(buffer, 0x200);
    +    // we need to test if there is a prefix value because the file name can be null
    +    // and the prefix can have a value and in this case we don't reset n.
    +    if (n == 0x200 && (buffer[0] != 0 || buffer[0x159] != 0)) {
    +        // Make sure this is actually a tar header
    +        if (strncmp(buffer + 257, "ustar", 5)) {
    +            // The magic isn't there (broken/old tars), but maybe a correct checksum?
    +
    +            int check = 0;
    +            for (uint j = 0; j < 0x200; ++j) {
    +                check += static_cast(buffer[j]);
    +            }
    +
    +            // adjust checksum to count the checksum fields as blanks
    +            for (uint j = 0; j < 8 /*size of the checksum field including the \0 and the space*/; j++) {
    +                check -= static_cast(buffer[148 + j]);
    +            }
    +            check += 8 * ' ';
    +
    +            QByteArray s = QByteArray::number(check, 8); // octal
    +
    +            // only compare those of the 6 checksum digits that mean something,
    +            // because the other digits are filled with all sorts of different chars by different tars ...
    +            // Some tars right-justify the checksum so it could start in one of three places - we have to check each.
    +            if (strncmp(buffer + 148 + 6 - s.length(), s.data(), s.length()) //
    +                && strncmp(buffer + 148 + 7 - s.length(), s.data(), s.length()) //
    +                && strncmp(buffer + 148 + 8 - s.length(), s.data(), s.length())) {
    +                /*qCWarning(KArchiveLog) << "KTar: invalid TAR file. Header is:" << QByteArray( buffer+257, 5 )
    +                               << "instead of ustar. Reading from wrong pos in file?"
    +                               << "checksum=" << QByteArray( buffer + 148 + 6 - s.length(), s.length() );*/
    +                return -1;
    +            }
    +        } /*end if*/
    +    } else {
    +        // reset to 0 if 0x200 because logical end of archive has been reached
    +        if (n == 0x200) {
    +            n = 0;
    +        }
    +    } /*end if*/
    +    return n;
    +}
    +
    +bool KTar::KTarPrivate::readLonglink(char *buffer, QByteArray &longlink)
    +{
    +    qint64 n = 0;
    +    // qCDebug(KArchiveLog) << "reading longlink from pos " << q->device()->pos();
    +    QIODevice *dev = q->device();
    +    // read size of longlink from size field in header
    +    // size is in bytes including the trailing null (which we ignore)
    +    qint64 size = QByteArray(buffer + 0x7c, 12).trimmed().toLongLong(nullptr, 8 /*octal*/);
    +
    +    size--; // ignore trailing null
    +    if (size > std::numeric_limits::max() - 32) { // QByteArray can't really be INT_MAX big, it's max size is something between INT_MAX - 32 and INT_MAX
    +                                                       // depending the platform so just be safe
    +        qCWarning(KArchiveLog) << "Failed to allocate memory for longlink of size" << size;
    +        return false;
    +    }
    +    if (size < 0) {
    +        qCWarning(KArchiveLog) << "Invalid longlink size" << size;
    +        return false;
    +    }
    +    longlink.resize(size);
    +    qint64 offset = 0;
    +    while (size > 0) {
    +        int chunksize = qMin(size, 0x200LL);
    +        n = dev->read(longlink.data() + offset, chunksize);
    +        if (n == -1) {
    +            return false;
    +        }
    +        size -= chunksize;
    +        offset += 0x200;
    +    } /*wend*/
    +    // jump over the rest
    +    const int skip = 0x200 - (n % 0x200);
    +    if (skip <= 0x200) {
    +        if (dev->read(buffer, skip) != skip) {
    +            return false;
    +        }
    +    }
    +    longlink.truncate(qstrlen(longlink.constData()));
    +    return true;
    +}
    +
    +qint64 KTar::KTarPrivate::readHeader(char *buffer, QString &name, QString &symlink)
    +{
    +    name.truncate(0);
    +    symlink.truncate(0);
    +    while (true) {
    +        qint64 n = readRawHeader(buffer);
    +        if (n != 0x200) {
    +            return n;
    +        }
    +
    +        // is it a longlink?
    +        if (strcmp(buffer, "././@LongLink") == 0) {
    +            char typeflag = buffer[0x9c];
    +            QByteArray longlink;
    +            if (readLonglink(buffer, longlink)) {
    +                switch (typeflag) {
    +                case 'L':
    +                    name = QFile::decodeName(longlink.constData());
    +                    break;
    +                case 'K':
    +                    symlink = QFile::decodeName(longlink.constData());
    +                    break;
    +                } /*end switch*/
    +            }
    +        } else {
    +            break;
    +        } /*end if*/
    +    } /*wend*/
    +
    +    // if not result of longlink, read names directly from the header
    +    if (name.isEmpty())
    +    // there are names that are exactly 100 bytes long
    +    // and neither longlink nor \0 terminated (bug:101472)
    +    {
    +        name = QFile::decodeName(QByteArray(buffer, qstrnlen(buffer, 100)));
    +    }
    +    if (symlink.isEmpty()) {
    +        char *symlinkBuffer = buffer + 0x9d /*?*/;
    +        symlink = QFile::decodeName(QByteArray(symlinkBuffer, qstrnlen(symlinkBuffer, 100)));
    +    }
    +
    +    return 0x200;
    +}
    +
    +/*
    + * If we have created a temporary file, we have
    + * to decompress the original file now and write
    + * the contents to the temporary file.
    + */
    +bool KTar::KTarPrivate::fillTempFile(const QString &fileName)
    +{
    +    if (!tmpFile) {
    +        return true;
    +    }
    +
    +    // qCDebug(KArchiveLog) << "filling tmpFile of mimetype" << mimetype;
    +
    +    KCompressionDevice::CompressionType compressionType = KCompressionDevice::compressionTypeForMimeType(mimetype);
    +    KCompressionDevice filterDev(fileName, compressionType);
    +
    +    QFile *file = tmpFile;
    +    Q_ASSERT(file->isOpen());
    +    Q_ASSERT(file->openMode() & QIODevice::WriteOnly);
    +    file->seek(0);
    +    QByteArray buffer;
    +    buffer.resize(8 * 1024);
    +    if (!filterDev.open(QIODevice::ReadOnly)) {
    +        q->setErrorString(tr("File %1 does not exist").arg(fileName));
    +        return false;
    +    }
    +    qint64 len = -1;
    +    while (!filterDev.atEnd() && len != 0) {
    +        len = filterDev.read(buffer.data(), buffer.size());
    +        if (len < 0) { // corrupted archive
    +            q->setErrorString(tr("Archive %1 is corrupt").arg(fileName));
    +            return false;
    +        }
    +        if (file->write(buffer.data(), len) != len) { // disk full
    +            q->setErrorString(tr("Disk full"));
    +            return false;
    +        }
    +    }
    +    filterDev.close();
    +
    +    file->flush();
    +    file->seek(0);
    +    Q_ASSERT(file->isOpen());
    +    Q_ASSERT(file->openMode() & QIODevice::ReadOnly);
    +
    +    // qCDebug(KArchiveLog) << "filling tmpFile finished.";
    +    return true;
    +}
    +
    +bool KTar::openArchive(QIODevice::OpenMode mode)
    +{
    +    if (!(mode & QIODevice::ReadOnly)) {
    +        return true;
    +    }
    +
    +    if (!d->fillTempFile(fileName())) {
    +        return false;
    +    }
    +
    +    // We'll use the permission and user/group of d->rootDir
    +    // for any directory we emulate (see findOrCreate)
    +    // struct stat buf;
    +    // stat( fileName(), &buf );
    +
    +    d->dirList.clear();
    +    QIODevice *dev = device();
    +
    +    if (!dev) {
    +        setErrorString(tr("Could not get underlying device"));
    +        qCWarning(KArchiveLog) << "Could not get underlying device";
    +        return false;
    +    }
    +
    +    // read dir information
    +    char buffer[0x200];
    +    bool ende = false;
    +    do {
    +        QString name;
    +        QString symlink;
    +
    +        // Read header
    +        qint64 n = d->readHeader(buffer, name, symlink);
    +        if (n < 0) {
    +            setErrorString(tr("Could not read tar header"));
    +            return false;
    +        }
    +        if (n == 0x200) {
    +            bool isdir = false;
    +
    +            if (name.isEmpty()) {
    +                continue;
    +            }
    +            if (name.endsWith(QLatin1Char('/'))) {
    +                isdir = true;
    +                name.truncate(name.length() - 1);
    +            }
    +
    +            QByteArray prefix = QByteArray(buffer + 0x159, 155);
    +            if (prefix[0] != '\0') {
    +                name = (QString::fromLatin1(prefix.constData()) + QLatin1Char('/') + name);
    +            }
    +
    +            int pos = name.lastIndexOf(QLatin1Char('/'));
    +            QString nm = (pos == -1) ? name : name.mid(pos + 1);
    +
    +            // read access
    +            buffer[0x6b] = 0;
    +            char *dummy;
    +            const char *p = buffer + 0x64;
    +            while (*p == ' ') {
    +                ++p;
    +            }
    +            int access = strtol(p, &dummy, 8);
    +
    +            // read user and group
    +            const int maxUserGroupLength = 32;
    +            const char *userStart = buffer + 0x109;
    +            const int userLen = qstrnlen(userStart, maxUserGroupLength);
    +            const QString user = QString::fromLocal8Bit(userStart, userLen);
    +            const char *groupStart = buffer + 0x129;
    +            const int groupLen = qstrnlen(groupStart, maxUserGroupLength);
    +            const QString group = QString::fromLocal8Bit(groupStart, groupLen);
    +
    +            // read time
    +            buffer[0x93] = 0;
    +            p = buffer + 0x88;
    +            while (*p == ' ') {
    +                ++p;
    +            }
    +            uint time = strtol(p, &dummy, 8);
    +
    +            // read type flag
    +            char typeflag = buffer[0x9c];
    +            // '0' for files, '1' hard link, '2' symlink, '5' for directory
    +            // (and 'L' for longlink fileNames, 'K' for longlink symlink targets)
    +            // 'D' for GNU tar extension DUMPDIR, 'x' for Extended header referring
    +            // to the next file in the archive and 'g' for Global extended header
    +
    +            if (typeflag == '5') {
    +                isdir = true;
    +            }
    +
    +            bool isDumpDir = false;
    +            if (typeflag == 'D') {
    +                isdir = false;
    +                isDumpDir = true;
    +            }
    +            // qCDebug(KArchiveLog) << nm << "isdir=" << isdir << "pos=" << dev->pos() << "typeflag=" << typeflag << " islink=" << ( typeflag == '1' || typeflag
    +            // == '2' );
    +
    +            if (typeflag == 'x' || typeflag == 'g') { // pax extended header, or pax global extended header
    +                // Skip it for now. TODO: implement reading of extended header, as per https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
    +                (void)dev->read(buffer, 0x200);
    +                continue;
    +            }
    +
    +            if (isdir) {
    +                access |= S_IFDIR; // broken tar files...
    +            }
    +
    +            KArchiveEntry *e;
    +            if (isdir) {
    +                // qCDebug(KArchiveLog) << "directory" << nm;
    +                e = new KArchiveDirectory(this, nm, access, KArchivePrivate::time_tToDateTime(time), user, group, symlink);
    +            } else {
    +                // read size
    +                QByteArray sizeBuffer(buffer + 0x7c, 12);
    +                qint64 size = sizeBuffer.trimmed().toLongLong(nullptr, 8 /*octal*/);
    +                if (size < 0) {
    +                    qWarning() << "Tar file has negative size, resetting to 0";
    +                    size = 0;
    +                }
    +                // qCDebug(KArchiveLog) << "sizeBuffer='" << sizeBuffer << "' -> size=" << size;
    +
    +                // for isDumpDir we will skip the additional info about that dirs contents
    +                if (isDumpDir) {
    +                    // qCDebug(KArchiveLog) << nm << "isDumpDir";
    +                    e = new KArchiveDirectory(this, nm, access, KArchivePrivate::time_tToDateTime(time), user, group, symlink);
    +                } else {
    +                    // Let's hack around hard links. Our classes don't support that, so make them symlinks
    +                    if (typeflag == '1') {
    +                        // qCDebug(KArchiveLog) << "Hard link, setting size to 0 instead of" << size;
    +                        size = 0; // no contents
    +                    }
    +
    +                    // qCDebug(KArchiveLog) << "file" << nm << "size=" << size;
    +                    e = new KArchiveFile(this, nm, access, KArchivePrivate::time_tToDateTime(time), user, group, symlink, dev->pos(), size);
    +                }
    +
    +                // Skip contents + align bytes
    +                qint64 rest = size % 0x200;
    +                qint64 skip = size + (rest ? 0x200 - rest : 0);
    +                // qCDebug(KArchiveLog) << "pos()=" << dev->pos() << "rest=" << rest << "skipping" << skip;
    +                if (!dev->seek(dev->pos() + skip)) {
    +                    // qCWarning(KArchiveLog) << "skipping" << skip << "failed";
    +                }
    +            }
    +
    +            if (pos == -1) {
    +                if (nm == QLatin1String(".")) { // special case
    +                    if (isdir) {
    +                        if (KArchivePrivate::hasRootDir(this)) {
    +                            qWarning() << "Broken tar file has two root dir entries";
    +                            delete e;
    +                        } else {
    +                            setRootDir(static_cast(e));
    +                        }
    +                    } else {
    +                        delete e;
    +                    }
    +                } else {
    +                    rootDir()->addEntry(e);
    +                }
    +            } else {
    +                // In some tar files we can find dir/./file => call cleanPath
    +                QString path = QDir::cleanPath(name.left(pos));
    +                // Ensure container directory exists, create otherwise
    +                KArchiveDirectory *d = findOrCreate(path);
    +                if (d) {
    +                    d->addEntry(e);
    +                } else {
    +                    delete e;
    +                    return false;
    +                }
    +            }
    +        } else {
    +            // qCDebug(KArchiveLog) << "Terminating. Read " << n << " bytes, first one is " << buffer[0];
    +            d->tarEnd = dev->pos() - n; // Remember end of archive
    +            ende = true;
    +        }
    +    } while (!ende);
    +    return true;
    +}
    +
    +/*
    + * Writes back the changes of the temporary file
    + * to the original file.
    + * Must only be called if in write mode, not in read mode
    + */
    +bool KTar::KTarPrivate::writeBackTempFile(const QString &fileName)
    +{
    +    if (!tmpFile) {
    +        return true;
    +    }
    +
    +    // qCDebug(KArchiveLog) << "Write temporary file to compressed file" << fileName << mimetype;
    +
    +    bool forced = false;
    +    /* clang-format off */
    +    if (MimeType::application_gzip_old() == mimetype ||
    +        QLatin1String(application_bzip) == mimetype ||
    +        QLatin1String(application_lzma) == mimetype ||
    +        QLatin1String(application_xz) == mimetype) {
    +        /* clang-format on */
    +        forced = true;
    +    }
    +
    +    // #### TODO this should use QSaveFile to avoid problems on disk full
    +    // (KArchive uses QSaveFile by default, but the temp-uncompressed-file trick
    +    // circumvents that).
    +
    +    KCompressionDevice dev(fileName);
    +    QFile *file = tmpFile;
    +    if (!dev.open(QIODevice::WriteOnly)) {
    +        file->close();
    +        q->setErrorString(tr("Failed to write back temp file: %1").arg(dev.errorString()));
    +        return false;
    +    }
    +    if (forced) {
    +        dev.setOrigFileName(origFileName);
    +    }
    +    file->seek(0);
    +    QByteArray buffer;
    +    buffer.resize(8 * 1024);
    +    qint64 len;
    +    while (!file->atEnd()) {
    +        len = file->read(buffer.data(), buffer.size());
    +        dev.write(buffer.data(), len); // TODO error checking
    +    }
    +    file->close();
    +    dev.close();
    +
    +    // qCDebug(KArchiveLog) << "Write temporary file to compressed file done.";
    +    return true;
    +}
    +
    +bool KTar::closeArchive()
    +{
    +    d->dirList.clear();
    +
    +    bool ok = true;
    +
    +    // If we are in readwrite mode and had created
    +    // a temporary tar file, we have to write
    +    // back the changes to the original file
    +    if (d->tmpFile && (mode() & QIODevice::WriteOnly)) {
    +        ok = d->writeBackTempFile(fileName());
    +        delete d->tmpFile;
    +        d->tmpFile = nullptr;
    +        setDevice(nullptr);
    +    }
    +
    +    return ok;
    +}
    +
    +bool KTar::doFinishWriting(qint64 size)
    +{
    +    // Write alignment
    +    int rest = size % 0x200;
    +    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
    +        d->tarEnd = device()->pos() + (rest ? 0x200 - rest : 0); // Record our new end of archive
    +    }
    +    if (rest) {
    +        char buffer[0x201];
    +        for (uint i = 0; i < 0x200; ++i) {
    +            buffer[i] = 0;
    +        }
    +        qint64 nwritten = device()->write(buffer, 0x200 - rest);
    +        const bool ok = nwritten == 0x200 - rest;
    +
    +        if (!ok) {
    +            setErrorString(tr("Couldn't write alignment: %1").arg(device()->errorString()));
    +        }
    +
    +        return ok;
    +    }
    +    return true;
    +}
    +
    +/*** Some help from the tar sources
    +struct posix_header
    +{                               byte offset
    +  char name[100];               *   0 *     0x0
    +  char mode[8];                 * 100 *     0x64
    +  char uid[8];                  * 108 *     0x6c
    +  char gid[8];                  * 116 *     0x74
    +  char size[12];                * 124 *     0x7c
    +  char mtime[12];               * 136 *     0x88
    +  char chksum[8];               * 148 *     0x94
    +  char typeflag;                * 156 *     0x9c
    +  char linkname[100];           * 157 *     0x9d
    +  char magic[6];                * 257 *     0x101
    +  char version[2];              * 263 *     0x107
    +  char uname[32];               * 265 *     0x109
    +  char gname[32];               * 297 *     0x129
    +  char devmajor[8];             * 329 *     0x149
    +  char devminor[8];             * 337 *     ...
    +  char prefix[155];             * 345 *
    +                                * 500 *
    +};
    +*/
    +
    +void KTar::KTarPrivate::fillBuffer(char *buffer, const char *mode, qint64 size, const QDateTime &mtime, char typeflag, const char *uname, const char *gname)
    +{
    +    // mode (as in stpos())
    +    assert(strlen(mode) == 6);
    +    memcpy(buffer + 0x64, mode, 6);
    +    buffer[0x6a] = ' ';
    +    buffer[0x6b] = '\0';
    +
    +    // dummy uid
    +    strcpy(buffer + 0x6c, "   765 "); // 501 in decimal
    +    // dummy gid
    +    strcpy(buffer + 0x74, "   144 "); // 100 in decimal
    +
    +    // size
    +    QByteArray s = QByteArray::number(size, 8); // octal
    +    s = s.rightJustified(11, '0');
    +    memcpy(buffer + 0x7c, s.data(), 11);
    +    buffer[0x87] = ' '; // space-terminate (no null after)
    +
    +    // modification time
    +    const QDateTime modificationTime = mtime.isValid() ? mtime : QDateTime::currentDateTime();
    +    s = QByteArray::number(static_cast(modificationTime.toMSecsSinceEpoch() / 1000), 8); // octal
    +    s = s.rightJustified(11, '0');
    +    memcpy(buffer + 0x88, s.data(), 11);
    +    buffer[0x93] = ' '; // space-terminate (no null after) -- well current tar writes a null byte
    +
    +    // spaces, replaced by the check sum later
    +    buffer[0x94] = 0x20;
    +    buffer[0x95] = 0x20;
    +    buffer[0x96] = 0x20;
    +    buffer[0x97] = 0x20;
    +    buffer[0x98] = 0x20;
    +    buffer[0x99] = 0x20;
    +
    +    /* From the tar sources :
    +       Fill in the checksum field.  It's formatted differently from the
    +       other fields: it has [6] digits, a null, then a space -- rather than
    +       digits, a space, then a null. */
    +
    +    buffer[0x9a] = '\0';
    +    buffer[0x9b] = ' ';
    +
    +    // type flag (dir, file, link)
    +    buffer[0x9c] = typeflag;
    +
    +    // magic + version
    +    strcpy(buffer + 0x101, "ustar");
    +    strcpy(buffer + 0x107, "00");
    +
    +    // user
    +    strcpy(buffer + 0x109, uname);
    +    // group
    +    strcpy(buffer + 0x129, gname);
    +
    +    // Header check sum
    +    int check = 32;
    +    for (uint j = 0; j < 0x200; ++j) {
    +        check += static_cast(buffer[j]);
    +    }
    +    s = QByteArray::number(check, 8); // octal
    +    s = s.rightJustified(6, '0');
    +    memcpy(buffer + 0x94, s.constData(), 6);
    +}
    +
    +void KTar::KTarPrivate::writeLonglink(char *buffer, const QByteArray &name, char typeflag, const char *uname, const char *gname)
    +{
    +    strcpy(buffer, "././@LongLink");
    +    qint64 namelen = name.length() + 1;
    +    fillBuffer(buffer, "     0", namelen, QDateTime(), typeflag, uname, gname);
    +    q->device()->write(buffer, 0x200); // TODO error checking
    +    qint64 offset = 0;
    +    while (namelen > 0) {
    +        int chunksize = qMin(namelen, 0x200LL);
    +        memcpy(buffer, name.data() + offset, chunksize);
    +        // write long name
    +        q->device()->write(buffer, 0x200); // TODO error checking
    +        // not even needed to reclear the buffer, tar doesn't do it
    +        namelen -= chunksize;
    +        offset += 0x200;
    +    } /*wend*/
    +}
    +
    +bool KTar::doPrepareWriting(const QString &name,
    +                            const QString &user,
    +                            const QString &group,
    +                            qint64 size,
    +                            mode_t perm,
    +                            const QDateTime & /*atime*/,
    +                            const QDateTime &mtime,
    +                            const QDateTime & /*ctime*/)
    +{
    +    if (!isOpen()) {
    +        setErrorString(tr("Application error: TAR file must be open before being written into"));
    +        qCWarning(KArchiveLog) << "doPrepareWriting failed: !isOpen()";
    +        return false;
    +    }
    +
    +    if (!(mode() & QIODevice::WriteOnly)) {
    +        setErrorString(tr("Application error: attempted to write into non-writable 7-Zip file"));
    +        qCWarning(KArchiveLog) << "doPrepareWriting failed: !(mode() & QIODevice::WriteOnly)";
    +        return false;
    +    }
    +
    +    const qint64 MAX_FILESIZE = 077777777777L; // the format we use only allows 11 octal digits for size
    +    if (size > MAX_FILESIZE) {
    +        setErrorString(tr("Application limitation: Can not add file larger than %1 bytes").arg(MAX_FILESIZE));
    +        return false;
    +    }
    +
    +    // In some tar files we can find dir/./file => call cleanPath
    +    QString fileName(QDir::cleanPath(name));
    +
    +    /*
    +      // Create toplevel dirs
    +      // Commented out by David since it's not necessary, and if anybody thinks it is,
    +      // he needs to implement a findOrCreate equivalent in writeDir.
    +      // But as KTar and the "tar" program both handle tar files without
    +      // dir entries, there's really no need for that
    +      QString tmp ( fileName );
    +      int i = tmp.lastIndexOf( '/' );
    +      if ( i != -1 )
    +      {
    +      QString d = tmp.left( i + 1 ); // contains trailing slash
    +      if ( !m_dirList.contains( d ) )
    +      {
    +      tmp = tmp.mid( i + 1 );
    +      writeDir( d, user, group ); // WARNING : this one doesn't create its toplevel dirs
    +      }
    +      }
    +    */
    +
    +    char buffer[0x201] = {0};
    +
    +    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
    +        device()->seek(d->tarEnd); // Go to end of archive as might have moved with a read
    +    }
    +
    +    // provide converted stuff we need later on
    +    const QByteArray encodedFileName = QFile::encodeName(fileName);
    +    const QByteArray uname = user.toLocal8Bit();
    +    const QByteArray gname = group.toLocal8Bit();
    +
    +    // If more than 100 bytes, we need to use the LongLink trick
    +    if (encodedFileName.length() > 99) {
    +        d->writeLonglink(buffer, encodedFileName, 'L', uname.constData(), gname.constData());
    +    }
    +
    +    // Write (potentially truncated) name
    +    strncpy(buffer, encodedFileName.constData(), 99);
    +    buffer[99] = 0;
    +    // zero out the rest (except for what gets filled anyways)
    +    memset(buffer + 0x9d, 0, 0x200 - 0x9d);
    +
    +    QByteArray permstr = QByteArray::number(static_cast(perm), 8);
    +    permstr = permstr.rightJustified(6, '0');
    +    d->fillBuffer(buffer, permstr.constData(), size, mtime, 0x30, uname.constData(), gname.constData());
    +
    +    // Write header
    +    if (device()->write(buffer, 0x200) != 0x200) {
    +        setErrorString(tr("Failed to write header: %1").arg(device()->errorString()));
    +        return false;
    +    } else {
    +        return true;
    +    }
    +}
    +
    +bool KTar::doWriteDir(const QString &name,
    +                      const QString &user,
    +                      const QString &group,
    +                      mode_t perm,
    +                      const QDateTime & /*atime*/,
    +                      const QDateTime &mtime,
    +                      const QDateTime & /*ctime*/)
    +{
    +    if (!isOpen()) {
    +        setErrorString(tr("Application error: TAR file must be open before being written into"));
    +        qCWarning(KArchiveLog) << "doWriteDir failed: !isOpen()";
    +        return false;
    +    }
    +
    +    if (!(mode() & QIODevice::WriteOnly)) {
    +        setErrorString(tr("Application error: attempted to write into non-writable TAR file"));
    +        qCWarning(KArchiveLog) << "doWriteDir failed: !(mode() & QIODevice::WriteOnly)";
    +        return false;
    +    }
    +
    +    // In some tar files we can find dir/./ => call cleanPath
    +    QString dirName(QDir::cleanPath(name));
    +
    +    // Need trailing '/'
    +    if (!dirName.endsWith(QLatin1Char('/'))) {
    +        dirName += QLatin1Char('/');
    +    }
    +
    +    if (d->dirList.contains(dirName)) {
    +        return true; // already there
    +    }
    +
    +    char buffer[0x201] = {0};
    +
    +    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
    +        device()->seek(d->tarEnd); // Go to end of archive as might have moved with a read
    +    }
    +
    +    // provide converted stuff we need lateron
    +    QByteArray encodedDirname = QFile::encodeName(dirName);
    +    QByteArray uname = user.toLocal8Bit();
    +    QByteArray gname = group.toLocal8Bit();
    +
    +    // If more than 100 bytes, we need to use the LongLink trick
    +    if (encodedDirname.length() > 99) {
    +        d->writeLonglink(buffer, encodedDirname, 'L', uname.constData(), gname.constData());
    +    }
    +
    +    // Write (potentially truncated) name
    +    strncpy(buffer, encodedDirname.constData(), 99);
    +    buffer[99] = 0;
    +    // zero out the rest (except for what gets filled anyways)
    +    memset(buffer + 0x9d, 0, 0x200 - 0x9d);
    +
    +    QByteArray permstr = QByteArray::number(static_cast(perm), 8);
    +    permstr = permstr.rightJustified(6, ' ');
    +    d->fillBuffer(buffer, permstr.constData(), 0, mtime, 0x35, uname.constData(), gname.constData());
    +
    +    // Write header
    +    device()->write(buffer, 0x200);
    +    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
    +        d->tarEnd = device()->pos();
    +    }
    +
    +    d->dirList.append(dirName); // contains trailing slash
    +    return true; // TODO if wanted, better error control
    +}
    +
    +bool KTar::doWriteSymLink(const QString &name,
    +                          const QString &target,
    +                          const QString &user,
    +                          const QString &group,
    +                          mode_t perm,
    +                          const QDateTime & /*atime*/,
    +                          const QDateTime &mtime,
    +                          const QDateTime & /*ctime*/)
    +{
    +    if (!isOpen()) {
    +        setErrorString(tr("Application error: TAR file must be open before being written into"));
    +        qCWarning(KArchiveLog) << "doWriteSymLink failed: !isOpen()";
    +        return false;
    +    }
    +
    +    if (!(mode() & QIODevice::WriteOnly)) {
    +        setErrorString(tr("Application error: attempted to write into non-writable TAR file"));
    +        qCWarning(KArchiveLog) << "doWriteSymLink failed: !(mode() & QIODevice::WriteOnly)";
    +        return false;
    +    }
    +
    +    // In some tar files we can find dir/./file => call cleanPath
    +    QString fileName(QDir::cleanPath(name));
    +
    +    char buffer[0x201] = {0};
    +
    +    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
    +        device()->seek(d->tarEnd); // Go to end of archive as might have moved with a read
    +    }
    +
    +    // provide converted stuff we need lateron
    +    QByteArray encodedFileName = QFile::encodeName(fileName);
    +    QByteArray encodedTarget = QFile::encodeName(target);
    +    QByteArray uname = user.toLocal8Bit();
    +    QByteArray gname = group.toLocal8Bit();
    +
    +    // If more than 100 bytes, we need to use the LongLink trick
    +    if (encodedTarget.length() > 99) {
    +        d->writeLonglink(buffer, encodedTarget, 'K', uname.constData(), gname.constData());
    +    }
    +    if (encodedFileName.length() > 99) {
    +        d->writeLonglink(buffer, encodedFileName, 'L', uname.constData(), gname.constData());
    +    }
    +
    +    // Write (potentially truncated) name
    +    strncpy(buffer, encodedFileName.constData(), 99);
    +    buffer[99] = 0;
    +    // Write (potentially truncated) symlink target
    +    strncpy(buffer + 0x9d, encodedTarget.constData(), 99);
    +    buffer[0x9d + 99] = 0;
    +    // zero out the rest
    +    memset(buffer + 0x9d + 100, 0, 0x200 - 100 - 0x9d);
    +
    +    QByteArray permstr = QByteArray::number(static_cast(perm), 8);
    +    permstr = permstr.rightJustified(6, ' ');
    +    d->fillBuffer(buffer, permstr.constData(), 0, mtime, 0x32, uname.constData(), gname.constData());
    +
    +    // Write header
    +    bool retval = device()->write(buffer, 0x200) == 0x200;
    +    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
    +        d->tarEnd = device()->pos();
    +    }
    +    return retval;
    +}
    +
    +void KTar::virtual_hook(int id, void *data)
    +{
    +    KArchive::virtual_hook(id, data);
    +}
    diff --git a/src/libs/3rdparty/karchive/src/ktar.h b/src/libs/3rdparty/karchive/src/ktar.h
    new file mode 100644
    index 00000000000..24f6c355e6e
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/ktar.h
    @@ -0,0 +1,117 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +   SPDX-FileCopyrightText: 2003 Leo Savernik 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef KTAR_H
    +#define KTAR_H
    +
    +#include "karchive.h"
    +
    +/**
    + * @class KTar ktar.h KTar
    + *
    + * A class for reading / writing (optionally compressed) tar archives.
    + *
    + * KTar allows you to read and write tar archives, including those
    + * that are compressed using gzip, bzip2 or xz.
    + *
    + * @author Torben Weis , David Faure 
    + */
    +class KARCHIVE_EXPORT KTar : public KArchive
    +{
    +    Q_DECLARE_TR_FUNCTIONS(KTar)
    +
    +public:
    +    /**
    +     * Creates an instance that operates on the given filename
    +     * using the compression filter associated to given mimetype.
    +     *
    +     * @param filename is a local path (e.g. "/home/weis/myfile.tgz")
    +     * @param mimetype "application/gzip" (before 5.85: "application/x-gzip"), "application/x-bzip",
    +     * "application/x-xz", "application/zstd" (since 5.82)
    +     * Do not use application/x-compressed-tar or similar - you only need to
    +     * specify the compression layer !  If the mimetype is omitted, it
    +     * will be determined from the filename.
    +     */
    +    explicit KTar(const QString &filename, const QString &mimetype = QString());
    +
    +    /**
    +     * Creates an instance that operates on the given device.
    +     * The device can be compressed (KCompressionDevice) or not (QFile, etc.).
    +     * @warning Do not assume that giving a QFile here will decompress the file,
    +     * in case it's compressed!
    +     * @param dev the device to read from. If the source is compressed, the
    +     * QIODevice must take care of decompression
    +     */
    +    explicit KTar(QIODevice *dev);
    +
    +    /**
    +     * If the tar ball is still opened, then it will be
    +     * closed automatically by the destructor.
    +     */
    +    ~KTar() override;
    +
    +    /**
    +     * Special function for setting the "original file name" in the gzip header,
    +     * when writing a tar.gz file. It appears when using in the "file" command,
    +     * for instance. Should only be called if the underlying device is a KCompressionDevice!
    +     * @param fileName the original file name
    +     */
    +    void setOrigFileName(const QByteArray &fileName);
    +
    +protected:
    +    /// Reimplemented from KArchive
    +    bool doWriteSymLink(
    +        const QString &name,
    +        const QString &target,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +    /// Reimplemented from KArchive
    +    bool doWriteDir(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +    /// Reimplemented from KArchive
    +    bool doPrepareWriting(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        qint64 size,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +    /// Reimplemented from KArchive
    +    bool doFinishWriting(qint64 size) override;
    +
    +    /**
    +     * Opens the archive for reading.
    +     * Parses the directory listing of the archive
    +     * and creates the KArchiveDirectory/KArchiveFile entries.
    +     * @param mode the mode of the file
    +     */
    +    bool openArchive(QIODevice::OpenMode mode) override;
    +    bool closeArchive() override;
    +
    +    bool createDevice(QIODevice::OpenMode mode) override;
    +
    +private:
    +protected:
    +    void virtual_hook(int id, void *data) override;
    +
    +private:
    +    class KTarPrivate;
    +    KTarPrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kxzfilter.cpp b/src/libs/3rdparty/karchive/src/kxzfilter.cpp
    new file mode 100644
    index 00000000000..f34c237c856
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kxzfilter.cpp
    @@ -0,0 +1,279 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2007-2008 Per Øyvind Karlsen 
    +
    +   Based on kbzip2filter:
    +   SPDX-FileCopyrightText: 2000-2005 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "kxzfilter.h"
    +#include "loggingcategory.h"
    +
    +#if HAVE_XZ_SUPPORT
    +extern "C" {
    +#include 
    +}
    +
    +#include 
    +
    +#include 
    +
    +class Q_DECL_HIDDEN KXzFilter::Private
    +{
    +public:
    +    Private()
    +        : isInitialized(false)
    +    {
    +        memset(&zStream, 0, sizeof(zStream));
    +        mode = 0;
    +    }
    +
    +    lzma_stream zStream;
    +    int mode;
    +    bool isInitialized;
    +    KXzFilter::Flag flag;
    +};
    +
    +KXzFilter::KXzFilter()
    +    : d(new Private)
    +{
    +}
    +
    +KXzFilter::~KXzFilter()
    +{
    +    delete d;
    +}
    +
    +bool KXzFilter::init(int mode)
    +{
    +    QList props;
    +    return init(mode, AUTO, props);
    +}
    +
    +static void freeFilters(lzma_filter filters[])
    +{
    +    for (int i = 0; filters[i].id != LZMA_VLI_UNKNOWN; i++) {
    +        free(filters[i].options);
    +    }
    +}
    +
    +bool KXzFilter::init(int mode, Flag flag, const QList &properties)
    +{
    +    if (d->isInitialized) {
    +        terminate();
    +    }
    +
    +    d->flag = flag;
    +    lzma_ret result;
    +    d->zStream.next_in = nullptr;
    +    d->zStream.avail_in = 0;
    +    if (mode == QIODevice::ReadOnly) {
    +        // TODO when we can depend on Qt 5.12 Use a QScopeGuard to call freeFilters
    +        lzma_filter filters[5];
    +        filters[0].id = LZMA_VLI_UNKNOWN;
    +
    +        switch (flag) {
    +        case AUTO:
    +            /* We set the memlimit for decompression to 100MiB which should be
    +             * more than enough to be sufficient for level 9 which requires 65 MiB.
    +             */
    +            result = lzma_auto_decoder(&d->zStream, 100 << 20, 0);
    +            if (result != LZMA_OK) {
    +                qCWarning(KArchiveLog) << "lzma_auto_decoder returned" << result;
    +                return false;
    +            }
    +            break;
    +        case LZMA: {
    +            filters[0].id = LZMA_FILTER_LZMA1;
    +            filters[0].options = nullptr;
    +            filters[1].id = LZMA_VLI_UNKNOWN;
    +            filters[1].options = nullptr;
    +
    +            Q_ASSERT(properties.size() == 5);
    +            unsigned char props[5];
    +            for (int i = 0; i < properties.size(); ++i) {
    +                props[i] = properties[i];
    +            }
    +
    +            result = lzma_properties_decode(&filters[0], nullptr, props, sizeof(props));
    +            if (result != LZMA_OK) {
    +                qCWarning(KArchiveLog) << "lzma_properties_decode returned" << result;
    +                freeFilters(filters);
    +                return false;
    +            }
    +            break;
    +        }
    +        case LZMA2: {
    +            filters[0].id = LZMA_FILTER_LZMA2;
    +            filters[0].options = nullptr;
    +            filters[1].id = LZMA_VLI_UNKNOWN;
    +            filters[1].options = nullptr;
    +
    +            Q_ASSERT(properties.size() == 1);
    +            unsigned char props[1];
    +            props[0] = properties[0];
    +
    +            result = lzma_properties_decode(&filters[0], nullptr, props, sizeof(props));
    +            if (result != LZMA_OK) {
    +                qCWarning(KArchiveLog) << "lzma_properties_decode returned" << result;
    +                freeFilters(filters);
    +                return false;
    +            }
    +            break;
    +        }
    +        case BCJ: {
    +            filters[0].id = LZMA_FILTER_X86;
    +            filters[0].options = nullptr;
    +
    +            unsigned char props[5] = {0x5d, 0x00, 0x00, 0x08, 0x00};
    +            filters[1].id = LZMA_FILTER_LZMA1;
    +            filters[1].options = nullptr;
    +            result = lzma_properties_decode(&filters[1], nullptr, props, sizeof(props));
    +            if (result != LZMA_OK) {
    +                qCWarning(KArchiveLog) << "lzma_properties_decode1 returned" << result;
    +                freeFilters(filters);
    +                return false;
    +            }
    +
    +            filters[2].id = LZMA_VLI_UNKNOWN;
    +            filters[2].options = nullptr;
    +
    +            break;
    +        }
    +        case POWERPC:
    +        case IA64:
    +        case ARM:
    +        case ARMTHUMB:
    +        case SPARC:
    +            // qCDebug(KArchiveLog) << "flag" << flag << "props size" << properties.size();
    +            break;
    +        }
    +
    +        if (flag != AUTO) {
    +            result = lzma_raw_decoder(&d->zStream, filters);
    +            if (result != LZMA_OK) {
    +                qCWarning(KArchiveLog) << "lzma_raw_decoder returned" << result;
    +                freeFilters(filters);
    +                return false;
    +            }
    +        }
    +        freeFilters(filters);
    +
    +    } else if (mode == QIODevice::WriteOnly) {
    +        if (flag == AUTO) {
    +            result = lzma_easy_encoder(&d->zStream, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC32);
    +        } else {
    +            lzma_filter filters[5];
    +            if (flag == LZMA2) {
    +                lzma_options_lzma lzma_opt;
    +                lzma_lzma_preset(&lzma_opt, LZMA_PRESET_DEFAULT);
    +
    +                filters[0].id = LZMA_FILTER_LZMA2;
    +                filters[0].options = &lzma_opt;
    +                filters[1].id = LZMA_VLI_UNKNOWN;
    +                filters[1].options = nullptr;
    +            }
    +            result = lzma_raw_encoder(&d->zStream, filters);
    +        }
    +        if (result != LZMA_OK) {
    +            qCWarning(KArchiveLog) << "lzma_easy_encoder returned" << result;
    +            return false;
    +        }
    +    } else {
    +        // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
    +        return false;
    +    }
    +    d->mode = mode;
    +    d->isInitialized = true;
    +    return true;
    +}
    +
    +int KXzFilter::mode() const
    +{
    +    return d->mode;
    +}
    +
    +bool KXzFilter::terminate()
    +{
    +    if (d->mode == QIODevice::ReadOnly || d->mode == QIODevice::WriteOnly) {
    +        lzma_end(&d->zStream);
    +    } else {
    +        // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
    +        return false;
    +    }
    +    d->isInitialized = false;
    +    return true;
    +}
    +
    +void KXzFilter::reset()
    +{
    +    // qCDebug(KArchiveLog) << "KXzFilter::reset";
    +    // liblzma doesn't have a reset call...
    +    terminate();
    +    init(d->mode);
    +}
    +
    +void KXzFilter::setOutBuffer(char *data, uint maxlen)
    +{
    +    d->zStream.avail_out = maxlen;
    +    d->zStream.next_out = (uint8_t *)data;
    +}
    +
    +void KXzFilter::setInBuffer(const char *data, unsigned int size)
    +{
    +    d->zStream.avail_in = size;
    +    d->zStream.next_in = (uint8_t *)const_cast(data);
    +}
    +
    +int KXzFilter::inBufferAvailable() const
    +{
    +    return d->zStream.avail_in;
    +}
    +
    +int KXzFilter::outBufferAvailable() const
    +{
    +    return d->zStream.avail_out;
    +}
    +
    +KXzFilter::Result KXzFilter::uncompress()
    +{
    +    // qCDebug(KArchiveLog) << "Calling lzma_code with avail_in=" << inBufferAvailable() << " avail_out =" << outBufferAvailable();
    +    lzma_ret result;
    +    result = lzma_code(&d->zStream, LZMA_RUN);
    +
    +    /*if (result != LZMA_OK) {
    +        qCDebug(KArchiveLog) << "lzma_code returned " << result;
    +        //qCDebug(KArchiveLog) << "KXzFilter::uncompress " << ( result == LZMA_STREAM_END ? KFilterBase::End : KFilterBase::Error );
    +    }*/
    +
    +    switch (result) {
    +    case LZMA_OK:
    +        return KFilterBase::Ok;
    +    case LZMA_STREAM_END:
    +        return KFilterBase::End;
    +    default:
    +        return KFilterBase::Error;
    +    }
    +}
    +
    +KXzFilter::Result KXzFilter::compress(bool finish)
    +{
    +    // qCDebug(KArchiveLog) << "Calling lzma_code with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
    +    lzma_ret result = lzma_code(&d->zStream, finish ? LZMA_FINISH : LZMA_RUN);
    +    switch (result) {
    +    case LZMA_OK:
    +        return KFilterBase::Ok;
    +        break;
    +    case LZMA_STREAM_END:
    +        // qCDebug(KArchiveLog) << "  lzma_code returned " << result;
    +        return KFilterBase::End;
    +        break;
    +    default:
    +        // qCDebug(KArchiveLog) << "  lzma_code returned " << result;
    +        return KFilterBase::Error;
    +        break;
    +    }
    +}
    +
    +#endif /* HAVE_XZ_SUPPORT */
    diff --git a/src/libs/3rdparty/karchive/src/kxzfilter.h b/src/libs/3rdparty/karchive/src/kxzfilter.h
    new file mode 100644
    index 00000000000..914d47dbe52
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kxzfilter.h
    @@ -0,0 +1,67 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2007-2008 Per Øyvind Karlsen 
    +
    +   Based on kbzip2filter:
    +   SPDX-FileCopyrightText: 2000 David Faure 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#ifndef KXZFILTER_H
    +#define KXZFILTER_H
    +
    +#if HAVE_XZ_SUPPORT
    +
    +#include "kfilterbase.h"
    +
    +/**
    + * Internal class used by KCompressionDevice
    + * @internal
    + */
    +class KXzFilter : public KFilterBase
    +{
    +public:
    +    KXzFilter();
    +    ~KXzFilter() override;
    +
    +    bool init(int) override;
    +
    +    enum Flag {
    +        AUTO = 0,
    +        LZMA = 1,
    +        LZMA2 = 2,
    +        BCJ = 3, // X86
    +        POWERPC = 4,
    +        IA64 = 5,
    +        ARM = 6,
    +        ARMTHUMB = 7,
    +        SPARC = 8,
    +    };
    +
    +    virtual bool init(int, Flag flag, const QList &props);
    +    int mode() const override;
    +    bool terminate() override;
    +    void reset() override;
    +    bool readHeader() override
    +    {
    +        return true; // lzma handles it by itself ! Cool !
    +    }
    +    bool writeHeader(const QByteArray &) override
    +    {
    +        return true;
    +    }
    +    void setOutBuffer(char *data, uint maxlen) override;
    +    void setInBuffer(const char *data, uint size) override;
    +    int inBufferAvailable() const override;
    +    int outBufferAvailable() const override;
    +    Result uncompress() override;
    +    Result compress(bool finish) override;
    +
    +private:
    +    class Private;
    +    Private *const d;
    +};
    +
    +#endif
    +
    +#endif // KXZFILTER_H
    diff --git a/src/libs/3rdparty/karchive/src/kzip.cpp b/src/libs/3rdparty/karchive/src/kzip.cpp
    new file mode 100644
    index 00000000000..23bf9aa4a3b
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kzip.cpp
    @@ -0,0 +1,1477 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2000 David Faure 
    +   SPDX-FileCopyrightText: 2002 Holger Schroeder 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "kzip.h"
    +#include "karchive_p.h"
    +#include "kcompressiondevice.h"
    +#include "klimitediodevice_p.h"
    +#include "loggingcategory.h"
    +
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include 
    +#include 
    +#include 
    +
    +#ifndef QT_STAT_LNK
    +#define QT_STAT_LNK 0120000
    +#endif // QT_STAT_LNK
    +
    +static const int max_path_len = 4095; // maximum number of character a path may contain
    +
    +static void transformToMsDos(const QDateTime &_dt, char *buffer)
    +{
    +    const QDateTime dt = _dt.isValid() ? _dt : QDateTime::currentDateTime();
    +    /* clang-format off */
    +    const quint16 time = (dt.time().hour() << 11) // 5 bit hour
    +                         | (dt.time().minute() << 5) // 6 bit minute
    +                         | (dt.time().second() >> 1); // 5 bit double seconds
    +    /* clang-format on */
    +
    +    buffer[0] = char(time);
    +    buffer[1] = char(time >> 8);
    +
    +    /* clang-format off */
    +    const quint16 date = ((dt.date().year() - 1980) << 9) // 7 bit year 1980-based
    +                         | (dt.date().month() << 5) // 4 bit month
    +                         | (dt.date().day()); // 5 bit day
    +    /* clang-format on */
    +
    +    buffer[2] = char(date);
    +    buffer[3] = char(date >> 8);
    +}
    +
    +static uint transformFromMsDos(const char *buffer)
    +{
    +    quint16 time = (uchar)buffer[0] | ((uchar)buffer[1] << 8);
    +    int h = time >> 11;
    +    int m = (time & 0x7ff) >> 5;
    +    int s = (time & 0x1f) * 2;
    +    QTime qt(h, m, s);
    +
    +    quint16 date = (uchar)buffer[2] | ((uchar)buffer[3] << 8);
    +    int y = (date >> 9) + 1980;
    +    int o = (date & 0x1ff) >> 5;
    +    int d = (date & 0x1f);
    +    QDate qd(y, o, d);
    +
    +    QDateTime dt(qd, qt);
    +    return dt.toSecsSinceEpoch();
    +}
    +
    +// == parsing routines for zip headers
    +
    +/** all relevant information about parsing file information */
    +struct ParseFileInfo {
    +    // file related info
    +    mode_t perm; // permissions of this file
    +    // TODO: use quint32 instead of a uint?
    +    uint atime; // last access time (UNIX format)
    +    uint mtime; // modification time (UNIX format)
    +    uint ctime; // creation time (UNIX format)
    +    int uid; // user id (-1 if not specified)
    +    int gid; // group id (-1 if not specified)
    +    QByteArray guessed_symlink; // guessed symlink target
    +    int extralen; // length of extra field
    +
    +    // parsing related info
    +    bool exttimestamp_seen; // true if extended timestamp extra field
    +    // has been parsed
    +    bool newinfounix_seen; // true if Info-ZIP Unix New extra field has
    +    // been parsed
    +
    +    // file sizes from a ZIP64 extra field
    +    quint64 uncompressedSize = 0;
    +    quint64 compressedSize = 0;
    +
    +    ParseFileInfo()
    +        : perm(0100644)
    +        , uid(-1)
    +        , gid(-1)
    +        , extralen(0)
    +        , exttimestamp_seen(false)
    +        , newinfounix_seen(false)
    +    {
    +        ctime = mtime = atime = time(nullptr);
    +    }
    +};
    +
    +/** updates the parse information with the given extended timestamp extra field.
    + * @param buffer start content of buffer known to contain an extended
    + *  timestamp extra field (without magic & size)
    + * @param size size of field content (must not count magic and size entries)
    + * @param islocal true if this is a local field, false if central
    + * @param pfi ParseFileInfo object to be updated
    + * @return true if processing was successful
    + */
    +static bool parseExtTimestamp(const char *buffer, int size, bool islocal, ParseFileInfo &pfi)
    +{
    +    if (size < 1) {
    +        // qCDebug(KArchiveLog) << "premature end of extended timestamp (#1)";
    +        return false;
    +    } /*end if*/
    +    int flags = *buffer; // read flags
    +    buffer += 1;
    +    size -= 1;
    +
    +    if (flags & 1) { // contains modification time
    +        if (size < 4) {
    +            // qCDebug(KArchiveLog) << "premature end of extended timestamp (#2)";
    +            return false;
    +        } /*end if*/
    +        pfi.mtime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
    +        buffer += 4;
    +        size -= 4;
    +    } /*end if*/
    +    // central extended field cannot contain more than the modification time
    +    // even if other flags are set
    +    if (!islocal) {
    +        pfi.exttimestamp_seen = true;
    +        return true;
    +    } /*end if*/
    +
    +    if (flags & 2) { // contains last access time
    +        if (size < 4) {
    +            // qCDebug(KArchiveLog) << "premature end of extended timestamp (#3)";
    +            return true;
    +        } /*end if*/
    +        pfi.atime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
    +        buffer += 4;
    +        size -= 4;
    +    } /*end if*/
    +
    +    if (flags & 4) { // contains creation time
    +        if (size < 4) {
    +            // qCDebug(KArchiveLog) << "premature end of extended timestamp (#4)";
    +            return true;
    +        } /*end if*/
    +        pfi.ctime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
    +        buffer += 4;
    +    } /*end if*/
    +
    +    pfi.exttimestamp_seen = true;
    +    return true;
    +}
    +
    +/** updates the parse information with the given Info-ZIP Unix old extra field.
    + * @param buffer start of content of buffer known to contain an Info-ZIP
    + *  Unix old extra field (without magic & size)
    + * @param size size of field content (must not count magic and size entries)
    + * @param islocal true if this is a local field, false if central
    + * @param pfi ParseFileInfo object to be updated
    + * @return true if processing was successful
    + */
    +static bool parseInfoZipUnixOld(const char *buffer, int size, bool islocal, ParseFileInfo &pfi)
    +{
    +    // spec mandates to omit this field if one of the newer fields are available
    +    if (pfi.exttimestamp_seen || pfi.newinfounix_seen) {
    +        return true;
    +    }
    +
    +    if (size < 8) {
    +        // qCDebug(KArchiveLog) << "premature end of Info-ZIP unix extra field old";
    +        return false;
    +    }
    +
    +    pfi.atime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
    +    buffer += 4;
    +    pfi.mtime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
    +    buffer += 4;
    +    if (islocal && size >= 12) {
    +        pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
    +        buffer += 2;
    +        pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
    +        buffer += 2;
    +    } /*end if*/
    +    return true;
    +}
    +
    +#if 0 // not needed yet
    +/** updates the parse information with the given Info-ZIP Unix new extra field.
    + * @param buffer start of content of buffer known to contain an Info-ZIP
    + *      Unix new extra field (without magic & size)
    + * @param size size of field content (must not count magic and size entries)
    + * @param islocal true if this is a local field, false if central
    + * @param pfi ParseFileInfo object to be updated
    + * @return true if processing was successful
    + */
    +static bool parseInfoZipUnixNew(const char *buffer, int size, bool islocal,
    +                                ParseFileInfo &pfi)
    +{
    +    if (!islocal) { // contains nothing in central field
    +        pfi.newinfounix = true;
    +        return true;
    +    }
    +
    +    if (size < 4) {
    +        qCDebug(KArchiveLog) << "premature end of Info-ZIP unix extra field new";
    +        return false;
    +    }
    +
    +    pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
    +    buffer += 2;
    +    pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
    +    buffer += 2;
    +
    +    pfi.newinfounix = true;
    +    return true;
    +}
    +#endif
    +
    +/**
    + * parses the extra field
    + * @param buffer start of buffer where the extra field is to be found
    + * @param size size of the extra field
    + * @param islocal true if this is part of a local header, false if of central
    + * @param pfi ParseFileInfo object which to write the results into
    + * @return true if parsing was successful
    + */
    +static bool parseExtraField(const char *buffer, int size, bool islocal, ParseFileInfo &pfi)
    +{
    +    // extra field in central directory doesn't contain useful data, so we
    +    // don't bother parsing it
    +    if (!islocal) {
    +        return true;
    +    }
    +
    +    while (size >= 4) { // as long as a potential extra field can be read
    +        int magic = (uchar)buffer[0] | (uchar)buffer[1] << 8;
    +        buffer += 2;
    +        int fieldsize = (uchar)buffer[0] | (uchar)buffer[1] << 8;
    +        buffer += 2;
    +        size -= 4;
    +
    +        if (fieldsize > size) {
    +            // qCDebug(KArchiveLog) << "fieldsize: " << fieldsize << " size: " << size;
    +            // qCDebug(KArchiveLog) << "premature end of extra fields reached";
    +            break;
    +        }
    +
    +        switch (magic) {
    +        case 0x0001: // ZIP64 extended file information
    +            if (size >= 8) {
    +                pfi.uncompressedSize = qFromLittleEndian(*reinterpret_cast(buffer));
    +            }
    +            if (size >= 16) {
    +                pfi.compressedSize = qFromLittleEndian(*reinterpret_cast(buffer + 8));
    +            }
    +            break;
    +        case 0x5455: // extended timestamp
    +            if (!parseExtTimestamp(buffer, fieldsize, islocal, pfi)) {
    +                return false;
    +            }
    +            break;
    +        case 0x5855: // old Info-ZIP unix extra field
    +            if (!parseInfoZipUnixOld(buffer, fieldsize, islocal, pfi)) {
    +                return false;
    +            }
    +            break;
    +#if 0 // not needed yet
    +        case 0x7855:        // new Info-ZIP unix extra field
    +            if (!parseInfoZipUnixNew(buffer, fieldsize, islocal, pfi)) {
    +                return false;
    +            }
    +            break;
    +#endif
    +        default:
    +            /* ignore everything else */
    +            ;
    +        } /*end switch*/
    +
    +        buffer += fieldsize;
    +        size -= fieldsize;
    +    } /*wend*/
    +    return true;
    +}
    +
    +/**
    + * Checks if a token for a central or local header has been found and resets
    + * the device to the begin of the token. If a token for the data descriptor is
    + * found it is assumed there is a central or local header token starting right
    + * behind the data descriptor, and the device is set accordingly to the begin
    + * of that token.
    + * To be called when a 'P' has been found.
    + * @param buffer start of buffer with the 3 bytes behind 'P'
    + * @param dev device that is read from
    + * @param dataDescriptor only search for data descriptor
    + * @return true if a local or central header begin is or could be reached
    + */
    +static bool handlePossibleHeaderBegin(const char *buffer, QIODevice *dev, bool dataDescriptor)
    +{
    +    // we have to detect three magic tokens here:
    +    // PK34 for the next local header in case there is no data descriptor
    +    // PK12 for the central header in case there is no data descriptor
    +    // PK78 for the data descriptor in case it is following the compressed data
    +    // TODO: optimize using 32bit const data for comparison instead of byte-wise,
    +    // given we run at least on 32bit CPUs
    +
    +    if (buffer[0] == 'K') {
    +        if (buffer[1] == 7 && buffer[2] == 8) {
    +            // data descriptor token found
    +            dev->seek(dev->pos() + 12); // skip the 'data_descriptor'
    +            return true;
    +        }
    +
    +        if (!dataDescriptor
    +            && ((buffer[1] == 1 && buffer[2] == 2) //
    +                || (buffer[1] == 3 && buffer[2] == 4))) {
    +            // central/local header token found
    +            dev->seek(dev->pos() - 4);
    +            // go back 4 bytes, so that the magic bytes can be found
    +            // in the next cycle...
    +            return true;
    +        }
    +    }
    +    return false;
    +}
    +
    +/**
    + * Reads the device forwards from the current pos until a token for a central or
    + * local header has been found or is to be assumed.
    + * @param dev device that is read from
    + * @return true if a local or central header token could be reached, false on error
    + */
    +static bool seekToNextHeaderToken(QIODevice *dev, bool dataDescriptor)
    +{
    +    bool headerTokenFound = false;
    +    char buffer[3];
    +
    +    while (!headerTokenFound) {
    +        int n = dev->read(buffer, 1);
    +        if (n < 1) {
    +            // qCWarning(KArchiveLog) << "Invalid ZIP file. Unexpected end of file. (#2)";
    +            return false;
    +        }
    +
    +        if (buffer[0] != 'P') {
    +            continue;
    +        }
    +
    +        n = dev->read(buffer, 3);
    +        if (n < 3) {
    +            // qCWarning(KArchiveLog) << "Invalid ZIP file. Unexpected end of file. (#3)";
    +            return false;
    +        }
    +
    +        if (handlePossibleHeaderBegin(buffer, dev, dataDescriptor)) {
    +            headerTokenFound = true;
    +        } else {
    +            for (int i = 0; i < 3; ++i) {
    +                if (buffer[i] == 'P') {
    +                    // We have another P character so we must go back a little to check if it is a magic
    +                    dev->seek(dev->pos() - 3 + i);
    +                    break;
    +                }
    +            }
    +        }
    +    }
    +    return true;
    +}
    +
    +////////////////////////////////////////////////////////////////////////
    +/////////////////////////// KZip ///////////////////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +
    +class Q_DECL_HIDDEN KZip::KZipPrivate
    +{
    +public:
    +    KZipPrivate()
    +        : m_crc(0)
    +        , m_currentFile(nullptr)
    +        , m_currentDev(nullptr)
    +        , m_compression(8)
    +        , m_extraField(KZip::NoExtraField)
    +        , m_offset(0)
    +    {
    +    }
    +
    +    unsigned long m_crc; // checksum
    +    KZipFileEntry *m_currentFile; // file currently being written
    +    QIODevice *m_currentDev; // filterdev used to write to the above file
    +    QList m_fileList; // flat list of all files, for the index (saves a recursive method ;)
    +    int m_compression;
    +    KZip::ExtraField m_extraField;
    +    // m_offset holds the offset of the place in the zip,
    +    // where new data can be appended. after openarchive it points to 0, when in
    +    // writeonly mode, or it points to the beginning of the central directory.
    +    // each call to writefile updates this value.
    +    quint64 m_offset;
    +};
    +
    +KZip::KZip(const QString &fileName)
    +    : KArchive(fileName)
    +    , d(new KZipPrivate)
    +{
    +}
    +
    +KZip::KZip(QIODevice *dev)
    +    : KArchive(dev)
    +    , d(new KZipPrivate)
    +{
    +}
    +
    +KZip::~KZip()
    +{
    +    // qCDebug(KArchiveLog) << this;
    +    if (isOpen()) {
    +        close();
    +    }
    +    delete d;
    +}
    +
    +bool KZip::openArchive(QIODevice::OpenMode mode)
    +{
    +    // qCDebug(KArchiveLog);
    +    d->m_fileList.clear();
    +
    +    if (mode == QIODevice::WriteOnly) {
    +        return true;
    +    }
    +
    +    char buffer[47];
    +
    +    // Check that it's a valid ZIP file
    +    // KArchive::open() opened the underlying device already.
    +
    +    quint64 offset = 0; // holds offset, where we read
    +    // contains information gathered from the local file headers
    +    QHash pfi_map;
    +
    +    QIODevice *dev = device();
    +
    +    // We set a bool for knowing if we are allowed to skip the start of the file
    +    bool startOfFile = true;
    +
    +    for (;;) { // repeat until 'end of entries' signature is reached
    +        // qCDebug(KArchiveLog) << "loop starts";
    +        // qCDebug(KArchiveLog) << "dev->pos() now : " << dev->pos();
    +        int n = dev->read(buffer, 4);
    +
    +        if (n < 4) {
    +            setErrorString(tr("Invalid ZIP file. Unexpected end of file. (Error code: %1)").arg(1));
    +            return false;
    +        }
    +
    +        if (!memcmp(buffer, "PK\5\6", 4)) { // 'end of entries'
    +            // qCDebug(KArchiveLog) << "PK56 found end of archive";
    +            startOfFile = false;
    +            break;
    +        }
    +
    +        if (!memcmp(buffer, "PK\3\4", 4)) { // local file header
    +            // qCDebug(KArchiveLog) << "PK34 found local file header";
    +            startOfFile = false;
    +            // can this fail ???
    +            dev->seek(dev->pos() + 2); // skip 'version needed to extract'
    +
    +            // read static header stuff
    +            n = dev->read(buffer, 24);
    +            if (n < 24) {
    +                setErrorString(tr("Invalid ZIP file. Unexpected end of file. (Error code: %1)").arg(4));
    +                return false;
    +            }
    +
    +            int gpf = (uchar)buffer[0]; // "general purpose flag" not "general protection fault" ;-)
    +            int compression_mode = (uchar)buffer[2] | (uchar)buffer[3] << 8;
    +            uint mtime = transformFromMsDos(buffer + 4);
    +
    +            const qint64 compr_size = uint(uchar(buffer[12])) | uint(uchar(buffer[13])) << 8 | uint(uchar(buffer[14])) << 16 | uint(uchar(buffer[15])) << 24;
    +            const qint64 uncomp_size = uint(uchar(buffer[16])) | uint(uchar(buffer[17])) << 8 | uint(uchar(buffer[18])) << 16 | uint(uchar(buffer[19])) << 24;
    +            const int namelen = uint(uchar(buffer[20])) | uint(uchar(buffer[21])) << 8;
    +            const int extralen = uint(uchar(buffer[22])) | uint(uchar(buffer[23])) << 8;
    +
    +            /*
    +              qCDebug(KArchiveLog) << "general purpose bit flag: " << gpf;
    +              qCDebug(KArchiveLog) << "compressed size: " << compr_size;
    +              qCDebug(KArchiveLog) << "uncompressed size: " << uncomp_size;
    +              qCDebug(KArchiveLog) << "namelen: " << namelen;
    +              qCDebug(KArchiveLog) << "extralen: " << extralen;
    +              qCDebug(KArchiveLog) << "archive size: " << dev->size();
    +            */
    +
    +            // read fileName
    +            if (namelen <= 0) {
    +                setErrorString(tr("Invalid ZIP file. Negative name length"));
    +                return false;
    +            }
    +            QByteArray fileName = dev->read(namelen);
    +            if (fileName.size() < namelen) {
    +                setErrorString(tr("Invalid ZIP file. Name not completely read (#2)"));
    +                return false;
    +            }
    +
    +            ParseFileInfo pfi;
    +            pfi.mtime = mtime;
    +
    +            // read and parse the beginning of the extra field,
    +            // skip rest of extra field in case it is too long
    +            unsigned int extraFieldEnd = dev->pos() + extralen;
    +            pfi.extralen = extralen;
    +            int handledextralen = qMin(extralen, (int)sizeof buffer);
    +
    +            // if (handledextralen)
    +            //    qCDebug(KArchiveLog) << "handledextralen: " << handledextralen;
    +
    +            n = dev->read(buffer, handledextralen);
    +            // no error msg necessary as we deliberately truncate the extra field
    +            if (!parseExtraField(buffer, n, true, pfi)) {
    +                setErrorString(tr("Invalid ZIP File. Broken ExtraField."));
    +                return false;
    +            }
    +
    +            // jump to end of extra field
    +            dev->seek(extraFieldEnd);
    +
    +            // we have to take care of the 'general purpose bit flag'.
    +            // if bit 3 is set, the header doesn't contain the length of
    +            // the file and we look for the signature 'PK\7\8'.
    +            if (gpf & 8) {
    +                // here we have to read through the compressed data to find
    +                // the next PKxx
    +                if (!seekToNextHeaderToken(dev, true)) {
    +                    setErrorString(tr("Could not seek to next header token"));
    +                    return false;
    +                }
    +            } else {
    +                // here we skip the compressed data and jump to the next header
    +                // qCDebug(KArchiveLog) << "general purpose bit flag indicates, that local file header contains valid size";
    +                bool foundSignature = false;
    +                // check if this could be a symbolic link
    +                if (compression_mode == NoCompression //
    +                    && uncomp_size <= max_path_len //
    +                    && uncomp_size > 0) {
    +                    // read content and store it
    +                    // If it's not a symlink, then we'll just discard the data for now.
    +                    pfi.guessed_symlink = dev->read(uncomp_size);
    +                    if (pfi.guessed_symlink.size() < uncomp_size) {
    +                        setErrorString(tr("Invalid ZIP file. Unexpected end of file. (#5)"));
    +                        return false;
    +                    }
    +                } else {
    +                    if (compr_size > dev->size()) {
    +                        // here we cannot trust the compressed size, so scan through the compressed
    +                        // data to find the next header
    +                        if (!seekToNextHeaderToken(dev, false)) {
    +                            setErrorString(tr("Could not seek to next header token"));
    +                            return false;
    +                        }
    +                        foundSignature = true;
    +                    } else {
    +                        //          qCDebug(KArchiveLog) << "before interesting dev->pos(): " << dev->pos();
    +                        const bool success = dev->seek(dev->pos() + compr_size);
    +                        if (!success) {
    +                            setErrorString(tr("Could not seek to file compressed size"));
    +                            return false;
    +                        }
    +                        /*          qCDebug(KArchiveLog) << "after interesting dev->pos(): " << dev->pos();
    +                                                if (success)
    +                                                qCDebug(KArchiveLog) << "dev->at was successful... ";
    +                                                else
    +                                                qCDebug(KArchiveLog) << "dev->at failed... ";*/
    +                    }
    +                }
    +                // test for optional data descriptor
    +                if (!foundSignature) {
    +                    //                     qCDebug(KArchiveLog) << "Testing for optional data descriptor";
    +                    // read static data descriptor
    +                    n = dev->read(buffer, 4);
    +                    if (n < 4) {
    +                        setErrorString(tr("Invalid ZIP file. Unexpected end of file. (#1)"));
    +                        return false;
    +                    }
    +
    +                    if (buffer[0] != 'P' || !handlePossibleHeaderBegin(buffer + 1, dev, false)) {
    +                        // assume data descriptor without signature
    +                        dev->seek(dev->pos() + 8); // skip rest of the 'data_descriptor'
    +                    }
    +                }
    +
    +                // not needed any more
    +                /*                // here we calculate the length of the file in the zip
    +                // with headers and jump to the next header.
    +                uint skip = compr_size + namelen + extralen;
    +                offset += 30 + skip;*/
    +            }
    +            pfi_map.insert(fileName, pfi);
    +        } else if (!memcmp(buffer, "PK\1\2", 4)) { // central block
    +            // qCDebug(KArchiveLog) << "PK12 found central block";
    +            startOfFile = false;
    +
    +            // so we reached the central header at the end of the zip file
    +            // here we get all interesting data out of the central header
    +            // of a file
    +            offset = dev->pos() - 4;
    +
    +            // set offset for appending new files
    +            if (d->m_offset == 0) {
    +                d->m_offset = offset;
    +            }
    +
    +            n = dev->read(buffer + 4, 42);
    +            if (n < 42) {
    +                setErrorString(tr("Invalid ZIP file, central entry too short (not long enough for valid entry)"));
    +                return false;
    +            }
    +
    +            // int gpf = (uchar)buffer[9] << 8 | (uchar)buffer[10];
    +            // qCDebug(KArchiveLog) << "general purpose flag=" << gpf;
    +            // length of the fileName (well, pathname indeed)
    +            int namelen = (uchar)buffer[29] << 8 | (uchar)buffer[28];
    +            if (namelen <= 0) {
    +                setErrorString(tr("Invalid ZIP file, file path name length smaller or equal to zero"));
    +                return false;
    +            }
    +            QByteArray bufferName = dev->read(namelen);
    +            if (bufferName.size() < namelen) {
    +                // qCWarning(KArchiveLog) << "Invalid ZIP file. Name not completely read";
    +            }
    +
    +            ParseFileInfo pfi = pfi_map.value(bufferName, ParseFileInfo());
    +
    +            QString name(QFile::decodeName(bufferName));
    +
    +            // qCDebug(KArchiveLog) << "name: " << name;
    +            // only in central header ! see below.
    +            // length of extra attributes
    +            int extralen = (uchar)buffer[31] << 8 | (uchar)buffer[30];
    +            // length of comment for this file
    +            int commlen = (uchar)buffer[33] << 8 | (uchar)buffer[32];
    +            // compression method of this file
    +            int cmethod = (uchar)buffer[11] << 8 | (uchar)buffer[10];
    +
    +            // qCDebug(KArchiveLog) << "cmethod: " << cmethod;
    +            // qCDebug(KArchiveLog) << "extralen: " << extralen;
    +
    +            // crc32 of the file
    +            uint crc32 = (uchar)buffer[19] << 24 | (uchar)buffer[18] << 16 | (uchar)buffer[17] << 8 | (uchar)buffer[16];
    +
    +            // uncompressed file size
    +            quint64 ucsize = uint32_t((uchar)buffer[27] << 24 | (uchar)buffer[26] << 16 | (uchar)buffer[25] << 8 | (uchar)buffer[24]);
    +            if (ucsize == 0xFFFFFFFF) {
    +                ucsize = pfi.uncompressedSize;
    +            }
    +            // compressed file size
    +            quint64 csize = uint32_t((uchar)buffer[23] << 24 | (uchar)buffer[22] << 16 | (uchar)buffer[21] << 8 | (uchar)buffer[20]);
    +            if (csize == 0xFFFFFFFF) {
    +                csize = pfi.compressedSize;
    +            }
    +
    +            // offset of local header
    +            uint localheaderoffset = (uchar)buffer[45] << 24 | (uchar)buffer[44] << 16 | (uchar)buffer[43] << 8 | (uchar)buffer[42];
    +
    +            // some clever people use different extra field lengths
    +            // in the central header and in the local header... funny.
    +            // so we need to get the localextralen to calculate the offset
    +            // from localheaderstart to dataoffset
    +            int localextralen = pfi.extralen; // FIXME: this will not work if
    +            // no local header exists
    +
    +            // qCDebug(KArchiveLog) << "localextralen: " << localextralen;
    +
    +            // offset, where the real data for uncompression starts
    +            uint dataoffset = localheaderoffset + 30 + localextralen + namelen; // comment only in central header
    +
    +            // qCDebug(KArchiveLog) << "csize: " << csize;
    +
    +            int os_madeby = (uchar)buffer[5];
    +            bool isdir = false;
    +            int access = 0100644;
    +
    +            if (os_madeby == 3) { // good ole unix
    +                access = (uchar)buffer[40] | (uchar)buffer[41] << 8;
    +            }
    +
    +            QString entryName;
    +
    +            if (name.endsWith(QLatin1Char('/'))) { // Entries with a trailing slash are directories
    +                isdir = true;
    +                name = name.left(name.length() - 1);
    +                if (os_madeby != 3) {
    +                    access = S_IFDIR | 0755;
    +                } else {
    +                    access |= S_IFDIR | 0700;
    +                }
    +            }
    +
    +            int pos = name.lastIndexOf(QLatin1Char('/'));
    +            if (pos == -1) {
    +                entryName = name;
    +            } else {
    +                entryName = name.mid(pos + 1);
    +            }
    +            if (entryName.isEmpty()) {
    +                setErrorString(tr("Invalid ZIP file, found empty entry name"));
    +                return false;
    +            }
    +
    +            KArchiveEntry *entry;
    +            if (isdir) {
    +                QString path = QDir::cleanPath(name);
    +                const KArchiveEntry *ent = rootDir()->entry(path);
    +                if (ent && ent->isDirectory()) {
    +                    // qCDebug(KArchiveLog) << "Directory already exists, NOT going to add it again";
    +                    entry = nullptr;
    +                } else {
    +                    QDateTime mtime = KArchivePrivate::time_tToDateTime(pfi.mtime);
    +                    entry = new KArchiveDirectory(this, entryName, access, mtime, rootDir()->user(), rootDir()->group(), QString());
    +                    // qCDebug(KArchiveLog) << "KArchiveDirectory created, entryName= " << entryName << ", name=" << name;
    +                }
    +            } else {
    +                QString symlink;
    +                if ((access & QT_STAT_MASK) == QT_STAT_LNK) {
    +                    symlink = QFile::decodeName(pfi.guessed_symlink);
    +                }
    +                QDateTime mtime = KArchivePrivate::time_tToDateTime(pfi.mtime);
    +                entry =
    +                    new KZipFileEntry(this, entryName, access, mtime, rootDir()->user(), rootDir()->group(), symlink, name, dataoffset, ucsize, cmethod, csize);
    +                static_cast(entry)->setHeaderStart(localheaderoffset);
    +                static_cast(entry)->setCRC32(crc32);
    +                // qCDebug(KArchiveLog) << "KZipFileEntry created, entryName= " << entryName << ", name=" << name;
    +                d->m_fileList.append(static_cast(entry));
    +            }
    +
    +            if (entry) {
    +                if (pos == -1) {
    +                    rootDir()->addEntry(entry);
    +                } else {
    +                    // In some tar files we can find dir/./file => call cleanPath
    +                    QString path = QDir::cleanPath(name.left(pos));
    +                    // Ensure container directory exists, create otherwise
    +                    KArchiveDirectory *tdir = findOrCreate(path);
    +                    if (tdir) {
    +                        tdir->addEntry(entry);
    +                    } else {
    +                        setErrorString(tr("File %1 is in folder %2, but %3 is actually a file.").arg(entryName, path, path));
    +                        delete entry;
    +                        return false;
    +                    }
    +                }
    +            }
    +
    +            // calculate offset to next entry
    +            offset += 46 + commlen + extralen + namelen;
    +            const bool b = dev->seek(offset);
    +            if (!b) {
    +                setErrorString(tr("Could not seek to next entry"));
    +                return false;
    +            }
    +        } else if (startOfFile) {
    +            // The file does not start with any ZIP header (e.g. self-extractable ZIP files)
    +            // Therefore we need to find the first PK\003\004 (local header)
    +            // qCDebug(KArchiveLog) << "Try to skip start of file";
    +            startOfFile = false;
    +            bool foundSignature = false;
    +
    +            while (!foundSignature) {
    +                n = dev->read(buffer, 1);
    +                if (n < 1) {
    +                    setErrorString(tr("Invalid ZIP file. Unexpected end of file."));
    +                    return false;
    +                }
    +
    +                if (buffer[0] != 'P') {
    +                    continue;
    +                }
    +
    +                n = dev->read(buffer, 3);
    +                if (n < 3) {
    +                    setErrorString(tr("Invalid ZIP file. Unexpected end of file."));
    +                    return false;
    +                }
    +
    +                // We have to detect the magic token for a local header: PK\003\004
    +                /*
    +                 * Note: we do not need to check the other magics, if the ZIP file has no
    +                 * local header, then it has not any files!
    +                 */
    +                if (buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4) {
    +                    foundSignature = true;
    +                    dev->seek(dev->pos() - 4); // go back 4 bytes, so that the magic bytes can be found...
    +                } else {
    +                    for (int i = 0; i < 3; ++i) {
    +                        if (buffer[i] == 'P') {
    +                            // We have another P character so we must go back a little to check if it is a magic
    +                            dev->seek(dev->pos() - 3 + i);
    +                            break;
    +                        }
    +                    }
    +                }
    +            }
    +        } else {
    +            setErrorString(tr("Invalid ZIP file. Unrecognized header at offset %1").arg(dev->pos() - 4));
    +            return false;
    +        }
    +    }
    +    // qCDebug(KArchiveLog) << "*** done *** ";
    +    return true;
    +}
    +
    +bool KZip::closeArchive()
    +{
    +    if (!(mode() & QIODevice::WriteOnly)) {
    +        // qCDebug(KArchiveLog) << "readonly";
    +        return true;
    +    }
    +
    +    // ReadWrite or WriteOnly
    +    // write all central dir file entries
    +
    +    // to be written at the end of the file...
    +    char buffer[22]; // first used for 12, then for 22 at the end
    +    uLong crc = crc32(0L, nullptr, 0);
    +
    +    qint64 centraldiroffset = device()->pos();
    +    // qCDebug(KArchiveLog) << "closearchive: centraldiroffset: " << centraldiroffset;
    +    qint64 atbackup = centraldiroffset;
    +    QMutableListIterator it(d->m_fileList);
    +
    +    while (it.hasNext()) {
    +        // set crc and compressed size in each local file header
    +        it.next();
    +        if (!device()->seek(it.value()->headerStart() + 14)) {
    +            setErrorString(tr("Could not seek to next file header: %1").arg(device()->errorString()));
    +            return false;
    +        }
    +        // qCDebug(KArchiveLog) << "closearchive setcrcandcsize: fileName:"
    +        //    << it.value()->path()
    +        //    << "encoding:" << it.value()->encoding();
    +
    +        uLong mycrc = it.value()->crc32();
    +        buffer[0] = char(mycrc); // crc checksum, at headerStart+14
    +        buffer[1] = char(mycrc >> 8);
    +        buffer[2] = char(mycrc >> 16);
    +        buffer[3] = char(mycrc >> 24);
    +
    +        int mysize1 = it.value()->compressedSize();
    +        buffer[4] = char(mysize1); // compressed file size, at headerStart+18
    +        buffer[5] = char(mysize1 >> 8);
    +        buffer[6] = char(mysize1 >> 16);
    +        buffer[7] = char(mysize1 >> 24);
    +
    +        int myusize = it.value()->size();
    +        buffer[8] = char(myusize); // uncompressed file size, at headerStart+22
    +        buffer[9] = char(myusize >> 8);
    +        buffer[10] = char(myusize >> 16);
    +        buffer[11] = char(myusize >> 24);
    +
    +        if (device()->write(buffer, 12) != 12) {
    +            setErrorString(tr("Could not write file header: %1").arg(device()->errorString()));
    +            return false;
    +        }
    +    }
    +    device()->seek(atbackup);
    +
    +    it.toFront();
    +    while (it.hasNext()) {
    +        it.next();
    +        // qCDebug(KArchiveLog) << "fileName:" << it.value()->path()
    +        //              << "encoding:" << it.value()->encoding();
    +
    +        QByteArray path = QFile::encodeName(it.value()->path());
    +
    +        const int extra_field_len = (d->m_extraField == ModificationTime) ? 9 : 0;
    +        const int bufferSize = extra_field_len + path.length() + 46;
    +        char *buffer = new char[bufferSize];
    +
    +        memset(buffer, 0, 46); // zero is a nice default for most header fields
    +
    +        /* clang-format off */
    +        const char head[] = {
    +            'P', 'K', 1, 2, // central file header signature
    +            0x14, 3, // version made by (3 == UNIX)
    +            0x14, 0 // version needed to extract
    +        };
    +        /* clang-format on */
    +
    +        // I do not know why memcpy is not working here
    +        // memcpy(buffer, head, sizeof(head));
    +        memmove(buffer, head, sizeof(head));
    +
    +        buffer[10] = char(it.value()->encoding()); // compression method
    +        buffer[11] = char(it.value()->encoding() >> 8);
    +
    +        transformToMsDos(it.value()->date(), &buffer[12]);
    +
    +        uLong mycrc = it.value()->crc32();
    +        buffer[16] = char(mycrc); // crc checksum
    +        buffer[17] = char(mycrc >> 8);
    +        buffer[18] = char(mycrc >> 16);
    +        buffer[19] = char(mycrc >> 24);
    +
    +        int mysize1 = it.value()->compressedSize();
    +        buffer[20] = char(mysize1); // compressed file size
    +        buffer[21] = char(mysize1 >> 8);
    +        buffer[22] = char(mysize1 >> 16);
    +        buffer[23] = char(mysize1 >> 24);
    +
    +        int mysize = it.value()->size();
    +        buffer[24] = char(mysize); // uncompressed file size
    +        buffer[25] = char(mysize >> 8);
    +        buffer[26] = char(mysize >> 16);
    +        buffer[27] = char(mysize >> 24);
    +
    +        buffer[28] = char(path.length()); // fileName length
    +        buffer[29] = char(path.length() >> 8);
    +
    +        buffer[30] = char(extra_field_len);
    +        buffer[31] = char(extra_field_len >> 8);
    +
    +        buffer[40] = char(it.value()->permissions());
    +        buffer[41] = char(it.value()->permissions() >> 8);
    +
    +        int myhst = it.value()->headerStart();
    +        buffer[42] = char(myhst); // relative offset of local header
    +        buffer[43] = char(myhst >> 8);
    +        buffer[44] = char(myhst >> 16);
    +        buffer[45] = char(myhst >> 24);
    +
    +        // file name
    +        strncpy(buffer + 46, path.constData(), path.length());
    +        // qCDebug(KArchiveLog) << "closearchive length to write: " << bufferSize;
    +
    +        // extra field
    +        if (d->m_extraField == ModificationTime) {
    +            char *extfield = buffer + 46 + path.length();
    +            // "Extended timestamp" header (0x5455)
    +            extfield[0] = 'U';
    +            extfield[1] = 'T';
    +            extfield[2] = 5; // data size
    +            extfield[3] = 0;
    +            extfield[4] = 1 | 2 | 4; // specify flags from local field
    +            // (unless I misread the spec)
    +            // provide only modification time
    +            unsigned long time = (unsigned long)it.value()->date().toSecsSinceEpoch();
    +            extfield[5] = char(time);
    +            extfield[6] = char(time >> 8);
    +            extfield[7] = char(time >> 16);
    +            extfield[8] = char(time >> 24);
    +        }
    +
    +        crc = crc32(crc, (Bytef *)buffer, bufferSize);
    +        bool ok = (device()->write(buffer, bufferSize) == bufferSize);
    +        delete[] buffer;
    +        if (!ok) {
    +            setErrorString(tr("Could not write file header: %1").arg(device()->errorString()));
    +            return false;
    +        }
    +    }
    +    qint64 centraldirendoffset = device()->pos();
    +    // qCDebug(KArchiveLog) << "closearchive: centraldirendoffset: " << centraldirendoffset;
    +    // qCDebug(KArchiveLog) << "closearchive: device()->pos(): " << device()->pos();
    +
    +    // write end of central dir record.
    +    buffer[0] = 'P'; // end of central dir signature
    +    buffer[1] = 'K';
    +    buffer[2] = 5;
    +    buffer[3] = 6;
    +
    +    buffer[4] = 0; // number of this disk
    +    buffer[5] = 0;
    +
    +    buffer[6] = 0; // number of disk with start of central dir
    +    buffer[7] = 0;
    +
    +    int count = d->m_fileList.count();
    +    // qCDebug(KArchiveLog) << "number of files (count): " << count;
    +
    +    buffer[8] = char(count); // total number of entries in central dir of
    +    buffer[9] = char(count >> 8); // this disk
    +
    +    buffer[10] = buffer[8]; // total number of entries in the central dir
    +    buffer[11] = buffer[9];
    +
    +    int cdsize = centraldirendoffset - centraldiroffset;
    +    buffer[12] = char(cdsize); // size of the central dir
    +    buffer[13] = char(cdsize >> 8);
    +    buffer[14] = char(cdsize >> 16);
    +    buffer[15] = char(cdsize >> 24);
    +
    +    // qCDebug(KArchiveLog) << "end : centraldiroffset: " << centraldiroffset;
    +    // qCDebug(KArchiveLog) << "end : centraldirsize: " << cdsize;
    +
    +    buffer[16] = char(centraldiroffset); // central dir offset
    +    buffer[17] = char(centraldiroffset >> 8);
    +    buffer[18] = char(centraldiroffset >> 16);
    +    buffer[19] = char(centraldiroffset >> 24);
    +
    +    buffer[20] = 0; // zipfile comment length
    +    buffer[21] = 0;
    +
    +    if (device()->write(buffer, 22) != 22) {
    +        setErrorString(tr("Could not write central dir record: %1").arg(device()->errorString()));
    +        return false;
    +    }
    +
    +    return true;
    +}
    +
    +bool KZip::doWriteDir(const QString &name,
    +                      const QString &user,
    +                      const QString &group,
    +                      mode_t perm,
    +                      const QDateTime &atime,
    +                      const QDateTime &mtime,
    +                      const QDateTime &ctime)
    +{
    +    // Zip files have no explicit directories, they are implicitly created during extraction time
    +    // when file entries have paths in them.
    +    // However, to support empty directories, we must create a dummy file entry which ends with '/'.
    +    QString dirName = name;
    +    if (!name.endsWith(QLatin1Char('/'))) {
    +        dirName = dirName.append(QLatin1Char('/'));
    +    }
    +    return writeFile(dirName, QByteArrayView(), perm, user, group, atime, mtime, ctime);
    +}
    +
    +bool KZip::doPrepareWriting(const QString &name,
    +                            const QString &user,
    +                            const QString &group,
    +                            qint64 /*size*/,
    +                            mode_t perm,
    +                            const QDateTime &accessTime,
    +                            const QDateTime &modificationTime,
    +                            const QDateTime &creationTime)
    +{
    +    // qCDebug(KArchiveLog);
    +    if (!isOpen()) {
    +        setErrorString(tr("Application error: ZIP file must be open before being written into"));
    +        qCWarning(KArchiveLog) << "doPrepareWriting failed: !isOpen()";
    +        return false;
    +    }
    +
    +    if (!(mode() & QIODevice::WriteOnly)) { // accept WriteOnly and ReadWrite
    +        setErrorString(tr("Application error: attempted to write into non-writable ZIP file"));
    +        qCWarning(KArchiveLog) << "doPrepareWriting failed: !(mode() & QIODevice::WriteOnly)";
    +        return false;
    +    }
    +
    +    if (!device()) {
    +        setErrorString(tr("Cannot create a device. Disk full?"));
    +        return false;
    +    }
    +
    +    // set right offset in zip.
    +    if (!device()->seek(d->m_offset)) {
    +        setErrorString(tr("Cannot seek in ZIP file. Disk full?"));
    +        return false;
    +    }
    +
    +    uint atime = accessTime.toSecsSinceEpoch();
    +    uint mtime = modificationTime.toSecsSinceEpoch();
    +    uint ctime = creationTime.toSecsSinceEpoch();
    +
    +    // Find or create parent dir
    +    KArchiveDirectory *parentDir = rootDir();
    +    QString fileName(name);
    +    int i = name.lastIndexOf(QLatin1Char('/'));
    +    if (i != -1) {
    +        QString dir = name.left(i);
    +        fileName = name.mid(i + 1);
    +        // qCDebug(KArchiveLog) << "ensuring" << dir << "exists. fileName=" << fileName;
    +        parentDir = findOrCreate(dir);
    +    }
    +
    +    // delete entries in the filelist with the same fileName as the one we want
    +    // to save, so that we don't have duplicate file entries when viewing the zip
    +    // with konqi...
    +    // CAUTION: the old file itself is still in the zip and won't be removed !!!
    +    QMutableListIterator it(d->m_fileList);
    +    // qCDebug(KArchiveLog) << "fileName to write: " << name;
    +    while (it.hasNext()) {
    +        it.next();
    +        // qCDebug(KArchiveLog) << "prepfileName: " << it.value()->path();
    +        if (name == it.value()->path()) {
    +            // also remove from the parentDir
    +            parentDir->removeEntry(it.value());
    +            // qCDebug(KArchiveLog) << "removing following entry: " << it.value()->path();
    +            delete it.value();
    +            it.remove();
    +        }
    +    }
    +
    +    // construct a KZipFileEntry and add it to list
    +    KZipFileEntry *e = new KZipFileEntry(this,
    +                                         fileName,
    +                                         perm,
    +                                         modificationTime,
    +                                         user,
    +                                         group,
    +                                         QString(),
    +                                         name,
    +                                         device()->pos() + 30 + name.length(), // start
    +                                         0 /*size unknown yet*/,
    +                                         d->m_compression,
    +                                         0 /*csize unknown yet*/);
    +    e->setHeaderStart(device()->pos());
    +    // qCDebug(KArchiveLog) << "wrote file start: " << e->position() << " name: " << name;
    +    if (!parentDir->addEntryV2(e)) {
    +        return false;
    +    }
    +
    +    d->m_currentFile = e;
    +    d->m_fileList.append(e);
    +
    +    int extra_field_len = 0;
    +    if (d->m_extraField == ModificationTime) {
    +        extra_field_len = 17; // value also used in finishWriting()
    +    }
    +
    +    // write out zip header
    +    QByteArray encodedName = QFile::encodeName(name);
    +    int bufferSize = extra_field_len + encodedName.length() + 30;
    +    // qCDebug(KArchiveLog) << "bufferSize=" << bufferSize;
    +    char *buffer = new char[bufferSize];
    +
    +    buffer[0] = 'P'; // local file header signature
    +    buffer[1] = 'K';
    +    buffer[2] = 3;
    +    buffer[3] = 4;
    +
    +    buffer[4] = 0x14; // version needed to extract
    +    buffer[5] = 0;
    +
    +    buffer[6] = 0; // general purpose bit flag
    +    buffer[7] = 0;
    +
    +    buffer[8] = char(e->encoding()); // compression method
    +    buffer[9] = char(e->encoding() >> 8);
    +
    +    transformToMsDos(e->date(), &buffer[10]);
    +
    +    buffer[14] = 'C'; // dummy crc
    +    buffer[15] = 'R';
    +    buffer[16] = 'C';
    +    buffer[17] = 'q';
    +
    +    buffer[18] = 'C'; // compressed file size
    +    buffer[19] = 'S';
    +    buffer[20] = 'I';
    +    buffer[21] = 'Z';
    +
    +    buffer[22] = 'U'; // uncompressed file size
    +    buffer[23] = 'S';
    +    buffer[24] = 'I';
    +    buffer[25] = 'Z';
    +
    +    buffer[26] = (uchar)(encodedName.length()); // fileName length
    +    buffer[27] = (uchar)(encodedName.length() >> 8);
    +
    +    buffer[28] = (uchar)(extra_field_len); // extra field length
    +    buffer[29] = (uchar)(extra_field_len >> 8);
    +
    +    // file name
    +    strncpy(buffer + 30, encodedName.constData(), encodedName.length());
    +
    +    // extra field
    +    if (d->m_extraField == ModificationTime) {
    +        char *extfield = buffer + 30 + encodedName.length();
    +        // "Extended timestamp" header (0x5455)
    +        extfield[0] = 'U';
    +        extfield[1] = 'T';
    +        extfield[2] = 13; // data size
    +        extfield[3] = 0;
    +        extfield[4] = 1 | 2 | 4; // contains mtime, atime, ctime
    +
    +        extfield[5] = char(mtime);
    +        extfield[6] = char(mtime >> 8);
    +        extfield[7] = char(mtime >> 16);
    +        extfield[8] = char(mtime >> 24);
    +
    +        extfield[9] = char(atime);
    +        extfield[10] = char(atime >> 8);
    +        extfield[11] = char(atime >> 16);
    +        extfield[12] = char(atime >> 24);
    +
    +        extfield[13] = char(ctime);
    +        extfield[14] = char(ctime >> 8);
    +        extfield[15] = char(ctime >> 16);
    +        extfield[16] = char(ctime >> 24);
    +    }
    +
    +    // Write header
    +    bool b = (device()->write(buffer, bufferSize) == bufferSize);
    +    d->m_crc = 0;
    +    delete[] buffer;
    +
    +    if (!b) {
    +        setErrorString(tr("Could not write to the archive. Disk full?"));
    +        return false;
    +    }
    +
    +    // Prepare device for writing the data
    +    // Either device() if no compression, or a KCompressionDevice to compress
    +    if (d->m_compression == 0) {
    +        d->m_currentDev = device();
    +        return true;
    +    }
    +
    +    auto compressionDevice = new KCompressionDevice(device(), false, KCompressionDevice::GZip);
    +    d->m_currentDev = compressionDevice;
    +    compressionDevice->setSkipHeaders(); // Just zlib, not gzip
    +
    +    b = d->m_currentDev->open(QIODevice::WriteOnly);
    +    Q_ASSERT(b);
    +
    +    if (!b) {
    +        setErrorString(tr("Could not open compression device: %1").arg(d->m_currentDev->errorString()));
    +    }
    +
    +    return b;
    +}
    +
    +bool KZip::doFinishWriting(qint64 size)
    +{
    +    if (d->m_currentFile->encoding() == 8) {
    +        // Finish
    +        (void)d->m_currentDev->write(nullptr, 0);
    +        delete d->m_currentDev;
    +    }
    +    // If 0, d->m_currentDev was device() - don't delete ;)
    +    d->m_currentDev = nullptr;
    +
    +    Q_ASSERT(d->m_currentFile);
    +    // qCDebug(KArchiveLog) << "fileName: " << d->m_currentFile->path();
    +    // qCDebug(KArchiveLog) << "getpos (at): " << device()->pos();
    +    d->m_currentFile->setSize(size);
    +    int extra_field_len = 0;
    +    if (d->m_extraField == ModificationTime) {
    +        extra_field_len = 17; // value also used in finishWriting()
    +    }
    +
    +    const QByteArray encodedName = QFile::encodeName(d->m_currentFile->path());
    +    int csize = device()->pos() - d->m_currentFile->headerStart() - 30 - encodedName.length() - extra_field_len;
    +    d->m_currentFile->setCompressedSize(csize);
    +    // qCDebug(KArchiveLog) << "usize: " << d->m_currentFile->size();
    +    // qCDebug(KArchiveLog) << "csize: " << d->m_currentFile->compressedSize();
    +    // qCDebug(KArchiveLog) << "headerstart: " << d->m_currentFile->headerStart();
    +
    +    // qCDebug(KArchiveLog) << "crc: " << d->m_crc;
    +    d->m_currentFile->setCRC32(d->m_crc);
    +
    +    d->m_currentFile = nullptr;
    +
    +    // update saved offset for appending new files
    +    d->m_offset = device()->pos();
    +    return true;
    +}
    +
    +bool KZip::doWriteSymLink(const QString &name,
    +                          const QString &target,
    +                          const QString &user,
    +                          const QString &group,
    +                          mode_t perm,
    +                          const QDateTime &atime,
    +                          const QDateTime &mtime,
    +                          const QDateTime &ctime)
    +{
    +    // reassure that symlink flag is set, otherwise strange things happen on
    +    // extraction
    +    perm |= QT_STAT_LNK;
    +    Compression c = compression();
    +    setCompression(NoCompression); // link targets are never compressed
    +
    +    if (!doPrepareWriting(name, user, group, 0, perm, atime, mtime, ctime)) {
    +        setCompression(c);
    +        return false;
    +    }
    +
    +    QByteArray symlink_target = QFile::encodeName(target);
    +    if (!writeData(symlink_target.constData(), symlink_target.length())) {
    +        setCompression(c);
    +        return false;
    +    }
    +
    +    if (!finishWriting(symlink_target.length())) {
    +        setCompression(c);
    +        return false;
    +    }
    +
    +    setCompression(c);
    +    return true;
    +}
    +
    +void KZip::virtual_hook(int id, void *data)
    +{
    +    KArchive::virtual_hook(id, data);
    +}
    +
    +bool KZip::doWriteData(const char *data, qint64 size)
    +{
    +    Q_ASSERT(d->m_currentFile);
    +    Q_ASSERT(d->m_currentDev);
    +    if (!d->m_currentFile || !d->m_currentDev) {
    +        setErrorString(tr("No file or device"));
    +        return false;
    +    }
    +
    +    // crc to be calculated over uncompressed stuff...
    +    // and they didn't mention it in their docs...
    +    d->m_crc = crc32(d->m_crc, (const Bytef *)data, size);
    +
    +    qint64 written = d->m_currentDev->write(data, size);
    +    // qCDebug(KArchiveLog) << "wrote" << size << "bytes.";
    +    const bool ok = written == size;
    +
    +    if (!ok) {
    +        setErrorString(tr("Error writing data: %1").arg(d->m_currentDev->errorString()));
    +    }
    +
    +    return ok;
    +}
    +
    +void KZip::setCompression(Compression c)
    +{
    +    d->m_compression = (c == NoCompression) ? 0 : 8;
    +}
    +
    +KZip::Compression KZip::compression() const
    +{
    +    return (d->m_compression == 8) ? DeflateCompression : NoCompression;
    +}
    +
    +void KZip::setExtraField(ExtraField ef)
    +{
    +    d->m_extraField = ef;
    +}
    +
    +KZip::ExtraField KZip::extraField() const
    +{
    +    return d->m_extraField;
    +}
    +
    +////////////////////////////////////////////////////////////////////////
    +////////////////////// KZipFileEntry////////////////////////////////////
    +////////////////////////////////////////////////////////////////////////
    +class Q_DECL_HIDDEN KZipFileEntry::KZipFileEntryPrivate
    +{
    +public:
    +    KZipFileEntryPrivate()
    +        : crc(0)
    +        , compressedSize(0)
    +        , headerStart(0)
    +        , encoding(0)
    +    {
    +    }
    +    unsigned long crc;
    +    qint64 compressedSize;
    +    qint64 headerStart;
    +    int encoding;
    +    QString path;
    +};
    +
    +KZipFileEntry::KZipFileEntry(KZip *zip,
    +                             const QString &name,
    +                             int access,
    +                             const QDateTime &date,
    +                             const QString &user,
    +                             const QString &group,
    +                             const QString &symlink,
    +                             const QString &path,
    +                             qint64 start,
    +                             qint64 uncompressedSize,
    +                             int encoding,
    +                             qint64 compressedSize)
    +    : KArchiveFile(zip, name, access, date, user, group, symlink, start, uncompressedSize)
    +    , d(new KZipFileEntryPrivate)
    +{
    +    d->path = path;
    +    d->encoding = encoding;
    +    d->compressedSize = compressedSize;
    +}
    +
    +KZipFileEntry::~KZipFileEntry()
    +{
    +    delete d;
    +}
    +
    +int KZipFileEntry::encoding() const
    +{
    +    return d->encoding;
    +}
    +
    +qint64 KZipFileEntry::compressedSize() const
    +{
    +    return d->compressedSize;
    +}
    +
    +void KZipFileEntry::setCompressedSize(qint64 compressedSize)
    +{
    +    d->compressedSize = compressedSize;
    +}
    +
    +void KZipFileEntry::setHeaderStart(qint64 headerstart)
    +{
    +    d->headerStart = headerstart;
    +}
    +
    +qint64 KZipFileEntry::headerStart() const
    +{
    +    return d->headerStart;
    +}
    +
    +unsigned long KZipFileEntry::crc32() const
    +{
    +    return d->crc;
    +}
    +
    +void KZipFileEntry::setCRC32(unsigned long crc32)
    +{
    +    d->crc = crc32;
    +}
    +
    +const QString &KZipFileEntry::path() const
    +{
    +    return d->path;
    +}
    +
    +QByteArray KZipFileEntry::data() const
    +{
    +    QIODevice *dev = createDevice();
    +    QByteArray arr;
    +    if (dev) {
    +        arr = dev->readAll();
    +        delete dev;
    +    }
    +    return arr;
    +}
    +
    +QIODevice *KZipFileEntry::createDevice() const
    +{
    +    // qCDebug(KArchiveLog) << "creating iodevice limited to pos=" << position() << ", csize=" << compressedSize();
    +    // Limit the reading to the appropriate part of the underlying device (e.g. file)
    +    KLimitedIODevice *limitedDev = new KLimitedIODevice(archive()->device(), position(), compressedSize());
    +    if (encoding() == 0 || compressedSize() == 0) { // no compression (or even no data)
    +        return limitedDev;
    +    }
    +
    +    if (encoding() == 8) {
    +        // On top of that, create a device that uncompresses the zlib data
    +        KCompressionDevice *filterDev = new KCompressionDevice(limitedDev, true, KCompressionDevice::GZip);
    +
    +        if (!filterDev) {
    +            return nullptr; // ouch
    +        }
    +        filterDev->setSkipHeaders(); // Just zlib, not gzip
    +        bool b = filterDev->open(QIODevice::ReadOnly);
    +        Q_UNUSED(b);
    +        Q_ASSERT(b);
    +        return filterDev;
    +    }
    +
    +    qCCritical(KArchiveLog) << "This zip file contains files compressed with method" << encoding() << ", this method is currently not supported by KZip,"
    +                            << "please use a command-line tool to handle this file.";
    +    delete limitedDev;
    +    return nullptr;
    +}
    diff --git a/src/libs/3rdparty/karchive/src/kzip.h b/src/libs/3rdparty/karchive/src/kzip.h
    new file mode 100644
    index 00000000000..da84285ba9a
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kzip.h
    @@ -0,0 +1,178 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2002 Holger Schroeder 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +#ifndef KZIP_H
    +#define KZIP_H
    +
    +#include "karchive.h"
    +
    +#include "kzipfileentry.h" // for source compat
    +
    +class KZipFileEntry;
    +/**
    + *   @class KZip zip.h KZip
    + *
    + *   A class for reading / writing zip archives.
    + *
    + *   You can use it in QIODevice::ReadOnly or in QIODevice::WriteOnly mode, and it
    + *   behaves just as expected.
    + *   It can also be used in QIODevice::ReadWrite mode, in this case one can
    + *   append files to an existing zip archive. When you append new files, which
    + *   are not yet in the zip, it works as expected, i.e. the files are appended at the end.
    + *   When you append a file, which is already in the file, the reference to the
    + *   old file is dropped and the new one is added to the zip - but the
    + *   old data from the file itself is not deleted, it is still in the
    + *   zipfile. So when you want to have a small and garbage-free zipfile,
    + *   just read the contents of the appended zip file and write it to a new one
    + *   in QIODevice::WriteOnly mode. This is especially important when you don't want
    + *   to leak information of how intermediate versions of files in the zip
    + *   were looking.
    + *
    + *   For more information on the zip fileformat go to
    + *   http://www.pkware.com/products/enterprise/white_papers/appnote.html
    + * @author Holger Schroeder 
    + */
    +class KARCHIVE_EXPORT KZip : public KArchive
    +{
    +    Q_DECLARE_TR_FUNCTIONS(KZip)
    +
    +public:
    +    /**
    +     * Creates an instance that operates on the given filename.
    +     * using the compression filter associated to given mimetype.
    +     *
    +     * @param filename is a local path (e.g. "/home/holger/myfile.zip")
    +     */
    +    explicit KZip(const QString &filename);
    +
    +    /**
    +     * Creates an instance that operates on the given device.
    +     * The device can be compressed (KCompressionDevice) or not (QFile, etc.).
    +     * @warning Do not assume that giving a QFile here will decompress the file,
    +     * in case it's compressed!
    +     * @param dev the device to access
    +     */
    +    explicit KZip(QIODevice *dev);
    +
    +    /**
    +     * If the zip file is still opened, then it will be
    +     * closed automatically by the destructor.
    +     */
    +    ~KZip() override;
    +
    +    /**
    +     * Describes the contents of the "extra field" for a given file in the Zip archive.
    +     */
    +    enum ExtraField {
    +        NoExtraField = 0,      ///< No extra field
    +        ModificationTime = 1,  ///< Modification time ("extended timestamp" header)
    +        DefaultExtraField = 1, // alias of ModificationTime
    +    };
    +
    +    /**
    +     * Call this before writeFile or prepareWriting, to define what the next
    +     * file to be written should have in its extra field.
    +     * @param ef the type of "extra field"
    +     * @see extraField()
    +     */
    +    void setExtraField(ExtraField ef);
    +
    +    /**
    +     * The current type of "extra field" that will be used for new files.
    +     * @return the current type of "extra field"
    +     * @see setExtraField()
    +     */
    +    ExtraField extraField() const;
    +
    +    /**
    +     * Describes the compression type for a given file in the Zip archive.
    +     */
    +    enum Compression {
    +        NoCompression = 0,      ///< Uncompressed.
    +        DeflateCompression = 1, ///< Deflate compression method.
    +    };
    +
    +    /**
    +     * Call this before writeFile or prepareWriting, to define whether the next
    +     * files to be written should be compressed or not.
    +     * @param c the new compression mode
    +     * @see compression()
    +     */
    +    void setCompression(Compression c);
    +
    +    /**
    +     * The current compression mode that will be used for new files.
    +     * @return the current compression mode
    +     * @see setCompression()
    +     */
    +    Compression compression() const;
    +
    +protected:
    +    /// Reimplemented from KArchive
    +    bool doWriteSymLink(
    +        const QString &name,
    +        const QString &target,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +    /// Reimplemented from KArchive
    +    bool doPrepareWriting(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        qint64 size,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &creationTime) override;
    +
    +    /**
    +     * Write data to a file that has been created using prepareWriting().
    +     * @param size the size of the file
    +     * @return true if successful, false otherwise
    +     */
    +    bool doFinishWriting(qint64 size) override;
    +
    +    /**
    +     * Write data to a file that has been created using prepareWriting().
    +     * @param data a pointer to the data
    +     * @param size the size of the chunk
    +     * @return true if successful, false otherwise
    +     */
    +    bool doWriteData(const char *data, qint64 size) override;
    +
    +    /**
    +     * Opens the archive for reading.
    +     * Parses the directory listing of the archive
    +     * and creates the KArchiveDirectory/KArchiveFile entries.
    +     * @param mode the mode of the file
    +     */
    +    bool openArchive(QIODevice::OpenMode mode) override;
    +
    +    /// Closes the archive
    +    bool closeArchive() override;
    +
    +    /// Reimplemented from KArchive
    +    bool doWriteDir(
    +        const QString &name,
    +        const QString &user,
    +        const QString &group,
    +        mode_t perm,
    +        const QDateTime &atime,
    +        const QDateTime &mtime,
    +        const QDateTime &ctime) override;
    +
    +protected:
    +    void virtual_hook(int id, void *data) override;
    +
    +private:
    +    class KZipPrivate;
    +    KZipPrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kzipfileentry.h b/src/libs/3rdparty/karchive/src/kzipfileentry.h
    new file mode 100644
    index 00000000000..c7c74e59561
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kzipfileentry.h
    @@ -0,0 +1,79 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2002 Holger Schroeder 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#ifndef KZIPFILEENTRY_H
    +#define KZIPFILEENTRY_H
    +
    +#include "karchive.h"
    +
    +class KZip;
    +/**
    + * @class KZipFileEntry kzipfileentry.h KZipFileEntry
    + *
    + * A KZipFileEntry represents a file in a zip archive.
    + */
    +class KARCHIVE_EXPORT KZipFileEntry : public KArchiveFile
    +{
    +public:
    +    /**
    +     * Creates a new zip file entry. Do not call this, KZip takes care of it.
    +     */
    +    KZipFileEntry(KZip *zip,
    +                  const QString &name,
    +                  int access,
    +                  const QDateTime &date,
    +                  const QString &user,
    +                  const QString &group,
    +                  const QString &symlink,
    +                  const QString &path,
    +                  qint64 start,
    +                  qint64 uncompressedSize,
    +                  int encoding,
    +                  qint64 compressedSize);
    +
    +    /**
    +     * Destructor. Do not call this.
    +     */
    +    ~KZipFileEntry() override;
    +
    +    int encoding() const;
    +    qint64 compressedSize() const;
    +
    +    /// Only used when writing
    +    void setCompressedSize(qint64 compressedSize);
    +
    +    /// Header start: only used when writing
    +    void setHeaderStart(qint64 headerstart);
    +    qint64 headerStart() const;
    +
    +    /// CRC: only used when writing
    +    unsigned long crc32() const;
    +    void setCRC32(unsigned long crc32);
    +
    +    /// Name with complete path - KArchiveFile::name() is the filename only (no path)
    +    const QString &path() const;
    +
    +    /**
    +     * @return the content of this file.
    +     * Call data() with care (only once per file), this data isn't cached.
    +     */
    +    QByteArray data() const override;
    +
    +    /**
    +     * This method returns a QIODevice to read the file contents.
    +     * This is obviously for reading only.
    +     * Note that the ownership of the device is being transferred to the caller,
    +     * who will have to delete it.
    +     * The returned device auto-opens (in readonly mode), no need to open it.
    +     */
    +    QIODevice *createDevice() const override;
    +
    +private:
    +    class KZipFileEntryPrivate;
    +    KZipFileEntryPrivate *const d;
    +};
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kzstdfilter.cpp b/src/libs/3rdparty/karchive/src/kzstdfilter.cpp
    new file mode 100644
    index 00000000000..cf28368a5b8
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kzstdfilter.cpp
    @@ -0,0 +1,134 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2021 Albert Astals Cid 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#include "kzstdfilter.h"
    +#include "loggingcategory.h"
    +
    +#include 
    +
    +#if HAVE_ZSTD_SUPPORT
    +
    +extern "C" {
    +#include 
    +}
    +
    +class Q_DECL_HIDDEN KZstdFilter::Private
    +{
    +public:
    +    union {
    +        ZSTD_CStream *cStream;
    +        ZSTD_DStream *dStream;
    +    };
    +    int mode;
    +    bool isInitialized = false;
    +    ZSTD_inBuffer inBuffer;
    +    ZSTD_outBuffer outBuffer;
    +};
    +
    +KZstdFilter::KZstdFilter()
    +    : d(new Private)
    +{
    +}
    +
    +KZstdFilter::~KZstdFilter()
    +{
    +}
    +
    +bool KZstdFilter::init(int mode)
    +{
    +    if (d->isInitialized) {
    +        terminate();
    +    }
    +
    +    d->inBuffer.size = 0;
    +    d->inBuffer.pos = 0;
    +
    +    if (mode == QIODevice::ReadOnly) {
    +        d->dStream = ZSTD_createDStream();
    +    } else if (mode == QIODevice::WriteOnly) {
    +        d->cStream = ZSTD_createCStream();
    +    } else {
    +        // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
    +        return false;
    +    }
    +    d->mode = mode;
    +    d->isInitialized = true;
    +    return true;
    +}
    +
    +int KZstdFilter::mode() const
    +{
    +    return d->mode;
    +}
    +
    +bool KZstdFilter::terminate()
    +{
    +    if (d->mode == QIODevice::ReadOnly) {
    +        ZSTD_freeDStream(d->dStream);
    +    } else if (d->mode == QIODevice::WriteOnly) {
    +        ZSTD_freeCStream(d->cStream);
    +    } else {
    +        // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
    +        return false;
    +    }
    +    d->isInitialized = false;
    +    return true;
    +}
    +
    +void KZstdFilter::reset()
    +{
    +    terminate();
    +    init(d->mode);
    +}
    +
    +void KZstdFilter::setOutBuffer(char *data, uint maxlen)
    +{
    +    d->outBuffer.dst = data;
    +    d->outBuffer.size = maxlen;
    +    d->outBuffer.pos = 0;
    +}
    +
    +void KZstdFilter::setInBuffer(const char *data, unsigned int size)
    +{
    +    d->inBuffer.src = data;
    +    d->inBuffer.size = size;
    +    d->inBuffer.pos = 0;
    +}
    +
    +int KZstdFilter::inBufferAvailable() const
    +{
    +    return d->inBuffer.size - d->inBuffer.pos;
    +}
    +
    +int KZstdFilter::outBufferAvailable() const
    +{
    +    return d->outBuffer.size - d->outBuffer.pos;
    +}
    +
    +KZstdFilter::Result KZstdFilter::uncompress()
    +{
    +    // qCDebug(KArchiveLog) << "Calling ZSTD_decompressStream with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
    +    const size_t result = ZSTD_decompressStream(d->dStream, &d->outBuffer, &d->inBuffer);
    +    if (ZSTD_isError(result)) {
    +        qCWarning(KArchiveLog) << "ZSTD_decompressStream returned" << result << ZSTD_getErrorName(result);
    +        return KFilterBase::Error;
    +    }
    +
    +    return result == 0 ? KFilterBase::End : KFilterBase::Ok;
    +}
    +
    +KZstdFilter::Result KZstdFilter::compress(bool finish)
    +{
    +    // qCDebug(KArchiveLog) << "Calling ZSTD_compressStream2 with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
    +    const size_t result = ZSTD_compressStream2(d->cStream, &d->outBuffer, &d->inBuffer, finish ? ZSTD_e_end : ZSTD_e_continue);
    +    if (ZSTD_isError(result)) {
    +        return KFilterBase::Error;
    +    }
    +
    +    return finish && result == 0 ? KFilterBase::End : KFilterBase::Ok;
    +}
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/kzstdfilter.h b/src/libs/3rdparty/karchive/src/kzstdfilter.h
    new file mode 100644
    index 00000000000..a61c0e96c2c
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/kzstdfilter.h
    @@ -0,0 +1,46 @@
    +/* This file is part of the KDE libraries
    +   SPDX-FileCopyrightText: 2021 Albert Astals Cid 
    +
    +   SPDX-License-Identifier: LGPL-2.0-or-later
    +*/
    +
    +#ifndef KZSTDFILTER_H
    +#define KZSTDFILTER_H
    +
    +#if HAVE_ZSTD_SUPPORT
    +
    +#include "kfilterbase.h"
    +
    +#include 
    +
    +/**
    + * Internal class used by KCompressionDevice
    + * @internal
    + */
    +class KZstdFilter : public KFilterBase
    +{
    +public:
    +    KZstdFilter();
    +    ~KZstdFilter() override;
    +
    +    bool init(int) override;
    +    int mode() const override;
    +    bool terminate() override;
    +    void reset() override;
    +    bool readHeader() override { return true; }
    +    bool writeHeader(const QByteArray &) override { return true; }
    +    void setOutBuffer(char *data, uint maxlen) override;
    +    void setInBuffer(const char *data, uint size) override;
    +    int inBufferAvailable() const override;
    +    int outBufferAvailable() const override;
    +    Result uncompress() override;
    +    Result compress(bool finish) override;
    +
    +private:
    +    class Private;
    +    const std::unique_ptr d;
    +};
    +
    +#endif
    +
    +#endif
    diff --git a/src/libs/3rdparty/karchive/src/loggingcategory.cpp b/src/libs/3rdparty/karchive/src/loggingcategory.cpp
    new file mode 100644
    index 00000000000..0b40e483c15
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/loggingcategory.cpp
    @@ -0,0 +1,3 @@
    +#include "loggingcategory.h"
    +
    +Q_LOGGING_CATEGORY(KArchiveLog, "kf.archive", QtWarningMsg)
    diff --git a/src/libs/3rdparty/karchive/src/loggingcategory.h b/src/libs/3rdparty/karchive/src/loggingcategory.h
    new file mode 100644
    index 00000000000..a05b84da4a3
    --- /dev/null
    +++ b/src/libs/3rdparty/karchive/src/loggingcategory.h
    @@ -0,0 +1,5 @@
    +#pragma once
    +
    +#include 
    +
    +Q_DECLARE_LOGGING_CATEGORY(KArchiveLog)
    
    From e054c9e3295b9fd56ea815d9ec250d08823ae930 Mon Sep 17 00:00:00 2001
    From: hjk 
    Date: Fri, 6 Dec 2024 17:21:54 +0100
    Subject: [PATCH 370/989] Debugger: Use internal decoding of  Process for
     gdbserver
    
    Change-Id: I174df8ef1c1a93aa25a8863030855552faea7bda
    Reviewed-by: Marcus Tillmanns 
    ---
     src/plugins/debugger/debuggerruncontrol.cpp | 14 ++++----------
     1 file changed, 4 insertions(+), 10 deletions(-)
    
    diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp
    index a585deb5fc7..18a4e1030cb 100644
    --- a/src/plugins/debugger/debuggerruncontrol.cpp
    +++ b/src/plugins/debugger/debuggerruncontrol.cpp
    @@ -54,7 +54,6 @@
     #include 
     
     #include 
    -#include 
     #include 
     
     using namespace Core;
    @@ -105,9 +104,6 @@ public:
     
         // DebugServer
         Process debuggerServerProc;
    -    QTextCodec *debuggerServerCodec = QTextCodec::codecForName("utf8");
    -    QTextCodec::ConverterState outputCodecState; // FIXME: Handle on Process side.
    -    QTextCodec::ConverterState errorCodecState;
         ProcessHandle serverAttachPid;
         bool serverUseMulti = true;
         bool serverEssential = true;
    @@ -875,6 +871,8 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm
         if (EngineManager::engines().isEmpty())
             toolRunCount = 0;
     
    +    d->debuggerServerProc.setUtf8Codec();
    +
         d->runId = QString::number(++toolRunCount);
         d->allowTerminal = allowTerminal;
     
    @@ -1155,17 +1153,13 @@ void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
     
         connect(&d->debuggerServerProc, &Process::readyReadStandardOutput,
                     this, [this] {
    -        const QByteArray data = d->debuggerServerProc.readAllRawStandardOutput();
    -        const QString msg = d->debuggerServerCodec->toUnicode(
    -                    data.constData(), data.length(), &d->outputCodecState);
    +        const QString msg = d->debuggerServerProc.readAllStandardOutput();
             runControl()->postMessage(msg, StdOutFormat, false);
         });
     
         connect(&d->debuggerServerProc, &Process::readyReadStandardError,
                     this, [this] {
    -        const QByteArray data = d->debuggerServerProc.readAllRawStandardError();
    -        const QString msg = d->debuggerServerCodec->toUnicode(
    -                    data.constData(), data.length(), &d->errorCodecState);
    +        const QString msg = d->debuggerServerProc.readAllStandardError();
             runControl()->postMessage(msg, StdErrFormat, false);
         });
     
    
    From dca49744a0f20e84ac3ad49177ee09bfd8cf17a3 Mon Sep 17 00:00:00 2001
    From: David Schulz 
    Date: Mon, 9 Dec 2024 10:37:07 +0100
    Subject: [PATCH 371/989] Editor: add start/end block logging to
     syntaxhighlighter
    
    Change-Id: I9d3ac6394e3010ac77e534158106493ba886ab46
    Reviewed-by: hjk 
    ---
     src/plugins/texteditor/syntaxhighlighter.cpp | 6 ++++++
     1 file changed, 6 insertions(+)
    
    diff --git a/src/plugins/texteditor/syntaxhighlighter.cpp b/src/plugins/texteditor/syntaxhighlighter.cpp
    index 1c16870d7a6..4585b2bb998 100644
    --- a/src/plugins/texteditor/syntaxhighlighter.cpp
    +++ b/src/plugins/texteditor/syntaxhighlighter.cpp
    @@ -15,6 +15,8 @@
     
     #include 
     
    +Q_LOGGING_CATEGORY(Log, "qtc.editor.syntaxhighlighter", QtWarningMsg)
    +
     namespace TextEditor {
     
     enum HighlighterTypeProperty
    @@ -208,6 +210,7 @@ void SyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int ch
         else if (block.blockNumber() > highlightEndBlock)
             highlightEndBlock = block.blockNumber();
     
    +    qCDebug(Log) << "reformat blocks from:" << from << "to:" << from + charsAdded - charsRemoved;
         reformatBlocks();
     }
     
    @@ -222,6 +225,8 @@ void SyntaxHighlighterPrivate::reformatBlocks()
         foldValidator.reset();
     
         bool forceHighlightOfNextBlock = false;
    +    qCDebug(Log) << "continue reformat blocks start block:" << highlightStartBlock
    +                 << "end block:" << highlightEndBlock << "blockCount:" << doc->blockCount();
         QTextBlock block = doc->findBlockByNumber(highlightStartBlock);
         QTC_ASSERT(block.isValid(), block = doc->firstBlock());
         QTextBlock endBlock = doc->findBlockByNumber(highlightEndBlock);
    @@ -256,6 +261,7 @@ void SyntaxHighlighterPrivate::reformatBlocks()
         } else {
             highlightEndBlock = 0;
             highlightStartBlock = INT_MAX;
    +        qCDebug(Log) << "reformat blocks done";
             syntaxInfoUpToDate = true;
             emit q->finished();
         }
    
    From fb964aa7d7bf6e827f0b6e75710897a27d46df53 Mon Sep 17 00:00:00 2001
    From: Alessandro Portale 
    Date: Wed, 4 Dec 2024 12:46:34 +0100
    Subject: [PATCH 372/989] =?UTF-8?q?ProjectExplorer:=20Fix=20warning=20abou?=
     =?UTF-8?q?t=20unused=20parameter=20=E2=80=98index=E2=80=99?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    Change-Id: I5a2643ceeaa262c151cad991803a425e7ad00957
    Reviewed-by: hjk 
    ---
     src/plugins/projectexplorer/projectwelcomepage.cpp | 6 +++---
     1 file changed, 3 insertions(+), 3 deletions(-)
    
    diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp
    index b02246d7499..5a82d076e24 100644
    --- a/src/plugins/projectexplorer/projectwelcomepage.cpp
    +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp
    @@ -692,7 +692,7 @@ public:
             m_projectPath->setText(displayPath);
         }
     
    -    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index)
    +    void paint(QPainter *painter, const QStyleOptionViewItem &option)
         {
             const bool hovered = option.widget->isActiveWindow()
                                  && option.state & QStyle::State_MouseOver;
    @@ -732,11 +732,11 @@ public:
             const override
         {
             m_itemWidget.setData(index);
    -        m_itemWidget.paint(painter, option, index);
    +        m_itemWidget.paint(painter, option);
         }
     
         QSize sizeHint([[maybe_unused]] const QStyleOptionViewItem &option,
    -                   const QModelIndex &index) const override
    +                   [[maybe_unused]] const QModelIndex &index) const override
         {
             return {-1, m_itemWidget.minimumSizeHint().height() + itemSpacing()};
         }
    
    From ac25398b7b5014874d7536f97490520609a24a17 Mon Sep 17 00:00:00 2001
    From: David Schulz 
    Date: Tue, 26 Nov 2024 13:49:27 +0100
    Subject: [PATCH 373/989] Editor: Do not allow changing document tab settings
     for clangformat
    
    the clangformat plugin ignores our internal tab settings so there is no
    need to be able to change those settings for files that are indented by
    the clang format indenter.
    
    Change-Id: I7b91f84e9ec4fbe977024aa648f49ea0b0dc6bcf
    Reviewed-by: Christian Stenger 
    ---
     .../clangformat/clangformatbaseindenter.cpp   |  5 ++
     .../clangformat/clangformatbaseindenter.h     |  2 +
     .../clangformat/clangformatindenter.cpp       |  5 ++
     src/plugins/clangformat/clangformatindenter.h |  2 +
     src/plugins/texteditor/indenter.h             |  2 +
     src/plugins/texteditor/texteditor.cpp         | 89 ++++++++++---------
     6 files changed, 62 insertions(+), 43 deletions(-)
    
    diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp
    index 7b4549a9b41..6fa11690538 100644
    --- a/src/plugins/clangformat/clangformatbaseindenter.cpp
    +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp
    @@ -1031,4 +1031,9 @@ void ClangFormatBaseIndenter::setOverriddenStyle(const clang::format::FormatStyl
         d->m_overriddenStyle = style;
     }
     
    +bool ClangFormatBaseIndenter::respectsTabSettings() const
    +{
    +    return false;
    +}
    +
     } // namespace ClangFormat
    diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h
    index 8d72bd4e0fe..8511e0d13ed 100644
    --- a/src/plugins/clangformat/clangformatbaseindenter.h
    +++ b/src/plugins/clangformat/clangformatbaseindenter.h
    @@ -55,6 +55,8 @@ public:
         void setOverriddenPreferences(TextEditor::ICodeStylePreferences *preferences) final;
         void setOverriddenStyle(const clang::format::FormatStyle &style);
     
    +    bool respectsTabSettings() const override;
    +
     protected:
         virtual bool formatCodeInsteadOfIndent() const { return false; }
         virtual bool formatWhileTyping() const { return false; }
    diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp
    index 1b2d76813f1..5f30c77ebf9 100644
    --- a/src/plugins/clangformat/clangformatindenter.cpp
    +++ b/src/plugins/clangformat/clangformatindenter.cpp
    @@ -235,4 +235,9 @@ std::optional ClangFormatForwardingIndenter::margin() const
         return currentIndenter()->margin();
     }
     
    +bool ClangFormatForwardingIndenter::respectsTabSettings() const
    +{
    +    return currentIndenter()->respectsTabSettings();
    +}
    +
     } // namespace ClangFormat
    diff --git a/src/plugins/clangformat/clangformatindenter.h b/src/plugins/clangformat/clangformatindenter.h
    index be3d54e6c8d..19d4c997428 100644
    --- a/src/plugins/clangformat/clangformatindenter.h
    +++ b/src/plugins/clangformat/clangformatindenter.h
    @@ -60,6 +60,8 @@ public:
                               int cursorPositionInEditor = -1) override;
         std::optional margin() const override;
     
    +    bool respectsTabSettings() const override;
    +
     private:
         TextEditor::Indenter *currentIndenter() const;
     
    diff --git a/src/plugins/texteditor/indenter.h b/src/plugins/texteditor/indenter.h
    index 645150fc6e6..c0acdb58248 100644
    --- a/src/plugins/texteditor/indenter.h
    +++ b/src/plugins/texteditor/indenter.h
    @@ -108,6 +108,8 @@ public:
     
         virtual std::optional margin() const { return std::nullopt; }
     
    +    virtual bool respectsTabSettings() const { return true; }
    +
     protected:
         QTextDocument *m_doc;
         Utils::FilePath m_fileName;
    diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
    index ac8e9800b40..5ddc6f1dcc1 100644
    --- a/src/plugins/texteditor/texteditor.cpp
    +++ b/src/plugins/texteditor/texteditor.cpp
    @@ -314,51 +314,54 @@ private:
             QTC_ASSERT(m_doc, return);
             auto menu = new QMenu;
             menu->addAction(ActionManager::command(Constants::AUTO_INDENT_SELECTION)->action());
    -        auto documentSettings = menu->addMenu(Tr::tr("Document Settings"));
    +        if (auto indenter = m_doc->indenter(); indenter && indenter->respectsTabSettings()) {
    +            auto documentSettings = menu->addMenu(Tr::tr("Document Settings"));
     
    -        auto modifyTabSettings = [this](std::function modifier) {
    -            return [this, modifier]() {
    -                auto ts = m_doc->tabSettings();
    -                modifier(ts);
    -                m_doc->setTabSettings(ts);
    -            };
    -        };
    -        documentSettings->addAction(
    -            Tr::tr("Auto detect"),
    -            modifyTabSettings([doc = m_doc->document()](TabSettings &tabSettings) {
    -                tabSettings = tabSettings.autoDetect(doc);
    -            }));
    -        auto tabSettings = documentSettings->addMenu(Tr::tr("Tab Settings"));
    -        tabSettings->addAction(Tr::tr("Spaces"), modifyTabSettings([](TabSettings &tabSettings) {
    -                                   tabSettings.m_tabPolicy = TabSettings::SpacesOnlyTabPolicy;
    -                               }));
    -        tabSettings->addAction(Tr::tr("Tabs"), modifyTabSettings([](TabSettings &tabSettings) {
    -                                   tabSettings.m_tabPolicy = TabSettings::TabsOnlyTabPolicy;
    -                               }));
    -        auto indentSize = documentSettings->addMenu(Tr::tr("Indent Size"));
    -        auto indentSizeGroup = new QActionGroup(indentSize);
    -        indentSizeGroup->setExclusive(true);
    -        for (int i = 1; i <= 8; ++i) {
    -            auto action = indentSizeGroup->addAction(QString::number(i));
    -            action->setCheckable(true);
    -            action->setChecked(i == m_doc->tabSettings().m_indentSize);
    -            connect(action, &QAction::triggered, modifyTabSettings([i](TabSettings &tabSettings) {
    -                        tabSettings.m_indentSize = i;
    -                    }));
    +            auto modifyTabSettings =
    +                [this](std::function modifier) {
    +                    return [this, modifier]() {
    +                        auto ts = m_doc->tabSettings();
    +                        modifier(ts);
    +                        m_doc->setTabSettings(ts);
    +                    };
    +                };
    +            documentSettings->addAction(
    +                Tr::tr("Auto detect"),
    +                modifyTabSettings([doc = m_doc->document()](TabSettings &tabSettings) {
    +                    tabSettings = tabSettings.autoDetect(doc);
    +                }));
    +            auto tabSettings = documentSettings->addMenu(Tr::tr("Tab Settings"));
    +            tabSettings->addAction(Tr::tr("Spaces"), modifyTabSettings([](TabSettings &tabSettings) {
    +                                       tabSettings.m_tabPolicy = TabSettings::SpacesOnlyTabPolicy;
    +                                   }));
    +            tabSettings->addAction(Tr::tr("Tabs"), modifyTabSettings([](TabSettings &tabSettings) {
    +                                       tabSettings.m_tabPolicy = TabSettings::TabsOnlyTabPolicy;
    +                                   }));
    +            auto indentSize = documentSettings->addMenu(Tr::tr("Indent Size"));
    +            auto indentSizeGroup = new QActionGroup(indentSize);
    +            indentSizeGroup->setExclusive(true);
    +            for (int i = 1; i <= 8; ++i) {
    +                auto action = indentSizeGroup->addAction(QString::number(i));
    +                action->setCheckable(true);
    +                action->setChecked(i == m_doc->tabSettings().m_indentSize);
    +                connect(action, &QAction::triggered, modifyTabSettings([i](TabSettings &tabSettings) {
    +                            tabSettings.m_indentSize = i;
    +                        }));
    +            }
    +            indentSize->addActions(indentSizeGroup->actions());
    +            auto tabSize = documentSettings->addMenu(Tr::tr("Tab Size"));
    +            auto tabSizeGroup = new QActionGroup(tabSize);
    +            tabSizeGroup->setExclusive(true);
    +            for (int i = 1; i <= 8; ++i) {
    +                auto action = tabSizeGroup->addAction(QString::number(i));
    +                action->setCheckable(true);
    +                action->setChecked(i == m_doc->tabSettings().m_tabSize);
    +                connect(action, &QAction::triggered, modifyTabSettings([i](TabSettings &tabSettings) {
    +                            tabSettings.m_tabSize = i;
    +                        }));
    +                }
    +                tabSize->addActions(tabSizeGroup->actions());
             }
    -        indentSize->addActions(indentSizeGroup->actions());
    -        auto tabSize = documentSettings->addMenu(Tr::tr("Tab Size"));
    -        auto tabSizeGroup = new QActionGroup(tabSize);
    -        tabSizeGroup->setExclusive(true);
    -        for (int i = 1; i <= 8; ++i) {
    -            auto action = tabSizeGroup->addAction(QString::number(i));
    -            action->setCheckable(true);
    -            action->setChecked(i == m_doc->tabSettings().m_tabSize);
    -            connect(action, &QAction::triggered, modifyTabSettings([i](TabSettings &tabSettings) {
    -                tabSettings.m_tabSize = i;
    -            }));
    -        }
    -        tabSize->addActions(tabSizeGroup->actions());
     
             Id globalSettingsCategory;
             if (auto codeStyle = m_doc->codeStyle())
    
    From 997c4b64d2b054a53668f7e15a6c10b068ecaa9a Mon Sep 17 00:00:00 2001
    From: hjk 
    Date: Mon, 9 Dec 2024 15:14:02 +0100
    Subject: [PATCH 374/989] Debugger: Remove a few unused enums
    
    Change-Id: I45fe9aa14833dc1741552310dc911291ed444ff1
    Reviewed-by: Orgad Shaneh 
    Reviewed-by: David Schulz 
    ---
     src/plugins/debugger/debuggerinternalconstants.h | 7 -------
     1 file changed, 7 deletions(-)
    
    diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h
    index dcb696d3d05..c1cef9f7f7f 100644
    --- a/src/plugins/debugger/debuggerinternalconstants.h
    +++ b/src/plugins/debugger/debuggerinternalconstants.h
    @@ -3,8 +3,6 @@
     
     #pragma once
     
    -#include 
    -
     namespace Debugger {
     
     namespace Constants {
    @@ -61,11 +59,6 @@ enum ModelRoles
     {
         DisplaySourceRole = 32,  // Qt::UserRole
     
    -    EngineStateRole,
    -    EngineActionsEnabledRole,
    -    RequestActivationRole,
    -    RequestContextMenuRole,
    -
         // Locals and Watchers
         LocalsINameRole,
         LocalsNameRole,
    
    From 65a3e484a905bf3fbac86784dd20ec421fbb401d Mon Sep 17 00:00:00 2001
    From: Andrii Semkiv 
    Date: Wed, 4 Dec 2024 15:26:07 +0100
    Subject: [PATCH 375/989] Debugger: Add an option to control heap debugging
    
    Added a checkbox (temporarily) in CDB settings page that toggles
    the heap debugging on Windows.
    Although it is "technically" a CDB option, it woks with LLDB on Windows
    as well.
    The default behavior is to keep the heap debugging off.
    The checkbox can still be overridden by the environment variable.
    
    Fixes: QTCREATORBUG-32102
    Change-Id: I580cd0d66da38776f3a51632ede6b5f60d4d4cfd
    Reviewed-by: hjk 
    Reviewed-by: David Schulz 
    ---
     src/plugins/debugger/cdb/cdbengine.cpp        |  4 ++++
     src/plugins/debugger/cdb/cdboptionspage.cpp   |  5 +++-
     src/plugins/debugger/debuggeractions.cpp      |  9 ++++++++
     src/plugins/debugger/debuggeractions.h        |  1 +
     .../debugger/debuggerinternalconstants.h      |  2 ++
     src/plugins/debugger/lldb/lldbengine.cpp      | 23 +++++++++++++------
     6 files changed, 36 insertions(+), 8 deletions(-)
    
    diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
    index 16aab0c920c..0dc2d321613 100644
    --- a/src/plugins/debugger/cdb/cdbengine.cpp
    +++ b/src/plugins/debugger/cdb/cdbengine.cpp
    @@ -406,6 +406,10 @@ void CdbEngine::setupEngine()
         if (!oldCdbExtensionPath.isEmpty())
             inferiorEnvironment.appendOrSet(cdbExtensionPathVariableC, oldCdbExtensionPath);
     
    +    if (!inferiorEnvironment.hasKey(Debugger::Constants::NO_DEBUG_HEAP)) {
    +        const QString value = s.enableHeapDebugging() ? "0" : "1";
    +        inferiorEnvironment.set(Debugger::Constants::NO_DEBUG_HEAP, value);
    +    }
         m_process.setEnvironment(inferiorEnvironment);
         if (!sp.inferior.workingDirectory.isEmpty())
             m_process.setWorkingDirectory(sp.inferior.workingDirectory);
    diff --git a/src/plugins/debugger/cdb/cdboptionspage.cpp b/src/plugins/debugger/cdb/cdboptionspage.cpp
    index ef3586e61b6..1cf5a2a2855 100644
    --- a/src/plugins/debugger/cdb/cdboptionspage.cpp
    +++ b/src/plugins/debugger/cdb/cdboptionspage.cpp
    @@ -171,6 +171,7 @@ CdbOptionsPageWidget::CdbOptionsPageWidget()
     
         m_breakEventWidget->setBreakEvents(settings().cdbBreakEvents());
     
    +    // clang-format off
         Column {
             Row {
                 Group {
    @@ -188,7 +189,8 @@ CdbOptionsPageWidget::CdbOptionsPageWidget()
                         s.ignoreFirstChanceAccessViolation,
                         s.cdbBreakOnCrtDbgReport,
                         s.cdbBreakPointCorrection,
    -                    s.cdbUsePythonDumper
    +                    s.cdbUsePythonDumper,
    +                    s.enableHeapDebugging
                     }
                 }
             },
    @@ -209,6 +211,7 @@ CdbOptionsPageWidget::CdbOptionsPageWidget()
             st
     
         }.attachTo(this);
    +    // clang-format on
     }
     
     void CdbOptionsPageWidget::apply()
    diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp
    index 20ff6cddefd..1033524538a 100644
    --- a/src/plugins/debugger/debuggeractions.cpp
    +++ b/src/plugins/debugger/debuggeractions.cpp
    @@ -190,6 +190,14 @@ DebuggerSettings::DebuggerSettings() :
         ignoreFirstChanceAccessViolation.setSettingsKey(cdbSettingsGroup, "IgnoreFirstChanceAccessViolation");
         ignoreFirstChanceAccessViolation.setLabelText(Tr::tr("Ignore first chance access violations"));
     
    +    enableHeapDebugging.setSettingsKey(cdbSettingsGroup, "EnableHeapDebugging");
    +    enableHeapDebugging.setLabelText(Tr::tr("Enable heap debugging"));
    +    enableHeapDebugging.setToolTip(
    +        "

    " + + Tr::tr("Allocate memory using the debug heap rather than the normal heap. The debug heap " + "enables additional checks to help diagnose heap related bugs. However it comes " + "at a performance cost when allocating memory in the debugged process")); + // // Locals & Watchers sortStructMembers.setSettingsKey(debugModeGroup, "SortStructMembers"); @@ -255,6 +263,7 @@ DebuggerSettings::DebuggerSettings() : page5.registerAspect(&firstChanceExceptionTaskEntry); page5.registerAspect(&secondChanceExceptionTaskEntry); page5.registerAspect(&ignoreFirstChanceAccessViolation); + page5.registerAspect(&enableHeapDebugging); // Page 6 page6.registerAspect(&cdbSymbolPaths); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 2134c5d03a4..e5d1ae0fa29 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -89,6 +89,7 @@ public: Utils::BoolAspect firstChanceExceptionTaskEntry; Utils::BoolAspect secondChanceExceptionTaskEntry; Utils::BoolAspect ignoreFirstChanceAccessViolation; + Utils::BoolAspect enableHeapDebugging; // Page 6: CDB Paths Utils::StringListAspect cdbSymbolPaths; diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h index c1cef9f7f7f..26c703ddcf4 100644 --- a/src/plugins/debugger/debuggerinternalconstants.h +++ b/src/plugins/debugger/debuggerinternalconstants.h @@ -53,6 +53,8 @@ const char DISASSEMBLER_SOURCE_FILE[] = "DisassemblerSourceFile"; const char CRT_DEBUG_REPORT[] = "CrtDbgReport"; +const char NO_DEBUG_HEAP[] = "_NO_DEBUG_HEAP"; + } // namespace Constants enum ModelRoles diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 65b45cbda61..93e82be4c0d 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -264,22 +264,31 @@ void LldbEngine::handleLldbStarted() for (const FilePath &path : rp.solibSearchPath) executeDebuggerCommand("settings append target.exec-search-paths " + path.toString()); + const ProcessRunData &inferior = rp.inferior; + const FilePath &executable = inferior.command.executable(); DebuggerCommand cmd2("setupInferior"); - cmd2.arg("executable", rp.inferior.command.executable().path()); + cmd2.arg("executable", executable.path()); cmd2.arg("breakonmain", rp.breakOnMain); cmd2.arg("useterminal", usesTerminal()); cmd2.arg("startmode", rp.startMode); cmd2.arg("nativemixed", isNativeMixedActive()); - cmd2.arg("workingdirectory", rp.inferior.workingDirectory.path()); - QStringList environment = rp.inferior.environment.toStringList(); + cmd2.arg("workingdirectory", inferior.workingDirectory.path()); + Environment environment = inferior.environment; // Prevent lldb from automatically setting OS_ACTIVITY_DT_MODE to mirror // NSLog to stderr, as that will also mirror os_log, which we pick up in // AppleUnifiedLogger::preventsStderrLogging(), and end up disabling Qt's // default stderr logger. We prefer Qt's own stderr logging if we can. - environment << "IDE_DISABLED_OS_ACTIVITY_DT_MODE=1"; - cmd2.arg("environment", environment); - cmd2.arg("processargs", toHex(ProcessArgs::splitArgs(rp.inferior.command.arguments(), - HostOsInfo::hostOs()).join(QChar(0)))); + environment.set("IDE_DISABLED_OS_ACTIVITY_DT_MODE", "1"); + if (executable.osType() == Utils::OsTypeWindows + && !environment.hasKey(Debugger::Constants::NO_DEBUG_HEAP)) { + const QString value = settings().enableHeapDebugging() ? "0" : "1"; + environment.set(Debugger::Constants::NO_DEBUG_HEAP, value); + } + cmd2.arg("environment", environment.toStringList()); + cmd2.arg( + "processargs", + toHex(ProcessArgs::splitArgs(inferior.command.arguments(), HostOsInfo::hostOs()) + .join(QChar(0)))); cmd2.arg("platform", rp.platform); cmd2.arg("symbolfile", rp.symbolFile.path()); From 2a990b84fafa0e3bd6bf15d37108d4777996cfee Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 29 Nov 2024 10:21:20 +0100 Subject: [PATCH 376/989] VCS: Detect VCS directories even for disabled VCS plugins Most of the version control support plugins detect that a directory/file is under version control by looking for certain files in the directory structure. This search doesn't really need anything specific from the plugin, except for a list of file names. Allow version control plugins to specify the list of files to look for in their plugin meta data as "VcsDetectionFiles". When it is checked if a directory is under version control, and none is found from the enabled plugins, use the meta data to find out if any installed but disabled plugin feels responsible for that directory. Show a notification if a plugin is found that handles such a detected version control system, with the option to enable the plugin and restart QtC if necessary. Since this adds discoverability of the version control support even when plugins are disabled, disable the VCS plugins that can use this mechanism (except for Git). Change-Id: Ib507572c0065dd889a2f9b780c794f9cd985e265 Reviewed-by: Orgad Shaneh Reviewed-by: Marcus Tillmanns --- src/plugins/bazaar/Bazaar.json.in | 4 ++ src/plugins/coreplugin/icore.cpp | 29 +++++++++ src/plugins/coreplugin/icore.h | 3 + src/plugins/coreplugin/vcsmanager.cpp | 73 +++++++++++++++++++++++ src/plugins/fossil/Fossil.json.in | 3 + src/plugins/git/Git.json.in | 4 ++ src/plugins/mercurial/Mercurial.json.in | 4 ++ src/plugins/subversion/Subversion.json.in | 5 ++ 8 files changed, 125 insertions(+) diff --git a/src/plugins/bazaar/Bazaar.json.in b/src/plugins/bazaar/Bazaar.json.in index e725b785734..8311877c71c 100644 --- a/src/plugins/bazaar/Bazaar.json.in +++ b/src/plugins/bazaar/Bazaar.json.in @@ -4,6 +4,7 @@ "Name" : "Bazaar", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", + "DisabledByDefault" : true, "VendorId" : "huguesdelorme", "Vendor" : "Hugues Delorme", "Copyright" : "(C) 2016 Hugues Delorme, ${IDE_COPYRIGHT}", @@ -23,5 +24,8 @@ ], "Url" : "https://www.qt.io", "DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-vcs-bazaar.html", + "VcsDetectionFiles" : [ + ".bzr/branch-format" + ], ${IDE_PLUGIN_DEPENDENCIES} } diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 6168acfd6c6..55e99c92e1d 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -1126,6 +1126,35 @@ void ICore::restart() exit(); } +/*! + Asks the user if they want to enable the \a plugins and their dependencies. + If the user agrees, the plugins are enabled. + If all plugins are soft loadable without restart, they get loaded directly. + Otherwise the "Restart Required" dialog is shown. + + Returns whether the user agreed to enabling the plugins. +*/ +bool ICore::enablePlugins(const QSet &plugins) +{ + std::optional> additionalPlugins + = PluginManager::askForEnablingPlugins(dialogParent(), plugins, /*enable=*/true); + if (!additionalPlugins) // canceled + return false; + const QSet affectedPlugins = plugins + *additionalPlugins; + bool softloadable = true; + for (PluginSpec *spec : affectedPlugins) { + spec->setEnabledBySettings(true); + softloadable = softloadable && spec->isSoftLoadable(); + } + ExtensionSystem::PluginManager::writeSettings(); + if (softloadable) { + PluginManager::loadPluginsAtRuntime(affectedPlugins); + } else { + ICore::askForRestart(Tr::tr("Plugin changes will take effect after restart.")); + } + return true; +} + /*! \internal */ diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h index 9aa1e93c393..10a90f66464 100644 --- a/src/plugins/coreplugin/icore.h +++ b/src/plugins/coreplugin/icore.h @@ -6,6 +6,7 @@ #include "core_global.h" #include "icontext.h" +#include #include #include #include @@ -116,6 +117,8 @@ public: static void restart(); + static bool enablePlugins(const QSet &plugins); + enum SaveSettingsReason { SettingsDialogDone, ModeChanged, diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp index de146a5656b..14271eab44f 100644 --- a/src/plugins/coreplugin/vcsmanager.cpp +++ b/src/plugins/coreplugin/vcsmanager.cpp @@ -12,12 +12,15 @@ #include "iversioncontrol.h" #include +#include #include #include #include #include +#include +#include #include #include #include @@ -177,6 +180,74 @@ static FilePath fixedDir(const FilePath &directory) return directory; } +static void askForDisabledVcsPlugins(const FilePath &inputDirectory) +{ + using namespace ExtensionSystem; + FilePath toplevel; + + PluginSpec *spec = Utils::findOrDefault( + PluginManager::plugins(), [&toplevel, inputDirectory](PluginSpec *plugin) { + if (plugin->isEffectivelyEnabled()) + return false; + const QJsonObject metaData = plugin->metaData(); + const QJsonArray filesArray = metaData.value("VcsDetectionFiles").toArray(); + if (filesArray.isEmpty()) + return false; + QStringList files; + for (const QJsonValue &v : filesArray) { + const QString str = v.toString(); + if (!str.isEmpty()) + files.append(str); + } + if (files.isEmpty()) + return false; + qCDebug(findRepoLog) << "Checking if plugin" << plugin->displayName() << "can handle" + << inputDirectory.toUserOutput(); + qCDebug(findRepoLog) << "by checking for" << files; + const FilePath dir = VcsManager::findRepositoryForFiles(inputDirectory, files); + if (dir.isEmpty()) + return false; + qCDebug(findRepoLog) << "The plugin" << plugin->displayName() << "can handle" + << inputDirectory.toUserOutput(); + toplevel = dir; + return true; + }); + + if (!spec) + return; + + const Id vcsSuggestion = Id("VcsManager.Suggestion.").withSuffix(spec->id()); + InfoBar *infoBar = ICore::infoBar(); + if (!infoBar->canInfoBeAdded(vcsSuggestion)) + return; + + const QString pluginDisplayName = spec->displayName(); + Utils::InfoBarEntry info( + vcsSuggestion, + Tr::tr("A directory under version control was detected that is supported by the %1 plugin.") + .arg(pluginDisplayName), + Utils::InfoBarEntry::GlobalSuppression::Enabled); + info.addCustomButton(Tr::tr("Enable %1").arg(pluginDisplayName), [vcsSuggestion, spec] { + // TODO In case the plugin is actually loaded during runtime (softloadable), + // we'd need to restructure findVersionControlForDirectory below to take the new plugin + // into account. + // At the moment softloadable VCS plugins are not supported though. + if (ICore::enablePlugins({spec})) + ICore::infoBar()->removeInfo(vcsSuggestion); + }); + + info.setDetailsWidgetCreator([toplevel, pluginDisplayName]() -> QWidget * { + auto label = new QLabel; + label->setWordWrap(true); + label->setOpenExternalLinks(true); + label->setText(Tr::tr("The directory \"%1\" seems to be under version control that can be " + "handled by the disabled %2 plugin.") + .arg(toplevel.toUserOutput(), pluginDisplayName)); + label->setContentsMargins(0, 0, 0, 8); + return label; + }); + ICore::infoBar()->addInfo(info); +}; IVersionControl* VcsManager::findVersionControlForDirectory(const FilePath &inputDirectory, FilePath *topLevelDirectory) @@ -221,6 +292,8 @@ IVersionControl* VcsManager::findVersionControlForDirectory(const FilePath &inpu // report result; if (topLevelDirectory) topLevelDirectory->clear(); + + askForDisabledVcsPlugins(directory); return nullptr; } diff --git a/src/plugins/fossil/Fossil.json.in b/src/plugins/fossil/Fossil.json.in index ccc9856d2bc..6018e41ed4e 100644 --- a/src/plugins/fossil/Fossil.json.in +++ b/src/plugins/fossil/Fossil.json.in @@ -24,6 +24,9 @@ ], "Url" : "https://www.qt.io", "DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-vcs-fossil.html", + "VcsDetectionFiles" : [ + ".fslckout" + ], ${IDE_PLUGIN_DEPENDENCIES}, "JsonWizardPaths" : [":/fossil/wizard"] diff --git a/src/plugins/git/Git.json.in b/src/plugins/git/Git.json.in index 6c6b476b880..d87f9341643 100644 --- a/src/plugins/git/Git.json.in +++ b/src/plugins/git/Git.json.in @@ -30,6 +30,10 @@ "Description" : "Show given commit hash" } ], + "VcsDetectionFiles" : [ + ".git", + ".git/config" + ], ${IDE_PLUGIN_DEPENDENCIES}, "Mimetypes" : [ diff --git a/src/plugins/mercurial/Mercurial.json.in b/src/plugins/mercurial/Mercurial.json.in index d8125d77ba2..835005771ca 100644 --- a/src/plugins/mercurial/Mercurial.json.in +++ b/src/plugins/mercurial/Mercurial.json.in @@ -4,6 +4,7 @@ "Name" : "Mercurial", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", + "DisabledByDefault" : true, "VendorId" : "brianmcgillion", "Vendor" : "Brian McGillion", "Copyright" : "(C) 2016 Brian McGillion, ${IDE_COPYRIGHT}", @@ -23,5 +24,8 @@ ], "Url" : "https://www.qt.io", "DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-vcs-mercurial.html", + "VcsDetectionFiles" : [ + ".hg/requires" + ], ${IDE_PLUGIN_DEPENDENCIES} } diff --git a/src/plugins/subversion/Subversion.json.in b/src/plugins/subversion/Subversion.json.in index 1941eb222c4..81420a0e3ac 100644 --- a/src/plugins/subversion/Subversion.json.in +++ b/src/plugins/subversion/Subversion.json.in @@ -4,6 +4,7 @@ "Name" : "Subversion", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", + "DisabledByDefault" : true, "VendorId" : "theqtcompany", "Vendor" : "The Qt Company Ltd", "Copyright" : "${IDE_COPYRIGHT}", @@ -23,6 +24,10 @@ ], "Url" : "https://www.qt.io", "DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-vcs-subversion.html", + "VcsDetectionFiles" : [ + ".svn/wc.db", + "_svn/wc.db" + ], ${IDE_PLUGIN_DEPENDENCIES}, "Mimetypes" : [ From 23c0ae336f1a8bbeb5a2db6edf85e1d736247040 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 4 Dec 2024 09:48:00 +0100 Subject: [PATCH 377/989] Core etc: Use dialogParent() for several wizards This was de-facto the case almost always, only the tests used a local dummy and StudioWelcome::WizardFactories. Change-Id: I20191d050d14664c95d9676098f90db76b25d57f Reviewed-by: Eike Ziller --- .../coreplugin/basefilewizardfactory.cpp | 17 ++++----- .../coreplugin/basefilewizardfactory.h | 4 +- src/plugins/coreplugin/dialogs/newdialog.cpp | 2 +- src/plugins/coreplugin/iwizardfactory.cpp | 7 ++-- src/plugins/coreplugin/iwizardfactory.h | 3 +- src/plugins/designer/cpp/formclasswizard.cpp | 4 +- src/plugins/designer/cpp/formclasswizard.h | 2 +- .../genericprojectwizard.cpp | 8 ++-- .../baseprojectwizarddialog.cpp | 6 +-- .../projectexplorer/baseprojectwizarddialog.h | 4 +- .../customwizard/customwizard.cpp | 9 ++--- .../customwizard/customwizard.h | 4 +- .../projectexplorer/jsonwizard/jsonwizard.cpp | 4 +- .../projectexplorer/jsonwizard/jsonwizard.h | 2 +- .../jsonwizard/jsonwizard_test.cpp | 37 +++++++++---------- .../jsonwizard/jsonwizardfactory.cpp | 5 +-- .../jsonwizard/jsonwizardfactory.h | 2 +- .../projectexplorer/projectexplorer.cpp | 2 +- .../projectexplorer/simpleprojectwizard.cpp | 9 ++--- .../projectexplorer/simpleprojectwizard.h | 2 +- .../customwidgetwizard/customwidgetwizard.cpp | 5 +-- .../customwidgetwizard/customwidgetwizard.h | 3 +- .../customwidgetwizarddialog.cpp | 5 +-- .../customwidgetwizarddialog.h | 1 - .../qmakeprojectmanager/wizards/qtwizard.cpp | 11 ++---- .../qmakeprojectmanager/wizards/qtwizard.h | 6 +-- .../wizards/subdirsprojectwizard.cpp | 6 +-- .../wizards/subdirsprojectwizard.h | 3 +- .../wizards/subdirsprojectwizarddialog.cpp | 5 +-- .../wizards/subdirsprojectwizarddialog.h | 7 ++-- src/plugins/studiowelcome/qdsnewdialog.cpp | 2 +- src/plugins/studiowelcome/wizardfactories.cpp | 13 +++---- src/plugins/studiowelcome/wizardfactories.h | 6 +-- 33 files changed, 88 insertions(+), 118 deletions(-) diff --git a/src/plugins/coreplugin/basefilewizardfactory.cpp b/src/plugins/coreplugin/basefilewizardfactory.cpp index 60000388ad6..9ffa51ff0a2 100644 --- a/src/plugins/coreplugin/basefilewizardfactory.cpp +++ b/src/plugins/coreplugin/basefilewizardfactory.cpp @@ -46,10 +46,9 @@ static int indexOfFile(const GeneratedFiles &f, const FilePath &path) \sa Core::BaseFileWizardFactory */ -Utils::Wizard *BaseFileWizardFactory::runWizardImpl(const FilePath &path, QWidget *parent, - Id platform, - const QVariantMap &extraValues, - bool showWizard) +Wizard *BaseFileWizardFactory::runWizardImpl(const FilePath &path, Id platform, + const QVariantMap &extraValues, + bool showWizard) { Q_UNUSED(showWizard); QTC_ASSERT(!path.isEmpty(), return nullptr); @@ -63,11 +62,11 @@ Utils::Wizard *BaseFileWizardFactory::runWizardImpl(const FilePath &path, QWidge if (flags().testFlag(ForceCapitalLetterForFileName)) dialogParameterFlags |= WizardDialogParameters::ForceCapitalLetterForFileName; - Wizard *wizard = create(parent, WizardDialogParameters(path, - platform, - requiredFeatures(), - dialogParameterFlags, - extraValues)); + Wizard *wizard = create(WizardDialogParameters(path, + platform, + requiredFeatures(), + dialogParameterFlags, + extraValues)); QTC_CHECK(wizard); return wizard; } diff --git a/src/plugins/coreplugin/basefilewizardfactory.h b/src/plugins/coreplugin/basefilewizardfactory.h index 0d9033d6d59..a2f25945aa4 100644 --- a/src/plugins/coreplugin/basefilewizardfactory.h +++ b/src/plugins/coreplugin/basefilewizardfactory.h @@ -67,7 +67,7 @@ public: static Utils::FilePath buildFileName(const Utils::FilePath &path, const QString &baseName, const QString &extension); protected: - virtual BaseFileWizard *create(QWidget *parent, const WizardDialogParameters ¶meters) const = 0; + virtual BaseFileWizard *create(const WizardDialogParameters ¶meters) const = 0; virtual GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const = 0; @@ -84,7 +84,7 @@ protected: static bool postGenerateOpenEditors(const GeneratedFiles &l, QString *errorMessage = nullptr); private: - Utils::Wizard *runWizardImpl(const Utils::FilePath &path, QWidget *parent, Utils::Id platform, + Utils::Wizard *runWizardImpl(const Utils::FilePath &path, Utils::Id platform, const QVariantMap &extraValues, bool showWizard = true) final; }; diff --git a/src/plugins/coreplugin/dialogs/newdialog.cpp b/src/plugins/coreplugin/dialogs/newdialog.cpp index f6be40905b9..4efd33cc010 100644 --- a/src/plugins/coreplugin/dialogs/newdialog.cpp +++ b/src/plugins/coreplugin/dialogs/newdialog.cpp @@ -544,7 +544,7 @@ static void runWizard(IWizardFactory *wizard, const FilePath &defaultLocation, I const QVariantMap &variables) { const FilePath path = wizard->runPath(defaultLocation); - wizard->runWizard(path, ICore::dialogParent(), platform, variables); + wizard->runWizard(path, platform, variables); } void NewDialogWidget::accept() diff --git a/src/plugins/coreplugin/iwizardfactory.cpp b/src/plugins/coreplugin/iwizardfactory.cpp index d5f85acc84f..4299ad888f4 100644 --- a/src/plugins/coreplugin/iwizardfactory.cpp +++ b/src/plugins/coreplugin/iwizardfactory.cpp @@ -209,7 +209,7 @@ QList IWizardFactory::allWizardFactories() .addOnTriggered(newFactory, [newFactory] { if (!ICore::isNewItemDialogRunning()) { FilePath path = newFactory->runPath({}); - newFactory->runWizard(path, ICore::dialogParent(), Id(), QVariantMap()); + newFactory->runWizard(path, Id(), QVariantMap()); } }); @@ -247,7 +247,6 @@ FilePath IWizardFactory::runPath(const FilePath &defaultPath) const Creates the wizard that the user selected for execution on the operating system \a platform with \a variables. - Any dialogs the wizard opens should use the given \a parent. The \a path argument is a suggestion for the location where files should be created. The wizard should fill this in its path selection elements as a default path. @@ -255,7 +254,7 @@ FilePath IWizardFactory::runPath(const FilePath &defaultPath) const When \a showWizard is \c false, the wizard instance is created and set up but not actually shown. */ -Wizard *IWizardFactory::runWizard(const FilePath &path, QWidget *parent, Id platform, +Wizard *IWizardFactory::runWizard(const FilePath &path, Id platform, const QVariantMap &variables, bool showWizard) { @@ -264,7 +263,7 @@ Wizard *IWizardFactory::runWizard(const FilePath &path, QWidget *parent, Id plat s_isWizardRunning = true; ICore::updateNewItemDialogState(); - Utils::Wizard *wizard = runWizardImpl(path, parent, platform, variables, showWizard); + Wizard *wizard = runWizardImpl(path, platform, variables, showWizard); if (wizard) { diff --git a/src/plugins/coreplugin/iwizardfactory.h b/src/plugins/coreplugin/iwizardfactory.h index 97b47ac3d3a..e7794907ce3 100644 --- a/src/plugins/coreplugin/iwizardfactory.h +++ b/src/plugins/coreplugin/iwizardfactory.h @@ -71,7 +71,7 @@ public: Utils::FilePath runPath(const Utils::FilePath &defaultPath) const; // Does bookkeeping and the calls runWizardImpl. Please implement that. - Utils::Wizard *runWizard(const Utils::FilePath &path, QWidget *parent, Utils::Id platform, + Utils::Wizard *runWizard(const Utils::FilePath &path, Utils::Id platform, const QVariantMap &variables, bool showWizard = true); virtual bool isAvailable(Utils::Id platformId) const; @@ -103,7 +103,6 @@ protected: static QSet availableFeatures(Utils::Id platformId); virtual Utils::Wizard *runWizardImpl(const Utils::FilePath &path, - QWidget *parent, Utils::Id platform, const QVariantMap &variables, bool showWizard = true) = 0; diff --git a/src/plugins/designer/cpp/formclasswizard.cpp b/src/plugins/designer/cpp/formclasswizard.cpp index 0290259527c..037f3456727 100644 --- a/src/plugins/designer/cpp/formclasswizard.cpp +++ b/src/plugins/designer/cpp/formclasswizard.cpp @@ -42,9 +42,9 @@ QString FormClassWizard::formSuffix() const return preferredSuffix(Utils::Constants::FORM_MIMETYPE); } -Core::BaseFileWizard *FormClassWizard::create(QWidget *parent, const Core::WizardDialogParameters ¶meters) const +Core::BaseFileWizard *FormClassWizard::create(const Core::WizardDialogParameters ¶meters) const { - auto wizardDialog = new FormClassWizardDialog(this, parent); + auto wizardDialog = new FormClassWizardDialog(this); wizardDialog->setFilePath(parameters.defaultPath()); return wizardDialog; } diff --git a/src/plugins/designer/cpp/formclasswizard.h b/src/plugins/designer/cpp/formclasswizard.h index 90238410738..bf4ade24a37 100644 --- a/src/plugins/designer/cpp/formclasswizard.h +++ b/src/plugins/designer/cpp/formclasswizard.h @@ -22,7 +22,7 @@ public: QString formSuffix() const; private: - Core::BaseFileWizard *create(QWidget *parent, const Core::WizardDialogParameters ¶meters) const final; + Core::BaseFileWizard *create(const Core::WizardDialogParameters ¶meters) const final; Core::GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const final; }; diff --git a/src/plugins/genericprojectmanager/genericprojectwizard.cpp b/src/plugins/genericprojectmanager/genericprojectwizard.cpp index a6e12cd029b..096a39e0b20 100644 --- a/src/plugins/genericprojectmanager/genericprojectwizard.cpp +++ b/src/plugins/genericprojectmanager/genericprojectwizard.cpp @@ -98,8 +98,8 @@ class GenericProjectWizard final : public BaseFileWizard Q_OBJECT public: - GenericProjectWizard(const BaseFileWizardFactory *factory, QWidget *parent) - : BaseFileWizard(factory, QVariantMap(), parent) + GenericProjectWizard(const BaseFileWizardFactory *factory) + : BaseFileWizard(factory, QVariantMap(), Core::ICore::dialogParent()) { setWindowTitle(Tr::tr("Import Existing Project")); @@ -172,9 +172,9 @@ public: } protected: - BaseFileWizard *create(QWidget *parent, const WizardDialogParameters ¶meters) const final + BaseFileWizard *create(const WizardDialogParameters ¶meters) const final { - auto wizard = new GenericProjectWizard(this, parent); + auto wizard = new GenericProjectWizard(this); wizard->setFilePath(parameters.defaultPath()); const QList pages = wizard->extensionPages(); for (QWizardPage *p : pages) diff --git a/src/plugins/projectexplorer/baseprojectwizarddialog.cpp b/src/plugins/projectexplorer/baseprojectwizarddialog.cpp index 733034b28c9..bb8af3e00ee 100644 --- a/src/plugins/projectexplorer/baseprojectwizarddialog.cpp +++ b/src/plugins/projectexplorer/baseprojectwizarddialog.cpp @@ -39,9 +39,8 @@ struct BaseProjectWizardDialogPrivate BaseProjectWizardDialog::BaseProjectWizardDialog(const Core::BaseFileWizardFactory *factory, - QWidget *parent, const Core::WizardDialogParameters ¶meters) : - Core::BaseFileWizard(factory, parameters.extraValues(), parent), + Core::BaseFileWizard(factory, parameters.extraValues()), d(std::make_unique(new ProjectIntroPage)) { setFilePath(parameters.defaultPath()); @@ -52,9 +51,8 @@ BaseProjectWizardDialog::BaseProjectWizardDialog(const Core::BaseFileWizardFacto BaseProjectWizardDialog::BaseProjectWizardDialog(const Core::BaseFileWizardFactory *factory, ProjectIntroPage *introPage, int introId, - QWidget *parent, const Core::WizardDialogParameters ¶meters) : - Core::BaseFileWizard(factory, parameters.extraValues(), parent), + Core::BaseFileWizard(factory, parameters.extraValues()), d(std::make_unique(introPage, introId)) { setFilePath(parameters.defaultPath()); diff --git a/src/plugins/projectexplorer/baseprojectwizarddialog.h b/src/plugins/projectexplorer/baseprojectwizarddialog.h index 8cee34db556..6cd2ba29160 100644 --- a/src/plugins/projectexplorer/baseprojectwizarddialog.h +++ b/src/plugins/projectexplorer/baseprojectwizarddialog.h @@ -26,10 +26,10 @@ class PROJECTEXPLORER_EXPORT BaseProjectWizardDialog : public Core::BaseFileWiza protected: explicit BaseProjectWizardDialog(const Core::BaseFileWizardFactory *factory, Utils::ProjectIntroPage *introPage, int introId, - QWidget *parent, const Core::WizardDialogParameters ¶meters); + const Core::WizardDialogParameters ¶meters); public: - explicit BaseProjectWizardDialog(const Core::BaseFileWizardFactory *factory, QWidget *parent, + explicit BaseProjectWizardDialog(const Core::BaseFileWizardFactory *factory, const Core::WizardDialogParameters ¶meters); ~BaseProjectWizardDialog() override; diff --git a/src/plugins/projectexplorer/customwizard/customwizard.cpp b/src/plugins/projectexplorer/customwizard/customwizard.cpp index c2ff5082bbb..fe81b3ba7e7 100644 --- a/src/plugins/projectexplorer/customwizard/customwizard.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizard.cpp @@ -138,10 +138,10 @@ void CustomWizard::setParameters(const CustomWizardParametersPtr &p) setFlags(p->flags); } -BaseFileWizard *CustomWizard::create(QWidget *parent, const WizardDialogParameters &p) const +BaseFileWizard *CustomWizard::create(const WizardDialogParameters &p) const { QTC_ASSERT(d->m_parameters, return nullptr); - auto wizard = new BaseFileWizard(this, p.extraValues(), parent); + auto wizard = new BaseFileWizard(this, p.extraValues()); d->m_context->reset(); auto customPage = new CustomWizardPage(d->m_context, parameters()); @@ -461,10 +461,9 @@ CustomProjectWizard::CustomProjectWizard() = default; initProjectWizardDialog() needs to be called. */ -BaseFileWizard *CustomProjectWizard::create(QWidget *parent, - const WizardDialogParameters ¶meters) const +BaseFileWizard *CustomProjectWizard::create(const WizardDialogParameters ¶meters) const { - auto projectDialog = new BaseProjectWizardDialog(this, parent, parameters); + auto projectDialog = new BaseProjectWizardDialog(this, parameters); initProjectWizardDialog(projectDialog, parameters.defaultPath(), projectDialog->extensionPages()); diff --git a/src/plugins/projectexplorer/customwizard/customwizard.h b/src/plugins/projectexplorer/customwizard/customwizard.h index e1c1813f31c..f3421a04496 100644 --- a/src/plugins/projectexplorer/customwizard/customwizard.h +++ b/src/plugins/projectexplorer/customwizard/customwizard.h @@ -64,7 +64,7 @@ public: // Can be reimplemented to create custom wizards. initWizardDialog() needs to be // called. - Core::BaseFileWizard *create(QWidget *parent, const Core::WizardDialogParameters ¶meters) const override; + Core::BaseFileWizard *create(const Core::WizardDialogParameters ¶meters) const override; Core::GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const override; @@ -110,7 +110,7 @@ signals: void projectLocationChanged(const Utils::FilePath &path); protected: - Core::BaseFileWizard *create(QWidget *parent, const Core::WizardDialogParameters ¶meters) const override; + Core::BaseFileWizard *create(const Core::WizardDialogParameters ¶meters) const override; Core::GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const override; diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp index 5ee0965e9ec..eb05160570c 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp @@ -127,8 +127,8 @@ private: } // namespace Internal -JsonWizard::JsonWizard(QWidget *parent) - : Wizard(parent) +JsonWizard::JsonWizard() + : Wizard(Core::ICore::dialogParent()) { setMinimumSize(800, 500); m_expander.registerExtraResolver([this](const QString &name, QString *ret) -> bool { diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.h b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h index 90dc4c5d74d..648f95b3cfd 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h @@ -61,7 +61,7 @@ public: using GeneratorFiles = QList; Q_PROPERTY(GeneratorFiles generateFileList READ generateFileList) - explicit JsonWizard(QWidget *parent = nullptr); + JsonWizard(); ~JsonWizard() override; void addGenerator(JsonWizardGenerator *gen); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp index 100be4c6cf0..2553c23c949 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard_test.cpp @@ -138,7 +138,6 @@ void ProjectExplorerTest::testJsonWizardsCheckBox() { QString errorMessage; - QWidget parent; const QJsonArray widgets({ createWidget("CheckBox", "Default", QJsonObject()), createWidget("CheckBox", "Checked", QJsonObject({{"checked", true}})), @@ -155,21 +154,21 @@ void ProjectExplorerTest::testJsonWizardsCheckBox() const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), {}, &errorMessage)); QVERIFY2(factory, qPrintable(errorMessage)); - Wizard *wizard = factory->runWizard({}, &parent, Id(), QVariantMap()); + std::unique_ptr wizard{factory->runWizard({}, Id(), QVariantMap())}; - QVERIFY(!findCheckBox(wizard, "Default")->isChecked()); + QVERIFY(!findCheckBox(wizard.get(), "Default")->isChecked()); QCOMPARE(wizard->field("DefaultCheckBox"), QVariant(false)); - QVERIFY(findCheckBox(wizard, "Checked")->isChecked()); + QVERIFY(findCheckBox(wizard.get(), "Checked")->isChecked()); QCOMPARE(wizard->field("CheckedCheckBox"), QVariant(true)); - QVERIFY(!findCheckBox(wizard, "UnChecked")->isChecked()); + QVERIFY(!findCheckBox(wizard.get(), "UnChecked")->isChecked()); QCOMPARE(wizard->field("UnCheckedCheckBox"), QVariant(false)); - QVERIFY(!findCheckBox(wizard, "SpecialValueUnChecked")->isChecked()); + QVERIFY(!findCheckBox(wizard.get(), "SpecialValueUnChecked")->isChecked()); QCOMPARE(qPrintable(wizard->field("SpecialValueUnCheckedCheckBox").toString()), "SpecialUnCheckedValue"); - QVERIFY(findCheckBox(wizard, "SpecialValueChecked")->isChecked()); + QVERIFY(findCheckBox(wizard.get(), "SpecialValueChecked")->isChecked()); QCOMPARE(qPrintable(wizard->field("SpecialValueCheckedCheckBox").toString()), "SpecialCheckedValue"); } @@ -177,7 +176,6 @@ void ProjectExplorerTest::testJsonWizardsLineEdit() { QString errorMessage; - QWidget parent; const QJsonArray widgets({ createWidget("LineEdit", "Default", QJsonObject()), createWidget("LineEdit", "WithText", QJsonObject({{"trText", "some text"}})) @@ -187,20 +185,20 @@ void ProjectExplorerTest::testJsonWizardsLineEdit() const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), {}, &errorMessage)); QVERIFY2(factory, qPrintable(errorMessage)); - Wizard *wizard = factory->runWizard({}, &parent, Id(), QVariantMap()); - QVERIFY(findLineEdit(wizard, "Default")); - QVERIFY(findLineEdit(wizard, "Default")->text().isEmpty()); - QCOMPARE(qPrintable(findLineEdit(wizard, "WithText")->text()), "some text"); + std::unique_ptr wizard{factory->runWizard({}, Id(), QVariantMap())}; + QVERIFY(wizard); + QVERIFY(findLineEdit(wizard.get(), "Default")); + QVERIFY(findLineEdit(wizard.get(), "Default")->text().isEmpty()); + QCOMPARE(qPrintable(findLineEdit(wizard.get(), "WithText")->text()), "some text"); QVERIFY(!wizard->page(0)->isComplete()); - findLineEdit(wizard, "Default")->setText("enable isComplete"); + findLineEdit(wizard.get(), "Default")->setText("enable isComplete"); QVERIFY(wizard->page(0)->isComplete()); } void ProjectExplorerTest::testJsonWizardsComboBox() { QString errorMessage; - QWidget parent; const QJsonArray items({"abc", "cde", "fgh"}); QJsonObject disabledComboBoxObject = createWidget("ComboBox", "Disabled", QJsonObject({ {{"disabledIndex", 2}, {"items", items}} })); @@ -215,9 +213,9 @@ void ProjectExplorerTest::testJsonWizardsComboBox() const QJsonObject wizardObject = createGeneralWizard(pages); const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), {}, &errorMessage)); QVERIFY2(factory, qPrintable(errorMessage)); - Wizard *wizard = factory->runWizard({}, &parent, Id(), QVariantMap()); + std::unique_ptr wizard{factory->runWizard({}, Id(), QVariantMap())}; - QComboBox *defaultComboBox = findComboBox(wizard, "Default"); + QComboBox *defaultComboBox = findComboBox(wizard.get(), "Default"); QVERIFY(defaultComboBox); QCOMPARE(defaultComboBox->count(), items.count()); QCOMPARE(qPrintable(defaultComboBox->currentText()), "abc"); @@ -225,11 +223,11 @@ void ProjectExplorerTest::testJsonWizardsComboBox() defaultComboBox->setCurrentIndex(2); QCOMPARE(qPrintable(defaultComboBox->currentText()), "fgh"); - QComboBox *index2ComboBox = findComboBox(wizard, "Index2"); + QComboBox *index2ComboBox = findComboBox(wizard.get(), "Index2"); QVERIFY(index2ComboBox); QCOMPARE(qPrintable(index2ComboBox->currentText()), "fgh"); - QComboBox *disabledComboBox = findComboBox(wizard, "Disabled"); + QComboBox *disabledComboBox = findComboBox(wizard.get(), "Disabled"); QVERIFY(disabledComboBox); QCOMPARE(qPrintable(disabledComboBox->currentText()), "fgh"); } @@ -242,7 +240,6 @@ static QString iconInsideResource(const QString &relativePathToIcon) void ProjectExplorerTest::testJsonWizardsIconList() { QString errorMessage; - QWidget parent; const QJsonArray items({ QJsonObject{ @@ -272,7 +269,7 @@ void ProjectExplorerTest::testJsonWizardsIconList() const QJsonObject wizardObject = createGeneralWizard(pages); const FactoryPtr factory(JsonWizardFactory::createWizardFactory(wizardObject.toVariantMap(), {}, &errorMessage)); QVERIFY2(factory, qPrintable(errorMessage)); - Wizard *wizard = factory->runWizard({}, &parent, Id(), QVariantMap()); + std::unique_ptr wizard{factory->runWizard({}, Id(), QVariantMap())}; auto view = wizard->findChild("FancyIconList"); QCOMPARE(view->model()->rowCount(), 2); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index 6cb79cef777..fbf7534ee6e 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -653,11 +653,10 @@ static QString qmlProjectName(const FilePath &folder) return {}; } -Wizard *JsonWizardFactory::runWizardImpl(const FilePath &path, QWidget *parent, - Id platform, +Wizard *JsonWizardFactory::runWizardImpl(const FilePath &path, Id platform, const QVariantMap &variables, bool showWizard) { - auto wizard = new JsonWizard(parent); + auto wizard = new JsonWizard; wizard->setWindowIcon(icon()); wizard->setWindowTitle(displayName()); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h index 5e7fba1f1de..2e18346b29f 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h @@ -62,7 +62,7 @@ public: static void setInstalledWizardsPath(const Utils::FilePath &path); private: - Utils::Wizard *runWizardImpl(const Utils::FilePath &path, QWidget *parent, Utils::Id platform, + Utils::Wizard *runWizardImpl(const Utils::FilePath &path, Utils::Id platform, const QVariantMap &variables, bool showWizard = true) override; // Create all wizards. As other plugins might register factories for derived diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index f3451b92ca3..c1cba541107 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3621,7 +3621,7 @@ void ProjectExplorerPluginPrivate::addNewHeaderOrSource() IWizardFactory::allWizardFactories(), [factoryId](const IWizardFactory *f) { return f->id() == factoryId; }); QTC_ASSERT(factory, return); - factory->runWizard(folderNode->directory(), ICore::dialogParent(), {}, map); + factory->runWizard(folderNode->directory(), {}, map); } void ProjectExplorerPluginPrivate::addNewSubproject() diff --git a/src/plugins/projectexplorer/simpleprojectwizard.cpp b/src/plugins/projectexplorer/simpleprojectwizard.cpp index ad6e05fbe3b..68ea0f998fa 100644 --- a/src/plugins/projectexplorer/simpleprojectwizard.cpp +++ b/src/plugins/projectexplorer/simpleprojectwizard.cpp @@ -110,8 +110,8 @@ class SimpleProjectWizardDialog : public BaseFileWizard Q_OBJECT public: - SimpleProjectWizardDialog(const BaseFileWizardFactory *factory, QWidget *parent) - : BaseFileWizard(factory, QVariantMap(), parent) + explicit SimpleProjectWizardDialog(const BaseFileWizardFactory *factory) + : BaseFileWizard(factory, QVariantMap()) { setWindowTitle(Tr::tr("Import Existing Project")); @@ -162,10 +162,9 @@ SimpleProjectWizard::SimpleProjectWizard() setFlags(IWizardFactory::PlatformIndependent); } -BaseFileWizard *SimpleProjectWizard::create(QWidget *parent, - const WizardDialogParameters ¶meters) const +BaseFileWizard *SimpleProjectWizard::create(const WizardDialogParameters ¶meters) const { - auto wizard = new SimpleProjectWizardDialog(this, parent); + auto wizard = new SimpleProjectWizardDialog(this); wizard->setProjectDir(parameters.defaultPath()); for (QWizardPage *p : wizard->extensionPages()) diff --git a/src/plugins/projectexplorer/simpleprojectwizard.h b/src/plugins/projectexplorer/simpleprojectwizard.h index 2f5ffcc4d33..6400670f6e8 100644 --- a/src/plugins/projectexplorer/simpleprojectwizard.h +++ b/src/plugins/projectexplorer/simpleprojectwizard.h @@ -16,7 +16,7 @@ public: SimpleProjectWizard(); private: - Core::BaseFileWizard *create(QWidget *parent, const Core::WizardDialogParameters ¶meters) const override; + Core::BaseFileWizard *create(const Core::WizardDialogParameters ¶meters) const override; Core::GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const override; bool postGenerateFiles(const QWizard *w, const Core::GeneratedFiles &l, QString *errorMessage) const override; diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizard.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizard.cpp index b5322031bf1..03936a66a38 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizard.cpp +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizard.cpp @@ -29,10 +29,9 @@ CustomWidgetWizard::CustomWidgetWizard() setRequiredFeatures({QtSupport::Constants::FEATURE_QWIDGETS}); } -Core::BaseFileWizard *CustomWidgetWizard::create(QWidget *parent, const Core::WizardDialogParameters ¶meters) const +Core::BaseFileWizard *CustomWidgetWizard::create(const Core::WizardDialogParameters ¶meters) const { - CustomWidgetWizardDialog *rc = new CustomWidgetWizardDialog(this, displayName(), - icon(), parent, parameters); + auto rc = new CustomWidgetWizardDialog(this, displayName(), icon(), parameters); rc->setProjectName(CustomWidgetWizardDialog::uniqueProjectName(parameters.defaultPath())); rc->setFileNamingParameters(FileNamingParameters(headerSuffix(), sourceSuffix(), QtWizard::lowerCaseFiles())); return rc; diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizard.h b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizard.h index 456c3c8071e..b7c96102852 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizard.h +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizard.h @@ -16,8 +16,7 @@ public: CustomWidgetWizard(); protected: - Core::BaseFileWizard *create(QWidget *parent, - const Core::WizardDialogParameters ¶meters) const override; + Core::BaseFileWizard *create(const Core::WizardDialogParameters ¶meters) const override; Core::GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const override; }; diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizarddialog.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizarddialog.cpp index 49ff339f45a..4b160f39eed 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizarddialog.cpp +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizarddialog.cpp @@ -19,9 +19,8 @@ enum { IntroPageId = 0}; CustomWidgetWizardDialog::CustomWidgetWizardDialog(const Core::BaseFileWizardFactory *factory, const QString &templateName, - const QIcon &icon, QWidget *parent, - const Core::WizardDialogParameters ¶meters) : - BaseQmakeProjectWizardDialog(factory, parent, parameters), + const QIcon &icon, const Core::WizardDialogParameters ¶meters) : + BaseQmakeProjectWizardDialog(factory, parameters), m_widgetsPage(new CustomWidgetWidgetsWizardPage), m_pluginPage(new CustomWidgetPluginWizardPage) { diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizarddialog.h b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizarddialog.h index 6fcf38cba78..a20602bcf21 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizarddialog.h +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwizarddialog.h @@ -19,7 +19,6 @@ class CustomWidgetWizardDialog : public BaseQmakeProjectWizardDialog public: explicit CustomWidgetWizardDialog(const Core::BaseFileWizardFactory *factory, const QString &templateName, const QIcon &icon, - QWidget *parent, const Core::WizardDialogParameters ¶meters); std::shared_ptr pluginOptions() const; diff --git a/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp b/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp index a4493d6361d..840a3f849a6 100644 --- a/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/qtwizard.cpp @@ -97,10 +97,9 @@ bool QtWizard::lowerCaseFiles() // ------------ CustomQmakeProjectWizard CustomQmakeProjectWizard::CustomQmakeProjectWizard() = default; -Core::BaseFileWizard *CustomQmakeProjectWizard::create(QWidget *parent, - const Core::WizardDialogParameters ¶meters) const +Core::BaseFileWizard *CustomQmakeProjectWizard::create(const Core::WizardDialogParameters ¶meters) const { - auto *wizard = new BaseQmakeProjectWizardDialog(this, parent, parameters); + auto *wizard = new BaseQmakeProjectWizardDialog(this, parameters); if (!parameters.extraValues().contains(QLatin1String(ProjectExplorer::Constants::PROJECT_KIT_IDS))) wizard->addTargetSetupPage(targetPageId); @@ -118,9 +117,8 @@ bool CustomQmakeProjectWizard::postGenerateFiles(const QWizard *w, const Core::G // ----------------- BaseQmakeProjectWizardDialog BaseQmakeProjectWizardDialog::BaseQmakeProjectWizardDialog( const Core::BaseFileWizardFactory *factory, - QWidget *parent, const Core::WizardDialogParameters ¶meters) - : ProjectExplorer::BaseProjectWizardDialog(factory, parent, parameters) + : ProjectExplorer::BaseProjectWizardDialog(factory, parameters) { m_profileIds = Utils::transform(parameters.extraValues() .value(ProjectExplorer::Constants::PROJECT_KIT_IDS) @@ -135,9 +133,8 @@ BaseQmakeProjectWizardDialog::BaseQmakeProjectWizardDialog( const Core::BaseFileWizardFactory *factory, Utils::ProjectIntroPage *introPage, int introId, - QWidget *parent, const Core::WizardDialogParameters ¶meters) - : ProjectExplorer::BaseProjectWizardDialog(factory, introPage, introId, parent, parameters) + : ProjectExplorer::BaseProjectWizardDialog(factory, introPage, introId, parameters) { m_profileIds = Utils::transform(parameters.extraValues() .value(ProjectExplorer::Constants::PROJECT_KIT_IDS) diff --git a/src/plugins/qmakeprojectmanager/wizards/qtwizard.h b/src/plugins/qmakeprojectmanager/wizards/qtwizard.h index ba6b7ce6339..a6913d1e58e 100644 --- a/src/plugins/qmakeprojectmanager/wizards/qtwizard.h +++ b/src/plugins/qmakeprojectmanager/wizards/qtwizard.h @@ -60,8 +60,7 @@ public: CustomQmakeProjectWizard(); private: - Core::BaseFileWizard *create(QWidget *parent, - const Core::WizardDialogParameters ¶meters) const override; + Core::BaseFileWizard *create(const Core::WizardDialogParameters ¶meters) const override; bool postGenerateFiles(const QWizard *, const Core::GeneratedFiles &l, QString *errorMessage) const override; @@ -81,11 +80,10 @@ class BaseQmakeProjectWizardDialog : public ProjectExplorer::BaseProjectWizardDi protected: explicit BaseQmakeProjectWizardDialog(const Core::BaseFileWizardFactory *factory, Utils::ProjectIntroPage *introPage, - int introId, QWidget *parent, + int introId, const Core::WizardDialogParameters ¶meters); public: explicit BaseQmakeProjectWizardDialog(const Core::BaseFileWizardFactory *factory, - QWidget *parent, const Core::WizardDialogParameters ¶meters); ~BaseQmakeProjectWizardDialog() override; diff --git a/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizard.cpp b/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizard.cpp index bba91520493..1e5e932efee 100644 --- a/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizard.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizard.cpp @@ -33,11 +33,9 @@ SubdirsProjectWizard::SubdirsProjectWizard() setRequiredFeatures({QtSupport::Constants::FEATURE_QT_PREFIX}); } -Core::BaseFileWizard *SubdirsProjectWizard::create(QWidget *parent, - const Core::WizardDialogParameters ¶meters) const +Core::BaseFileWizard *SubdirsProjectWizard::create(const Core::WizardDialogParameters ¶meters) const { - SubdirsProjectWizardDialog *dialog = new SubdirsProjectWizardDialog(this, displayName(), icon(), - parent, parameters); + auto dialog = new SubdirsProjectWizardDialog(this, displayName(), icon(), parameters); dialog->setProjectName(SubdirsProjectWizardDialog::uniqueProjectName(parameters.defaultPath())); const QString buttonText = dialog->wizardStyle() == QWizard::MacStyle diff --git a/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizard.h b/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizard.h index 449c3a7e6d5..379c3456e0e 100644 --- a/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizard.h +++ b/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizard.h @@ -16,8 +16,7 @@ public: SubdirsProjectWizard(); private: - Core::BaseFileWizard *create(QWidget *parent, - const Core::WizardDialogParameters ¶meters) const override; + Core::BaseFileWizard *create(const Core::WizardDialogParameters ¶meters) const override; Core::GeneratedFiles generateFiles(const QWizard *w, QString *errorMessage) const override; bool postGenerateFiles(const QWizard *, const Core::GeneratedFiles &l, diff --git a/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizarddialog.cpp b/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizarddialog.cpp index 86b9f940f28..8a9dada3b99 100644 --- a/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizarddialog.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizarddialog.cpp @@ -13,9 +13,8 @@ namespace Internal { SubdirsProjectWizardDialog::SubdirsProjectWizardDialog(const Core::BaseFileWizardFactory *factory, const QString &templateName, - const QIcon &icon, QWidget *parent, - const Core::WizardDialogParameters ¶meters) : - BaseQmakeProjectWizardDialog(factory, parent, parameters) + const QIcon &icon, const Core::WizardDialogParameters ¶meters) : + BaseQmakeProjectWizardDialog(factory, parameters) { setWindowIcon(icon); setWindowTitle(templateName); diff --git a/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizarddialog.h b/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizarddialog.h index 4080e29ce94..3af2906e920 100644 --- a/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizarddialog.h +++ b/src/plugins/qmakeprojectmanager/wizards/subdirsprojectwizarddialog.h @@ -14,10 +14,9 @@ class SubdirsProjectWizardDialog : public BaseQmakeProjectWizardDialog { Q_OBJECT public: - explicit SubdirsProjectWizardDialog(const Core::BaseFileWizardFactory *factory, const QString &templateName, - const QIcon &icon, - QWidget *parent, - const Core::WizardDialogParameters ¶meters); + SubdirsProjectWizardDialog(const Core::BaseFileWizardFactory *factory, const QString &templateName, + const QIcon &icon, + const Core::WizardDialogParameters ¶meters); QtProjectParameters parameters() const; }; diff --git a/src/plugins/studiowelcome/qdsnewdialog.cpp b/src/plugins/studiowelcome/qdsnewdialog.cpp index 1032e7fceea..e483effd8ae 100644 --- a/src/plugins/studiowelcome/qdsnewdialog.cpp +++ b/src/plugins/studiowelcome/qdsnewdialog.cpp @@ -340,7 +340,7 @@ void QdsNewDialog::setWizardFactories(QList factories_, { Utils::Id platform = Utils::Id::fromSetting("Desktop"); - WizardFactories factories{factories_, m_dialog.get(), platform}; + WizardFactories factories{factories_, platform}; std::vector recents = m_recentsStore.fetchAll(); std::vector userPresets = m_userPresetsStore.fetchAll(); diff --git a/src/plugins/studiowelcome/wizardfactories.cpp b/src/plugins/studiowelcome/wizardfactories.cpp index 0b285d1c493..248b41b5e25 100644 --- a/src/plugins/studiowelcome/wizardfactories.cpp +++ b/src/plugins/studiowelcome/wizardfactories.cpp @@ -17,10 +17,8 @@ using namespace StudioWelcome; WizardFactories::GetIconUnicodeFunc WizardFactories::m_getIconUnicode = &QmlDesigner::Theme::getIconUnicode; WizardFactories::WizardFactories(const QList &factories, - QWidget *wizardParent, const Utils::Id &platform) - : m_wizardParent{wizardParent} - , m_platform{platform} + : m_platform{platform} { m_factories = Utils::filtered(Utils::transform(factories, [](Core::IWizardFactory *f) { return qobject_cast(f); @@ -56,8 +54,7 @@ void WizardFactories::filter() m_factories = acceptedFactories; } -std::shared_ptr WizardFactories::makePresetItem(JsonWizardFactory *f, QWidget *parent, - const Utils::Id &platform) +std::shared_ptr WizardFactories::makePresetItem(JsonWizardFactory *f, const Utils::Id &platform) { using namespace std::placeholders; @@ -77,7 +74,7 @@ std::shared_ptr WizardFactories::makePresetItem(JsonWizardFactory *f result->qmlPath = f->detailsPageQmlPath(); result->fontIconCode = m_getIconUnicode(f->fontIconName()); result->create - = std::bind(&JsonWizardFactory::runWizard, f, _1, parent, platform, QVariantMap(), false); + = std::bind(&JsonWizardFactory::runWizard, f, _1, platform, QVariantMap(), false); return result; } @@ -93,11 +90,11 @@ std::map WizardFactories::makePresetItemsGroupedByCateg /*.name =*/ f->displayCategory(), /*.items = */ { - makePresetItem(f, m_wizardParent, m_platform), + makePresetItem(f, m_platform), }, }; } else { - auto presetItem = makePresetItem(f, m_wizardParent, m_platform); + auto presetItem = makePresetItem(f, m_platform); categories[f->category()].items.push_back(presetItem); } } diff --git a/src/plugins/studiowelcome/wizardfactories.h b/src/plugins/studiowelcome/wizardfactories.h index 1a5640af629..dc9606fab09 100644 --- a/src/plugins/studiowelcome/wizardfactories.h +++ b/src/plugins/studiowelcome/wizardfactories.h @@ -25,8 +25,7 @@ public: using GetIconUnicodeFunc = QString (*)(const QString &); public: - WizardFactories(const QList &factories, QWidget *wizardParent, - const Utils::Id &platform); + WizardFactories(const QList &factories, const Utils::Id &platform); const Core::IWizardFactory *front() const; const std::map &presetsGroupedByCategory() const @@ -42,11 +41,10 @@ private: void sortByCategoryAndId(); void filter(); - std::shared_ptr makePresetItem(JsonWizardFactory *f, QWidget *parent, const Utils::Id &platform); + std::shared_ptr makePresetItem(JsonWizardFactory *f, const Utils::Id &platform); std::map makePresetItemsGroupedByCategory(); private: - QWidget *m_wizardParent; Utils::Id m_platform; // filter wizards to only those supported by this platform. QList m_factories; From 853ca0ccebffab6a52c212def634c00241310e5f Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Dec 2024 17:30:39 +0100 Subject: [PATCH 378/989] Debugger: Use internal decoding of Utils::Process for gdb output Change-Id: I1c7ec589370228588103909cad88ed51e897146d Reviewed-by: Marcus Tillmanns --- src/plugins/debugger/gdb/gdbengine.cpp | 6 ++---- src/plugins/debugger/gdb/gdbengine.h | 4 +--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index a3b16abdd60..1efb8e5081d 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -131,7 +131,6 @@ GdbEngine::GdbEngine() setObjectName("GdbEngine"); setDebuggerName("GDB"); - m_gdbOutputCodec = QTextCodec::codecForLocale(); m_inferiorOutputCodec = QTextCodec::codecForLocale(); m_commandTimer.setSingleShot(true); @@ -632,7 +631,7 @@ void GdbEngine::readGdbStandardOutput() int newstart = 0; int scan = m_inbuffer.size(); - QByteArray out = m_gdbProc.readAllRawStandardOutput(); + QString out = m_gdbProc.readAllStandardOutput(); m_inbuffer.append(out); // This can trigger when a dialog starts a nested event loop. @@ -657,8 +656,7 @@ void GdbEngine::readGdbStandardOutput() } m_busy = true; - QString msg = m_gdbOutputCodec->toUnicode(m_inbuffer.constData() + start, end - start, - &m_gdbOutputCodecState); + QString msg = m_inbuffer.mid(start, end - start); handleResponse(msg); m_busy = false; diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 33eec793a40..4beaaf29453 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -92,12 +92,10 @@ private: ////////// General Interface ////////// void readGdbStandardError(); void readDebuggeeOutput(const QByteArray &ba); - QTextCodec *m_gdbOutputCodec; - QTextCodec::ConverterState m_gdbOutputCodecState; QTextCodec *m_inferiorOutputCodec; QTextCodec::ConverterState m_inferiorOutputCodecState; - QByteArray m_inbuffer; + QString m_inbuffer; bool m_busy = false; // Name of the convenience variable containing the last From db11237dd559fe93acdf7d26c863280662f9adaf Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 10 Dec 2024 10:13:58 +0100 Subject: [PATCH 379/989] ProjectExplorer: Finish consolidating build and run device aspects The aspect factories were almost, but not entirely the same, leading to annoying differences in behavior. They now share the structural implementation. Fixes: QTCREATORBUG-32124 Change-Id: I7282141c2a0b4a6505dfdcb4b177bee558afd48b Reviewed-by: hjk --- .../cmakeprojectmanager/cmakekitaspect.cpp | 5 +- src/plugins/debugger/debuggerkitaspect.cpp | 2 + .../devicesupport/devicekitaspects.cpp | 542 +++++++----------- .../projectexplorer/devicesupport/idevice.cpp | 10 - .../projectexplorer/devicesupport/idevice.h | 1 - .../projectexplorer/toolchainkitaspect.cpp | 3 +- src/plugins/qtsupport/qtkitaspect.cpp | 5 +- 7 files changed, 226 insertions(+), 342 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp index 1b7ece214cc..36f2ec9801e 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp @@ -80,7 +80,10 @@ public: { clear(); - const FilePath rootPath = BuildDeviceKitAspect::device(&m_kit)->rootPath(); + const IDevice::ConstPtr dev = BuildDeviceKitAspect::device(&m_kit); + if (!dev) + return; + const FilePath rootPath = dev->rootPath(); const QList toolsForBuildDevice = Utils::filtered(CMakeToolManager::cmakeTools(), [rootPath](CMakeTool *item) { return item->cmakeExecutable().isSameDevice(rootPath); diff --git a/src/plugins/debugger/debuggerkitaspect.cpp b/src/plugins/debugger/debuggerkitaspect.cpp index 40294f56986..00f08ac5d37 100644 --- a/src/plugins/debugger/debuggerkitaspect.cpp +++ b/src/plugins/debugger/debuggerkitaspect.cpp @@ -49,6 +49,8 @@ public: clear(); const IDeviceConstPtr device = BuildDeviceKitAspect::device(&m_kit); + if (!device) + return; const Utils::FilePath rootPath = device->rootPath(); const QList debuggersForBuildDevice = Utils::filtered(DebuggerItemManager::debuggers(), [&](const DebuggerItem &item) { diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 33dde8b3578..0c0f067d03f 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -162,6 +162,169 @@ public: Tasks validate(const Kit *) const override { return {}; } }; +template +class DeviceKitAspectFactory : public KitAspectFactory +{ +public: + DeviceKitAspectFactory(const QByteArray &varPrefix) : m_varPrefix(varPrefix) + { + setId(DeviceAspect::id()); + setEmbeddableAspects({TypeAspect::id()}); + } + + static Id defaultValue(const Kit *k) + { + if (const IDeviceConstPtr &dev = DeviceManager::instance()->defaultDevice( + TypeAspect::deviceTypeId(k))) { + return dev->id(); + } + return {}; + } + +private: + static bool isCompatible(const IDevice::ConstPtr &dev, const Kit *k) + { + return dev->type() == TypeAspect::deviceTypeId(k); + } + + Tasks validate(const Kit *k) const override + { + const auto noDeviceMsg = [] { + if constexpr (std::is_same_v) + return Tr::tr("No build device set."); + if constexpr (std::is_same_v) + return Tr::tr("No run device set."); + }; + const auto incompatibleDeviceMsg = [] { + if constexpr (std::is_same_v) + return Tr::tr("Build device is incompatible with this kit."); + if constexpr (std::is_same_v) + return Tr::tr("Run device is incompatible with this kit."); + }; + const IDevice::ConstPtr dev = DeviceAspect::device(k); + Tasks result; + if (!dev) + result.append(BuildSystemTask(Task::Warning, noDeviceMsg())); + else if (!isCompatible(dev, k)) // FIXME: Impossible? + result.append(BuildSystemTask(Task::Error, incompatibleDeviceMsg())); + if (dev) + result.append(dev->validate()); + return result; + } + + void fix(Kit *k) override + { + const IDevice::ConstPtr dev = DeviceAspect::device(k); + if (dev && !isCompatible(dev, k)) + DeviceAspect::setDeviceId(k, defaultValue(k)); + } + + void setup(Kit *k) override + { + QTC_ASSERT(DeviceManager::instance()->isLoaded(), return); + if (const IDevice::ConstPtr dev = DeviceAspect::device(k); dev && isCompatible(dev, k)) + return; + DeviceAspect::setDeviceId(k, defaultValue(k)); + } + + KitAspect *createKitAspect(Kit *k) const override + { + QTC_ASSERT(k, return nullptr); + return new DeviceKitAspectImpl(k, this); + } + + QString displayNamePostfix(const Kit *k) const override + { + if (const IDevice::ConstPtr dev = DeviceAspect::device(k)) + return dev->displayName(); + return {}; + } + + ItemList toUserOutput(const Kit *k) const override + { + const IDevice::ConstPtr dev = DeviceAspect::device(k); + return {{displayName(), dev ? dev->displayName() : Tr::tr("Unconfigured") }}; + } + + QByteArray varName(const QByteArray &suffix) const + { + return m_varPrefix + ':' + suffix; + } + + QString varDescription(const QString &pattern) const + { + return pattern.arg(displayName()); + } + + void addToMacroExpander(Kit *kit, MacroExpander *expander) const override + { + QTC_ASSERT(kit, return); + expander->registerVariable( + varName("HostAddress"), varDescription(Tr::tr("Host address (%1)")), [kit] { + const IDevice::ConstPtr device = DeviceAspect::device(kit); + return device ? device->sshParameters().host() : QString(); + }); + expander + ->registerVariable(varName("SshPort"), varDescription(Tr::tr("SSH port (%1)")), [kit] { + const IDevice::ConstPtr device = DeviceAspect::device(kit); + return device ? QString::number(device->sshParameters().port()) : QString(); + }); + expander + ->registerVariable(varName("UserName"), varDescription(Tr::tr("User name (%1)")), [kit] { + const IDevice::ConstPtr device = DeviceAspect::device(kit); + return device ? device->sshParameters().userName() : QString(); + }); + expander->registerVariable( + varName("KeyFile"), varDescription(Tr::tr("Private key file (%1)")), [kit] { + const IDevice::ConstPtr device = DeviceAspect::device(kit); + return device ? device->sshParameters().privateKeyFile.toString() : QString(); + }); + expander + ->registerVariable(varName("Name"), varDescription(Tr::tr("Device name (%1)")), [kit] { + const IDevice::ConstPtr device = DeviceAspect::device(kit); + return device ? device->displayName() : QString(); + }); + expander->registerFileVariables( + varName("Root"), varDescription(Tr::tr("Device root directory (%1)")), [kit] { + const IDevice::ConstPtr device = DeviceAspect::device(kit); + return device ? device->rootPath() : FilePath{}; + }); + } + + void onKitsLoaded() override + { + for (Kit *k : KitManager::kits()) + fix(k); + + DeviceManager *dm = DeviceManager::instance(); + connect(dm, &DeviceManager::deviceListReplaced, this, &DeviceKitAspectFactory::devicesChanged); + connect(dm, &DeviceManager::deviceAdded, this, &DeviceKitAspectFactory::devicesChanged); + connect(dm, &DeviceManager::deviceRemoved, this, &DeviceKitAspectFactory::devicesChanged); + connect(dm, &DeviceManager::deviceUpdated, this, &DeviceKitAspectFactory::deviceUpdated); + + connect(KitManager::instance(), &KitManager::kitUpdated, + this, &DeviceKitAspectFactory::setup); + connect(KitManager::instance(), &KitManager::unmanagedKitUpdated, + this, &DeviceKitAspectFactory::setup); + } + + void deviceUpdated(Id id) + { + for (Kit *k : KitManager::kits()) { + if (DeviceAspect::deviceId(k) == id) + notifyAboutUpdate(k); + } + } + + void devicesChanged() + { + for (Kit *k : KitManager::kits()) + setup(k); // Set default device if necessary + } + + const QByteArray m_varPrefix; +}; + // -------------------------------------------------------------------------- // RunDeviceTypeKitAspect: // -------------------------------------------------------------------------- @@ -187,13 +350,17 @@ const Id RunDeviceTypeKitAspect::id() const Id RunDeviceTypeKitAspect::deviceTypeId(const Kit *k) { - return k ? Id::fromSetting(k->value(RunDeviceTypeKitAspect::id())) : Id(); + if (!k) + return {}; + if (const Id theId = Id::fromSetting(k->value(id())); theId.isValid()) + return theId; + return Constants::DESKTOP_DEVICE_TYPE; } void RunDeviceTypeKitAspect::setDeviceTypeId(Kit *k, Id type) { QTC_ASSERT(k, return); - k->setValue(RunDeviceTypeKitAspect::id(), type.toSetting()); + k->setValue(id(), type.toSetting()); } // -------------------------------------------------------------------------- @@ -201,176 +368,18 @@ void RunDeviceTypeKitAspect::setDeviceTypeId(Kit *k, Id type) // -------------------------------------------------------------------------- namespace Internal { -class RunDeviceKitAspectFactory : public KitAspectFactory +class RunDeviceKitAspectFactory + : public DeviceKitAspectFactory { public: - RunDeviceKitAspectFactory(); - -private: - Tasks validate(const Kit *k) const override; - void fix(Kit *k) override; - void setup(Kit *k) override; - - KitAspect *createKitAspect(Kit *k) const override; - - QString displayNamePostfix(const Kit *k) const override; - - ItemList toUserOutput(const Kit *k) const override; - - void addToMacroExpander(Kit *kit, MacroExpander *expander) const override; - - QVariant defaultValue(const Kit *k) const; - - void onKitsLoaded() override; - void deviceUpdated(Id dataId); - void devicesChanged(); - void kitUpdated(Kit *k); + RunDeviceKitAspectFactory() : DeviceKitAspectFactory("Device") + { + setDisplayName(Tr::tr("Run device")); + setDescription(Tr::tr("The device to run the applications on.")); + setPriority(32000); + } }; -RunDeviceKitAspectFactory::RunDeviceKitAspectFactory() -{ - setId(RunDeviceKitAspect::id()); - setDisplayName(Tr::tr("Run device")); - setDescription(Tr::tr("The device to run the applications on.")); - setPriority(32000); - setEmbeddableAspects({RunDeviceTypeKitAspect::id()}); -} - -QVariant RunDeviceKitAspectFactory::defaultValue(const Kit *k) const -{ - Id type = RunDeviceTypeKitAspect::deviceTypeId(k); - // Use default device if that is compatible: - IDevice::ConstPtr dev = DeviceManager::instance()->defaultDevice(type); - if (dev && dev->isCompatibleWith(k)) - return dev->id().toString(); - // Use any other device that is compatible: - for (int i = 0; i < DeviceManager::instance()->deviceCount(); ++i) { - dev = DeviceManager::instance()->deviceAt(i); - if (dev && dev->isCompatibleWith(k)) - return dev->id().toString(); - } - // Fail: No device set up. - return {}; -} - -Tasks RunDeviceKitAspectFactory::validate(const Kit *k) const -{ - IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); - Tasks result; - if (!dev) - result.append(BuildSystemTask(Task::Warning, Tr::tr("No device set."))); - else if (!dev->isCompatibleWith(k)) - result.append(BuildSystemTask(Task::Error, Tr::tr("Device is incompatible with this kit."))); - - if (dev) - result.append(dev->validate()); - - return result; -} - -void RunDeviceKitAspectFactory::fix(Kit *k) -{ - IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); - if (dev && !dev->isCompatibleWith(k)) { - qWarning("Device is no longer compatible with kit \"%s\", removing it.", - qPrintable(k->displayName())); - RunDeviceKitAspect::setDeviceId(k, Id()); - } -} - -void RunDeviceKitAspectFactory::setup(Kit *k) -{ - QTC_ASSERT(DeviceManager::instance()->isLoaded(), return); - IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); - if (dev && dev->isCompatibleWith(k)) - return; - - RunDeviceKitAspect::setDeviceId(k, Id::fromSetting(defaultValue(k))); -} - -KitAspect *RunDeviceKitAspectFactory::createKitAspect(Kit *k) const -{ - QTC_ASSERT(k, return nullptr); - return new Internal::DeviceKitAspectImpl(k, this); -} - -QString RunDeviceKitAspectFactory::displayNamePostfix(const Kit *k) const -{ - IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); - return dev ? dev->displayName() : QString(); -} - -KitAspectFactory::ItemList RunDeviceKitAspectFactory::toUserOutput(const Kit *k) const -{ - IDevice::ConstPtr dev = RunDeviceKitAspect::device(k); - return {{Tr::tr("Device"), dev ? dev->displayName() : Tr::tr("Unconfigured") }}; -} - -void RunDeviceKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expander) const -{ - QTC_ASSERT(kit, return); - expander->registerVariable("Device:HostAddress", Tr::tr("Host address"), [kit] { - const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); - return device ? device->sshParameters().host() : QString(); - }); - expander->registerVariable("Device:SshPort", Tr::tr("SSH port"), [kit] { - const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); - return device ? QString::number(device->sshParameters().port()) : QString(); - }); - expander->registerVariable("Device:UserName", Tr::tr("User name"), [kit] { - const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); - return device ? device->sshParameters().userName() : QString(); - }); - expander->registerVariable("Device:KeyFile", Tr::tr("Private key file"), [kit] { - const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); - return device ? device->sshParameters().privateKeyFile.toString() : QString(); - }); - expander->registerVariable("Device:Name", Tr::tr("Device name"), [kit] { - const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); - return device ? device->displayName() : QString(); - }); - expander->registerFileVariables("Device::Root", Tr::tr("Device root directory"), [kit] { - const IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); - return device ? device->rootPath() : FilePath{}; - }); -} - -void RunDeviceKitAspectFactory::onKitsLoaded() -{ - for (Kit *k : KitManager::kits()) - fix(k); - - DeviceManager *dm = DeviceManager::instance(); - connect(dm, &DeviceManager::deviceListReplaced, this, &RunDeviceKitAspectFactory::devicesChanged); - connect(dm, &DeviceManager::deviceAdded, this, &RunDeviceKitAspectFactory::devicesChanged); - connect(dm, &DeviceManager::deviceRemoved, this, &RunDeviceKitAspectFactory::devicesChanged); - connect(dm, &DeviceManager::deviceUpdated, this, &RunDeviceKitAspectFactory::deviceUpdated); - - connect(KitManager::instance(), &KitManager::kitUpdated, - this, &RunDeviceKitAspectFactory::kitUpdated); - connect(KitManager::instance(), &KitManager::unmanagedKitUpdated, - this, &RunDeviceKitAspectFactory::kitUpdated); -} - -void RunDeviceKitAspectFactory::deviceUpdated(Id id) -{ - for (Kit *k : KitManager::kits()) { - if (RunDeviceKitAspect::deviceId(k) == id) - notifyAboutUpdate(k); - } -} - -void RunDeviceKitAspectFactory::kitUpdated(Kit *k) -{ - setup(k); // Set default device if necessary -} - -void RunDeviceKitAspectFactory::devicesChanged() -{ - for (Kit *k : KitManager::kits()) - setup(k); // Set default device if necessary -} - const RunDeviceKitAspectFactory theDeviceKitAspectFactory; } // namespace Internal @@ -389,7 +398,11 @@ IDevice::ConstPtr RunDeviceKitAspect::device(const Kit *k) Id RunDeviceKitAspect::deviceId(const Kit *k) { - return k ? Id::fromSetting(k->value(RunDeviceKitAspect::id())) : Id(); + if (!k) + return {}; + if (const Id theId = Id::fromSetting(k->value(id())); theId.isValid()) + return theId; + return Internal::RunDeviceKitAspectFactory::defaultValue(k); } void RunDeviceKitAspect::setDevice(Kit *k, IDevice::ConstPtr dev) @@ -447,177 +460,49 @@ Id BuildDeviceTypeKitAspect::id() Id BuildDeviceTypeKitAspect::deviceTypeId(const Kit *k) { - return k ? Id::fromSetting(k->value(BuildDeviceTypeKitAspect::id())) : Id(); + if (!k) + return {}; + if (const Id theId = Id::fromSetting(k->value(id())); theId.isValid()) + return theId; + return Constants::DESKTOP_DEVICE_TYPE; } void BuildDeviceTypeKitAspect::setDeviceTypeId(Kit *k, Utils::Id type) { QTC_ASSERT(k, return); - k->setValue(BuildDeviceTypeKitAspect::id(), type.toSetting()); + k->setValue(id(), type.toSetting()); } // -------------------------------------------------------------------------- // BuildDeviceKitAspect: // -------------------------------------------------------------------------- namespace Internal { -class BuildDeviceKitAspectFactory : public KitAspectFactory +class BuildDeviceKitAspectFactory + : public DeviceKitAspectFactory { public: - BuildDeviceKitAspectFactory(); + BuildDeviceKitAspectFactory() : DeviceKitAspectFactory("BuildDevice") + { + setDisplayName(Tr::tr("Build device")); + setDescription(Tr::tr("The device used to build applications on.")); + setPriority(31900); + } private: - void setup(Kit *k) override; - Tasks validate(const Kit *k) const override; - - KitAspect *createKitAspect(Kit *k) const override; - - QString displayNamePostfix(const Kit *k) const override; - - ItemList toUserOutput(const Kit *k) const override; - - void addToMacroExpander(Kit *kit, MacroExpander *expander) const override; - void addToBuildEnvironment(const Kit *k, Utils::Environment &env) const override; - - void onKitsLoaded() override; - void deviceUpdated(Id dataId); - void devicesChanged(); - void kitUpdated(Kit *k); -}; - -BuildDeviceKitAspectFactory::BuildDeviceKitAspectFactory() -{ - setId(BuildDeviceKitAspect::id()); - setDisplayName(Tr::tr("Build device")); - setDescription(Tr::tr("The device used to build applications on.")); - setPriority(31900); - setEmbeddableAspects({BuildDeviceTypeKitAspect::id()}); -} - -static IDeviceConstPtr defaultDevice() -{ - return DeviceManager::defaultDesktopDevice(); -} - -void BuildDeviceKitAspectFactory::setup(Kit *k) -{ - QTC_ASSERT(DeviceManager::instance()->isLoaded(), return ); - IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k); - if (dev) - return; - - dev = defaultDevice(); - BuildDeviceKitAspect::setDeviceId(k, dev ? dev->id() : Id()); -} - -Tasks BuildDeviceKitAspectFactory::validate(const Kit *k) const -{ - IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k); - Tasks result; - if (!dev) - result.append(BuildSystemTask(Task::Warning, Tr::tr("No build device set."))); - - return result; -} - -KitAspect *BuildDeviceKitAspectFactory::createKitAspect(Kit *k) const -{ - QTC_ASSERT(k, return nullptr); - return new Internal::DeviceKitAspectImpl(k, this); -} - -QString BuildDeviceKitAspectFactory::displayNamePostfix(const Kit *k) const -{ - IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k); - return dev ? dev->displayName() : QString(); -} - -KitAspectFactory::ItemList BuildDeviceKitAspectFactory::toUserOutput(const Kit *k) const -{ - IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k); - return {{Tr::tr("Build device"), dev ? dev->displayName() : Tr::tr("Unconfigured")}}; -} - -void BuildDeviceKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expander) const -{ - QTC_ASSERT(kit, return); - expander->registerVariable("BuildDevice:HostAddress", Tr::tr("Build host address"), [kit] { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? device->sshParameters().host() : QString(); - }); - expander->registerVariable("BuildDevice:SshPort", Tr::tr("Build SSH port"), [kit] { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? QString::number(device->sshParameters().port()) : QString(); - }); - expander->registerVariable("BuildDevice:UserName", Tr::tr("Build user name"), [kit] { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? device->sshParameters().userName() : QString(); - }); - expander->registerVariable("BuildDevice:KeyFile", Tr::tr("Build private key file"), [kit] { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? device->sshParameters().privateKeyFile.toString() : QString(); - }); - expander->registerVariable("BuildDevice:Name", Tr::tr("Build device name"), [kit] { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? device->displayName() : QString(); - }); - expander - ->registerFileVariables("BuildDevice::Root", Tr::tr("Build device root directory"), [kit] { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? device->rootPath() : FilePath{}; - }); -} - -void BuildDeviceKitAspectFactory::addToBuildEnvironment(const Kit *k, Environment &env) const -{ - IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k); - if (dev->osType() == OsType::OsTypeWindows && dev->type() == Constants::DESKTOP_DEVICE_TYPE) { - if (const FilePath appSdkLocation = windowsAppSdkSettings().windowsAppSdkLocation(); - !appSdkLocation.isEmpty()) { - env.set(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY, appSdkLocation.path()); + void addToBuildEnvironment(const Kit *k, Utils::Environment &env) const override + { + IDevice::ConstPtr dev = BuildDeviceKitAspect::device(k); + if (!dev) + return; + if (dev->osType() == OsType::OsTypeWindows + && dev->type() == Constants::DESKTOP_DEVICE_TYPE) { + if (const FilePath appSdkLocation = windowsAppSdkSettings().windowsAppSdkLocation(); + !appSdkLocation.isEmpty()) { + env.set(Constants::WINDOWS_WINAPPSDK_ROOT_ENV_KEY, appSdkLocation.path()); + } } } -} - -void BuildDeviceKitAspectFactory::onKitsLoaded() -{ - for (Kit *k : KitManager::kits()) - fix(k); - - DeviceManager *dm = DeviceManager::instance(); - connect(dm, &DeviceManager::deviceListReplaced, - this, &BuildDeviceKitAspectFactory::devicesChanged); - connect(dm, &DeviceManager::deviceAdded, - this, &BuildDeviceKitAspectFactory::devicesChanged); - connect(dm, &DeviceManager::deviceRemoved, - this, &BuildDeviceKitAspectFactory::devicesChanged); - connect(dm, &DeviceManager::deviceUpdated, - this, &BuildDeviceKitAspectFactory::deviceUpdated); - connect(KitManager::instance(), &KitManager::kitUpdated, - this, &BuildDeviceKitAspectFactory::kitUpdated); - connect(KitManager::instance(), &KitManager::unmanagedKitUpdated, - this, &BuildDeviceKitAspectFactory::kitUpdated); -} - -void BuildDeviceKitAspectFactory::deviceUpdated(Id id) -{ - const QList kits = KitManager::kits(); - for (Kit *k : kits) { - if (BuildDeviceKitAspect::deviceId(k) == id) - notifyAboutUpdate(k); - } -} - -void BuildDeviceKitAspectFactory::kitUpdated(Kit *k) -{ - setup(k); // Set default device if necessary -} - -void BuildDeviceKitAspectFactory::devicesChanged() -{ - const QList kits = KitManager::kits(); - for (Kit *k : kits) - setup(k); // Set default device if necessary -} +}; const BuildDeviceKitAspectFactory theBuildDeviceKitAspectFactory; @@ -631,15 +516,16 @@ Id BuildDeviceKitAspect::id() IDevice::ConstPtr BuildDeviceKitAspect::device(const Kit *k) { QTC_ASSERT(DeviceManager::instance()->isLoaded(), return IDevice::ConstPtr()); - IDevice::ConstPtr dev = DeviceManager::instance()->find(deviceId(k)); - if (!dev) - dev = Internal::defaultDevice(); - return dev; + return DeviceManager::instance()->find(deviceId(k)); } Id BuildDeviceKitAspect::deviceId(const Kit *k) { - return k ? Id::fromSetting(k->value(BuildDeviceKitAspect::id())) : Id(); + if (!k) + return {}; + if (const Id theId = Id::fromSetting(k->value(id())); theId.isValid()) + return theId; + return Internal::BuildDeviceKitAspectFactory::defaultValue(k); } void BuildDeviceKitAspect::setDevice(Kit *k, IDevice::ConstPtr dev) diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index bb5479539f6..35235cba2a4 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -415,16 +415,6 @@ Id IDevice::id() const return d->id; } -/*! - Tests whether a device can be compatible with the given kit. The default - implementation will match the device type specified in the kit against - the device's own type. -*/ -bool IDevice::isCompatibleWith(const Kit *k) const -{ - return RunDeviceTypeKitAspect::deviceTypeId(k) == type(); -} - QList IDevice::validate() const { return {}; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 58737ec6c7a..77b09e3afd2 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -119,7 +119,6 @@ public: bool isAutoDetected() const; Utils::Id id() const; - virtual bool isCompatibleWith(const Kit *k) const; virtual QList validate() const; QString displayType() const; diff --git a/src/plugins/projectexplorer/toolchainkitaspect.cpp b/src/plugins/projectexplorer/toolchainkitaspect.cpp index 77ea6a6981b..657b1ab216f 100644 --- a/src/plugins/projectexplorer/toolchainkitaspect.cpp +++ b/src/plugins/projectexplorer/toolchainkitaspect.cpp @@ -13,7 +13,6 @@ #include "toolchainmanager.h" #include "toolchainoptionspage.h" -#include #include #include #include @@ -44,6 +43,8 @@ public: const Toolchains ltcList = ToolchainManager::toolchains( [this](const Toolchain *tc) { return m_category.contains(tc->language()); }); IDeviceConstPtr device = BuildDeviceKitAspect::device(&m_kit); + if (!device) + return; const QList toolchainsForBuildDevice = Utils::filtered(ltcList, [device](Toolchain *tc) { diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index fb0d7a4a504..4af43dbbf85 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -49,7 +49,10 @@ public: { clear(); - const FilePath deviceRoot = BuildDeviceKitAspect::device(&m_kit)->rootPath(); + const IDevice::ConstPtr device = BuildDeviceKitAspect::device(&m_kit); + if (!device) + return; + const FilePath deviceRoot = device->rootPath(); const QtVersions versionsForBuildDevice = QtVersionManager::versions( [&deviceRoot](const QtVersion *qt) { return qt->qmakeFilePath().isSameDevice(deviceRoot); From 3f6522c38b71966cc6d74cf09375b3971eb7019e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 4 Dec 2024 17:09:08 +0100 Subject: [PATCH 380/989] CPlusPlus: Store concept name as QualifiedNameAST This simplifies the code and improves handling of nested template type parameters in some contexts. Fixes: QTCREATORBUG-32079 Change-Id: Ifb28fc19ab3cb1747df097589027bb8e33cf037a Reviewed-by: Christian Stenger --- src/libs/3rdparty/cplusplus/AST.cpp | 2 -- src/libs/3rdparty/cplusplus/AST.h | 3 +-- src/libs/3rdparty/cplusplus/ASTClone.cpp | 3 --- src/libs/3rdparty/cplusplus/ASTMatcher.cpp | 4 ---- src/libs/3rdparty/cplusplus/ASTVisit.cpp | 1 - src/libs/3rdparty/cplusplus/Parser.cpp | 5 +++-- 6 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 5c59bb683ca..cfff38692ed 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -4667,8 +4667,6 @@ int NoExceptOperatorExpressionAST::lastToken() const int TypeConstraintAST::firstToken() const { - if (nestedName) - return nestedName->firstToken(); return conceptName->firstToken(); } diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 70ee37b9f9d..b42caca73b3 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -646,8 +646,7 @@ protected: class CPLUSPLUS_EXPORT TypeConstraintAST: public AST { public: - NestedNameSpecifierListAST *nestedName = nullptr; - NameAST *conceptName = nullptr; + QualifiedNameAST *conceptName = nullptr; int lessToken = 0; ExpressionListAST *templateArgs = nullptr; int greaterToken = 0; diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index 688a7708534..55aa6fdbf25 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -144,9 +144,6 @@ DecltypeSpecifierAST *DecltypeSpecifierAST::clone(MemoryPool *pool) const TypeConstraintAST *TypeConstraintAST::clone(MemoryPool *pool) const { const auto ast = new (pool) TypeConstraintAST; - for (NestedNameSpecifierListAST *iter = nestedName, **ast_iter = &ast->nestedName; iter; - iter = iter->next, ast_iter = &(*ast_iter)->next) - *ast_iter = new (pool) NestedNameSpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr); if (conceptName) ast->conceptName = conceptName->clone(pool); ast->lessToken = lessToken; diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index e417ecc3072..747abaa2ae4 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -218,10 +218,6 @@ bool ASTMatcher::match(DecltypeSpecifierAST *node, DecltypeSpecifierAST *pattern bool ASTMatcher::match(TypeConstraintAST *node, TypeConstraintAST *pattern) { - if (!pattern->nestedName) - pattern->nestedName = node->nestedName; - else if (!AST::match(node->nestedName, pattern->nestedName, this)) - return false; if (!pattern->conceptName) pattern->conceptName = node->conceptName; else if (!AST::match(node->conceptName, pattern->conceptName, this)) diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index 937a9a0ab15..af47e6d4792 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -113,7 +113,6 @@ void DecltypeSpecifierAST::accept0(ASTVisitor *visitor) void TypeConstraintAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { - accept(nestedName, visitor); accept(conceptName, visitor); accept(templateArgs, visitor); } diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 21465014748..40d0997692a 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -1338,8 +1338,9 @@ bool Parser::parseTypeConstraint(TypeConstraintAST *&node) if (!parseUnqualifiedName(conceptName, false)) return false; const auto typeConstraint = new (_pool) TypeConstraintAST; - typeConstraint->nestedName = nestedName; - typeConstraint->conceptName = conceptName; + typeConstraint->conceptName = new (_pool) QualifiedNameAST; + typeConstraint->conceptName->nested_name_specifier_list = nestedName; + typeConstraint->conceptName->unqualified_name = conceptName; if (LA() != T_LESS) { node = typeConstraint; return true; From bd0988f32738cb311907f26c816f8c4b46ae2184 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Dec 2024 16:44:47 +0100 Subject: [PATCH 381/989] ProjectExplorer: Add more Device{Const,}Ref interface Change-Id: Iada993c11c645bbaf97ebdd269ce5929fa66c62f Reviewed-by: Christian Kandeler --- .../projectexplorer/devicesupport/idevice.cpp | 24 +++++++++++++++++++ .../projectexplorer/devicesupport/idevice.h | 6 +++++ 2 files changed, 30 insertions(+) diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 35235cba2a4..411398bfdef 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -794,6 +794,11 @@ DeviceConstRef::DeviceConstRef(const IDevice::Ptr &device) : m_constDevice(device) {} +IDevice::ConstPtr DeviceConstRef::lock() const +{ + return m_constDevice.lock(); +} + DeviceConstRef::~DeviceConstRef() = default; Id DeviceConstRef::id() const @@ -817,12 +822,31 @@ SshParameters DeviceConstRef::sshParameters() const return device->sshParameters(); } +QVariant DeviceConstRef::extraData(Id kind) const +{ + const IDevice::ConstPtr device = m_constDevice.lock(); + QTC_ASSERT(device, return {}); + return device->extraData(kind); +} + +FilePath DeviceConstRef::filePath(const QString &pathOnDevice) const +{ + const IDevice::ConstPtr device = m_constDevice.lock(); + QTC_ASSERT(device, return {}); + return device->filePath(pathOnDevice); +} + // DeviceRef, mutable DeviceRef::DeviceRef(const IDevice::Ptr &device) : DeviceConstRef(device), m_mutableDevice(device) {} +IDevice::Ptr DeviceRef::lock() const +{ + return m_mutableDevice.lock(); +} + void DeviceRef::setDisplayName(const QString &displayName) { const IDevice::Ptr device = m_mutableDevice.lock(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 77b09e3afd2..5892ba36c55 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -251,9 +251,13 @@ public: DeviceConstRef(const IDevice::Ptr &device); virtual ~DeviceConstRef(); + IDevice::ConstPtr lock() const; + Utils::Id id() const; QString displayName() const; SshParameters sshParameters() const; + Utils::FilePath filePath(const QString &pathOnDevice) const; + QVariant extraData(Utils::Id kind) const; private: std::weak_ptr m_constDevice; @@ -264,6 +268,8 @@ class PROJECTEXPLORER_EXPORT DeviceRef : public DeviceConstRef public: DeviceRef(const IDevice::Ptr &device); + IDevice::Ptr lock() const; + void setDisplayName(const QString &displayName); void setSshParameters(const SshParameters ¶ms); From 286512d5992ba3736c1323dd9207fa82a815f201 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 10 Dec 2024 13:05:39 +0100 Subject: [PATCH 382/989] ProjectExplorer: Re-use CommandLine::addCommandLineAsSingleArg() ... for its intended purpose. Change-Id: Idd3c2888e22f8d1d62902365e55456f043616866 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/linuxdevice.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 6975372d4b6..b0c48da1d4f 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -486,11 +486,11 @@ qint64 SshProcessInterface::processId() const ProcessResult SshProcessInterface::runInShell(const CommandLine &command, const QByteArray &data) { + CommandLine cmd{d->m_device->filePath("/bin/sh"), {"-c"}}; + cmd.addCommandLineAsSingleArg(command); + Process process; - QString tmp; - ProcessArgs::addArg(&tmp, command.executable().path()); - ProcessArgs::addArgs(&tmp, command.arguments()); - process.setCommand({d->m_device->filePath("/bin/sh"), {"-c", tmp}}); + process.setCommand(cmd); process.setWriteData(data); using namespace std::chrono_literals; process.runBlocking(2s); From 9a94da70da608b794f6183f618adc05ec6232dc7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 21 Nov 2024 10:33:18 +0100 Subject: [PATCH 383/989] KArchive: Add creator specific changes Change-Id: I8227bffd0e83d69d456e49a9d5f66a5ef00ba60e Reviewed-by: Eike Ziller --- scripts/build.py | 3 + src/libs/3rdparty/CMakeLists.txt | 3 +- src/libs/3rdparty/karchive/CMakeLists.txt | 398 ++++++++++++------ src/libs/3rdparty/karchive/CMakeLists.txt.kde | 152 +++++++ src/libs/3rdparty/karchive/src/k7zip.cpp | 11 +- src/libs/3rdparty/karchive/src/karchive.cpp | 16 +- .../karchive/src/kcompressiondevice.cpp | 2 - .../3rdparty/karchive/src/kgzipfilter.cpp | 3 + src/libs/3rdparty/karchive/src/ktar.cpp | 2 +- src/libs/3rdparty/karchive/src/kzip.cpp | 80 ++-- 10 files changed, 496 insertions(+), 174 deletions(-) create mode 100644 src/libs/3rdparty/karchive/CMakeLists.txt.kde diff --git a/scripts/build.py b/scripts/build.py index 6f2cd39e668..737c84a7066 100755 --- a/scripts/build.py +++ b/scripts/build.py @@ -169,6 +169,9 @@ def build_qtcreator(args, paths): '-DBUILD_DEVELOPER_DOCS=' + cmake_option(not args.no_docs), '-DBUILD_EXECUTABLE_SDKTOOL=' + cmake_option(args.with_sdk_tool), '-DQTC_FORCE_XCB=ON', + '-DQTC_USE_SYSTEM_ZLIB=OFF', + '-DQTC_USE_SYSTEM_BZIP2=OFF', + '-DQTC_USE_SYSTEM_LZMA=OFF', '-DWITH_TESTS=' + cmake_option(args.with_tests)] cmake_args += common_cmake_arguments(args) diff --git a/src/libs/3rdparty/CMakeLists.txt b/src/libs/3rdparty/CMakeLists.txt index 3c28a28afd1..e11e6cea919 100644 --- a/src/libs/3rdparty/CMakeLists.txt +++ b/src/libs/3rdparty/CMakeLists.txt @@ -5,8 +5,7 @@ add_subdirectory(libptyqt) add_subdirectory(qtkeychain) add_subdirectory(lua) add_subdirectory(sol2) -# Do not enable it yet, as the necessary changes are only introduced with the next patch. -#add_subdirectory(karchive) +add_subdirectory(karchive) if(WIN32) add_subdirectory(winpty) diff --git a/src/libs/3rdparty/karchive/CMakeLists.txt b/src/libs/3rdparty/karchive/CMakeLists.txt index 43b61a998f1..26fe6ae5484 100644 --- a/src/libs/3rdparty/karchive/CMakeLists.txt +++ b/src/libs/3rdparty/karchive/CMakeLists.txt @@ -1,152 +1,302 @@ -cmake_minimum_required(VERSION 3.16) +option(QTC_USE_SYSTEM_BZIP2 "Use system bzip2 instead of included bzip2" ON) +option(QTC_USE_SYSTEM_ZLIB "Use system zlib instead of included zlib" ON) +option(QTC_USE_SYSTEM_LZMA "Use system liblzma instead of included liblzma" ON) -set(KF_VERSION "6.10.0") # handled by release scripts -project(KArchive VERSION ${KF_VERSION}) - -include(FeatureSummary) -find_package(ECM 6.9.0 NO_MODULE) -set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") -feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) - -option(WITH_BZIP2 "Make bzip2 required" ON) -option(WITH_LIBLZMA "Make liblzma required" ON) -option(WITH_LIBZSTD "Make libzstd required" ON) - -set(PKGCONFIG_REQUIRED_TYPE "") - -if(WITH_BZIP2) - set(BZIP2_PACKAGE_TYPE "REQUIRED") -else() - set(BZIP2_PACKAGE_TYPE "RECOMMENDED") +if (QTC_USE_SYSTEM_BZIP2) + find_package(BZip2) + if (NOT TARGET BZip2::BZip2) + set(BZIP2_FALLBACK " (No system bzip2 found)") + endif() endif() -if(WITH_LIBLZMA) - set(LIBLZMA_PACKAGE_TYPE "REQUIRED") -else() - set(LIBLZMA_PACKAGE_TYPE "RECOMMENDED") +if (QTC_USE_SYSTEM_ZLIB) + find_package(ZLIB) + if (NOT TARGET ZLIB::ZLIB) + set(ZLIB_FALLBACK " (No system zlib found)") + endif() endif() -if(WITH_LIBZSTD) - set(PKGCONFIG_REQUIRED_TYPE "REQUIRED") - set(LIBZSTD_REQUIRED_TYPE "REQUIRED") -else() - set(LIBZSTD_REQUIRED_TYPE "") +if (QTC_USE_SYSTEM_LZMA) + find_package(LibLZMA) + if (NOT TARGET LibLZMA::LibLZMA) + set(LZMA_FALLBACK " (No system liblzma found)") + endif() endif() -set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) - -include(KDEInstallDirs) -include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) -include(KDECMakeSettings) -include(KDEGitCommitHooks) - -include(ECMGenerateExportHeader) - -set(REQUIRED_QT_VERSION 6.6.0) -find_package(Qt6Core ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) - -find_package(ZLIB) -set_package_properties(ZLIB PROPERTIES - URL "https://www.zlib.net" - DESCRIPTION "Support for gzip compressed files and data streams" - TYPE REQUIRED - PURPOSE "Support for gzip compressed files and data streams" +add_qtc_library( + karchive + DEPENDS Qt::Core + PUBLIC_INCLUDES src + SOURCES + src/kar.cpp + src/kar.h + src/karchive_export.h + src/karchive_p.h + src/karchive.cpp + src/karchive.h + src/karchivedirectory.h + src/karchiveentry.h + src/karchivefile.h + src/kcompressiondevice_p.h + src/kcompressiondevice.cpp + src/kcompressiondevice.h + src/kfilterbase.cpp + src/kfilterbase.h + src/klimitediodevice_p.h + src/klimitediodevice.cpp + src/knonefilter.cpp + src/knonefilter.h + src/krcc.cpp + src/krcc.h + src/ktar.cpp + src/ktar.h + src/kzipfileentry.h + src/loggingcategory.cpp + src/loggingcategory.h ) -find_package(BZip2) -set_package_properties(BZip2 PROPERTIES - URL "https://sourceware.org/bzip2/" - DESCRIPTION "Support for BZip2 compressed files and data streams" - TYPE ${BZIP2_PACKAGE_TYPE} - PURPOSE "Support for BZip2 compressed files and data streams" +# ZIP support +extend_qtc_library( + karchive + CONDITION QTC_USE_SYSTEM_ZLIB AND TARGET ZLIB::ZLIB + FEATURE_INFO "KArchive (System) zlib support" + DEPENDS ZLIB::ZLIB + DEFINES + HAVE_ZLIB_SUPPORT=1 + SOURCES + src/kgzipfilter.cpp + src/kgzipfilter.h + src/kzip.cpp + src/kzip.h ) -find_package(LibLZMA) -set_package_properties(LibLZMA PROPERTIES - URL "https://tukaani.org/xz/" - DESCRIPTION "Support for xz compressed files and data streams" - TYPE ${LIBLZMA_PACKAGE_TYPE} - PURPOSE "Support for xz compressed files and data streams" +extend_qtc_library( + karchive + CONDITION NOT QTC_USE_SYSTEM_ZLIB OR NOT TARGET ZLIB::ZLIB + SKIP_AUTOMOC + DEFINES + HAVE_ZLIB_SUPPORT=1 + PUBLIC_DEFINES + KARCHIVE_HAS_ZLIB + FEATURE_INFO "KArchive zlib support${ZLIB_FALLBACK}" + INCLUDES + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/ + SOURCES + src/kgzipfilter.cpp + src/kgzipfilter.h + src/kzip.cpp + src/kzip.h + + # Embed zlib sources + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/adler32.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/compress.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/crc32.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/crc32.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/deflate.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/deflate.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/gzclose.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/gzguts.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/gzlib.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/gzread.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/gzwrite.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/infback.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/inffast.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/inffast.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/inffixed.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/inflate.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/inflate.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/inftrees.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/inftrees.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/trees.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/trees.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/uncompr.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/zconf.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/zlib.h + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/zutil.c + ${CMAKE_CURRENT_LIST_DIR}/../zlib/src/zutil.h ) +# BZip2 support +extend_qtc_library(karchive + CONDITION QTC_USE_SYSTEM_BZIP2 AND TARGET BZip2::BZip2 + FEATURE_INFO "KArchive (System) BZip2 support" + DEPENDS BZip2::BZip2 + DEFINES + HAVE_BZIP2_SUPPORT=1 + NEED_BZ2_PREFIX=1 + PUBLIC_DEFINES + KARCHIVE_HAS_BZIP2 -find_package(PkgConfig ${PKGCONFIG_REQUIRED_TYPE}) -if (PkgConfig_FOUND) - pkg_check_modules(LibZstd ${LIBZSTD_REQUIRED_TYPE} IMPORTED_TARGET "libzstd") -endif() -add_feature_info(LibZstd LibZstd_FOUND - "Support for zstd compressed files and data streams" + SOURCES + src/kbzip2filter.cpp ) -include(ECMSetupVersion) -include(ECMGenerateHeaders) -include(ECMQtDeclareLoggingCategory) -include(ECMAddQch) -include(ECMDeprecationSettings) -include(ECMPoQmTools) +extend_qtc_library( + karchive + CONDITION NOT QTC_USE_SYSTEM_BZIP2 OR NOT TARGET BZip2::BZip2 + INCLUDES ./3rdparty/bzip2 + FEATURE_INFO "KArchive BZip2 support${BZIP2_FALLBACK}" + DEFINES + HAVE_BZIP2_SUPPORT=1 + NEED_BZ2_PREFIX=1 + PUBLIC_DEFINES + KARCHIVE_HAS_BZIP2 -set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") + SOURCES + src/kbzip2filter.cpp -option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) -add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") - -set(karchive_version_header "${CMAKE_CURRENT_BINARY_DIR}/src/karchive_version.h") -ecm_setup_version(PROJECT - VARIABLE_PREFIX KARCHIVE - VERSION_HEADER "${karchive_version_header}" - PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfigVersion.cmake" - SOVERSION 6) - -ecm_set_disabled_deprecation_versions( - QT 6.8 + # Embed bzip2 sources + ./3rdparty/bzip2/blocksort.c + ./3rdparty/bzip2/bzlib.c + ./3rdparty/bzip2/bzlib.h + ./3rdparty/bzip2/compress.c + ./3rdparty/bzip2/crctable.c + ./3rdparty/bzip2/decompress.c + ./3rdparty/bzip2/huffman.c + ./3rdparty/bzip2/randtable.c ) - -add_subdirectory(src) -if (BUILD_TESTING) - add_subdirectory(autotests) - add_subdirectory(tests) +# libLZMA support +if (NOT QTC_USE_SYSTEM_LZMA) + include (CheckTypeSize) + include (CheckIncludeFile) + CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T) + CHECK_INCLUDE_FILE("stdbool.h" HAVE_STDBOOL_H) endif() -ecm_install_po_files_as_qm(poqm) - -# create a Config.cmake and a ConfigVersion.cmake file and install them -set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF6Archive") - -if (BUILD_QCH) - ecm_install_qch_export( - TARGETS KF6Archive_QCH - FILE KF6ArchiveQchTargets.cmake - DESTINATION "${CMAKECONFIG_INSTALL_DIR}" - COMPONENT Devel - ) - set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF6ArchiveQchTargets.cmake\")") -endif() - -include(CMakePackageConfigHelpers) - -configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/KF6ArchiveConfig.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfig.cmake" - INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} +extend_qtc_library( + karchive + CONDITION QTC_USE_SYSTEM_LZMA AND TARGET LibLZMA::LibLZMA + FEATURE_INFO "KArchive (System) libLZMA support" + DEPENDS LibLZMA::LibLZMA + DEFINES + HAVE_XZ_SUPPORT=1 + SOURCES + src/kxzfilter.cpp + src/kxzfilter.h + src/k7zip.cpp + src/k7zip.h ) -install(FILES ${karchive_version_header} - DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KArchive - COMPONENT Devel) +extend_qtc_library( + karchive + CONDITION NOT QTC_USE_SYSTEM_LZMA OR NOT TARGET LibLZMA::LibLZMA + FEATURE_INFO "KArchive 7zip & xz support${LZMA_FALLBACK}" + DEFINES + HAVE_XZ_SUPPORT=1 + SIZEOF_SIZE_T=${SIZEOF_SIZE_T} + HAVE_STDBOOL_H=${HAVE_STDBOOL_H} + HAVE_CHECK_CRC32 + HAVE_CHECK_CRC64 + HAVE_CHECK_SHA256 -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfigVersion.cmake" - DESTINATION "${CMAKECONFIG_INSTALL_DIR}" - COMPONENT Devel) + HAVE_ENCODER_LZMA1 HAVE_DECODER_LZMA1 + HAVE_ENCODER_LZMA2 HAVE_DECODER_LZMA2 + HAVE_ENCODER_X86 HAVE_DECODER_X86 + HAVE_ENCODER_POWERPC HAVE_DECODER_POWERPC + HAVE_ENCODER_IA64 HAVE_DECODER_IA64 + HAVE_ENCODER_ARM HAVE_DECODER_ARM + HAVE_ENCODER_ARMTHUMB HAVE_DECODER_ARMTHUMB + HAVE_ENCODER_ARM64 HAVE_DECODER_ARM64 + HAVE_ENCODER_SPARC HAVE_DECODER_SPARC + HAVE_ENCODER_RISCV HAVE_DECODER_RISCV + HAVE_ENCODER_DELTA HAVE_DECODER_DELTA -install(EXPORT KF6ArchiveTargets - DESTINATION "${CMAKECONFIG_INSTALL_DIR}" - FILE KF6ArchiveTargets.cmake - NAMESPACE KF6::) + HAVE_MF_HC3 HAVE_MF_HC4 HAVE_MF_BT2 HAVE_MF_BT3 HAVE_MF_BT4 + PUBLIC_DEFINES + KARCHIVE_HAS_XZ + INCLUDES + ./3rdparty/xz/src/common + ./3rdparty/xz/src/liblzma/api + ./3rdparty/xz/src/liblzma/check + ./3rdparty/xz/src/liblzma/common + ./3rdparty/xz/src/liblzma/delta + ./3rdparty/xz/src/liblzma/lz + ./3rdparty/xz/src/liblzma/lzma + ./3rdparty/xz/src/liblzma/range_decoder + ./3rdparty/xz/src/liblzma/rangecoder + ./3rdparty/xz/src/liblzma/simple + SOURCES + src/kxzfilter.cpp + src/kxzfilter.h + src/k7zip.cpp + src/k7zip.h -include(ECMFeatureSummary) -ecm_feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) + # Embed liblzma sources + ./3rdparty/xz/src/liblzma/check/check.c + ./3rdparty/xz/src/liblzma/check/crc32_fast.c + ./3rdparty/xz/src/liblzma/check/crc32_table.c + ./3rdparty/xz/src/liblzma/check/crc64_fast.c + ./3rdparty/xz/src/liblzma/check/crc64_table.c + ./3rdparty/xz/src/liblzma/check/sha256.c + ./3rdparty/xz/src/liblzma/common/alone_decoder.c + ./3rdparty/xz/src/liblzma/common/auto_decoder.c + ./3rdparty/xz/src/liblzma/common/block_decoder.c + ./3rdparty/xz/src/liblzma/common/block_encoder.c + ./3rdparty/xz/src/liblzma/common/block_header_decoder.c + ./3rdparty/xz/src/liblzma/common/block_header_encoder.c + ./3rdparty/xz/src/liblzma/common/block_util.c + ./3rdparty/xz/src/liblzma/common/common.c + ./3rdparty/xz/src/liblzma/common/easy_encoder.c + ./3rdparty/xz/src/liblzma/common/easy_preset.c + ./3rdparty/xz/src/liblzma/common/filter_common.c + ./3rdparty/xz/src/liblzma/common/filter_decoder.c + ./3rdparty/xz/src/liblzma/common/filter_encoder.c + ./3rdparty/xz/src/liblzma/common/filter_flags_decoder.c + ./3rdparty/xz/src/liblzma/common/filter_flags_encoder.c + ./3rdparty/xz/src/liblzma/common/index_decoder.c + ./3rdparty/xz/src/liblzma/common/index_encoder.c + ./3rdparty/xz/src/liblzma/common/index_hash.c + ./3rdparty/xz/src/liblzma/common/index.c + ./3rdparty/xz/src/liblzma/common/stream_decoder.c + ./3rdparty/xz/src/liblzma/common/stream_encoder.c + ./3rdparty/xz/src/liblzma/common/stream_flags_common.c + ./3rdparty/xz/src/liblzma/common/stream_flags_decoder.c + ./3rdparty/xz/src/liblzma/common/stream_flags_encoder.c + ./3rdparty/xz/src/liblzma/common/vli_decoder.c + ./3rdparty/xz/src/liblzma/common/vli_encoder.c + ./3rdparty/xz/src/liblzma/common/vli_size.c + ./3rdparty/xz/src/liblzma/delta/delta_common.c + ./3rdparty/xz/src/liblzma/delta/delta_decoder.c + ./3rdparty/xz/src/liblzma/delta/delta_encoder.c + ./3rdparty/xz/src/liblzma/lz/lz_decoder.c + ./3rdparty/xz/src/liblzma/lz/lz_encoder_mf.c + ./3rdparty/xz/src/liblzma/lz/lz_encoder.c + ./3rdparty/xz/src/liblzma/lzma/fastpos_table.c + ./3rdparty/xz/src/liblzma/lzma/lzma_decoder.c + ./3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c + ./3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c + ./3rdparty/xz/src/liblzma/lzma/lzma_encoder_presets.c + ./3rdparty/xz/src/liblzma/lzma/lzma_encoder.c + ./3rdparty/xz/src/liblzma/lzma/lzma2_decoder.c + ./3rdparty/xz/src/liblzma/lzma/lzma2_encoder.c + ./3rdparty/xz/src/liblzma/rangecoder/price_table.c + ./3rdparty/xz/src/liblzma/simple/arm.c + ./3rdparty/xz/src/liblzma/simple/arm64.c + ./3rdparty/xz/src/liblzma/simple/armthumb.c + ./3rdparty/xz/src/liblzma/simple/ia64.c + ./3rdparty/xz/src/liblzma/simple/powerpc.c + ./3rdparty/xz/src/liblzma/simple/riscv.c + ./3rdparty/xz/src/liblzma/simple/simple_coder.c + ./3rdparty/xz/src/liblzma/simple/simple_decoder.c + ./3rdparty/xz/src/liblzma/simple/simple_encoder.c + ./3rdparty/xz/src/liblzma/simple/sparc.c + ./3rdparty/xz/src/liblzma/simple/x86.c +) -kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT) +# Zstd support +# BSD License: https://github.com/facebook/zstd/blob/dev/LICENSE +# Disabled for now as we don't need it and the packages are suboptimal +#extend_qtc_library( +# karchive +# CONDITION TARGET PkgConfig::LibZstd +# DEPENDS PkgConfig::LibZstd +# FEATURE_INFO "KArchive Zstd support" +# DEFINES +# HAVE_ZSTD_SUPPORT=1 +# PUBLIC_DEFINES +# KARCHIVE_HAS_ZSTD +# SOURCES +# src/kzstdfilter.cpp +# src/kzstdfilter.h +#) diff --git a/src/libs/3rdparty/karchive/CMakeLists.txt.kde b/src/libs/3rdparty/karchive/CMakeLists.txt.kde new file mode 100644 index 00000000000..43b61a998f1 --- /dev/null +++ b/src/libs/3rdparty/karchive/CMakeLists.txt.kde @@ -0,0 +1,152 @@ +cmake_minimum_required(VERSION 3.16) + +set(KF_VERSION "6.10.0") # handled by release scripts +project(KArchive VERSION ${KF_VERSION}) + +include(FeatureSummary) +find_package(ECM 6.9.0 NO_MODULE) +set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") +feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) + +option(WITH_BZIP2 "Make bzip2 required" ON) +option(WITH_LIBLZMA "Make liblzma required" ON) +option(WITH_LIBZSTD "Make libzstd required" ON) + +set(PKGCONFIG_REQUIRED_TYPE "") + +if(WITH_BZIP2) + set(BZIP2_PACKAGE_TYPE "REQUIRED") +else() + set(BZIP2_PACKAGE_TYPE "RECOMMENDED") +endif() + +if(WITH_LIBLZMA) + set(LIBLZMA_PACKAGE_TYPE "REQUIRED") +else() + set(LIBLZMA_PACKAGE_TYPE "RECOMMENDED") +endif() + +if(WITH_LIBZSTD) + set(PKGCONFIG_REQUIRED_TYPE "REQUIRED") + set(LIBZSTD_REQUIRED_TYPE "REQUIRED") +else() + set(LIBZSTD_REQUIRED_TYPE "") +endif() + +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) + +include(KDEInstallDirs) +include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) +include(KDECMakeSettings) +include(KDEGitCommitHooks) + +include(ECMGenerateExportHeader) + +set(REQUIRED_QT_VERSION 6.6.0) +find_package(Qt6Core ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) + +find_package(ZLIB) +set_package_properties(ZLIB PROPERTIES + URL "https://www.zlib.net" + DESCRIPTION "Support for gzip compressed files and data streams" + TYPE REQUIRED + PURPOSE "Support for gzip compressed files and data streams" +) + +find_package(BZip2) +set_package_properties(BZip2 PROPERTIES + URL "https://sourceware.org/bzip2/" + DESCRIPTION "Support for BZip2 compressed files and data streams" + TYPE ${BZIP2_PACKAGE_TYPE} + PURPOSE "Support for BZip2 compressed files and data streams" +) + +find_package(LibLZMA) +set_package_properties(LibLZMA PROPERTIES + URL "https://tukaani.org/xz/" + DESCRIPTION "Support for xz compressed files and data streams" + TYPE ${LIBLZMA_PACKAGE_TYPE} + PURPOSE "Support for xz compressed files and data streams" +) + + +find_package(PkgConfig ${PKGCONFIG_REQUIRED_TYPE}) +if (PkgConfig_FOUND) + pkg_check_modules(LibZstd ${LIBZSTD_REQUIRED_TYPE} IMPORTED_TARGET "libzstd") +endif() +add_feature_info(LibZstd LibZstd_FOUND + "Support for zstd compressed files and data streams" +) + +include(ECMSetupVersion) +include(ECMGenerateHeaders) +include(ECMQtDeclareLoggingCategory) +include(ECMAddQch) +include(ECMDeprecationSettings) +include(ECMPoQmTools) + +set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") + +option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) +add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") + +set(karchive_version_header "${CMAKE_CURRENT_BINARY_DIR}/src/karchive_version.h") +ecm_setup_version(PROJECT + VARIABLE_PREFIX KARCHIVE + VERSION_HEADER "${karchive_version_header}" + PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfigVersion.cmake" + SOVERSION 6) + +ecm_set_disabled_deprecation_versions( + QT 6.8 +) + + +add_subdirectory(src) +if (BUILD_TESTING) + add_subdirectory(autotests) + add_subdirectory(tests) +endif() + +ecm_install_po_files_as_qm(poqm) + +# create a Config.cmake and a ConfigVersion.cmake file and install them +set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF6Archive") + +if (BUILD_QCH) + ecm_install_qch_export( + TARGETS KF6Archive_QCH + FILE KF6ArchiveQchTargets.cmake + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel + ) + set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF6ArchiveQchTargets.cmake\")") +endif() + +include(CMakePackageConfigHelpers) + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/KF6ArchiveConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfig.cmake" + INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} +) + +install(FILES ${karchive_version_header} + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KArchive + COMPONENT Devel) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfigVersion.cmake" + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel) + +install(EXPORT KF6ArchiveTargets + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + FILE KF6ArchiveTargets.cmake + NAMESPACE KF6::) + +include(ECMFeatureSummary) +ecm_feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) + +kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT) diff --git a/src/libs/3rdparty/karchive/src/k7zip.cpp b/src/libs/3rdparty/karchive/src/k7zip.cpp index 03ee383aa11..5d029ee53a0 100644 --- a/src/libs/3rdparty/karchive/src/k7zip.cpp +++ b/src/libs/3rdparty/karchive/src/k7zip.cpp @@ -16,13 +16,15 @@ #include #include "kcompressiondevice.h" +#include "kfilterbase.h" #include "klimitediodevice_p.h" -#include -#include +#include "kxzfilter.h" -#include "zlib.h" #include #include // time() +#include + +#undef uncompress #ifndef QT_STAT_LNK #define QT_STAT_LNK 0120000 @@ -2789,7 +2791,8 @@ bool K7Zip::closeArchive() QBuffer inBuffer(&enc); KCompressionDevice flt(&inBuffer, false, KCompressionDevice::Xz); - flt.open(QIODevice::WriteOnly); + if(!flt.open(QIODevice::WriteOnly)) + return false; KFilterBase *filter = flt.filterBase(); diff --git a/src/libs/3rdparty/karchive/src/karchive.cpp b/src/libs/3rdparty/karchive/src/karchive.cpp index 2a3e7b38348..5431dbcfcd2 100644 --- a/src/libs/3rdparty/karchive/src/karchive.cpp +++ b/src/libs/3rdparty/karchive/src/karchive.cpp @@ -964,7 +964,10 @@ static bool sortByPosition(const KArchiveFile *file1, const KArchiveFile *file2) return file1->position() < file2->position(); } -bool KArchiveDirectory::copyTo(const QString &dest, bool recursiveCopy) const +bool KArchiveDirectory::copyTo( + const QString &dest, + bool recursiveCopy, + std::function progress) const { QDir root; const QString destDir(QDir(dest).absolutePath()); // get directory path without any "." or ".." @@ -1029,11 +1032,16 @@ bool KArchiveDirectory::copyTo(const QString &dest, bool recursiveCopy) const } } while (!dirStack.isEmpty()); - std::sort(fileList.begin(), fileList.end(), sortByPosition); // sort on d->pos, so we have a linear access + std::sort( + fileList.begin(), + fileList.end(), + sortByPosition); // sort on d->pos, so we have a linear access - for (QList::const_iterator it = fileList.constBegin(), end = fileList.constEnd(); it != end; ++it) { - const KArchiveFile *f = *it; + for (const KArchiveFile *f : fileList) { qint64 pos = f->position(); + if (progress) + if (!progress(f, fileToDir[pos])) + return false; if (!f->copyTo(fileToDir[pos])) { return false; } diff --git a/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp b/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp index 56f2f47bef3..8094813d1aa 100644 --- a/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp +++ b/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp @@ -12,8 +12,6 @@ #include "kgzipfilter.h" #include "knonefilter.h" -#include "config-compression.h" - #if HAVE_BZIP2_SUPPORT #include "kbzip2filter.h" #endif diff --git a/src/libs/3rdparty/karchive/src/kgzipfilter.cpp b/src/libs/3rdparty/karchive/src/kgzipfilter.cpp index c7623f7ba57..1d69497df3d 100644 --- a/src/libs/3rdparty/karchive/src/kgzipfilter.cpp +++ b/src/libs/3rdparty/karchive/src/kgzipfilter.cpp @@ -13,6 +13,9 @@ #include #include +#undef uncompress +#undef compress + /* gzip flag byte */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ diff --git a/src/libs/3rdparty/karchive/src/ktar.cpp b/src/libs/3rdparty/karchive/src/ktar.cpp index 0ea6313b931..c8535f0fddc 100644 --- a/src/libs/3rdparty/karchive/src/ktar.cpp +++ b/src/libs/3rdparty/karchive/src/ktar.cpp @@ -102,7 +102,7 @@ bool KTar::createDevice(QIODevice::OpenMode mode) if (f.open(QIODevice::ReadOnly)) { mime = db.mimeTypeForData(&f); } - if (!mime.isValid()) { + if (!mime.isValid() || mime.name() == QStringLiteral("application/octet-stream")) { // Unable to determine mimetype from contents, get it from file name mime = db.mimeTypeForFile(fileName(), QMimeDatabase::MatchExtension); } diff --git a/src/libs/3rdparty/karchive/src/kzip.cpp b/src/libs/3rdparty/karchive/src/kzip.cpp index 23bf9aa4a3b..c583990351f 100644 --- a/src/libs/3rdparty/karchive/src/kzip.cpp +++ b/src/libs/3rdparty/karchive/src/kzip.cpp @@ -25,6 +25,16 @@ #include #include +// "Our" zip zconf.h defines "Z_PREFIX", so we need to undef it here, as this class has another +// function called crc32. Instead of a define, we create a forwarder function. +#ifdef Z_PREFIX +#undef crc32 +uLong crc32(uLong crc, const Bytef *buf, uInt len) +{ + return z_crc32(crc, buf, len); +} +#endif + #ifndef QT_STAT_LNK #define QT_STAT_LNK 0120000 #endif // QT_STAT_LNK @@ -835,32 +845,31 @@ bool KZip::closeArchive() qint64 centraldiroffset = device()->pos(); // qCDebug(KArchiveLog) << "closearchive: centraldiroffset: " << centraldiroffset; qint64 atbackup = centraldiroffset; - QMutableListIterator it(d->m_fileList); - while (it.hasNext()) { + for (KZipFileEntry *entry : d->m_fileList) { // set crc and compressed size in each local file header - it.next(); - if (!device()->seek(it.value()->headerStart() + 14)) { - setErrorString(tr("Could not seek to next file header: %1").arg(device()->errorString())); + if (!device()->seek(entry->headerStart() + 14)) { + setErrorString( + tr("Could not seek to next file header: %1").arg(device()->errorString())); return false; } // qCDebug(KArchiveLog) << "closearchive setcrcandcsize: fileName:" - // << it.value()->path() - // << "encoding:" << it.value()->encoding(); + // << entry->path() + // << "encoding:" << entry->encoding(); - uLong mycrc = it.value()->crc32(); + uLong mycrc = entry->crc32(); buffer[0] = char(mycrc); // crc checksum, at headerStart+14 buffer[1] = char(mycrc >> 8); buffer[2] = char(mycrc >> 16); buffer[3] = char(mycrc >> 24); - int mysize1 = it.value()->compressedSize(); + int mysize1 = entry->compressedSize(); buffer[4] = char(mysize1); // compressed file size, at headerStart+18 buffer[5] = char(mysize1 >> 8); buffer[6] = char(mysize1 >> 16); buffer[7] = char(mysize1 >> 24); - int myusize = it.value()->size(); + int myusize = entry->size(); buffer[8] = char(myusize); // uncompressed file size, at headerStart+22 buffer[9] = char(myusize >> 8); buffer[10] = char(myusize >> 16); @@ -873,13 +882,11 @@ bool KZip::closeArchive() } device()->seek(atbackup); - it.toFront(); - while (it.hasNext()) { - it.next(); - // qCDebug(KArchiveLog) << "fileName:" << it.value()->path() - // << "encoding:" << it.value()->encoding(); + for (KZipFileEntry *entry : d->m_fileList) { + // qCDebug(KArchiveLog) << "fileName:" << entry->path() + // << "encoding:" << entry->encoding(); - QByteArray path = QFile::encodeName(it.value()->path()); + QByteArray path = QFile::encodeName(entry->path()); const int extra_field_len = (d->m_extraField == ModificationTime) ? 9 : 0; const int bufferSize = extra_field_len + path.length() + 46; @@ -899,24 +906,24 @@ bool KZip::closeArchive() // memcpy(buffer, head, sizeof(head)); memmove(buffer, head, sizeof(head)); - buffer[10] = char(it.value()->encoding()); // compression method - buffer[11] = char(it.value()->encoding() >> 8); + buffer[10] = char(entry->encoding()); // compression method + buffer[11] = char(entry->encoding() >> 8); - transformToMsDos(it.value()->date(), &buffer[12]); + transformToMsDos(entry->date(), &buffer[12]); - uLong mycrc = it.value()->crc32(); + uLong mycrc = entry->crc32(); buffer[16] = char(mycrc); // crc checksum buffer[17] = char(mycrc >> 8); buffer[18] = char(mycrc >> 16); buffer[19] = char(mycrc >> 24); - int mysize1 = it.value()->compressedSize(); + int mysize1 = entry->compressedSize(); buffer[20] = char(mysize1); // compressed file size buffer[21] = char(mysize1 >> 8); buffer[22] = char(mysize1 >> 16); buffer[23] = char(mysize1 >> 24); - int mysize = it.value()->size(); + int mysize = entry->size(); buffer[24] = char(mysize); // uncompressed file size buffer[25] = char(mysize >> 8); buffer[26] = char(mysize >> 16); @@ -928,10 +935,10 @@ bool KZip::closeArchive() buffer[30] = char(extra_field_len); buffer[31] = char(extra_field_len >> 8); - buffer[40] = char(it.value()->permissions()); - buffer[41] = char(it.value()->permissions() >> 8); + buffer[40] = char(entry->permissions()); + buffer[41] = char(entry->permissions() >> 8); - int myhst = it.value()->headerStart(); + int myhst = entry->headerStart(); buffer[42] = char(myhst); // relative offset of local header buffer[43] = char(myhst >> 8); buffer[44] = char(myhst >> 16); @@ -952,14 +959,14 @@ bool KZip::closeArchive() extfield[4] = 1 | 2 | 4; // specify flags from local field // (unless I misread the spec) // provide only modification time - unsigned long time = (unsigned long)it.value()->date().toSecsSinceEpoch(); + unsigned long time = (unsigned long) entry->date().toSecsSinceEpoch(); extfield[5] = char(time); extfield[6] = char(time >> 8); extfield[7] = char(time >> 16); extfield[8] = char(time >> 24); } - crc = crc32(crc, (Bytef *)buffer, bufferSize); + crc = crc32(crc, (Bytef *) buffer, bufferSize); bool ok = (device()->write(buffer, bufferSize) == bufferSize); delete[] buffer; if (!ok) { @@ -1087,18 +1094,17 @@ bool KZip::doPrepareWriting(const QString &name, // to save, so that we don't have duplicate file entries when viewing the zip // with konqi... // CAUTION: the old file itself is still in the zip and won't be removed !!! - QMutableListIterator it(d->m_fileList); // qCDebug(KArchiveLog) << "fileName to write: " << name; - while (it.hasNext()) { - it.next(); - // qCDebug(KArchiveLog) << "prepfileName: " << it.value()->path(); - if (name == it.value()->path()) { + for (auto it = d->m_fileList.begin(); it != d->m_fileList.end();) { + // qCDebug(KArchiveLog) << "prepfileName: " << entry->path(); + if (name == (*it)->path()) { // also remove from the parentDir - parentDir->removeEntry(it.value()); - // qCDebug(KArchiveLog) << "removing following entry: " << it.value()->path(); - delete it.value(); - it.remove(); - } + parentDir->removeEntry(*it); + // qCDebug(KArchiveLog) << "removing following entry: " << entry->path(); + delete *it; + it = d->m_fileList.erase(it); + } else + it++; } // construct a KZipFileEntry and add it to list From 5ed231b1aeec92fcc9f2d522b86fe9c395d4b537 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 27 Nov 2024 10:15:38 +0100 Subject: [PATCH 384/989] Editor: simplify behavior settings page Layout the groupboxes of this page in a single column layout instead of trying to compress them in two columns. Additionally transform some of the groupbox layouts to form layouts that make more use of the now increased horizontal space and take less vertical space. Change-Id: Id481221816be7752b0e245f7be101019b6f65727 Reviewed-by: Christian Stenger --- .../texteditor/behaviorsettingswidget.cpp | 48 ++++++++++--------- src/plugins/texteditor/tabsettingswidget.cpp | 18 ++++--- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp index ad99679c122..5a702e5b33e 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.cpp +++ b/src/plugins/texteditor/behaviorsettingswidget.cpp @@ -67,7 +67,6 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) , d(new BehaviorSettingsWidgetPrivate) { d->tabPreferencesWidget = new SimpleCodeStylePreferencesWidget(this); - d->tabPreferencesWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // FIXME: Desirable? d->tabKeyBehavior = new QComboBox; d->tabKeyBehavior->addItem(Tr::tr("Never")); @@ -165,7 +164,6 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) d->encodingBox = new CodecChooser; d->encodingBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); - d->encodingBox->setMinimumContentsLength(20); d->utf8BomBox = new QComboBox; d->utf8BomBox->addItem(Tr::tr("Add If Encoding Is UTF-8")); @@ -210,15 +208,14 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) const auto indent = [](QWidget *inner) { return Row { Space(30), inner }; }; - Column { - d->autoIndent, - Tr::tr("Backspace indentation:"), - indent(d->smartBackspaceBehavior), - Tr::tr("Tab key performs auto-indent:"), - indent(d->tabKeyBehavior), - d->preferSingleLineComments, - commentPositionLabel, - indent(d->commentPosition) + Row { + Form { + d->autoIndent, br, + Tr::tr("Backspace indentation:"), d->smartBackspaceBehavior, br, + Tr::tr("Tab key performs auto-indent:"), d->tabKeyBehavior, br, + d->preferSingleLineComments, br, + commentPositionLabel, d->commentPosition, br + }, st }.attachTo(d->groupBoxTyping); Column { @@ -237,20 +234,25 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) }, st }.attachTo(d->groupBoxEncodings); - Column { - d->mouseHiding, - d->mouseNavigation, - d->scrollWheelZooming, - d->camelCaseNavigation, - d->smartSelectionChanging, - d->keyboardTooltips, - Tr::tr("Show help tooltips using the mouse:"), - Row { Space(30), d->constrainTooltipsBox, st } + Row { + Form { + d->mouseHiding, br, + d->mouseNavigation, br, + d->scrollWheelZooming, br, + d->camelCaseNavigation, br, + d->smartSelectionChanging, br, + d->keyboardTooltips, br, + Tr::tr("Show help tooltips using the mouse:"), d->constrainTooltipsBox, br + }, st }.attachTo(d->groupBoxMouse); - Row { - Column { d->tabPreferencesWidget, d->groupBoxTyping, st }, - Column { d->groupBoxStorageSettings, d->groupBoxEncodings, d->groupBoxMouse, st }, + Column { + d->tabPreferencesWidget, + d->groupBoxTyping, + d->groupBoxStorageSettings, + d->groupBoxEncodings, + d->groupBoxMouse, + st, noMargin, }.attachTo(this); diff --git a/src/plugins/texteditor/tabsettingswidget.cpp b/src/plugins/texteditor/tabsettingswidget.cpp index f3476ec5f42..c796591ffc6 100644 --- a/src/plugins/texteditor/tabsettingswidget.cpp +++ b/src/plugins/texteditor/tabsettingswidget.cpp @@ -56,13 +56,11 @@ TabSettingsWidget::TabSettingsWidget(QWidget *parent) : Tr::tr("Code indentation is configured in C++ " "and Qt Quick settings.")); m_codingStyleWarning->setVisible(false); - m_codingStyleWarning->setWordWrap(true); m_codingStyleWarning->setToolTip( Tr::tr("The text editor indentation setting is used for non-code files only. See the C++ " "and Qt Quick coding style settings to configure indentation for code files.")); m_tabPolicy = new QComboBox(this); - m_tabPolicy->setMinimumContentsLength(28); m_tabPolicy->addItem(Tr::tr("Spaces Only")); m_tabPolicy->addItem(Tr::tr("Tabs Only")); m_tabPolicy->addItem(Tr::tr("Mixed")); @@ -87,15 +85,15 @@ TabSettingsWidget::TabSettingsWidget(QWidget *parent) : indentSizeLabel->setBuddy(m_indentSize); using namespace Layouting; - const auto indent = [](QWidget *inner) { return Row { Space(30), inner }; }; - Column { - m_codingStyleWarning, - Tr::tr("Tab policy:"), - indent(m_tabPolicy), - Row { tabSizeLabel, m_tabSize, indentSizeLabel, m_indentSize, st }, - Tr::tr("Align continuation lines:"), - indent(m_continuationAlignBehavior) + Row { + Form { + m_codingStyleWarning, br, + Tr::tr("Tab policy:"), m_tabPolicy, br, + tabSizeLabel, m_tabSize, br, + indentSizeLabel, m_indentSize, br, + Tr::tr("Align continuation lines:"), m_continuationAlignBehavior, br + }, st }.attachTo(this); connect(m_codingStyleWarning, &QLabel::linkActivated, From 908e77b9eb2d6061993585bbe0d72a44362b0d8f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 11 Dec 2024 07:40:24 +0100 Subject: [PATCH 385/989] PE: Fix missing include Change-Id: Id54ada66cd8631fac6ec49a243a59fe8bf54e237 Reviewed-by: Marcus Tillmanns --- src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp index eb05160570c..c8e1bde9bc0 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include From 8d02ee45bfa00f1d33f7eb961cd5162657d7c2c9 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 11 Dec 2024 08:57:06 +0100 Subject: [PATCH 386/989] KArchive: Fix libZMA if "Use System LZMA" is on but not found Change-Id: I0c5d089d61cca9c312e4d36052a7713514f5d117 Reviewed-by: Christian Stenger --- src/libs/3rdparty/karchive/CMakeLists.txt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libs/3rdparty/karchive/CMakeLists.txt b/src/libs/3rdparty/karchive/CMakeLists.txt index 26fe6ae5484..41a595d728b 100644 --- a/src/libs/3rdparty/karchive/CMakeLists.txt +++ b/src/libs/3rdparty/karchive/CMakeLists.txt @@ -157,12 +157,10 @@ extend_qtc_library( ) # libLZMA support -if (NOT QTC_USE_SYSTEM_LZMA) - include (CheckTypeSize) - include (CheckIncludeFile) - CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T) - CHECK_INCLUDE_FILE("stdbool.h" HAVE_STDBOOL_H) -endif() +include (CheckTypeSize) +include (CheckIncludeFile) +CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T) +CHECK_INCLUDE_FILE("stdbool.h" HAVE_STDBOOL_H) extend_qtc_library( karchive From e4d23646f3fc717d74c05608133cd5269b31706c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 10 Dec 2024 14:08:10 +0100 Subject: [PATCH 387/989] Coco: Slim down project panel creation interface Change-Id: I7ac8c3551e906fdf2f19d2fbcee0db586fb94aae Reviewed-by: Christian Stenger --- src/plugins/coco/cocoplugin.cpp | 20 +------ .../coco/cocoprojectsettingswidget.cpp | 57 ++++++++++++++----- src/plugins/coco/cocoprojectsettingswidget.h | 20 +------ 3 files changed, 47 insertions(+), 50 deletions(-) diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index b838d8c81dc..a2b754e1544 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -104,7 +104,6 @@ public: } void initialize() final; - void addEntryToProjectSettings(); private: CocoLanguageClient *m_client = nullptr; @@ -121,27 +120,12 @@ void CocoPlugin::initialize() GlobalSettings::read(); GlobalSettingsPage::instance().widget(); - addEntryToProjectSettings(); + + setupCocoProjectPanel(); initLanguageServer(); } -void CocoPlugin::addEntryToProjectSettings() -{ - auto panelFactory = new ProjectPanelFactory; - panelFactory->setPriority(50); - panelFactory->setDisplayName(tr("Coco Code Coverage")); - panelFactory->setSupportsFunction([](Project *project) { - if (Target *target = project->activeTarget()) { - if (BuildConfiguration *abc = target->activeBuildConfiguration()) - return BuildSettings::supportsBuildConfig(*abc); - } - return false; - }); - panelFactory->setCreateWidgetFunction( - [](Project *project) { return new CocoProjectSettingsWidget(project); }); -} - } // namespace Coco #include "cocoplugin.moc" diff --git a/src/plugins/coco/cocoprojectsettingswidget.cpp b/src/plugins/coco/cocoprojectsettingswidget.cpp index 6b6b05426c0..c7121cb22ff 100644 --- a/src/plugins/coco/cocoprojectsettingswidget.cpp +++ b/src/plugins/coco/cocoprojectsettingswidget.cpp @@ -5,36 +5,67 @@ #include "cocopluginconstants.h" #include "cocoprojectwidget.h" +#include "cocotr.h" #include + #include #include +#include +#include #include + #include +#include #include +using namespace ProjectExplorer; + namespace Coco::Internal { -CocoProjectSettingsWidget::CocoProjectSettingsWidget(ProjectExplorer::Project *project) - : m_layout{new QVBoxLayout} +class CocoProjectSettingsWidget final : public ProjectSettingsWidget { - setUseGlobalSettingsCheckBoxVisible(false); - setGlobalSettingsId(Constants::COCO_SETTINGS_PAGE_ID); +public: + explicit CocoProjectSettingsWidget(Project *project) + { + setUseGlobalSettingsCheckBoxVisible(false); + setGlobalSettingsId(Constants::COCO_SETTINGS_PAGE_ID); - if (auto *target = project->activeTarget()) { - auto abc = target->activeBuildConfiguration(); + auto layout = new QVBoxLayout; + if (auto *target = project->activeTarget()) { + auto abc = target->activeBuildConfiguration(); - if (abc->id() == QmakeProjectManager::Constants::QMAKE_BC_ID - || abc->id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID) - m_layout->addWidget(new CocoProjectWidget(project, abc)); + if (abc->id() == QmakeProjectManager::Constants::QMAKE_BC_ID + || abc->id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID) + layout->addWidget(new CocoProjectWidget(project, abc)); + } + setLayout(layout); } - setLayout(m_layout); -} +}; -CocoProjectSettingsWidget::~CocoProjectSettingsWidget() +class CocoProjectPanelFactory final : public ProjectPanelFactory { - delete m_layout; +public: + CocoProjectPanelFactory() + { + setPriority(50); + setDisplayName(Tr::tr("Coco Code Coverage")); + setSupportsFunction([](Project *project) { + if (Target *target = project->activeTarget()) { + if (BuildConfiguration *abc = target->activeBuildConfiguration()) + return BuildSettings::supportsBuildConfig(*abc); + } + return false; + }); + setCreateWidgetFunction( + [](Project *project) { return new CocoProjectSettingsWidget(project); }); + } +}; + +void setupCocoProjectPanel() +{ + static CocoProjectPanelFactory theCocoProjectPanelFactory; } } // namespace Coco::Internal diff --git a/src/plugins/coco/cocoprojectsettingswidget.h b/src/plugins/coco/cocoprojectsettingswidget.h index c201a55ece7..b7cc19fcd0c 100644 --- a/src/plugins/coco/cocoprojectsettingswidget.h +++ b/src/plugins/coco/cocoprojectsettingswidget.h @@ -3,26 +3,8 @@ #pragma once -#include - -#include - -namespace ProjectExplorer { -class Project; -} - namespace Coco::Internal { -class CocoProjectSettingsWidget : public ProjectExplorer::ProjectSettingsWidget -{ - Q_OBJECT - -public: - explicit CocoProjectSettingsWidget(ProjectExplorer::Project *project); - ~CocoProjectSettingsWidget(); - -private: - QVBoxLayout *m_layout; -}; +void setupCocoProjectPanel(); } // namespace Coco::Internal From a952ab4dd7e980be9277646c58f544d2516ded43 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 10 Dec 2024 10:15:02 +0100 Subject: [PATCH 388/989] RemoteLinux: Separate file transfer out of LinuxDevice ... into a new file pair again. The interface is essentially just SshConnectionHandle. Change-Id: I115fcefbfca4606c6440f97efb3e71121c87ee52 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/CMakeLists.txt | 1 + src/plugins/remotelinux/linuxdevice.cpp | 427 +---------------- src/plugins/remotelinux/linuxdevice.h | 26 +- src/plugins/remotelinux/remotelinux.qbs | 2 + .../remotelinux/remotelinuxfiletransfer.cpp | 434 ++++++++++++++++++ .../remotelinux/remotelinuxfiletransfer.h | 15 + 6 files changed, 485 insertions(+), 420 deletions(-) create mode 100644 src/plugins/remotelinux/remotelinuxfiletransfer.cpp create mode 100644 src/plugins/remotelinux/remotelinuxfiletransfer.h diff --git a/src/plugins/remotelinux/CMakeLists.txt b/src/plugins/remotelinux/CMakeLists.txt index e19cc472dfd..d1d45cbe86c 100644 --- a/src/plugins/remotelinux/CMakeLists.txt +++ b/src/plugins/remotelinux/CMakeLists.txt @@ -21,6 +21,7 @@ add_qtc_plugin(RemoteLinux remotelinuxdebugsupport.cpp remotelinuxdebugsupport.h remotelinuxdeploysupport.cpp remotelinuxdeploysupport.h remotelinuxenvironmentaspect.cpp remotelinuxenvironmentaspect.h + remotelinuxfiletransfer.cpp remotelinuxfiletransfer.h remotelinuxplugin.cpp remotelinuxrunconfiguration.cpp remotelinuxrunconfiguration.h remotelinuxsignaloperation.cpp remotelinuxsignaloperation.h diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index b0c48da1d4f..6c041a5dfa5 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -8,6 +8,7 @@ #include "linuxprocessinterface.h" #include "publickeydeploymentdialog.h" #include "remotelinux_constants.h" +#include "remotelinuxfiletransfer.h" #include "remotelinuxsignaloperation.h" #include "remotelinuxtr.h" #include "sshdevicewizard.h" @@ -16,15 +17,11 @@ #include #include -#include -#include #include #include #include #include -#include - #include #include #include @@ -56,6 +53,8 @@ using namespace ProjectExplorer; using namespace Utils; +using namespace RemoteLinux::Internal; + namespace RemoteLinux { const QByteArray s_pidMarker = "__qtc"; @@ -261,28 +260,6 @@ QStringList SshSharedConnection::connectionArgs(const FilePath &binary) const << m_sshParameters.host(); } -// SshConnectionHandle - -class SshConnectionHandle : public QObject -{ - Q_OBJECT -public: - SshConnectionHandle(const IDevice::ConstPtr &device) : m_device(device) {} - ~SshConnectionHandle() override { emit detachFromSharedConnection(); } - -signals: - // direction: connection -> caller - void connected(const QString &socketFilePath); - void disconnected(const ProcessResultData &result); - // direction: caller -> connection - void detachFromSharedConnection(); - -private: - // Store the IDevice::ConstPtr in order to extend the lifetime of device for as long - // as this object is alive. - IDevice::ConstPtr m_device; -}; - // LinuxDevicePrivate class ShellThreadHandler; @@ -728,8 +705,7 @@ void SshProcessInterfacePrivate::start() this, &SshProcessInterfacePrivate::handleConnected); connect(m_connectionHandle.get(), &SshConnectionHandle::disconnected, this, &SshProcessInterfacePrivate::handleDisconnected); - linuxDevice->connectionAccess() - ->attachToSharedConnection(m_connectionHandle.get(), m_sshParameters); + linuxDevice->attachToSharedConnection(m_connectionHandle.get(), m_sshParameters); } else { doStart(); } @@ -1275,403 +1251,16 @@ void LinuxDeviceAccess::attachToSharedConnection(SshConnectionHandle *connection emit connectionHandle->connected(socketFilePath); } -static FilePaths dirsToCreate(const FilesToTransfer &files) -{ - FilePaths dirs; - for (const FileToTransfer &file : files) { - FilePath parentDir = file.m_target.parentDir(); - while (true) { - if (dirs.contains(parentDir) || QDir(parentDir.path()).isRoot()) - break; - dirs << parentDir; - parentDir = parentDir.parentDir(); - } - } - return sorted(std::move(dirs)); -} - -static QByteArray transferCommand(bool link) -{ - return link ? "ln -s" : "put -R"; -} - -class SshTransferInterface : public FileTransferInterface -{ - Q_OBJECT - -protected: - SshTransferInterface(const FileTransferSetupData &setup, const IDevice::ConstPtr &device) - : FileTransferInterface(setup) - , m_device(device) - , m_process(this) - { - SshParameters::setupSshEnvironment(&m_process); - connect(&m_process, &Process::readyReadStandardOutput, this, [this] { - emit progress(QString::fromLocal8Bit(m_process.readAllRawStandardOutput())); - }); - connect(&m_process, &Process::done, this, &SshTransferInterface::doneImpl); - } - - IDevice::ConstPtr device() const { return m_device; } - - bool handleError() - { - ProcessResultData resultData = m_process.resultData(); - if (resultData.m_error == QProcess::FailedToStart) { - resultData.m_errorString = Tr::tr("\"%1\" failed to start: %2") - .arg(FileTransfer::transferMethodName(m_setup.m_method), resultData.m_errorString); - } else if (resultData.m_exitStatus != QProcess::NormalExit) { - resultData.m_errorString = Tr::tr("\"%1\" crashed.") - .arg(FileTransfer::transferMethodName(m_setup.m_method)); - } else if (resultData.m_exitCode != 0) { - resultData.m_errorString = QString::fromLocal8Bit(m_process.readAllRawStandardError()); - } else { - return false; - } - emit done(resultData); - return true; - } - - void handleDone() - { - if (!handleError()) - emit done(m_process.resultData()); - } - - QStringList fullConnectionOptions() const - { - QStringList options = m_sshParameters.connectionOptions(SshSettings::sshFilePath()); - if (!m_socketFilePath.isEmpty()) - options << "-o" << ("ControlPath=" + m_socketFilePath); - return options; - } - - QString host() const { return m_sshParameters.host(); } - QString userAtHost() const { return m_sshParameters.userAtHost(); } - - Process &process() { return m_process; } - -private: - virtual void startImpl() = 0; - virtual void doneImpl() = 0; - - void start() final - { - m_sshParameters = displayless(m_device->sshParameters()); - const Id linkDeviceId = Id::fromSetting(m_device->extraData(Constants::LinkDevice)); - const auto linkDevice = DeviceManager::instance()->find(linkDeviceId); - const bool useConnectionSharing = !linkDevice && SshSettings::connectionSharingEnabled(); - - if (useConnectionSharing) { - m_connecting = true; - m_connectionHandle.reset(new SshConnectionHandle(m_device)); - m_connectionHandle->setParent(this); - connect(m_connectionHandle.get(), &SshConnectionHandle::connected, - this, &SshTransferInterface::handleConnected); - connect(m_connectionHandle.get(), &SshConnectionHandle::disconnected, - this, &SshTransferInterface::handleDisconnected); - auto linuxDevice = std::dynamic_pointer_cast(m_device); - QTC_ASSERT(linuxDevice, startFailed("No Linux device"); return); - linuxDevice->connectionAccess() - ->attachToSharedConnection(m_connectionHandle.get(), m_sshParameters); - } else { - startImpl(); - } - } - - void handleConnected(const QString &socketFilePath) - { - m_connecting = false; - m_socketFilePath = socketFilePath; - startImpl(); - } - - void handleDisconnected(const ProcessResultData &result) - { - ProcessResultData resultData = result; - if (m_connecting) - resultData.m_error = QProcess::FailedToStart; - - m_connecting = false; - if (m_connectionHandle) // TODO: should it disconnect from signals first? - m_connectionHandle.release()->deleteLater(); - - if (resultData.m_error != QProcess::UnknownError || m_process.state() != QProcess::NotRunning) - emit done(resultData); // TODO: don't emit done() on process finished afterwards - } - - IDevice::ConstPtr m_device; - SshParameters m_sshParameters; - - // ssh shared connection related - std::unique_ptr m_connectionHandle; - QString m_socketFilePath; - bool m_connecting = false; - - Process m_process; -}; - -class SftpTransferImpl : public SshTransferInterface -{ -public: - SftpTransferImpl(const FileTransferSetupData &setup, const IDevice::ConstPtr &device) - : SshTransferInterface(setup, device) - {} - -private: - void startImpl() final - { - FilePath sftpBinary = SshSettings::sftpFilePath(); - - // This is a hack. We only test the last hop here. - const Id linkDeviceId = Id::fromSetting(device()->extraData(Constants::LinkDevice)); - if (const auto linkDevice = DeviceManager::instance()->find(linkDeviceId)) - sftpBinary = linkDevice->filePath(sftpBinary.fileName()).searchInPath(); - - if (!sftpBinary.exists()) { - startFailed(Tr::tr("\"sftp\" binary \"%1\" does not exist.") - .arg(sftpBinary.toUserOutput())); - return; - } - - QByteArray batchData; - - const FilePaths dirs = dirsToCreate(m_setup.m_files); - for (const FilePath &dir : dirs) { - if (!dir.exists()) - batchData += "-mkdir " + ProcessArgs::quoteArgUnix(dir.path()).toLocal8Bit() + '\n'; - } - - for (const FileToTransfer &file : m_setup.m_files) { - FilePath sourceFileOrLinkTarget = file.m_source; - bool link = false; - - const QFileInfo fi(file.m_source.toFileInfo()); - if (fi.isSymLink()) { - link = true; - batchData += "-rm " + ProcessArgs::quoteArgUnix( - file.m_target.path()).toLocal8Bit() + '\n'; - // see QTBUG-5817. - sourceFileOrLinkTarget = - sourceFileOrLinkTarget.withNewPath(fi.dir().relativeFilePath(fi.symLinkTarget())); - } - - const QByteArray source = ProcessArgs::quoteArgUnix(sourceFileOrLinkTarget.path()) - .toLocal8Bit(); - const QByteArray target = ProcessArgs::quoteArgUnix(file.m_target.path()).toLocal8Bit(); - - batchData += transferCommand(link) + ' ' + source + ' ' + target + '\n'; - if (file.m_targetPermissions == FilePermissions::ForceExecutable) - batchData += "chmod 1775 " + target + '\n'; - } - process().setCommand({sftpBinary, {fullConnectionOptions(), "-b", "-", host()}}); - process().setWriteData(batchData); - process().start(); - } - - void doneImpl() final { handleDone(); } -}; - -class RsyncTransferImpl : public SshTransferInterface -{ -public: - RsyncTransferImpl(const FileTransferSetupData &setup, const IDevice::ConstPtr &device) - : SshTransferInterface(setup, device) - { } - -private: - void startImpl() final - { - // Note: This assumes that files do not get renamed when transferring. - for (auto it = m_setup.m_files.cbegin(); it != m_setup.m_files.cend(); ++it) - m_batches[it->m_target.parentDir()] << *it; - startNextBatch(); - } - - void doneImpl() final - { - if (m_batches.isEmpty()) - return handleDone(); - - if (handleError()) - return; - - startNextBatch(); - } - - void startNextBatch() - { - process().close(); - - const QString sshCmdLine = ProcessArgs::joinArgs( - QStringList{SshSettings::sshFilePath().toUserOutput()} - << fullConnectionOptions(), OsTypeLinux); - QStringList options{"-e", sshCmdLine}; - options << ProcessArgs::splitArgs(m_setup.m_rsyncFlags, HostOsInfo::hostOs()); - - if (!m_batches.isEmpty()) { // NormalRun - const auto batchIt = m_batches.begin(); - for (auto filesIt = batchIt->cbegin(); filesIt != batchIt->cend(); ++filesIt) { - const FileToTransfer fixedFile = fixLocalFileOnWindows(*filesIt, options); - options << fixedFile.m_source.path(); - } - options << fixedRemotePath(batchIt.key(), userAtHost()); - m_batches.erase(batchIt); - } else { // TestRun - options << "-n" << "--exclude=*" << (userAtHost() + ":/tmp"); - } - // TODO: Get rsync location from settings? - process().setCommand(CommandLine("rsync", options)); - process().start(); - } - - // On Windows, rsync is either from msys or cygwin. Neither work with the other's ssh.exe. - FileToTransfer fixLocalFileOnWindows(const FileToTransfer &file, const QStringList &options) const - { - if (!HostOsInfo::isWindowsHost()) - return file; - - QString localFilePath = file.m_source.path(); - localFilePath = '/' + localFilePath.at(0) + localFilePath.mid(2); - if (anyOf(options, [](const QString &opt) { - return opt.contains("cygwin", Qt::CaseInsensitive); })) { - localFilePath.prepend("/cygdrive"); - } - - FileToTransfer fixedFile = file; - fixedFile.m_source = fixedFile.m_source.withNewPath(localFilePath); - return fixedFile; - } - - QString fixedRemotePath(const FilePath &file, const QString &remoteHost) const - { - return remoteHost + ':' + file.path(); - } - - QHash m_batches; -}; - -static void createDir(QPromise &promise, const FilePath &pathToCreate) -{ - const Result result = pathToCreate.ensureWritableDir(); - promise.addResult(result); - - if (!result) - promise.future().cancel(); -}; - -static void copyFile(QPromise &promise, const FileToTransfer &file) -{ - const Result result = file.m_source.copyFile(file.m_target); - promise.addResult(result); - - if (!result) - promise.future().cancel(); -}; - -class GenericTransferImpl : public FileTransferInterface -{ - Tasking::TaskTreeRunner m_taskTree; - -public: - GenericTransferImpl(const FileTransferSetupData &setup) - : FileTransferInterface(setup) - {} - -private: - void start() final - { - using namespace Tasking; - - const QSet allParentDirs - = Utils::transform(m_setup.m_files, [](const FileToTransfer &f) { - return f.m_target.parentDir(); - }); - - const LoopList iteratorParentDirs(QList(allParentDirs.cbegin(), allParentDirs.cend())); - - const auto onCreateDirSetup = [iteratorParentDirs](Async &async) { - async.setConcurrentCallData(createDir, *iteratorParentDirs); - }; - - const auto onCreateDirDone = [this, - iteratorParentDirs](const Async &async) { - const Result result = async.result(); - if (result) - emit progress( - Tr::tr("Created directory: \"%1\".\n").arg(iteratorParentDirs->toUserOutput())); - else - emit progress(result.error()); - }; - - const LoopList iterator(m_setup.m_files); - const Storage counterStorage; - - const auto onCopySetup = [iterator](Async &async) { - async.setConcurrentCallData(copyFile, *iterator); - }; - - const auto onCopyDone = [this, iterator, counterStorage]( - const Async &async) { - const Result result = async.result(); - int &counter = *counterStorage; - ++counter; - - if (result) { - //: %1/%2 = progress in the form 4/15, %3 and %4 = source and target file paths - emit progress(Tr::tr("Copied %1/%2: \"%3\" -> \"%4\".\n") - .arg(counter) - .arg(m_setup.m_files.size()) - .arg(iterator->m_source.toUserOutput()) - .arg(iterator->m_target.toUserOutput())); - } else { - emit progress(result.error() + "\n"); - } - }; - - const Group recipe { - For (iteratorParentDirs) >> Do { - parallelIdealThreadCountLimit, - AsyncTask(onCreateDirSetup, onCreateDirDone), - }, - For (iterator) >> Do { - parallelLimit(2), - counterStorage, - AsyncTask(onCopySetup, onCopyDone), - }, - }; - - m_taskTree.start(recipe, {}, [this](DoneWith result) { - ProcessResultData resultData; - if (result != DoneWith::Success) { - resultData.m_exitCode = -1; - resultData.m_errorString = Tr::tr("Failed to deploy files."); - } - emit done(resultData); - }); - } -}; - FileTransferInterface *LinuxDevice::createFileTransferInterface( const FileTransferSetupData &setup) const { - if (Utils::anyOf(setup.m_files, - [](const FileToTransfer &f) { return !f.m_source.isLocal(); })) { - return new GenericTransferImpl(setup); - } - - switch (setup.m_method) { - case FileTransferMethod::Sftp: return new SftpTransferImpl(setup, shared_from_this()); - case FileTransferMethod::Rsync: return new RsyncTransferImpl(setup, shared_from_this()); - case FileTransferMethod::GenericCopy: return new GenericTransferImpl(setup); - } - QTC_CHECK(false); - return {}; + return Internal::createRemoteLinuxFileTransferInterface(*this, setup); } -LinuxDeviceAccess *LinuxDevice::connectionAccess() const +void LinuxDevice::attachToSharedConnection(SshConnectionHandle *sshConnectionHandle, + const SshParameters &sshParams) const { - return &d->m_scriptAccess; + return d->m_scriptAccess.attachToSharedConnection(sshConnectionHandle, sshParams); } void LinuxDevice::checkOsType() diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index d2a67c03c64..35ca80549b2 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -8,7 +8,30 @@ #include #include +namespace Utils { class ProcessResultData; } + namespace RemoteLinux { +namespace Internal { + +class SshConnectionHandle : public QObject +{ + Q_OBJECT + +public: + SshConnectionHandle(const ProjectExplorer::DeviceConstRef &device) : m_device(device) {} + ~SshConnectionHandle() override { emit detachFromSharedConnection(); } + +signals: + void connected(const QString &socketFilePath); + void disconnected(const Utils::ProcessResultData &result); + + void detachFromSharedConnection(); + +private: + ProjectExplorer::DeviceConstRef m_device; +}; + +} // Internal class REMOTELINUX_EXPORT LinuxDevice : public ProjectExplorer::IDevice { @@ -38,7 +61,6 @@ public: ProjectExplorer::FileTransferInterface *createFileTransferInterface( const ProjectExplorer::FileTransferSetupData &setup) const override; - class LinuxDeviceAccess *connectionAccess() const; void checkOsType() override; DeviceState deviceState() const override; @@ -47,6 +69,8 @@ public: bool isDisconnected() const; bool tryToConnect(); + void attachToSharedConnection(Internal::SshConnectionHandle *sshConnectionHandle, + const ProjectExplorer::SshParameters &sshParams) const; protected: LinuxDevice(); diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs index 07b2dd9b9c9..c2a91fd2e75 100644 --- a/src/plugins/remotelinux/remotelinux.qbs +++ b/src/plugins/remotelinux/remotelinux.qbs @@ -44,6 +44,8 @@ QtcPlugin { "remotelinuxdeploysupport.h", "remotelinuxenvironmentaspect.cpp", "remotelinuxenvironmentaspect.h", + "remotelinuxfiletransfer.cpp", + "remotelinuxfiletransfer.h", "remotelinuxplugin.cpp", "remotelinuxrunconfiguration.cpp", "remotelinuxrunconfiguration.h", diff --git a/src/plugins/remotelinux/remotelinuxfiletransfer.cpp b/src/plugins/remotelinux/remotelinuxfiletransfer.cpp new file mode 100644 index 00000000000..15d43306573 --- /dev/null +++ b/src/plugins/remotelinux/remotelinuxfiletransfer.cpp @@ -0,0 +1,434 @@ +// 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 "linuxdevice.h" + +#include "remotelinux_constants.h" +#include "remotelinuxtr.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace RemoteLinux::Internal { + +const QByteArray s_pidMarker = "__qtc"; + +static SshParameters displayless(const SshParameters &sshParameters) +{ + SshParameters parameters = sshParameters; + parameters.x11DisplayName.clear(); + return parameters; +} + +static FilePaths dirsToCreate(const FilesToTransfer &files) +{ + FilePaths dirs; + for (const FileToTransfer &file : files) { + FilePath parentDir = file.m_target.parentDir(); + while (true) { + if (dirs.contains(parentDir) || QDir(parentDir.path()).isRoot()) + break; + dirs << parentDir; + parentDir = parentDir.parentDir(); + } + } + return sorted(std::move(dirs)); +} + +static QByteArray transferCommand(bool link) +{ + return link ? "ln -s" : "put -R"; +} + +class SshTransferInterface : public FileTransferInterface +{ +protected: + SshTransferInterface(const FileTransferSetupData &setup, const DeviceConstRef &device) + : FileTransferInterface(setup) + , m_device(device) + , m_process(this) + { + SshParameters::setupSshEnvironment(&m_process); + connect(&m_process, &Process::readyReadStandardOutput, this, [this] { + emit progress(QString::fromLocal8Bit(m_process.readAllRawStandardOutput())); + }); + connect(&m_process, &Process::done, this, &SshTransferInterface::doneImpl); + } + + DeviceConstRef device() const { return m_device; } + + bool handleError() + { + ProcessResultData resultData = m_process.resultData(); + if (resultData.m_error == QProcess::FailedToStart) { + resultData.m_errorString = Tr::tr("\"%1\" failed to start: %2") + .arg(FileTransfer::transferMethodName(m_setup.m_method), resultData.m_errorString); + } else if (resultData.m_exitStatus != QProcess::NormalExit) { + resultData.m_errorString = Tr::tr("\"%1\" crashed.") + .arg(FileTransfer::transferMethodName(m_setup.m_method)); + } else if (resultData.m_exitCode != 0) { + resultData.m_errorString = QString::fromLocal8Bit(m_process.readAllRawStandardError()); + } else { + return false; + } + emit done(resultData); + return true; + } + + void handleDone() + { + if (!handleError()) + emit done(m_process.resultData()); + } + + QStringList fullConnectionOptions() const + { + QStringList options = m_sshParameters.connectionOptions(SshSettings::sshFilePath()); + if (!m_socketFilePath.isEmpty()) + options << "-o" << ("ControlPath=" + m_socketFilePath); + return options; + } + + QString host() const { return m_sshParameters.host(); } + QString userAtHost() const { return m_sshParameters.userAtHost(); } + + Process &process() { return m_process; } + +private: + virtual void startImpl() = 0; + virtual void doneImpl() = 0; + + void start() final + { + m_sshParameters = displayless(m_device.sshParameters()); + const Id linkDeviceId = Id::fromSetting(m_device.extraData(Constants::LinkDevice)); + const auto linkDevice = DeviceManager::instance()->find(linkDeviceId); + const bool useConnectionSharing = !linkDevice && SshSettings::connectionSharingEnabled(); + + if (useConnectionSharing) { + m_connecting = true; + m_connectionHandle.reset(new SshConnectionHandle(m_device)); + m_connectionHandle->setParent(this); + connect(m_connectionHandle.get(), &SshConnectionHandle::connected, + this, &SshTransferInterface::handleConnected); + connect(m_connectionHandle.get(), &SshConnectionHandle::disconnected, + this, &SshTransferInterface::handleDisconnected); + auto linuxDevice = std::dynamic_pointer_cast(m_device.lock()); + QTC_ASSERT(linuxDevice, startFailed("No Linux device"); return); + linuxDevice->attachToSharedConnection(m_connectionHandle.get(), m_sshParameters); + } else { + startImpl(); + } + } + + void handleConnected(const QString &socketFilePath) + { + m_connecting = false; + m_socketFilePath = socketFilePath; + startImpl(); + } + + void handleDisconnected(const ProcessResultData &result) + { + ProcessResultData resultData = result; + if (m_connecting) + resultData.m_error = QProcess::FailedToStart; + + m_connecting = false; + if (m_connectionHandle) // TODO: should it disconnect from signals first? + m_connectionHandle.release()->deleteLater(); + + if (resultData.m_error != QProcess::UnknownError || m_process.state() != QProcess::NotRunning) + emit done(resultData); // TODO: don't emit done() on process finished afterwards + } + + DeviceConstRef m_device; + SshParameters m_sshParameters; + + // ssh shared connection related + std::unique_ptr m_connectionHandle; + QString m_socketFilePath; + bool m_connecting = false; + + Process m_process; +}; + +class SftpTransferImpl : public SshTransferInterface +{ +public: + SftpTransferImpl(const FileTransferSetupData &setup, const DeviceConstRef &device) + : SshTransferInterface(setup, device) + {} + +private: + void startImpl() final + { + FilePath sftpBinary = SshSettings::sftpFilePath(); + + // This is a hack. We only test the last hop here. + const Id linkDeviceId = Id::fromSetting(device().extraData(Constants::LinkDevice)); + if (const auto linkDevice = DeviceManager::instance()->find(linkDeviceId)) + sftpBinary = linkDevice->filePath(sftpBinary.fileName()).searchInPath(); + + if (!sftpBinary.exists()) { + startFailed(Tr::tr("\"sftp\" binary \"%1\" does not exist.") + .arg(sftpBinary.toUserOutput())); + return; + } + + QByteArray batchData; + + const FilePaths dirs = dirsToCreate(m_setup.m_files); + for (const FilePath &dir : dirs) { + if (!dir.exists()) + batchData += "-mkdir " + ProcessArgs::quoteArgUnix(dir.path()).toLocal8Bit() + '\n'; + } + + for (const FileToTransfer &file : m_setup.m_files) { + FilePath sourceFileOrLinkTarget = file.m_source; + bool link = false; + + const QFileInfo fi(file.m_source.toFileInfo()); + if (fi.isSymLink()) { + link = true; + batchData += "-rm " + ProcessArgs::quoteArgUnix( + file.m_target.path()).toLocal8Bit() + '\n'; + // see QTBUG-5817. + sourceFileOrLinkTarget = + sourceFileOrLinkTarget.withNewPath(fi.dir().relativeFilePath(fi.symLinkTarget())); + } + + const QByteArray source = ProcessArgs::quoteArgUnix(sourceFileOrLinkTarget.path()) + .toLocal8Bit(); + const QByteArray target = ProcessArgs::quoteArgUnix(file.m_target.path()).toLocal8Bit(); + + batchData += transferCommand(link) + ' ' + source + ' ' + target + '\n'; + if (file.m_targetPermissions == FilePermissions::ForceExecutable) + batchData += "chmod 1775 " + target + '\n'; + } + process().setCommand({sftpBinary, {fullConnectionOptions(), "-b", "-", host()}}); + process().setWriteData(batchData); + process().start(); + } + + void doneImpl() final { handleDone(); } +}; + +class RsyncTransferImpl : public SshTransferInterface +{ +public: + RsyncTransferImpl(const FileTransferSetupData &setup, const DeviceConstRef &device) + : SshTransferInterface(setup, device) + { } + +private: + void startImpl() final + { + // Note: This assumes that files do not get renamed when transferring. + for (auto it = m_setup.m_files.cbegin(); it != m_setup.m_files.cend(); ++it) + m_batches[it->m_target.parentDir()] << *it; + startNextBatch(); + } + + void doneImpl() final + { + if (m_batches.isEmpty()) + return handleDone(); + + if (handleError()) + return; + + startNextBatch(); + } + + void startNextBatch() + { + process().close(); + + const QString sshCmdLine = ProcessArgs::joinArgs( + QStringList{SshSettings::sshFilePath().toUserOutput()} + << fullConnectionOptions(), OsTypeLinux); + QStringList options{"-e", sshCmdLine}; + options << ProcessArgs::splitArgs(m_setup.m_rsyncFlags, HostOsInfo::hostOs()); + + if (!m_batches.isEmpty()) { // NormalRun + const auto batchIt = m_batches.begin(); + for (auto filesIt = batchIt->cbegin(); filesIt != batchIt->cend(); ++filesIt) { + const FileToTransfer fixedFile = fixLocalFileOnWindows(*filesIt, options); + options << fixedFile.m_source.path(); + } + options << fixedRemotePath(batchIt.key(), userAtHost()); + m_batches.erase(batchIt); + } else { // TestRun + options << "-n" << "--exclude=*" << (userAtHost() + ":/tmp"); + } + // TODO: Get rsync location from settings? + process().setCommand(CommandLine("rsync", options)); + process().start(); + } + + // On Windows, rsync is either from msys or cygwin. Neither work with the other's ssh.exe. + FileToTransfer fixLocalFileOnWindows(const FileToTransfer &file, const QStringList &options) const + { + if (!HostOsInfo::isWindowsHost()) + return file; + + QString localFilePath = file.m_source.path(); + localFilePath = '/' + localFilePath.at(0) + localFilePath.mid(2); + if (anyOf(options, [](const QString &opt) { + return opt.contains("cygwin", Qt::CaseInsensitive); })) { + localFilePath.prepend("/cygdrive"); + } + + FileToTransfer fixedFile = file; + fixedFile.m_source = fixedFile.m_source.withNewPath(localFilePath); + return fixedFile; + } + + QString fixedRemotePath(const FilePath &file, const QString &remoteHost) const + { + return remoteHost + ':' + file.path(); + } + + QHash m_batches; +}; + +static void createDir(QPromise &promise, const FilePath &pathToCreate) +{ + const Result result = pathToCreate.ensureWritableDir(); + promise.addResult(result); + + if (!result) + promise.future().cancel(); +}; + +static void copyFile(QPromise &promise, const FileToTransfer &file) +{ + const Result result = file.m_source.copyFile(file.m_target); + promise.addResult(result); + + if (!result) + promise.future().cancel(); +}; + +class GenericTransferImpl : public FileTransferInterface +{ + Tasking::TaskTreeRunner m_taskTree; + +public: + GenericTransferImpl(const FileTransferSetupData &setup) + : FileTransferInterface(setup) + {} + +private: + void start() final + { + using namespace Tasking; + + const QSet allParentDirs + = Utils::transform(m_setup.m_files, [](const FileToTransfer &f) { + return f.m_target.parentDir(); + }); + + const LoopList iteratorParentDirs(QList(allParentDirs.cbegin(), allParentDirs.cend())); + + const auto onCreateDirSetup = [iteratorParentDirs](Async &async) { + async.setConcurrentCallData(createDir, *iteratorParentDirs); + }; + + const auto onCreateDirDone = [this, + iteratorParentDirs](const Async &async) { + const Result result = async.result(); + if (result) + emit progress( + Tr::tr("Created directory: \"%1\".\n").arg(iteratorParentDirs->toUserOutput())); + else + emit progress(result.error()); + }; + + const LoopList iterator(m_setup.m_files); + const Storage counterStorage; + + const auto onCopySetup = [iterator](Async &async) { + async.setConcurrentCallData(copyFile, *iterator); + }; + + const auto onCopyDone = [this, iterator, counterStorage]( + const Async &async) { + const Result result = async.result(); + int &counter = *counterStorage; + ++counter; + + if (result) { + //: %1/%2 = progress in the form 4/15, %3 and %4 = source and target file paths + emit progress(Tr::tr("Copied %1/%2: \"%3\" -> \"%4\".\n") + .arg(counter) + .arg(m_setup.m_files.size()) + .arg(iterator->m_source.toUserOutput()) + .arg(iterator->m_target.toUserOutput())); + } else { + emit progress(result.error() + "\n"); + } + }; + + const Group recipe { + For (iteratorParentDirs) >> Do { + parallelIdealThreadCountLimit, + AsyncTask(onCreateDirSetup, onCreateDirDone), + }, + For (iterator) >> Do { + parallelLimit(2), + counterStorage, + AsyncTask(onCopySetup, onCopyDone), + }, + }; + + m_taskTree.start(recipe, {}, [this](DoneWith result) { + ProcessResultData resultData; + if (result != DoneWith::Success) { + resultData.m_exitCode = -1; + resultData.m_errorString = Tr::tr("Failed to deploy files."); + } + emit done(resultData); + }); + } +}; + +FileTransferInterface *createRemoteLinuxFileTransferInterface + (const LinuxDevice &device, const FileTransferSetupData &setup) +{ + if (Utils::anyOf(setup.m_files, + [](const FileToTransfer &f) { return !f.m_source.isLocal(); })) { + return new GenericTransferImpl(setup); + } + + switch (setup.m_method) { + case FileTransferMethod::Sftp: return new SftpTransferImpl(setup, device.shared_from_this()); + case FileTransferMethod::Rsync: return new RsyncTransferImpl(setup, device.shared_from_this()); + case FileTransferMethod::GenericCopy: return new GenericTransferImpl(setup); + } + QTC_CHECK(false); + return {}; +} + +} // namespace RemoteLinux::Internal diff --git a/src/plugins/remotelinux/remotelinuxfiletransfer.h b/src/plugins/remotelinux/remotelinuxfiletransfer.h new file mode 100644 index 00000000000..fb0804bbfd5 --- /dev/null +++ b/src/plugins/remotelinux/remotelinuxfiletransfer.h @@ -0,0 +1,15 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "linuxdevice.h" + +namespace RemoteLinux::Internal { + +ProjectExplorer::FileTransferInterface * + createRemoteLinuxFileTransferInterface( + const LinuxDevice &device, + const ProjectExplorer::FileTransferSetupData &setup); + +} // namespace RemoteLinux From e8383bc3b2c2cff2caa2ef062cc8f3d54d620a8c Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 11 Dec 2024 08:25:34 +0100 Subject: [PATCH 389/989] PE: Fix possible crash In case of an invalid device we may crash when trying to generate a build directory path. Prevent this by leaving earlier. Change-Id: Ieb02abd98467693d38df6dde434e2a6962e4d137 Reviewed-by: Marcus Tillmanns --- src/plugins/projectexplorer/buildconfiguration.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 1f076e0751b..c6fd9f43988 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -644,6 +644,8 @@ FilePath BuildConfiguration::buildDirectoryFromTemplate(const FilePath &projectD buildDir = buildDir.withNewPath(buildDir.path().replace(" ", "-")); auto buildDevice = BuildDeviceKitAspect::device(kit); + if (!buildDevice) + return buildDir; if (buildDir.isAbsolutePath()) return buildDevice->rootPath().withNewMappedPath(buildDir); From 248cd3ce08708d2541d5a205a8433b5afdf447b7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 10 Dec 2024 15:13:40 +0100 Subject: [PATCH 390/989] ProjectExplorer: Fix UI of various kit aspects ... when there is no value compatible with the current build device. The combo box was missing the "none" entry in that case. Amends db11237dd559fe93acdf7d26c863280662f9adaf. Task-number: QTCREATORBUG-26870 Change-Id: I195b13026ac299d57287772040c1fc78ab9289d2 Reviewed-by: hjk --- .../cmakeprojectmanager/cmakekitaspect.cpp | 19 +++++++------- src/plugins/debugger/debuggerkitaspect.cpp | 23 ++++++++-------- src/plugins/projectexplorer/kitaspect.cpp | 5 +++- .../projectexplorer/toolchainkitaspect.cpp | 26 +++++++++---------- src/plugins/qtsupport/qtkitaspect.cpp | 19 +++++++------- 5 files changed, 45 insertions(+), 47 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp index 36f2ec9801e..f0c62a9a258 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp @@ -80,16 +80,15 @@ public: { clear(); - const IDevice::ConstPtr dev = BuildDeviceKitAspect::device(&m_kit); - if (!dev) - return; - const FilePath rootPath = dev->rootPath(); - const QList toolsForBuildDevice - = Utils::filtered(CMakeToolManager::cmakeTools(), [rootPath](CMakeTool *item) { - return item->cmakeExecutable().isSameDevice(rootPath); - }); - for (CMakeTool *item : toolsForBuildDevice) - rootItem()->appendChild(new CMakeToolTreeItem(item, false)); + if (const IDevice::ConstPtr dev = BuildDeviceKitAspect::device(&m_kit)) { + const FilePath rootPath = dev->rootPath(); + const QList toolsForBuildDevice + = Utils::filtered(CMakeToolManager::cmakeTools(), [rootPath](CMakeTool *item) { + return item->cmakeExecutable().isSameDevice(rootPath); + }); + for (CMakeTool *item : toolsForBuildDevice) + rootItem()->appendChild(new CMakeToolTreeItem(item, false)); + } rootItem()->appendChild(new CMakeToolTreeItem); // The "none" item. } diff --git a/src/plugins/debugger/debuggerkitaspect.cpp b/src/plugins/debugger/debuggerkitaspect.cpp index 00f08ac5d37..6f578828434 100644 --- a/src/plugins/debugger/debuggerkitaspect.cpp +++ b/src/plugins/debugger/debuggerkitaspect.cpp @@ -48,18 +48,17 @@ public: { clear(); - const IDeviceConstPtr device = BuildDeviceKitAspect::device(&m_kit); - if (!device) - return; - const Utils::FilePath rootPath = device->rootPath(); - const QList debuggersForBuildDevice - = Utils::filtered(DebuggerItemManager::debuggers(), [&](const DebuggerItem &item) { - if (item.isGeneric()) - return device->id() != ProjectExplorer::Constants::DESKTOP_DEVICE_ID; - return item.command().isSameDevice(rootPath); - }); - for (const DebuggerItem &item : debuggersForBuildDevice) - rootItem()->appendChild(new DebuggerTreeItem(item, false)); + if (const IDeviceConstPtr device = BuildDeviceKitAspect::device(&m_kit)) { + const Utils::FilePath rootPath = device->rootPath(); + const QList debuggersForBuildDevice + = Utils::filtered(DebuggerItemManager::debuggers(), [&](const DebuggerItem &item) { + if (item.isGeneric()) + return device->id() != ProjectExplorer::Constants::DESKTOP_DEVICE_ID; + return item.command().isSameDevice(rootPath); + }); + for (const DebuggerItem &item : debuggersForBuildDevice) + rootItem()->appendChild(new DebuggerTreeItem(item, false)); + } DebuggerItem noneItem; noneItem.setUnexpandedDisplayName(Tr::tr("None")); rootItem()->appendChild(new DebuggerTreeItem(noneItem, false)); diff --git a/src/plugins/projectexplorer/kitaspect.cpp b/src/plugins/projectexplorer/kitaspect.cpp index c8fabb17792..f1fcf6b5813 100644 --- a/src/plugins/projectexplorer/kitaspect.cpp +++ b/src/plugins/projectexplorer/kitaspect.cpp @@ -164,7 +164,10 @@ void KitAspect::refresh() la.spec.resetModel(); la.comboBox->model()->sort(0); const QVariant itemId = la.spec.getter(*kit()); - la.comboBox->setCurrentIndex(la.comboBox->findData(itemId, IdRole)); + int idx = la.comboBox->findData(itemId, IdRole); + if (idx == -1) + idx = la.comboBox->count() - 1; + la.comboBox->setCurrentIndex(idx); la.comboBox->setEnabled(!d->readOnly && la.comboBox->count() > 1); } } diff --git a/src/plugins/projectexplorer/toolchainkitaspect.cpp b/src/plugins/projectexplorer/toolchainkitaspect.cpp index 657b1ab216f..d68d3b24ae8 100644 --- a/src/plugins/projectexplorer/toolchainkitaspect.cpp +++ b/src/plugins/projectexplorer/toolchainkitaspect.cpp @@ -40,20 +40,18 @@ public: { clear(); - const Toolchains ltcList = ToolchainManager::toolchains( - [this](const Toolchain *tc) { return m_category.contains(tc->language()); }); - IDeviceConstPtr device = BuildDeviceKitAspect::device(&m_kit); - if (!device) - return; - - const QList toolchainsForBuildDevice - = Utils::filtered(ltcList, [device](Toolchain *tc) { - return tc->compilerCommand().isSameDevice(device->rootPath()); - }); - const QList bundlesForBuildDevice = ToolchainBundle::collectBundles( - toolchainsForBuildDevice, ToolchainBundle::HandleMissing::CreateAndRegister); - for (const ToolchainBundle &b : bundlesForBuildDevice) - rootItem()->appendChild(new ToolchainTreeItem(b)); + if (const IDeviceConstPtr device = BuildDeviceKitAspect::device(&m_kit)) { + const Toolchains ltcList = ToolchainManager::toolchains( + [this](const Toolchain *tc) { return m_category.contains(tc->language()); }); + const Toolchains toolchainsForBuildDevice + = Utils::filtered(ltcList, [device](Toolchain *tc) { + return tc->compilerCommand().isSameDevice(device->rootPath()); + }); + const QList bundlesForBuildDevice = ToolchainBundle::collectBundles( + toolchainsForBuildDevice, ToolchainBundle::HandleMissing::CreateAndRegister); + for (const ToolchainBundle &b : bundlesForBuildDevice) + rootItem()->appendChild(new ToolchainTreeItem(b)); + } rootItem()->appendChild(new ToolchainTreeItem); } diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index 4af43dbbf85..b232d203579 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -49,16 +49,15 @@ public: { clear(); - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(&m_kit); - if (!device) - return; - const FilePath deviceRoot = device->rootPath(); - const QtVersions versionsForBuildDevice = QtVersionManager::versions( - [&deviceRoot](const QtVersion *qt) { - return qt->qmakeFilePath().isSameDevice(deviceRoot); - }); - for (QtVersion *v : versionsForBuildDevice) - rootItem()->appendChild(new QtVersionItem(v->uniqueId())); + if (const IDevice::ConstPtr device = BuildDeviceKitAspect::device(&m_kit)) { + const FilePath deviceRoot = device->rootPath(); + const QtVersions versionsForBuildDevice = QtVersionManager::versions( + [&deviceRoot](const QtVersion *qt) { + return qt->qmakeFilePath().isSameDevice(deviceRoot); + }); + for (QtVersion *v : versionsForBuildDevice) + rootItem()->appendChild(new QtVersionItem(v->uniqueId())); + } rootItem()->appendChild(new QtVersionItem(-1)); // The "No Qt" entry. } From 594edc49dcf7b4692fea1f5f79d690475402360d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 10 Dec 2024 16:04:34 +0100 Subject: [PATCH 391/989] Kit aspects: Make sure to always use createSubWidget() ... to create sub-widgets. Otherwise, parts of the aspect will stay visible when it gets hidden. Change-Id: I967ef745348c10f7b5e78d726efcdb9c6005f887 Reviewed-by: hjk --- .../projectexplorer/devicesupport/devicekitaspects.cpp | 4 ++-- src/plugins/qtsupport/qtkitaspect.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp index 0c0f067d03f..367045b4717 100644 --- a/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicekitaspects.cpp @@ -99,9 +99,9 @@ private: { if (const QList embedded = aspectsToEmbed(); !embedded.isEmpty()) { Layouting::Layout box(new QHBoxLayout); - box.addItem(Tr::tr("Type:")); + box.addItem(createSubWidget(Tr::tr("Type:"))); embedded.first()->addToInnerLayout(box); - box.addItem(Tr::tr("Device:")); + box.addItem(createSubWidget(Tr::tr("Device:"))); KitAspect::addToInnerLayout(box); QSizePolicy p = comboBoxes().first()->sizePolicy(); p.setHorizontalStretch(1); diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index b232d203579..a69c7997864 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -95,7 +95,7 @@ private: QSizePolicy p = comboBoxes().first()->sizePolicy(); p.setHorizontalStretch(2); comboBoxes().first()->setSizePolicy(p); - box.addItem(Tr::tr("Mkspec:")); + box.addItem(createSubWidget(Tr::tr("Mkspec:"))); embedded.first()->addToInnerLayout(box); layout.addItem(box); } else { From 5bf709b6281d3c6cf81c6a344c43cc633dbf94fe Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 9 Dec 2024 14:42:06 +0100 Subject: [PATCH 392/989] Utils: Add simple unittest for karchive Change-Id: Ib2048c1a8adf9887f936126b476e6fb95e36a72d Reviewed-by: Eike Ziller --- tests/auto/utils/CMakeLists.txt | 1 + tests/auto/utils/archive/CMakeLists.txt | 4 + tests/auto/utils/archive/archive.qbs | 12 +++ tests/auto/utils/archive/tst_archive.cpp | 106 +++++++++++++++++++++++ tests/auto/utils/utils.qbs | 1 + 5 files changed, 124 insertions(+) create mode 100644 tests/auto/utils/archive/CMakeLists.txt create mode 100644 tests/auto/utils/archive/archive.qbs create mode 100644 tests/auto/utils/archive/tst_archive.cpp diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt index 2ce149800dd..a8ef9312186 100644 --- a/tests/auto/utils/CMakeLists.txt +++ b/tests/auto/utils/CMakeLists.txt @@ -21,3 +21,4 @@ add_subdirectory(templateengine) add_subdirectory(treemodel) add_subdirectory(text) add_subdirectory(unixdevicefileaccess) +add_subdirectory(archive) diff --git a/tests/auto/utils/archive/CMakeLists.txt b/tests/auto/utils/archive/CMakeLists.txt new file mode 100644 index 00000000000..4eef25931a9 --- /dev/null +++ b/tests/auto/utils/archive/CMakeLists.txt @@ -0,0 +1,4 @@ +add_qtc_test(tst_utils_archive + DEPENDS Utils karchive + SOURCES tst_archive.cpp +) diff --git a/tests/auto/utils/archive/archive.qbs b/tests/auto/utils/archive/archive.qbs new file mode 100644 index 00000000000..15af3f2c30b --- /dev/null +++ b/tests/auto/utils/archive/archive.qbs @@ -0,0 +1,12 @@ +Project { + QtcAutotest { + name: "Archive autotest" + + Depends { name: "Utils" } + Depends { name: "karchive" } + + files: [ + "tst_archive.cpp", + ] + } +} diff --git a/tests/auto/utils/archive/tst_archive.cpp b/tests/auto/utils/archive/tst_archive.cpp new file mode 100644 index 00000000000..e4be07a2828 --- /dev/null +++ b/tests/auto/utils/archive/tst_archive.cpp @@ -0,0 +1,106 @@ +// 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 + +#include +#include +#include +#include + +#include +#include + +using namespace Utils; + +static const QByteArray testData = R"(Hello, World! +Compress me please! +Thank you! + +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut +labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores +et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut +labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores +et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut +labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores +et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut +labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores +et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut +labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores +et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +)"; + +class tst_Archive : public QObject +{ + Q_OBJECT + + void testArchive(KArchive &&archive, const FilePath &testFile) + { + QVERIFY(testFile.writeFileContents(testData)); + + QVERIFY(archive.open(QIODevice::WriteOnly)); + QVERIFY(archive.addLocalFile(testFile.toFSPathString(), "data/test.txt")); + QVERIFY(archive.close()); + QVERIFY(testFile.removeFile()); + QVERIFY(!testFile.exists()); + } + + void testUnarchive(KArchive &&archive, const FilePath &testFile) + { + QVERIFY(!testFile.exists()); + + QVERIFY(archive.open(QIODevice::ReadOnly)); + QVERIFY(archive.directory()->entries().contains("data")); + QVERIFY(archive.directory()->entry("data")); + QVERIFY(archive.directory()->entry("data")->isDirectory()); + auto dataDir = static_cast(archive.directory()->entry("data")); + QVERIFY(dataDir->entries().contains("test.txt")); + QVERIFY(dataDir->entry("test.txt")->isFile()); + QVERIFY(dataDir->file("test.txt")->copyTo(".")); + + QVERIFY(testFile.exists()); + auto contents = testFile.fileContents(); + QVERIFY(contents); + QCOMPARE(*contents, QByteArray(testData)); + QVERIFY(testFile.removeFile()); + } + + template + void unArchive(const FilePath &archivePath, bool testSize = true) + { + FilePath p = FilePath::fromString("test.txt"); + + testArchive(ARCHIVE(archivePath.toFSPathString()), p); + QVERIFY(archivePath.exists()); + qDebug() << "Archive size:" << archivePath.fileSize() << "(expected roughly less than" + << testData.size() << ")"; + if (testSize) + QVERIFY(archivePath.fileSize() < testData.size()); + testUnarchive(ARCHIVE(archivePath.toFSPathString()), p); + QVERIFY(archivePath.removeFile()); + } + +private slots: + void initTestCase() {} + + void cleanupTestCase() {} + + void test7zip() { unArchive(FilePath::fromString("test.7z")); } + void testZip() { unArchive(FilePath::fromString("test.zip")); } + void testTar() { unArchive(FilePath::fromString("test.tar"), false); } + void testXZ() { unArchive(FilePath::fromString("test.tar.xz")); } + void testGZ() { unArchive(FilePath::fromString("test.tar.gz")); } + void testBZip2() { unArchive(FilePath::fromString("test.tar.bz2")); } +}; + +QTEST_GUILESS_MAIN(tst_Archive) + +#include "tst_archive.moc" diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs index 14d18d29d58..9a652c1c367 100644 --- a/tests/auto/utils/utils.qbs +++ b/tests/auto/utils/utils.qbs @@ -4,6 +4,7 @@ Project { name: "Utils autotests" references: [ "ansiescapecodehandler/ansiescapecodehandler.qbs", + "archive/archive.qbs", "async/async.qbs", "commandline/commandline.qbs", "deviceshell/deviceshell.qbs", From df26841798ab2f2c88ea9130bea31c696f02423f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 11 Dec 2024 11:18:21 +0100 Subject: [PATCH 393/989] CppEditor: Deprecate "assign to local" quickfix ... in favor of clangd's "Extract Variable" tweak. As of https://github.com/llvm/llvm-project/pull/112525, this functionality should be fully covered by clangd. Task-number: QTCREATORBUG-9363 Task-number: QTCREATORBUG-9578 Change-Id: I00ce996ef37b26152d93ed91fa5d1ea69e619618 Reviewed-by: Christian Stenger --- src/plugins/cppeditor/quickfixes/assigntolocalvariable.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/quickfixes/assigntolocalvariable.cpp b/src/plugins/cppeditor/quickfixes/assigntolocalvariable.cpp index ae63681dc26..c3bc3e85daf 100644 --- a/src/plugins/cppeditor/quickfixes/assigntolocalvariable.cpp +++ b/src/plugins/cppeditor/quickfixes/assigntolocalvariable.cpp @@ -123,8 +123,13 @@ private: //! Assigns the return value of a function call or a new expression to a local variable class AssignToLocalVariable : public CppQuickFixFactory { -#ifdef WITH_TESTS public: + AssignToLocalVariable() + { + setClangdReplacement({20}); + } + +#ifdef WITH_TESTS static QObject *createTest(); #endif From d7adccc521019b3eaaddc9a1f0d35c973b542204 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 28 Nov 2024 09:05:25 +0100 Subject: [PATCH 394/989] KArchive: Provide qbs build integration Change-Id: Idd2a8808d79b6ee3f9b6ad8e0f0f4c313662f0a0 Reviewed-by: Christian Kandeler Reviewed-by: Christian Stenger --- src/libs/3rdparty/karchive/karchive.qbs | 285 ++++++++++++++++++++++++ src/libs/libs.qbs | 1 + 2 files changed, 286 insertions(+) create mode 100644 src/libs/3rdparty/karchive/karchive.qbs diff --git a/src/libs/3rdparty/karchive/karchive.qbs b/src/libs/3rdparty/karchive/karchive.qbs new file mode 100644 index 00000000000..b3e612a537f --- /dev/null +++ b/src/libs/3rdparty/karchive/karchive.qbs @@ -0,0 +1,285 @@ +import qbs.Probes + +QtcLibrary { + name: "karchive" + + property bool preferSystemZlib: true + property bool preferSystemBZip2: true + property bool preferSystemLzma: true + + readonly property bool useSystemZlib: preferSystemZlib && zlibHProbe.found && zlibLibProbe.found + readonly property bool useSystemBZip2: preferSystemBZip2 && bzlibProbe.found && bzip2LibProbe.found + readonly property bool useSystemLzma: preferSystemLzma && lzmaHProbe.found && lzmaLibProbe.found + + cpp.defines: base.concat([ + "KARCHIVE_LIBRARY", // general define + "HAVE_ZLIB_SUPPORT=1", + "HAVE_BZIP2_SUPPORT=1", "NEED_BZ2_PREFIX=1", + "HAVE_XZ_SUPPORT=1" + ]) + + cpp.includePaths: { + var paths = base; + paths.push("src"); // general include + + if (useSystemZlib) + paths.push(zlibHProbe.path); + else + paths.push("../zlib/src"); + + if (useSystemBZip2) + paths.push(bzlibProbe.path); + else + paths.push("3rdparty/bzip2"); + + if (useSystemLzma) { + paths.push(lzmaHProbe.path); + } else { + paths.push( + "3rdparty/xz/src/common", + "3rdparty/xz/src/liblzma/api", + "3rdparty/xz/src/liblzma/check", + "3rdparty/xz/src/liblzma/common", + "3rdparty/xz/src/liblzma/delta", + "3rdparty/xz/src/liblzma/lz", + "3rdparty/xz/src/liblzma/lzma", + "3rdparty/xz/src/liblzma/range_decoder", + "3rdparty/xz/src/liblzma/rangecoder", + "3rdparty/xz/src/liblzma/simple" + ); + } + return paths; + } + + cpp.libraryPaths: { + var paths = base; + if (useSystemZlib) + paths.push(zlibLibProbe.path); + if (useSystemBZip2) + paths.push(bzip2LibProbe.path); + if (useSystemLzma) + paths.push(lzmaLibProbe.path); + return paths; + } + + cpp.dynamicLibraries: { + var libs = base; + if (qbs.targetOS.contains("windows")) + libs.push("advapi32"); + if (useSystemZlib) + libs = libs.concat(zlibLibProbe.names); + if (useSystemBZip2) + libs = libs.concat(bzip2LibProbe.names); + if (useSystemLzma) + libs = libs.concat(lzmaLibProbe.names); + return libs; + } + + Group { + name: "KArchive files" + prefix: "src/" + files: [ + "kar.cpp", + "kar.h", + "karchive_export.h", + "karchive_p.h", + "karchive.cpp", + "karchive.h", + "karchivedirectory.h", + "karchiveentry.h", + "karchivefile.h", + "kcompressiondevice_p.h", + "kcompressiondevice.cpp", + "kcompressiondevice.h", + "kfilterbase.cpp", + "kfilterbase.h", + "klimitediodevice_p.h", + "klimitediodevice.cpp", + "knonefilter.cpp", + "knonefilter.h", + "krcc.cpp", + "krcc.h", + "ktar.cpp", + "ktar.h", + "kzipfileentry.h", + "loggingcategory.cpp", + "loggingcategory.h", + ] + } + + Probes.IncludeProbe { id: zlibHProbe; names: "zlib.h" } + Probes.LibraryProbe { id: zlibLibProbe; names: "zlib" } + Group { + name: "zlib support" + prefix: "src/" + files: [ + "kgzipfilter.cpp", + "kgzipfilter.h", + "kzip.cpp", + "kzip.h", + ] + } + Group { + name: "embedded zlib" + condition: !useSystemZlib + prefix: "../zlib/src/" + files: [ + "adler32.c", + "compress.c", + "crc32.c", + "crc32.h", + "deflate.c", + "deflate.h", + "gzclose.c", + "gzguts.h", + "gzlib.c", + "gzread.c", + "gzwrite.c", + "infback.c", + "inffast.c", + "inffast.h", + "inffixed.h", + "inflate.c", + "inflate.h", + "inftrees.c", + "inftrees.h", + "trees.c", + "trees.h", + "uncompr.c", + "zconf.h", + "zlib.h", + "zutil.c", + "zutil.h", + ] + } + + Probes.LibraryProbe { id: bzip2LibProbe; names: "bzip2" } + Probes.IncludeProbe { id: bzlibProbe; names: "bzlib.h" } + Group { + name: "bzip2 support" + files: [ "src/kbzip2filter.cpp"] + } + Group { + name: "embedded bzip2" + condition: !useSystemBZip2 + cpp.cFlags: (qbs.toolchain.contains("msvc") ? ["/wd26819", "/wd4100"] : []) + .concat(qbs.toolchain.contains("gcc") ? ["-Wno-implicit-fallthrough", "-Wno-unused-parameter"] : []) + prefix: "3rdparty/bzip2/" + files: [ + "blocksort.c", + "bzlib.c", + "bzlib.h", + "compress.c", + "crctable.c", + "decompress.c", + "huffman.c", + "randtable.c", + ] + } + + Probes.IncludeProbe { id: lzmaHProbe; names: "lzma.h" } + Probes.LibraryProbe { id: lzmaLibProbe; names: "lzma" } + Group { + name: "lzma support" + prefix: "src/" + files: [ + "kxzfilter.cpp", + "kxzfilter.h", + "k7zip.cpp", + "k7zip.h", + ] + } + + Probes.IncludeProbe { id: stdBoolProbe; names: "stdbool.h" } + Group { + name: "embedded lzma" + condition: !useSystemLzma + cpp.defines: outer.concat([ + "SIZEOF_SIZE_T=" + "8", // FIXME! + "HAVE_STDBOOL_H=" + "1", // FIXME! stdBoolProbe.found ? "1" : "0", + "HAVE_CHECK_CRC32", "HAVE_CHECK_CRC64", + "HAVE_CHECK_SHA256", + "HAVE_ENCODER_LZMA1", "HAVE_DECODER_LZMA1", + "HAVE_ENCODER_LZMA2", "HAVE_DECODER_LZMA2", + "HAVE_ENCODER_X86", "HAVE_DECODER_X86", + "HAVE_ENCODER_POWERPC", "HAVE_DECODER_POWERPC", + "HAVE_ENCODER_IA64", "HAVE_DECODER_IA64", + "HAVE_ENCODER_ARM", "HAVE_DECODER_ARM", + "HAVE_ENCODER_ARMTHUMB", "HAVE_DECODER_ARMTHUMB", + "HAVE_ENCODER_ARM64", "HAVE_DECODER_ARM64", + "HAVE_ENCODER_SPARC", "HAVE_DECODER_SPARC", + "HAVE_ENCODER_RISCV", "HAVE_DECODER_RISCV", + "HAVE_ENCODER_DELTA", "HAVE_DECODER_DELTA", + "HAVE_MF_HC3", "HAVE_MF_HC4", "HAVE_MF_BT2", + "HAVE_MF_BT3", "HAVE_MF_BT4", + ]) + prefix: "3rdparty/xz/src/liblzma/" + files: [ + "check/check.c", + "check/crc32_fast.c", + "check/crc32_table.c", + "check/crc64_fast.c", + "check/crc64_table.c", + "check/sha256.c", + "common/alone_decoder.c", + "common/auto_decoder.c", + "common/block_decoder.c", + "common/block_encoder.c", + "common/block_header_decoder.c", + "common/block_header_encoder.c", + "common/block_util.c", + "common/common.c", + "common/easy_encoder.c", + "common/easy_preset.c", + "common/filter_common.c", + "common/filter_decoder.c", + "common/filter_encoder.c", + "common/filter_flags_decoder.c", + "common/filter_flags_encoder.c", + "common/index_decoder.c", + "common/index_encoder.c", + "common/index_hash.c", + "common/index.c", + "common/stream_decoder.c", + "common/stream_encoder.c", + "common/stream_flags_common.c", + "common/stream_flags_decoder.c", + "common/stream_flags_encoder.c", + "common/vli_decoder.c", + "common/vli_encoder.c", + "common/vli_size.c", + "delta/delta_common.c", + "delta/delta_decoder.c", + "delta/delta_encoder.c", + "lz/lz_decoder.c", + "lz/lz_encoder_mf.c", + "lz/lz_encoder.c", + "lzma/fastpos_table.c", + "lzma/lzma_decoder.c", + "lzma/lzma_encoder_optimum_fast.c", + "lzma/lzma_encoder_optimum_normal.c", + "lzma/lzma_encoder_presets.c", + "lzma/lzma_encoder.c", + "lzma/lzma2_decoder.c", + "lzma/lzma2_encoder.c", + "rangecoder/price_table.c", + "simple/arm.c", + "simple/arm64.c", + "simple/armthumb.c", + "simple/ia64.c", + "simple/powerpc.c", + "simple/riscv.c", + "simple/simple_coder.c", + "simple/simple_decoder.c", + "simple/simple_encoder.c", + "simple/sparc.c", + "simple/x86.c", + ] + } + + Export { + Depends { name: "cpp" } + cpp.defines: [ "KARCHIVE_HAS_ZLIB", "KARCHIVE_HAS_BZIP2", "KARCHIVE_HAS_XZ" ] + cpp.includePaths: path + "/src" + } +} diff --git a/src/libs/libs.qbs b/src/libs/libs.qbs index 83ec97a444b..9f6cffc82d3 100644 --- a/src/libs/libs.qbs +++ b/src/libs/libs.qbs @@ -25,6 +25,7 @@ Project { "tracing/tracing.qbs", "utils/process_ctrlc_stub.qbs", "utils/utils.qbs", + "3rdparty/karchive/karchive.qbs", "3rdparty/libptyqt/ptyqt.qbs", "3rdparty/libvterm/vterm.qbs", "3rdparty/lua/lua.qbs", From be22ef9ed4f4640a17404bedc66a52698bd8ad15 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 11 Dec 2024 17:36:55 +0200 Subject: [PATCH 395/989] karchive: Suppress MSVC warnings Sample warnings: k7zip.cpp(70): warning C4005: 'FILE_ATTRIBUTE_READONLY': macro redefinition C4244: '=': conversion from '__int64' to 'Int32', possible loss of data C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data C4996: 'write': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _write. See online help for details. Change-Id: If37c98964ddc19517491829f75aa203228585c90 Reviewed-by: Marcus Tillmanns --- src/libs/3rdparty/karchive/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/3rdparty/karchive/CMakeLists.txt b/src/libs/3rdparty/karchive/CMakeLists.txt index 41a595d728b..a8643e4d433 100644 --- a/src/libs/3rdparty/karchive/CMakeLists.txt +++ b/src/libs/3rdparty/karchive/CMakeLists.txt @@ -282,6 +282,10 @@ extend_qtc_library( ./3rdparty/xz/src/liblzma/simple/x86.c ) +if(MSVC) + target_compile_options(karchive PUBLIC /wd4005 /wd4244 /wd4267 /wd4996) +endif() + # Zstd support # BSD License: https://github.com/facebook/zstd/blob/dev/LICENSE # Disabled for now as we don't need it and the packages are suboptimal From 7a893394eb98043f1f36b4d75d3371401c4d8f84 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 9 Dec 2024 14:45:37 +0100 Subject: [PATCH 396/989] DiffEditor: Code cosmetics in diffeditordocument.cpp Change-Id: I598559babec268c7f519071ace7da95eae4847ee Reviewed-by: David Schulz --- src/plugins/diffeditor/diffeditordocument.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp index 5068da1f0f1..c7e9ae1e1f3 100644 --- a/src/plugins/diffeditor/diffeditordocument.cpp +++ b/src/plugins/diffeditor/diffeditordocument.cpp @@ -14,19 +14,12 @@ #include #include -#include -#include -#include -#include -#include - using namespace Core; using namespace Utils; namespace DiffEditor::Internal { -DiffEditorDocument::DiffEditorDocument() : - Core::BaseTextDocument() +DiffEditorDocument::DiffEditorDocument() { setId(Constants::DIFF_EDITOR_ID); setMimeType(Constants::DIFF_EDITOR_MIMETYPE); From cb1b71b026b72254ac49b9127514e6a8981fbc8c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 21 Nov 2024 10:27:55 +0100 Subject: [PATCH 397/989] Ios: Move part of start setup into IosDebugSupport's c'tor Task-number: QTCREATORBUG-29168 Change-Id: Id241748271a9accb9b7f84cdb3a128934bc056d4 Reviewed-by: Eike Ziller --- src/plugins/ios/iosrunner.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index 9102390b3d2..abbe728c5bb 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -764,14 +764,6 @@ IosDebugSupport::IosDebugSupport(RunControl *runControl) m_runner->setQmlDebugging(isQmlDebugging() ? QmlDebuggerServices : NoQmlDebugServices); addStartDependency(m_runner); -} - -void IosDebugSupport::start() -{ - if (!m_runner->isAppRunning()) { - reportFailure(Tr::tr("Application not running.")); - return; - } if (device()->type() == Ios::Constants::IOS_DEVICE_TYPE) { IosDevice::ConstPtr dev = std::dynamic_pointer_cast(device()); @@ -804,6 +796,14 @@ void IosDebugSupport::start() setStartMode(AttachToLocalProcess); setIosPlatform("ios-simulator"); } +} + +void IosDebugSupport::start() +{ + if (!m_runner->isAppRunning()) { + reportFailure(Tr::tr("Application not running.")); + return; + } const IosDeviceTypeAspect::Data *data = runControl()->aspectData(); QTC_ASSERT(data, reportFailure("Broken IosDeviceTypeAspect setup."); return); From 59635ee0e897c79c79c13440184f865eb1198b9e Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 12 Dec 2024 13:07:34 +0100 Subject: [PATCH 398/989] RemoteLinux: Use qCDebug instead of qCWarning Change-Id: I9fe9707d9d3cc00f87689ab5695450bcbd83aa33 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/linuxdevice.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 6c041a5dfa5..bda9b9e6e10 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -900,8 +900,8 @@ public: }); Result result = m_shell->start(); if (!result) { - qCWarning(linuxDeviceLog) << "Failed to start shell for:" << parameters.userAtHostAndPort() - << ", " << result.error(); + qCDebug(linuxDeviceLog) << "Failed to start shell for:" << parameters.userAtHostAndPort() + << ", " << result.error(); } return result; } @@ -1038,7 +1038,7 @@ LinuxDevice::LinuxDevice() QObject::connect(proc, &Process::done, proc, [proc](){ if (proc->exitCode() != 0){ - qCWarning(linuxDeviceLog) << proc->exitMessage(); + qCDebug(linuxDeviceLog) << proc->exitMessage(); Core::MessageManager::writeFlashing(proc->exitMessage()); } proc->deleteLater(); From 23cf6a83820db641738cc6ef08e075e1102db886 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 26 Nov 2024 09:01:40 +0100 Subject: [PATCH 399/989] Axivion: Merge Axivion settings tabs and place it under Analyzer Change-Id: I637309b6c49488a52ef72ca8ab31b330222cb840 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionsettings.cpp | 357 +++++++++++------------- 1 file changed, 167 insertions(+), 190 deletions(-) diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index b29423c844e..89b75e63492 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -429,6 +429,65 @@ bool DashboardSettingsWidget::isValid() const return isUrlValid(m_dashboardUrl()); } +// PathMappingSettingsWidget + +class PathMappingDetails : public AspectContainer +{ +public: + PathMappingDetails() + { + m_projectName.setLabelText(Tr::tr("Project name:")); + m_projectName.setDisplayStyle(StringAspect::LineEditDisplay); + m_projectName.setValidationFunction([](FancyLineEdit *edit, QString *error) { + QTC_ASSERT(edit, return false); + if (!edit->text().isEmpty()) + return true; + if (error) + *error = QString("Project name must be non-empty."); + return false; + }); + m_analysisPath.setLabelText(Tr::tr("Analysis path:")); + m_analysisPath.setDisplayStyle(StringAspect::LineEditDisplay); + m_analysisPath.setValidationFunction([](FancyLineEdit *edit, QString *error) { + QTC_ASSERT(edit, return false); + // do NOT use fromUserInput() as this also cleans the path + const FilePath fp = FilePath::fromString(edit->text().replace('\\', '/')); + return analysisPathValid(fp, error); + }); + m_localPath.setLabelText(Tr::tr("Local path:")); + m_localPath.setExpectedKind(PathChooser::ExistingDirectory); + m_localPath.setAllowPathFromDevice(false); + + using namespace Layouting; + setLayouter([this] { + return Form { + &m_projectName, br, + &m_analysisPath, br, + &m_localPath, + noMargin}; + }); + } + + void updateContent(const PathMapping &mapping) + { + m_projectName.setValue(mapping.projectName, BaseAspect::BeQuiet); + m_analysisPath.setValue(mapping.analysisPath.toUserOutput(), BaseAspect::BeQuiet); + m_localPath.setValue(mapping.localPath, BaseAspect::BeQuiet); + } + + PathMapping toPathMapping() const + { + return PathMapping{ + m_projectName(), FilePath::fromUserInput(m_analysisPath()), m_localPath() + }; + } + +private: + StringAspect m_projectName{this}; + StringAspect m_analysisPath{this}; + FilePathAspect m_localPath{this}; +}; + class AxivionSettingsWidget : public IOptionsPageWidget { public: @@ -441,10 +500,21 @@ private: void removeCurrentServerConfig(); void updateDashboardServers(); void updateEnabledStates(); + void addMapping(); + void deleteMapping(); + void mappingChanged(); + void currentChanged(const QModelIndex &index, const QModelIndex &previous); + void moveCurrentMapping(bool up); QComboBox *m_dashboardServers = nullptr; - QPushButton *m_edit = nullptr; - QPushButton *m_remove = nullptr; + QPushButton *m_editServerButton = nullptr; + QPushButton *m_removeServerButton = nullptr; + QTreeWidget m_mappingTree; + PathMappingDetails m_details; + QWidget *m_detailsWidget = nullptr; + QPushButton *m_deleteMappingButton = nullptr; + QPushButton *m_moveUpMappingButton = nullptr; + QPushButton *m_moveDownMappingButton = nullptr; }; AxivionSettingsWidget::AxivionSettingsWidget() @@ -455,30 +525,85 @@ AxivionSettingsWidget::AxivionSettingsWidget() m_dashboardServers->setSizeAdjustPolicy(QComboBox::AdjustToContents); updateDashboardServers(); - auto addButton = new QPushButton(Tr::tr("Add..."), this); - m_edit = new QPushButton(Tr::tr("Edit..."), this); - m_remove = new QPushButton(Tr::tr("Remove"), this); + auto addServerButton = new QPushButton(Tr::tr("Add..."), this); + m_editServerButton = new QPushButton(Tr::tr("Edit..."), this); + m_removeServerButton = new QPushButton(Tr::tr("Remove"), this); + + m_detailsWidget = new QWidget(this); + m_details.layouter()().attachTo(m_detailsWidget); + + m_mappingTree.setSelectionMode(QAbstractItemView::SingleSelection); + m_mappingTree.setSelectionBehavior(QAbstractItemView::SelectRows); + m_mappingTree.setHeaderLabels({Tr::tr("Project Name"), Tr::tr("Analysis Path"), + Tr::tr("Local Path")}); + + auto addMappingButton = new QPushButton(Tr::tr("Add"), this); + m_deleteMappingButton = new QPushButton(Tr::tr("Delete"), this); + m_moveUpMappingButton = new QPushButton(Tr::tr("Move Up"), this); + m_moveDownMappingButton = new QPushButton(Tr::tr("Move Down"), this); + + Column buttons { addMappingButton, m_deleteMappingButton, empty, m_moveUpMappingButton, m_moveDownMappingButton, st }; + Column { - Row { - Form { Tr::tr("Default dashboard server:"), m_dashboardServers, br }, - st, - Column { addButton, m_edit, st, m_remove }, + Layouting::Group { + title(Tr::tr("Dashboard Servers")), + Row { + Form { Tr::tr("Default dashboard server:"), m_dashboardServers, br }, + st, + Column { addServerButton, m_editServerButton, m_removeServerButton }, + }, + }, + Layouting::Group { + title(Tr::tr("Path Mapping")), + Column { + Row { &m_mappingTree, buttons }, + m_detailsWidget + } + }, + Layouting::Group { + title(Tr::tr("Misc Options")), + Row {settings().highlightMarks }, }, - Space(10), - br, - Row {settings().highlightMarks }, st }.attachTo(this); - connect(addButton, &QPushButton::clicked, this, [this] { + connect(addServerButton, &QPushButton::clicked, this, [this] { // add an empty item unconditionally m_dashboardServers->addItem(Tr::tr("unset"), QVariant::fromValue(AxivionServer())); m_dashboardServers->setCurrentIndex(m_dashboardServers->count() - 1); showServerDialog(true); }); - connect(m_edit, &QPushButton::clicked, this, [this] { showServerDialog(false); }); - connect(m_remove, &QPushButton::clicked, + connect(m_editServerButton, &QPushButton::clicked, this, [this] { showServerDialog(false); }); + connect(m_removeServerButton, &QPushButton::clicked, this, &AxivionSettingsWidget::removeCurrentServerConfig); + + const QList items = Utils::transform(pathMappingSettings().validPathMappings(), + [this](const PathMapping &m) { + QTreeWidgetItem *item = new QTreeWidgetItem(&m_mappingTree, + {m.projectName, + m.analysisPath.toUserOutput(), + m.localPath.toUserOutput()}); + if (!m.isValid()) + item->setIcon(0, Icons::CRITICAL.icon()); + return item; + }); + m_mappingTree.addTopLevelItems(items); + + m_deleteMappingButton->setEnabled(false); + m_moveUpMappingButton->setEnabled(false); + m_moveDownMappingButton->setEnabled(false); + + m_detailsWidget->setVisible(false); + + connect(addMappingButton, &QPushButton::clicked, this, &AxivionSettingsWidget::addMapping); + connect(m_deleteMappingButton, &QPushButton::clicked, this, &AxivionSettingsWidget::deleteMapping); + connect(m_moveUpMappingButton, &QPushButton::clicked, this, [this]{ moveCurrentMapping(true); }); + connect(m_moveDownMappingButton, &QPushButton::clicked, this, [this]{ moveCurrentMapping(false); }); + connect(m_mappingTree.selectionModel(), &QItemSelectionModel::currentChanged, + this, &AxivionSettingsWidget::currentChanged); + connect(&m_details, &AspectContainer::changed, this, + &AxivionSettingsWidget::mappingChanged); + updateEnabledStates(); } @@ -492,6 +617,20 @@ void AxivionSettingsWidget::apply() if (settings().updateDashboardServers(servers, selected)) settings().toSettings(); settings().apply(); + + const QList oldMappings = settings().validPathMappings(); + QList newMappings; + for (int row = 0, count = m_mappingTree.topLevelItemCount(); row < count; ++row) { + const QTreeWidgetItem * const item = m_mappingTree.topLevelItem(row); + newMappings.append({item->text(0), + FilePath::fromUserInput(item->text(1)), + FilePath::fromUserInput(item->text(2))}); + } + if (oldMappings == newMappings) + return; + + pathMappingSettings().setVariantValue(pathMappingsToSetting(newMappings)); + pathMappingSettings().writeSettings(); } void AxivionSettingsWidget::updateDashboardServers() @@ -511,8 +650,8 @@ void AxivionSettingsWidget::updateDashboardServers() void AxivionSettingsWidget::updateEnabledStates() { const bool enabled = m_dashboardServers->count(); - m_edit->setEnabled(enabled); - m_remove->setEnabled(enabled); + m_editServerButton->setEnabled(enabled); + m_removeServerButton->setEnabled(enabled); } void AxivionSettingsWidget::removeCurrentServerConfig() @@ -567,163 +706,14 @@ void AxivionSettingsWidget::showServerDialog(bool add) updateEnabledStates(); } -// PathMappingSettingsWidget - -class PathMappingDetails : public AspectContainer -{ -public: - PathMappingDetails() - { - m_projectName.setLabelText(Tr::tr("Project name:")); - m_projectName.setDisplayStyle(StringAspect::LineEditDisplay); - m_projectName.setValidationFunction([](FancyLineEdit *edit, QString *error) { - QTC_ASSERT(edit, return false); - if (!edit->text().isEmpty()) - return true; - if (error) - *error = QString("Project name must be non-empty."); - return false; - }); - m_analysisPath.setLabelText(Tr::tr("Analysis path:")); - m_analysisPath.setDisplayStyle(StringAspect::LineEditDisplay); - m_analysisPath.setValidationFunction([](FancyLineEdit *edit, QString *error) { - QTC_ASSERT(edit, return false); - // do NOT use fromUserInput() as this also cleans the path - const FilePath fp = FilePath::fromString(edit->text().replace('\\', '/')); - return analysisPathValid(fp, error); - }); - m_localPath.setLabelText(Tr::tr("Local path:")); - m_localPath.setExpectedKind(PathChooser::ExistingDirectory); - m_localPath.setAllowPathFromDevice(false); - - using namespace Layouting; - setLayouter([this] { - return Form { - &m_projectName, br, - &m_analysisPath, br, - &m_localPath, - noMargin}; - }); - } - - void updateContent(const PathMapping &mapping) - { - m_projectName.setValue(mapping.projectName, BaseAspect::BeQuiet); - m_analysisPath.setValue(mapping.analysisPath.toUserOutput(), BaseAspect::BeQuiet); - m_localPath.setValue(mapping.localPath, BaseAspect::BeQuiet); - } - - PathMapping toPathMapping() const - { - return PathMapping{ - m_projectName(), FilePath::fromUserInput(m_analysisPath()), m_localPath() - }; - } - -private: - StringAspect m_projectName{this}; - StringAspect m_analysisPath{this}; - FilePathAspect m_localPath{this}; -}; - -class PathMappingSettingsWidget final : public IOptionsPageWidget -{ -public: - PathMappingSettingsWidget(); - - void apply() final; - -private: - void addMapping(); - void deleteMapping(); - void mappingChanged(); - void currentChanged(const QModelIndex &index, const QModelIndex &previous); - void moveCurrent(bool up); - - QTreeWidget m_mappingTree; - PathMappingDetails m_details; - QWidget *m_detailsWidget = nullptr; - QPushButton *m_deleteButton = nullptr; - QPushButton *m_moveUp = nullptr; - QPushButton *m_moveDown = nullptr; -}; - -PathMappingSettingsWidget::PathMappingSettingsWidget() -{ - m_detailsWidget = new QWidget(this); - m_details.layouter()().attachTo(m_detailsWidget); - - m_mappingTree.setSelectionMode(QAbstractItemView::SingleSelection); - m_mappingTree.setSelectionBehavior(QAbstractItemView::SelectRows); - m_mappingTree.setHeaderLabels({Tr::tr("Project Name"), Tr::tr("Analysis Path"), - Tr::tr("Local Path")}); - - auto addButton = new QPushButton(Tr::tr("Add"), this); - m_deleteButton = new QPushButton(Tr::tr("Delete"), this); - m_moveUp = new QPushButton(Tr::tr("Move Up"), this); - m_moveDown = new QPushButton(Tr::tr("Move Down"), this); - - using namespace Layouting; - Column buttons { addButton, m_deleteButton, empty, m_moveUp, m_moveDown, st }; - - Column { - Row { &m_mappingTree, buttons }, - m_detailsWidget - }.attachTo(this); - - const QList items = Utils::transform(pathMappingSettings().validPathMappings(), - [this](const PathMapping &m) { - QTreeWidgetItem *item = new QTreeWidgetItem(&m_mappingTree, - {m.projectName, - m.analysisPath.toUserOutput(), - m.localPath.toUserOutput()}); - if (!m.isValid()) - item->setIcon(0, Icons::CRITICAL.icon()); - return item; - }); - m_mappingTree.addTopLevelItems(items); - - m_deleteButton->setEnabled(false); - m_moveUp->setEnabled(false); - m_moveDown->setEnabled(false); - - m_detailsWidget->setVisible(false); - - connect(addButton, &QPushButton::clicked, this, &PathMappingSettingsWidget::addMapping); - connect(m_deleteButton, &QPushButton::clicked, this, &PathMappingSettingsWidget::deleteMapping); - connect(m_moveUp, &QPushButton::clicked, this, [this]{ moveCurrent(true); }); - connect(m_moveDown, &QPushButton::clicked, this, [this]{ moveCurrent(false); }); - connect(m_mappingTree.selectionModel(), &QItemSelectionModel::currentChanged, - this, &PathMappingSettingsWidget::currentChanged); - connect(&m_details, &AspectContainer::changed, this, - &PathMappingSettingsWidget::mappingChanged); -} - -void PathMappingSettingsWidget::apply() -{ - const QList oldMappings = settings().validPathMappings(); - QList newMappings; - for (int row = 0, count = m_mappingTree.topLevelItemCount(); row < count; ++row) { - const QTreeWidgetItem * const item = m_mappingTree.topLevelItem(row); - newMappings.append({item->text(0), - FilePath::fromUserInput(item->text(1)), - FilePath::fromUserInput(item->text(2))}); - } - if (oldMappings == newMappings) - return; - - pathMappingSettings().setVariantValue(pathMappingsToSetting(newMappings)); - pathMappingSettings().writeSettings(); -} - -void PathMappingSettingsWidget::addMapping() +void AxivionSettingsWidget::addMapping() { QTreeWidgetItem *item = new QTreeWidgetItem(&m_mappingTree, {"", "", ""}); m_mappingTree.setCurrentItem(item); item->setIcon(0, Icons::CRITICAL.icon()); } -void PathMappingSettingsWidget::deleteMapping() +void AxivionSettingsWidget::deleteMapping() { QTreeWidgetItem *item = m_mappingTree.currentItem(); QTC_ASSERT(item, return); @@ -733,7 +723,7 @@ void PathMappingSettingsWidget::deleteMapping() m_mappingTree.model()->removeRow(index.row()); } -void PathMappingSettingsWidget::mappingChanged() +void AxivionSettingsWidget::mappingChanged() { QTreeWidgetItem *item = m_mappingTree.currentItem(); QTC_ASSERT(item, return); @@ -744,14 +734,14 @@ void PathMappingSettingsWidget::mappingChanged() item->setIcon(0, modified.isValid() ? QIcon{} : Icons::CRITICAL.icon()); } -void PathMappingSettingsWidget::currentChanged(const QModelIndex &index, +void AxivionSettingsWidget::currentChanged(const QModelIndex &index, const QModelIndex &/*previous*/) { const bool indexValid = index.isValid(); const int row = index.row(); - m_deleteButton->setEnabled(indexValid); - m_moveUp->setEnabled(indexValid && row > 0); - m_moveDown->setEnabled(indexValid && row < m_mappingTree.topLevelItemCount() - 1); + m_deleteMappingButton->setEnabled(indexValid); + m_moveUpMappingButton->setEnabled(indexValid && row > 0); + m_moveDownMappingButton->setEnabled(indexValid && row < m_mappingTree.topLevelItemCount() - 1); m_detailsWidget->setVisible(indexValid); if (indexValid) { const QTreeWidgetItem * const item = m_mappingTree.itemFromIndex(index); @@ -761,7 +751,7 @@ void PathMappingSettingsWidget::currentChanged(const QModelIndex &index, } } -void PathMappingSettingsWidget::moveCurrent(bool up) +void AxivionSettingsWidget::moveCurrentMapping(bool up) { const int itemCount = m_mappingTree.topLevelItemCount(); const QModelIndexList indexes = m_mappingTree.selectionModel()->selectedRows(); @@ -783,26 +773,13 @@ class AxivionSettingsPage : public IOptionsPage public: AxivionSettingsPage() { - setId("Axivion.Settings.General"); - setDisplayName(Tr::tr("General")); - setCategory("XY.Axivion"); + setId("Analyzer.Axivion.Settings"); + setDisplayName(Tr::tr("Axivion")); + setCategory("T.Analyzer"); setWidgetCreator([] { return new AxivionSettingsWidget; }); } }; -class PathMappingSettingsPage : public IOptionsPage -{ -public: - PathMappingSettingsPage() - { - setId("Axivion.Settings.PathMapping"); - setDisplayName(Tr::tr("Path Mapping")); - setCategory("XY.Axivion"); - setWidgetCreator([] { return new PathMappingSettingsWidget; }); - } -}; - const AxivionSettingsPage generalSettingsPage; -const PathMappingSettingsPage pathMappingSettingsPage; } // Axivion::Internal From a106c1ef9964904f6bcc891ec4c77e93017b278f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 21 Nov 2024 09:20:40 +0100 Subject: [PATCH 400/989] Utils: Let MarkdownBrowser preload first frame async Change-Id: Ib732874c27247dbe11cf6a1eda5c92d0ff678a3a Reviewed-by: Jarek Kobus --- src/libs/utils/markdownbrowser.cpp | 150 ++++++++++++++++++----------- 1 file changed, 94 insertions(+), 56 deletions(-) diff --git a/src/libs/utils/markdownbrowser.cpp b/src/libs/utils/markdownbrowser.cpp index 58ab1a0259e..3f5fc11c65e 100644 --- a/src/libs/utils/markdownbrowser.cpp +++ b/src/libs/utils/markdownbrowser.cpp @@ -6,6 +6,7 @@ #include "algorithm.h" #include "async.h" #include "mimeutils.h" +#include "movie.h" #include "networkaccessmanager.h" #include "stylehelper.h" #include "textutils.h" @@ -19,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -145,7 +145,7 @@ public: class Entry { public: - using Pointer = std::unique_ptr; + using Pointer = std::shared_ptr; Entry(const QByteArray &data) { @@ -154,10 +154,22 @@ public: buffer.setData(data); movie.setDevice(&buffer); + if (movie.isValid()) { + if (!movie.frameRect().isValid()) + movie.jumpToFrame(0); + } + + moveToThread(nullptr); + } + + void moveToThread(QThread *thread) + { + buffer.moveToThread(thread); + movie.moveToThread(thread); } QBuffer buffer; - QMovie movie; + QtcMovie movie; }; public: @@ -176,19 +188,24 @@ public: { Q_UNUSED(doc); Q_UNUSED(posInDocument); + QSize result = Utils::Icons::UNKNOWN_FILE.icon().actualSize(QSize(16, 16)); QString name = format.toImageFormat().name(); - Entry *entry = m_entries.object(name); - - if (entry && entry->movie.isValid()) { - if (!entry->movie.frameRect().isValid()) - entry->movie.jumpToFrame(0); - return entry->movie.frameRect().size(); - } else if (!entry) { + Entry::Pointer *entryPtr = m_entries.object(name); + if (!entryPtr) { m_scheduleLoad(name); + return result; } - return Utils::Icons::UNKNOWN_FILE.icon().actualSize(QSize(16, 16)); + Entry::Pointer entry = *entryPtr; + + if (entry->movie.isValid()) { + if (!entry->movie.frameRect().isValid()) + entry->movie.jumpToFrame(0); + result = entry->movie.frameRect().size(); + } + + return result; } void drawObject( @@ -201,18 +218,15 @@ public: Q_UNUSED(document); Q_UNUSED(posInDocument); - Entry *entry = m_entries.object(format.toImageFormat().name()); + Entry::Pointer *entryPtr = m_entries.object(format.toImageFormat().name()); - if (entry) { - if (entry->movie.isValid()) - painter->drawImage(rect, entry->movie.currentImage()); - else - painter->drawPixmap(rect.toRect(), m_brokenImage.pixmap(rect.size().toSize())); - return; - } - - painter->drawPixmap( - rect.toRect(), Utils::Icons::UNKNOWN_FILE.icon().pixmap(rect.size().toSize())); + if (!entryPtr) + painter->drawPixmap( + rect.toRect(), Utils::Icons::UNKNOWN_FILE.icon().pixmap(rect.size().toSize())); + else if (!(*entryPtr)->movie.isValid()) + painter->drawPixmap(rect.toRect(), m_brokenImage.pixmap(rect.size().toSize())); + else + painter->drawImage(rect, (*entryPtr)->movie.currentImage()); } void set(const QString &name, QByteArray data) @@ -220,17 +234,21 @@ public: if (data.size() > m_entries.maxCost()) data.clear(); - set(name, std::make_unique(data)); + set(name, std::make_shared(data)); } - void set(const QString &name, std::unique_ptr entry) + void set(const QString &name, Entry::Pointer entry) { + entry->moveToThread(thread()); + if (entry->movie.frameCount() > 1) { - connect(&entry->movie, &QMovie::frameChanged, this, [this]() { m_redraw(); }); + connect(&entry->movie, &QtcMovie::frameChanged, this, [this]() { m_redraw(); }); entry->movie.start(); } const qint64 size = qMax(1, entry->buffer.size()); - if (m_entries.insert(name, entry.release(), size)) + + Entry::Pointer *entryPtr = new Entry::Pointer(entry); + if (m_entries.insert(name, entryPtr, size)) m_redraw(); } @@ -239,7 +257,7 @@ public: private: std::function m_redraw; std::function m_scheduleLoad; - QCache m_entries; + QCache m_entries; const Icon ErrorCloseIcon = Utils::Icon({{":/utils/images/close.png", Theme::IconsErrorColor}}); @@ -292,57 +310,73 @@ public: if (!m_loadRemoteImages) remoteUrls.clear(); + Storage> remoteData; + const LoopList remoteIterator(Utils::toList(remoteUrls)); const LoopList localIterator(Utils::toList(localUrls)); - auto onQuerySetup = [this, remoteIterator, base = m_basePath.toUrl()](NetworkQuery &query) { - QUrl url = *remoteIterator; - if (url.isRelative()) - url = base.resolved(url); + auto onQuerySetup = + [remoteData, this, remoteIterator, base = m_basePath.toUrl()](NetworkQuery &query) { + QUrl url = *remoteIterator; + if (url.isRelative()) + url = base.resolved(url); - QNetworkRequest request(url); - if (m_requestHook) - m_requestHook(&request); + QNetworkRequest request(url); + if (m_requestHook) + m_requestHook(&request); - query.setRequest(request); - query.setNetworkAccessManager(m_networkAccessManager); - query.setProperty("originalName", *remoteIterator); - }; + query.setRequest(request); + query.setNetworkAccessManager(m_networkAccessManager); + remoteData->first = *remoteIterator; + }; - auto onQueryDone = [this](const NetworkQuery &query, DoneWith result) { + auto onQueryDone = [this, remoteData](const NetworkQuery &query, DoneWith result) { if (result == DoneWith::Cancel) return; m_urlsToLoad.remove(query.reply()->url()); - if (result == DoneWith::Success) - m_imageHandler.set(query.property("originalName").toString(), query.reply()->readAll()); - else - m_imageHandler.set(query.property("originalName").toString(), QByteArray{}); - - markContentsDirty(0, this->characterCount()); + if (result == DoneWith::Success) { + remoteData->second = query.reply()->readAll(); + } else { + m_imageHandler.set(remoteData->first.toString(), QByteArray{}); + markContentsDirty(0, this->characterCount()); + } }; using EntryPointer = AnimatedImageHandler::Entry::Pointer; + auto onMakeEntrySetup = [remoteData](Async &async) { + async.setConcurrentCallData( + [](const QByteArray &data) { + return std::make_shared(data); + }, + remoteData->second); + }; + + auto onMakeEntryDone = + [this, remoteIterator, remoteData](const Async &async) { + EntryPointer result = async.result(); + if (result) { + m_imageHandler.set(remoteData->first.toString(), result); + markContentsDirty(0, this->characterCount()); + } + }; + auto onLocalSetup = [localIterator, basePath = m_basePath](Async &async) { const FilePath u = basePath.resolvePath(localIterator->path()); async.setConcurrentCallData( - [](FilePath f) -> EntryPointer { + [](QPromise &promise, const FilePath &f) { auto data = f.fileContents(); - if (!data) - return nullptr; + if (!data || promise.isCanceled()) + return; - return std::make_unique(*data); + promise.addResult(std::make_shared(*data)); }, u); }; auto onLocalDone = [localIterator, this](const Async &async) { -#if QT_VERSION > QT_VERSION_CHECK(6, 5, 2) - EntryPointer result = async.takeResult(); -#else - EntryPointer result = {}; -#endif + EntryPointer result = async.result(); if (result) m_imageHandler.set(localIterator->toString(), std::move(result)); }; @@ -351,7 +385,11 @@ public: Group group { parallelLimit(2), For(remoteIterator) >> Do { - NetworkQueryTask{onQuerySetup, onQueryDone} || successItem, + remoteData, + Group { + NetworkQueryTask{onQuerySetup, onQueryDone}, + AsyncTask(onMakeEntrySetup, onMakeEntryDone), + } || successItem, }, For(localIterator) >> Do { AsyncTask(onLocalSetup, onLocalDone) || successItem, @@ -372,7 +410,7 @@ public: void setBasePath(const FilePath &filePath) { m_basePath = filePath; } void setAllowRemoteImages(bool allow) { m_loadRemoteImages = allow; } - void setNetworkAccessManager(QNetworkAccessManager *nam) { m_networkAccessManager = nam;} + void setNetworkAccessManager(QNetworkAccessManager *nam) { m_networkAccessManager = nam; } void setRequestHook(const MarkdownBrowser::RequestHook &hook) { m_requestHook = hook; } void setMaximumCacheSize(qsizetype maxSize) { m_imageHandler.setMaximumCacheSize(maxSize); } From 1ccac26eb70c33f0db013929976b86c91b8bab35 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 27 Nov 2024 12:17:50 +0100 Subject: [PATCH 401/989] Utils: Cleanup MarkdownBrowser cache handling Change-Id: I4eb7fa7247645a5b2a8db3b6164d0a40f258e14e Reviewed-by: hjk --- src/libs/utils/markdownbrowser.cpp | 68 +++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/src/libs/utils/markdownbrowser.cpp b/src/libs/utils/markdownbrowser.cpp index 3f5fc11c65e..f56612e5b82 100644 --- a/src/libs/utils/markdownbrowser.cpp +++ b/src/libs/utils/markdownbrowser.cpp @@ -183,6 +183,18 @@ public: , m_entries(1024 * 1024 * 10) // 10 MB max image cache size {} + static Entry::Pointer makeEntry(const QByteArray &data, qsizetype maxSize) + { + // If the image is larger than what we allow in our cache, + // we still want to create an entry, but one with an empty image. + // So we clear it here, but still create the entry, so the painter can + // correctly show the "broken image" placeholder instead. + if (data.size() > maxSize) + return std::make_shared(QByteArray()); + + return std::make_shared(data); + } + virtual QSizeF intrinsicSize( QTextDocument *doc, int posInDocument, const QTextFormat &format) override { @@ -229,15 +241,12 @@ public: painter->drawImage(rect, (*entryPtr)->movie.currentImage()); } - void set(const QString &name, QByteArray data) + void set(const QString &name, const QByteArray &data) { - if (data.size() > m_entries.maxCost()) - data.clear(); - - set(name, std::make_shared(data)); + set(name, makeEntry(data, m_entries.maxCost())); } - void set(const QString &name, Entry::Pointer entry) + void set(const QString &name, const Entry::Pointer &entry) { entry->moveToThread(thread()); @@ -247,12 +256,17 @@ public: } const qint64 size = qMax(1, entry->buffer.size()); + if (size > m_entries.maxCost()) { + return; + } + Entry::Pointer *entryPtr = new Entry::Pointer(entry); if (m_entries.insert(name, entryPtr, size)) m_redraw(); } void setMaximumCacheSize(qsizetype maxSize) { m_entries.setMaxCost(maxSize); } + qsizetype maximumCacheSize() const { return m_entries.maxCost(); } private: std::function m_redraw; @@ -310,7 +324,13 @@ public: if (!m_loadRemoteImages) remoteUrls.clear(); - Storage> remoteData; + struct RemoteData + { + QUrl url; + QByteArray data; + }; + + Storage remoteData; const LoopList remoteIterator(Utils::toList(remoteUrls)); const LoopList localIterator(Utils::toList(localUrls)); @@ -327,7 +347,7 @@ public: query.setRequest(request); query.setNetworkAccessManager(m_networkAccessManager); - remoteData->first = *remoteIterator; + remoteData->url = *remoteIterator; }; auto onQueryDone = [this, remoteData](const NetworkQuery &query, DoneWith result) { @@ -336,43 +356,49 @@ public: m_urlsToLoad.remove(query.reply()->url()); if (result == DoneWith::Success) { - remoteData->second = query.reply()->readAll(); + remoteData->data = query.reply()->readAll(); } else { - m_imageHandler.set(remoteData->first.toString(), QByteArray{}); + m_imageHandler.set(remoteData->url.toString(), QByteArray{}); markContentsDirty(0, this->characterCount()); } }; using EntryPointer = AnimatedImageHandler::Entry::Pointer; - auto onMakeEntrySetup = [remoteData](Async &async) { + auto onMakeEntrySetup = [remoteData, maxSize = m_imageHandler.maximumCacheSize()]( + Async &async) { async.setConcurrentCallData( - [](const QByteArray &data) { - return std::make_shared(data); + [](const QByteArray &data, qsizetype maxSize) { + return AnimatedImageHandler::makeEntry(data, maxSize); }, - remoteData->second); + remoteData->data, + maxSize); }; auto onMakeEntryDone = [this, remoteIterator, remoteData](const Async &async) { EntryPointer result = async.result(); if (result) { - m_imageHandler.set(remoteData->first.toString(), result); + m_imageHandler.set(remoteData->url.toString(), result); markContentsDirty(0, this->characterCount()); } }; - auto onLocalSetup = [localIterator, basePath = m_basePath](Async &async) { - const FilePath u = basePath.resolvePath(localIterator->path()); + auto onLocalSetup = [localIterator, + basePath = m_basePath, + maxSize = m_imageHandler.maximumCacheSize()]( + Async &async) { + const FilePath path = basePath.resolvePath(localIterator->path()); async.setConcurrentCallData( - [](QPromise &promise, const FilePath &f) { - auto data = f.fileContents(); + [](QPromise &promise, const FilePath &path, qsizetype maxSize) { + auto data = path.fileContents(); if (!data || promise.isCanceled()) return; - promise.addResult(std::make_shared(*data)); + promise.addResult(AnimatedImageHandler::makeEntry(*data, maxSize)); }, - u); + path, + maxSize); }; auto onLocalDone = [localIterator, this](const Async &async) { From 502e1e4a70f3562f6cae494f8fb592e2e6df3f1d Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 6 Dec 2024 15:10:08 +0100 Subject: [PATCH 402/989] PE: apply project specific settings to nested text editors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: QTCREATORBUG-31875 Change-Id: I82749c43061d46c13d8ad06d4919343ee0074348 Reviewed-by: Christian Kandeler Reviewed-by: Eike Ziller Reviewed-by: André Hartmann --- .../projectexplorer/editorconfiguration.cpp | 28 +++++++++---------- .../projectexplorer/editorconfiguration.h | 5 ++-- .../projectexplorer/projectmanager.cpp | 15 ++++------ 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/plugins/projectexplorer/editorconfiguration.cpp b/src/plugins/projectexplorer/editorconfiguration.cpp index bb0cc2fe24d..f67db95cd67 100644 --- a/src/plugins/projectexplorer/editorconfiguration.cpp +++ b/src/plugins/projectexplorer/editorconfiguration.cpp @@ -58,7 +58,7 @@ struct EditorConfigurationPrivate QTextCodec *m_textCodec; QMap m_languageCodeStylePreferences; - QList m_editors; + QList m_editors; }; EditorConfiguration::EditorConfiguration() : d(std::make_unique()) @@ -230,29 +230,29 @@ void EditorConfiguration::fromMap(const Store &map) setUseGlobalSettings(map.value(kUseGlobal, d->m_useGlobal).toBool()); } -void EditorConfiguration::configureEditor(BaseTextEditor *textEditor) const +void EditorConfiguration::configureEditor(Core::IEditor *editor) const { - TextEditorWidget *widget = textEditor->editorWidget(); - if (widget) + TextEditorWidget *widget = TextEditorWidget::fromEditor(editor); + if (widget) { widget->textDocument()->setCodeStyle(codeStyle(widget->languageSettingsId())); - if (!d->m_useGlobal) { - textEditor->textDocument()->setCodec(d->m_textCodec); - if (widget) + if (!d->m_useGlobal) { + widget->textDocument()->setCodec(d->m_textCodec); switchSettings(widget); + } } - d->m_editors.append(textEditor); - connect(textEditor, &BaseTextEditor::destroyed, this, [this, textEditor]() { - d->m_editors.removeOne(textEditor); + d->m_editors.append(editor); + connect(editor, &Core::IEditor::destroyed, this, [this, editor]() { + d->m_editors.removeOne(editor); }); } -void EditorConfiguration::deconfigureEditor(BaseTextEditor *textEditor) const +void EditorConfiguration::deconfigureEditor(Core::IEditor *editor) const { - TextEditorWidget *widget = textEditor->editorWidget(); + TextEditorWidget *widget = TextEditorWidget::fromEditor(editor); if (widget) widget->textDocument()->setCodeStyle(TextEditorSettings::codeStyle(widget->languageSettingsId())); - d->m_editors.removeOne(textEditor); + d->m_editors.removeOne(editor); // TODO: what about text codec and switching settings? } @@ -391,7 +391,7 @@ void EditorConfiguration::slotAboutToRemoveProject(Project *project) if (project->editorConfiguration() != this) return; - for (BaseTextEditor *editor : std::as_const(d->m_editors)) + for (Core::IEditor *editor : std::as_const(d->m_editors)) deconfigureEditor(editor); } diff --git a/src/plugins/projectexplorer/editorconfiguration.h b/src/plugins/projectexplorer/editorconfiguration.h index 8b5aab4230a..7c7791f7cd4 100644 --- a/src/plugins/projectexplorer/editorconfiguration.h +++ b/src/plugins/projectexplorer/editorconfiguration.h @@ -29,6 +29,7 @@ class ExtraEncodingSettings; class MarginSettings; } // namespace TextEditor +namespace Core { class IEditor; } namespace Utils { class FilePath; } namespace ProjectExplorer { @@ -61,8 +62,8 @@ public: TextEditor::ICodeStylePreferences *codeStyle(Utils::Id languageId) const; QMap codeStyles() const; - void configureEditor(TextEditor::BaseTextEditor *textEditor) const; - void deconfigureEditor(TextEditor::BaseTextEditor *textEditor) const; + void configureEditor(Core::IEditor *editor) const; + void deconfigureEditor(Core::IEditor *editor) const; Utils::Store toMap() const; void fromMap(const Utils::Store &map); diff --git a/src/plugins/projectexplorer/projectmanager.cpp b/src/plugins/projectexplorer/projectmanager.cpp index f4be94de57b..70f2efb40ec 100644 --- a/src/plugins/projectexplorer/projectmanager.cpp +++ b/src/plugins/projectexplorer/projectmanager.cpp @@ -567,11 +567,9 @@ Project *ProjectManager::projectWithProjectFilePath(const FilePath &filePath) void ProjectManager::configureEditor(IEditor *editor, const FilePath &filePath) { - if (auto textEditor = qobject_cast(editor)) { - // Global settings are the default. - if (Project *project = projectForFile(filePath)) - project->editorConfiguration()->configureEditor(textEditor); - } + // Global settings are the default. + if (Project *project = projectForFile(filePath)) + project->editorConfiguration()->configureEditor(editor); } void ProjectManager::configureEditors(Project *project) @@ -580,11 +578,8 @@ void ProjectManager::configureEditors(Project *project) for (IDocument *document : documents) { if (project->isKnownFile(document->filePath())) { const QList editors = DocumentModel::editorsForDocument(document); - for (IEditor *editor : editors) { - if (auto textEditor = qobject_cast(editor)) { - project->editorConfiguration()->configureEditor(textEditor); - } - } + for (IEditor *editor : editors) + project->editorConfiguration()->configureEditor(editor); } } } From f14066428e535185c2b4ceafa9348366c2c49afb Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 11 Dec 2024 15:55:02 +0100 Subject: [PATCH 403/989] Coco: Merge settings related file pairs A step towards the standard pattern. Change-Id: I5443d0ffb4c8cb6911a99a3238b6377ed3a068f6 Reviewed-by: Jarek Kobus --- src/plugins/coco/CMakeLists.txt | 2 - src/plugins/coco/coco.qbs | 2 - src/plugins/coco/cocoplugin.cpp | 1 - src/plugins/coco/cocoprojectwidget.cpp | 2 +- src/plugins/coco/globalsettings.cpp | 108 +++++++++++++++++++++ src/plugins/coco/globalsettings.h | 55 ++++++++++- src/plugins/coco/globalsettingspage.cpp | 119 ------------------------ src/plugins/coco/globalsettingspage.h | 59 ------------ 8 files changed, 163 insertions(+), 185 deletions(-) delete mode 100644 src/plugins/coco/globalsettingspage.cpp delete mode 100644 src/plugins/coco/globalsettingspage.h diff --git a/src/plugins/coco/CMakeLists.txt b/src/plugins/coco/CMakeLists.txt index 81c72afc8d9..7a70c23b50e 100644 --- a/src/plugins/coco/CMakeLists.txt +++ b/src/plugins/coco/CMakeLists.txt @@ -39,8 +39,6 @@ add_qtc_plugin(Coco files/cocoplugin.prf globalsettings.cpp globalsettings.h - globalsettingspage.cpp - globalsettingspage.h images/SquishCoco_48x48.png modificationfile.cpp modificationfile.h diff --git a/src/plugins/coco/coco.qbs b/src/plugins/coco/coco.qbs index 711e86e4880..0395e286435 100644 --- a/src/plugins/coco/coco.qbs +++ b/src/plugins/coco/coco.qbs @@ -45,8 +45,6 @@ QtcPlugin { "files/cocoplugin.prf", "globalsettings.cpp", "globalsettings.h", - "globalsettingspage.cpp", - "globalsettingspage.h", "images/SquishCoco_48x48.png", "modificationfile.cpp", "modificationfile.h", diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index a2b754e1544..4162fc5a8af 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -7,7 +7,6 @@ #include "cocoprojectsettingswidget.h" #include "cocotr.h" #include "globalsettings.h" -#include "globalsettingspage.h" #include #include diff --git a/src/plugins/coco/cocoprojectwidget.cpp b/src/plugins/coco/cocoprojectwidget.cpp index 88138a716c0..88b0d78e321 100644 --- a/src/plugins/coco/cocoprojectwidget.cpp +++ b/src/plugins/coco/cocoprojectwidget.cpp @@ -7,7 +7,7 @@ #include "cococommon.h" #include "cocopluginconstants.h" #include "cocotr.h" -#include "globalsettingspage.h" +#include "globalsettings.h" #include #include diff --git a/src/plugins/coco/globalsettings.cpp b/src/plugins/coco/globalsettings.cpp index 594355964ee..82d71e8d766 100644 --- a/src/plugins/coco/globalsettings.cpp +++ b/src/plugins/coco/globalsettings.cpp @@ -5,9 +5,13 @@ #include "cocoinstallation.h" #include "cocopluginconstants.h" +#include "cocotr.h" #include + +#include #include +#include #include #include @@ -50,4 +54,108 @@ void save() } } // namespace GlobalSettings + +GlobalSettingsWidget::GlobalSettingsWidget(QFrame *parent) + : QFrame(parent) +{ + m_cocoPathAspect.setDefaultPathValue(m_coco.directory()); + m_cocoPathAspect.setExpectedKind(Utils::PathChooser::ExistingDirectory); + m_cocoPathAspect.setPromptDialogTitle(Tr::tr("Coco Installation Directory")); + + connect( + &m_cocoPathAspect, + &Utils::FilePathAspect::changed, + this, + &GlobalSettingsWidget::onCocoPathChanged); + + using namespace Layouting; + Form{ + Column{ + Row{Tr::tr("Coco Directory"), m_cocoPathAspect}, + Row{m_messageLabel}} + }.attachTo(this); +} + +void GlobalSettingsWidget::onCocoPathChanged() +{ + if (!verifyCocoDirectory(m_cocoPathAspect())) + m_cocoPathAspect.setValue(m_previousCocoDir, Utils::BaseAspect::BeQuiet); +} + +bool GlobalSettingsWidget::verifyCocoDirectory(const Utils::FilePath &cocoDir) +{ + m_coco.setDirectory(cocoDir); + m_messageLabel.setText(m_coco.errorMessage()); + if (m_coco.isValid()) + m_messageLabel.setIconType(Utils::InfoLabel::None); + else + m_messageLabel.setIconType(Utils::InfoLabel::Error); + return m_coco.isValid(); +} + +void GlobalSettingsWidget::apply() +{ + if (!verifyCocoDirectory(widgetCocoDir())) + return; + + m_coco.setDirectory(widgetCocoDir()); + GlobalSettings::save(); + + emit updateCocoDir(); +} + +void GlobalSettingsWidget::cancel() +{ + m_coco.setDirectory(m_previousCocoDir); +} + +void GlobalSettingsWidget::setVisible(bool visible) +{ + QFrame::setVisible(visible); + m_previousCocoDir = m_coco.directory(); +} + +Utils::FilePath GlobalSettingsWidget::widgetCocoDir() const +{ + return Utils::FilePath::fromUserInput(m_cocoPathAspect.value()); +} + +GlobalSettingsPage::GlobalSettingsPage() + : m_widget(nullptr) +{ + setId(Constants::COCO_SETTINGS_PAGE_ID); + setDisplayName(QCoreApplication::translate("Coco", "Coco")); + setCategory("I.Coco"); // Category I contains also the C++ settings. +} + +GlobalSettingsPage &GlobalSettingsPage::instance() +{ + static GlobalSettingsPage instance; + return instance; +} + +GlobalSettingsWidget *GlobalSettingsPage::widget() +{ + if (!m_widget) + m_widget = new GlobalSettingsWidget; + return m_widget; +} + +void GlobalSettingsPage::apply() +{ + if (m_widget) + m_widget->apply(); +} + +void GlobalSettingsPage::cancel() +{ + if (m_widget) + m_widget->cancel(); +} + +void GlobalSettingsPage::finish() +{ + delete m_widget; +} + } // namespace Coco::Internal diff --git a/src/plugins/coco/globalsettings.h b/src/plugins/coco/globalsettings.h index e57f7e790f3..5bd4a1107f3 100644 --- a/src/plugins/coco/globalsettings.h +++ b/src/plugins/coco/globalsettings.h @@ -3,11 +3,64 @@ #pragma once +#include "cocoinstallation.h" + +#include + +#include + namespace Coco::Internal { namespace GlobalSettings { void read(); void save(); -} // namespace GlobalSettings +} // GlobalSettings + + +class GlobalSettingsWidget : public QFrame +{ + Q_OBJECT + +public: + GlobalSettingsWidget(QFrame *parent = nullptr); + + void apply(); + void cancel(); + +signals: + void updateCocoDir(); + +public slots: + void setVisible(bool visible) override; + +private: + void onCocoPathChanged(); + + Utils::FilePath widgetCocoDir() const; + bool verifyCocoDirectory(const Utils::FilePath &cocoDir); + + Utils::FilePathAspect m_cocoPathAspect; + Utils::TextDisplay m_messageLabel; + + CocoInstallation m_coco; + Utils::FilePath m_previousCocoDir; +}; + +class GlobalSettingsPage : public Core::IOptionsPage +{ +public: + static GlobalSettingsPage &instance(); + + GlobalSettingsWidget *widget() override; + void apply() override; + void cancel() override; + void finish() override; + +private: + GlobalSettingsPage(); + + QPointer m_widget; +}; + } // namespace Coco::Internal diff --git a/src/plugins/coco/globalsettingspage.cpp b/src/plugins/coco/globalsettingspage.cpp deleted file mode 100644 index c76e424e040..00000000000 --- a/src/plugins/coco/globalsettingspage.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// 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 "globalsettingspage.h" - -#include "cocoinstallation.h" -#include "cocopluginconstants.h" -#include "cocotr.h" -#include "globalsettings.h" - -#include -#include - -namespace Coco::Internal { - -GlobalSettingsWidget::GlobalSettingsWidget(QFrame *parent) - : QFrame(parent) -{ - m_cocoPathAspect.setDefaultPathValue(m_coco.directory()); - m_cocoPathAspect.setExpectedKind(Utils::PathChooser::ExistingDirectory); - m_cocoPathAspect.setPromptDialogTitle(Tr::tr("Coco Installation Directory")); - - connect( - &m_cocoPathAspect, - &Utils::FilePathAspect::changed, - this, - &GlobalSettingsWidget::onCocoPathChanged); - - using namespace Layouting; - Form{ - Column{ - Row{Tr::tr("Coco Directory"), m_cocoPathAspect}, - Row{m_messageLabel}} - }.attachTo(this); -} - -void GlobalSettingsWidget::onCocoPathChanged() -{ - if (!verifyCocoDirectory(m_cocoPathAspect())) - m_cocoPathAspect.setValue(m_previousCocoDir, Utils::BaseAspect::BeQuiet); -} - -bool GlobalSettingsWidget::verifyCocoDirectory(const Utils::FilePath &cocoDir) -{ - m_coco.setDirectory(cocoDir); - m_messageLabel.setText(m_coco.errorMessage()); - if (m_coco.isValid()) - m_messageLabel.setIconType(Utils::InfoLabel::None); - else - m_messageLabel.setIconType(Utils::InfoLabel::Error); - return m_coco.isValid(); -} - -void GlobalSettingsWidget::apply() -{ - if (!verifyCocoDirectory(widgetCocoDir())) - return; - - m_coco.setDirectory(widgetCocoDir()); - GlobalSettings::save(); - - emit updateCocoDir(); -} - -void GlobalSettingsWidget::cancel() -{ - m_coco.setDirectory(m_previousCocoDir); -} - -void GlobalSettingsWidget::setVisible(bool visible) -{ - QFrame::setVisible(visible); - m_previousCocoDir = m_coco.directory(); -} - -Utils::FilePath GlobalSettingsWidget::widgetCocoDir() const -{ - return Utils::FilePath::fromUserInput(m_cocoPathAspect.value()); -} - -GlobalSettingsPage::GlobalSettingsPage() - : m_widget(nullptr) -{ - setId(Constants::COCO_SETTINGS_PAGE_ID); - setDisplayName(QCoreApplication::translate("Coco", "Coco")); - setCategory("I.Coco"); // Category I contains also the C++ settings. -} - -GlobalSettingsPage &GlobalSettingsPage::instance() -{ - static GlobalSettingsPage instance; - return instance; -} - -GlobalSettingsWidget *GlobalSettingsPage::widget() -{ - if (!m_widget) - m_widget = new GlobalSettingsWidget; - return m_widget; -} - -void GlobalSettingsPage::apply() -{ - if (m_widget) - m_widget->apply(); -} - -void GlobalSettingsPage::cancel() -{ - if (m_widget) - m_widget->cancel(); -} - -void GlobalSettingsPage::finish() -{ - delete m_widget; -} - -} // namespace Coco::Internal diff --git a/src/plugins/coco/globalsettingspage.h b/src/plugins/coco/globalsettingspage.h deleted file mode 100644 index e55d6881b86..00000000000 --- a/src/plugins/coco/globalsettingspage.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "cocoinstallation.h" - -#include - -#include - -namespace Coco::Internal { - -class GlobalSettingsWidget : public QFrame -{ - Q_OBJECT - -public: - GlobalSettingsWidget(QFrame *parent = nullptr); - - void apply(); - void cancel(); - -signals: - void updateCocoDir(); - -public slots: - void setVisible(bool visible) override; - -private: - void onCocoPathChanged(); - - Utils::FilePath widgetCocoDir() const; - bool verifyCocoDirectory(const Utils::FilePath &cocoDir); - - Utils::FilePathAspect m_cocoPathAspect; - Utils::TextDisplay m_messageLabel; - - CocoInstallation m_coco; - Utils::FilePath m_previousCocoDir; -}; - -class GlobalSettingsPage : public Core::IOptionsPage -{ -public: - static GlobalSettingsPage &instance(); - - GlobalSettingsWidget *widget() override; - void apply() override; - void cancel() override; - void finish() override; - -private: - GlobalSettingsPage(); - - QPointer m_widget; -}; - -} // namespace Coco::Internal From 4212350c10149d347f8582ff7bce52013be06029 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 6 Dec 2024 12:47:49 +0100 Subject: [PATCH 404/989] ProjectExplorer: Fix compiler executable duplication ... in findCompilerCandidates(). While at it, also improve the readability, as I had surprisingly big difficulties understanding the code: - Try to use more self-documenting constructs. - Add more comments. Change-Id: I5ee9c795b915fb80f5912c98170348c3e5d403ad Reviewed-by: hjk --- src/plugins/projectexplorer/gcctoolchain.cpp | 39 +++++++++++--------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 4061c94d2d4..60271688a51 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1390,7 +1390,7 @@ static FilePaths findCompilerCandidates(OsType os, { // We expect the following patterns: // compilerName "clang", "gcc" - // compilerName + "-[1-9]*" "clang-8", "gcc-5" + // compilerName + "-[1-9]*" "clang-18", "gcc-5" // "*-" + compilerName "avr-gcc", "avr32-gcc" // "arm-none-eabi-gcc" // "x86_64-pc-linux-gnu-gcc" @@ -1400,39 +1400,45 @@ static FilePaths findCompilerCandidates(OsType os, // but not "c89-gcc" or "c99-gcc" FilePaths compilerPaths; - const int cl = compilerName.size(); + const int nameLen = compilerName.size(); for (const FilePath &executable : executables) { QStringView fileName = executable.fileNameView(); if (os == OsTypeWindows && fileName.endsWith(u".exe", Qt::CaseInsensitive)) fileName.chop(4); - // Do not `continue`, proceed to detect further variants - if (fileName == compilerName) + // Exact file (base) name match with no prefix or suffix, e.g. "/usr/bin/gcc" for "gcc". + if (fileName == compilerName) { compilerPaths << executable; + continue; + } + // Not an exact match and we are only interested in those. if (!detectVariants) continue; + // These are always links intended for more generic tools. if (fileName == u"c89-gcc" || fileName == u"c99-gcc") continue; - int pos = fileName.indexOf(compilerName); - if (pos == -1) + const int nameOffset = fileName.indexOf(compilerName); + + // No match at all. + if (nameOffset == -1) continue; - // if not at the beginning, it must be preceded by a hyphen. - if (pos > 0 && fileName.at(pos - 1) != '-') + // If there is a prefix, it must end with a hyphen. + if (nameOffset > 0 && fileName.at(nameOffset - 1) != '-') continue; - // if not at the end, it must by followed by a hyphen and a digit between 1 and 9 - pos += cl; - if (pos != fileName.size()) { - if (pos + 1 >= fileName.size()) + // If there is a suffix, it must start with a hyphen followed by a digit between 1 and 9. + const QStringView suffix = fileName.sliced(nameOffset + nameLen); + switch (suffix.size()) { + case 0: break; + case 1: continue; + default: + if (suffix.first() != '-') continue; - if (fileName.at(pos) != '-') - continue; - const QChar c = fileName.at(pos + 1); - if (c < '1' || c > '9') + if (const QChar c = suffix.at(1); c < '1' || c > '9') continue; } @@ -1442,7 +1448,6 @@ static FilePaths findCompilerCandidates(OsType os, return compilerPaths; } - Toolchains GccToolchainFactory::autoDetect(const ToolchainDetector &detector) const { QTC_ASSERT(detector.device, return {}); From b916c6e4d3a6bdc375175e8b9d4a2c42389381c4 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 12 Dec 2024 08:55:55 +0100 Subject: [PATCH 405/989] SquishTests: Fix finding session dialogs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id621c724bad826588a07a379ae0ac56b9c131ab2 Reviewed-by: Jukka Nokso Reviewed-by: Robert Löhning --- tests/system/objects.map | 2 +- tests/system/suite_general/tst_session_handling/test.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/system/objects.map b/tests/system/objects.map index 461b867b905..f5343e9118b 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -189,7 +189,7 @@ :Send to Codepaster.protocolBox_QComboBox {name='protocolBox' type='QComboBox' visible='1' window=':Send to Codepaster_CodePaster::PasteView'} :Send to Codepaster.qt_spinbox_lineedit_QLineEdit {name='qt_spinbox_lineedit' type='QLineEdit' visible='1' window=':Send to Codepaster_CodePaster::PasteView'} :Send to Codepaster_CodePaster::PasteView {name='CodePaster.ViewDialog' type='QDialog' visible='1' windowTitle='Send to Codepaster'} -:Session Manager_ProjectExplorer::Internal::SessionDialog {name='ProjectExplorer.SessionDialog' type='Core::Internal::SessionDialog' visible='1'} +:Session Manager_ProjectExplorer::Internal::SessionDialog {name='ProjectExplorer.SessionDialog' type='QDialog' visible='1'} :Startup.contextHelpComboBox_QComboBox {container=':Form.Startup_QGroupBox' name='contextHelpComboBox' type='QComboBox' visible='1'} :User Interface.languageBox_QComboBox {name='languageBox' type='QComboBox' visible='1'} :Utils::FakeToolTip {type='Utils::FakeToolTip' unnamed='1' visible='1'} diff --git a/tests/system/suite_general/tst_session_handling/test.py b/tests/system/suite_general/tst_session_handling/test.py index 20b4ae51bb1..d6a1ad2a14f 100644 --- a/tests/system/suite_general/tst_session_handling/test.py +++ b/tests/system/suite_general/tst_session_handling/test.py @@ -70,8 +70,7 @@ def switchSession(toSession): "window=':Session Manager_ProjectExplorer::Internal::SessionDialog'}")) def createAndSwitchToSession(toSession): - sessionInputDialog = ("{type='Core::Internal::SessionNameInputDialog' unnamed='1' " - "visible='1' windowTitle='New Session Name'}") + sessionInputDialog = ("{type='QDialog' unnamed='1' visible='1' windowTitle='New Session Name'}") test.log("Switching to session '%s' after creating it." % toSession) invokeMenuItem("File", "Sessions", "Manage...") clickButton(waitForObject("{name='btCreateNew' type='QPushButton' visible='1' " From d175c629aa34f49f7a229e77aa8d647e9a9d8d67 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Dec 2024 07:30:33 +0100 Subject: [PATCH 406/989] Coco: Merge cocoinstallation.* into globalsettings.* This is mechanical so far, the plan is to merge the class together with the GlobalSettings namespace into a CocoSettings class with the usual access pattern. Later the m_cocoPathAspect from GlobalSettingsWidget can be moved there and /probably/ be merged with CocoInstallationPrivate ::cocoPath. Change-Id: If156a5ea78335e30372414cb1583d8e68f4f90ba Reviewed-by: Jarek Kobus --- src/plugins/coco/CMakeLists.txt | 2 - src/plugins/coco/coco.qbs | 2 - src/plugins/coco/cocobuildstep.cpp | 2 +- src/plugins/coco/cocoinstallation.cpp | 177 ------------------------- src/plugins/coco/cocoinstallation.h | 39 ------ src/plugins/coco/cocoprojectwidget.h | 2 +- src/plugins/coco/cocoqmakesettings.cpp | 2 +- src/plugins/coco/globalsettings.cpp | 163 ++++++++++++++++++++++- src/plugins/coco/globalsettings.h | 28 +++- 9 files changed, 191 insertions(+), 226 deletions(-) diff --git a/src/plugins/coco/CMakeLists.txt b/src/plugins/coco/CMakeLists.txt index 7a70c23b50e..0fde8939412 100644 --- a/src/plugins/coco/CMakeLists.txt +++ b/src/plugins/coco/CMakeLists.txt @@ -17,8 +17,6 @@ add_qtc_plugin(Coco cococmakesettings.h cococommon.cpp cococommon.h - cocoinstallation.cpp - cocoinstallation.h cocolanguageclient.cpp cocolanguageclient.h cocoplugin.cpp diff --git a/src/plugins/coco/coco.qbs b/src/plugins/coco/coco.qbs index 0395e286435..19630ad09cf 100644 --- a/src/plugins/coco/coco.qbs +++ b/src/plugins/coco/coco.qbs @@ -23,8 +23,6 @@ QtcPlugin { "cococmakesettings.h", "cococommon.cpp", "cococommon.h", - "cocoinstallation.cpp", - "cocoinstallation.h", "cocolanguageclient.cpp", "cocolanguageclient.h", "cocoplugin.cpp", diff --git a/src/plugins/coco/cocobuildstep.cpp b/src/plugins/coco/cocobuildstep.cpp index e809785f493..dea41c52dee 100644 --- a/src/plugins/coco/cocobuildstep.cpp +++ b/src/plugins/coco/cocobuildstep.cpp @@ -3,9 +3,9 @@ #include "cocobuildstep.h" -#include "cocoinstallation.h" #include "cocopluginconstants.h" #include "cocotr.h" +#include "globalsettings.h" #include #include diff --git a/src/plugins/coco/cocoinstallation.cpp b/src/plugins/coco/cocoinstallation.cpp index 7a3c4441249..e69de29bb2d 100644 --- a/src/plugins/coco/cocoinstallation.cpp +++ b/src/plugins/coco/cocoinstallation.cpp @@ -1,177 +0,0 @@ -// 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 "cocoinstallation.h" - -#include "cococommon.h" -#include "cocotr.h" -#include "globalsettings.h" - -#include -#include - -#include -#include -#include - -namespace Coco::Internal { - -struct CocoInstallationPrivate -{ - Utils::FilePath cocoPath; - bool isValid = false; - QString errorMessage = Tr::tr("Error: Coco installation directory not set. (This can't happen.)"); -}; - -CocoInstallationPrivate *CocoInstallation::d = nullptr; - -CocoInstallation::CocoInstallation() -{ - if (!d) - d = new CocoInstallationPrivate; -} - -Utils::FilePath CocoInstallation::directory() const -{ - return d->cocoPath; -} - -Utils::FilePath CocoInstallation::coverageBrowserPath() const -{ - QString browserPath; - - if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost()) - browserPath = "bin/coveragebrowser"; - else - browserPath = "coveragebrowser.exe"; - - return d->cocoPath.resolvePath(browserPath); -} - -void CocoInstallation::setDirectory(const Utils::FilePath &dir) -{ - if (isCocoDirectory(dir)) { - d->cocoPath = dir; - d->isValid = true; - d->errorMessage = ""; - verifyCocoDirectory(); - } - else { - d->cocoPath = Utils::FilePath(); - d->isValid = false; - d->errorMessage - = Tr::tr("Error: Coco installation directory not found at \"%1\".").arg(dir.nativePath()); - } -} - -Utils::FilePath CocoInstallation::coverageScannerPath(const Utils::FilePath &cocoDir) const -{ - QString scannerPath; - - if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost()) - scannerPath = "bin/coveragescanner"; - else - scannerPath = "coveragescanner.exe"; - - return cocoDir.resolvePath(scannerPath); -} - -bool CocoInstallation::isCocoDirectory(const Utils::FilePath &cocoDir) const -{ - return coverageScannerPath(cocoDir).exists(); -} - -void CocoInstallation::logError(const QString &msg) -{ - logFlashing(msg); - d->isValid = false; - d->errorMessage = msg; -} - -bool CocoInstallation::verifyCocoDirectory() -{ - QString coveragescanner = coverageScannerPath(d->cocoPath).nativePath(); - - QProcess proc; - proc.setProgram(coveragescanner); - proc.setArguments({"--cs-help"}); - proc.start(); - - if (!proc.waitForStarted()) { - logError(Tr::tr("Error: Coveragescanner at \"%1\" did not start.").arg(coveragescanner)); - return false; - } - - if (!proc.waitForFinished()) { - logError(Tr::tr("Error: Coveragescanner at \"%1\" did not finish.").arg(coveragescanner)); - return false; - } - - QString result = QString::fromLatin1(proc.readAll()); - static const QRegularExpression linebreak("\n|\r\n|\r"); - QStringList lines = result.split(linebreak, Qt::SkipEmptyParts); - - const qsizetype n = lines.size(); - if (n >= 2 && lines[n - 2].startsWith("Version:") && lines[n - 1].startsWith("Date:")) { - logSilently(Tr::tr("Valid CoverageScanner found at \"%1\":").arg(coveragescanner)); - logSilently(" " + lines[n - 2]); - logSilently(" " + lines[n - 1]); - return true; - } else { - logError( - Tr::tr("Error: Coveragescanner at \"%1\" did not run correctly.").arg(coveragescanner)); - for (const QString &l : lines) { - logSilently(l); - } - return false; - } -} - -bool CocoInstallation::isValid() const -{ - return d->isValid; -} - -QString CocoInstallation::errorMessage() const -{ - return d->errorMessage; -} - -void CocoInstallation::tryPath(const QString &path) -{ - if (d->isValid) - return; - - const auto fpath = Utils::FilePath::fromString(path); - const QString nativePath = fpath.nativePath(); - if (isCocoDirectory(fpath)) { - logSilently(Tr::tr("Found Coco directory \"%1\".").arg(nativePath)); - setDirectory(fpath); - GlobalSettings::save(); - } else - logSilently(Tr::tr("Checked Coco directory \"%1\".").arg(nativePath)); -} - -QString CocoInstallation::envVar(const QString &var) const -{ - return QProcessEnvironment::systemEnvironment().value(var); -} - -void CocoInstallation::findDefaultDirectory() -{ - if (Utils::HostOsInfo::isMacHost()) - tryPath("/Applications/SquishCoco"); - else if (Utils::HostOsInfo::isAnyUnixHost()) { - tryPath((Utils::FileUtils::homePath() / "SquishCoco").nativePath()); - tryPath("/opt/SquishCoco"); - } else { - tryPath(envVar("SQUISHCOCO")); - QStringList homeDirs = QStandardPaths::standardLocations(QStandardPaths::HomeLocation); - if (!homeDirs.isEmpty()) - tryPath(homeDirs[0] + "/squishcoco"); - tryPath(envVar("ProgramFiles") + "\\squishcoco"); - tryPath(envVar("ProgramFiles(x86)") + "\\squishcoco"); - } -} - -} // namespace Coco::Internal diff --git a/src/plugins/coco/cocoinstallation.h b/src/plugins/coco/cocoinstallation.h index 73d83bf704d..e69de29bb2d 100644 --- a/src/plugins/coco/cocoinstallation.h +++ b/src/plugins/coco/cocoinstallation.h @@ -1,39 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -class QString; - -namespace Coco::Internal { - -struct CocoInstallationPrivate; - -// Borg pattern: There are many instances of this class, but all are the same. -class CocoInstallation -{ -public: - CocoInstallation(); - - Utils::FilePath directory() const; - Utils::FilePath coverageBrowserPath() const; - void setDirectory(const Utils::FilePath &dir); - void findDefaultDirectory(); - - bool isValid() const; - QString errorMessage() const; - -private: - Utils::FilePath coverageScannerPath(const Utils::FilePath &cocoDir) const; - void logError(const QString &msg); - bool isCocoDirectory(const Utils::FilePath &cocoDir) const; - bool verifyCocoDirectory(); - void tryPath(const QString &path); - QString envVar(const QString &var) const; - - static CocoInstallationPrivate *d; -}; - -} // namespace Coco::Internal diff --git a/src/plugins/coco/cocoprojectwidget.h b/src/plugins/coco/cocoprojectwidget.h index 8c39b0ad363..ccc04fddc5d 100644 --- a/src/plugins/coco/cocoprojectwidget.h +++ b/src/plugins/coco/cocoprojectwidget.h @@ -4,7 +4,7 @@ #pragma once #include "buildsettings.h" -#include "cocoinstallation.h" +#include "globalsettings.h" #include #include diff --git a/src/plugins/coco/cocoqmakesettings.cpp b/src/plugins/coco/cocoqmakesettings.cpp index ea8a3fef4bd..61115a8c01d 100644 --- a/src/plugins/coco/cocoqmakesettings.cpp +++ b/src/plugins/coco/cocoqmakesettings.cpp @@ -5,10 +5,10 @@ #include "buildsettings.h" #include "cococommon.h" -#include "cocoinstallation.h" #include "cocopluginconstants.h" #include "cocoprojectwidget.h" #include "cocotr.h" +#include "globalsettings.h" #include "qmakefeaturefile.h" #include diff --git a/src/plugins/coco/globalsettings.cpp b/src/plugins/coco/globalsettings.cpp index 82d71e8d766..7a83e3309c0 100644 --- a/src/plugins/coco/globalsettings.cpp +++ b/src/plugins/coco/globalsettings.cpp @@ -3,7 +3,7 @@ #include "globalsettings.h" -#include "cocoinstallation.h" +#include "cococommon.h" #include "cocopluginconstants.h" #include "cocotr.h" @@ -11,10 +11,14 @@ #include #include +#include +#include #include #include +#include #include +#include namespace Coco::Internal { namespace GlobalSettings { @@ -55,6 +59,163 @@ void save() } // namespace GlobalSettings +struct CocoInstallationPrivate +{ + Utils::FilePath cocoPath; + bool isValid = false; + QString errorMessage = Tr::tr("Error: Coco installation directory not set. (This can't happen.)"); +}; + +CocoInstallationPrivate *CocoInstallation::d = nullptr; + +CocoInstallation::CocoInstallation() +{ + if (!d) + d = new CocoInstallationPrivate; +} + +Utils::FilePath CocoInstallation::directory() const +{ + return d->cocoPath; +} + +Utils::FilePath CocoInstallation::coverageBrowserPath() const +{ + QString browserPath; + + if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost()) + browserPath = "bin/coveragebrowser"; + else + browserPath = "coveragebrowser.exe"; + + return d->cocoPath.resolvePath(browserPath); +} + +void CocoInstallation::setDirectory(const Utils::FilePath &dir) +{ + if (isCocoDirectory(dir)) { + d->cocoPath = dir; + d->isValid = true; + d->errorMessage = ""; + verifyCocoDirectory(); + } + else { + d->cocoPath = Utils::FilePath(); + d->isValid = false; + d->errorMessage + = Tr::tr("Error: Coco installation directory not found at \"%1\".").arg(dir.nativePath()); + } +} + +Utils::FilePath CocoInstallation::coverageScannerPath(const Utils::FilePath &cocoDir) const +{ + QString scannerPath; + + if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost()) + scannerPath = "bin/coveragescanner"; + else + scannerPath = "coveragescanner.exe"; + + return cocoDir.resolvePath(scannerPath); +} + +bool CocoInstallation::isCocoDirectory(const Utils::FilePath &cocoDir) const +{ + return coverageScannerPath(cocoDir).exists(); +} + +void CocoInstallation::logError(const QString &msg) +{ + logFlashing(msg); + d->isValid = false; + d->errorMessage = msg; +} + +bool CocoInstallation::verifyCocoDirectory() +{ + QString coveragescanner = coverageScannerPath(d->cocoPath).nativePath(); + + QProcess proc; + proc.setProgram(coveragescanner); + proc.setArguments({"--cs-help"}); + proc.start(); + + if (!proc.waitForStarted()) { + logError(Tr::tr("Error: Coveragescanner at \"%1\" did not start.").arg(coveragescanner)); + return false; + } + + if (!proc.waitForFinished()) { + logError(Tr::tr("Error: Coveragescanner at \"%1\" did not finish.").arg(coveragescanner)); + return false; + } + + QString result = QString::fromLatin1(proc.readAll()); + static const QRegularExpression linebreak("\n|\r\n|\r"); + QStringList lines = result.split(linebreak, Qt::SkipEmptyParts); + + const qsizetype n = lines.size(); + if (n >= 2 && lines[n - 2].startsWith("Version:") && lines[n - 1].startsWith("Date:")) { + logSilently(Tr::tr("Valid CoverageScanner found at \"%1\":").arg(coveragescanner)); + logSilently(" " + lines[n - 2]); + logSilently(" " + lines[n - 1]); + return true; + } else { + logError( + Tr::tr("Error: Coveragescanner at \"%1\" did not run correctly.").arg(coveragescanner)); + for (const QString &l : lines) { + logSilently(l); + } + return false; + } +} + +bool CocoInstallation::isValid() const +{ + return d->isValid; +} + +QString CocoInstallation::errorMessage() const +{ + return d->errorMessage; +} + +void CocoInstallation::tryPath(const QString &path) +{ + if (d->isValid) + return; + + const auto fpath = Utils::FilePath::fromString(path); + const QString nativePath = fpath.nativePath(); + if (isCocoDirectory(fpath)) { + logSilently(Tr::tr("Found Coco directory \"%1\".").arg(nativePath)); + setDirectory(fpath); + GlobalSettings::save(); + } else + logSilently(Tr::tr("Checked Coco directory \"%1\".").arg(nativePath)); +} + +QString CocoInstallation::envVar(const QString &var) const +{ + return QProcessEnvironment::systemEnvironment().value(var); +} + +void CocoInstallation::findDefaultDirectory() +{ + if (Utils::HostOsInfo::isMacHost()) + tryPath("/Applications/SquishCoco"); + else if (Utils::HostOsInfo::isAnyUnixHost()) { + tryPath((Utils::FileUtils::homePath() / "SquishCoco").nativePath()); + tryPath("/opt/SquishCoco"); + } else { + tryPath(envVar("SQUISHCOCO")); + QStringList homeDirs = QStandardPaths::standardLocations(QStandardPaths::HomeLocation); + if (!homeDirs.isEmpty()) + tryPath(homeDirs[0] + "/squishcoco"); + tryPath(envVar("ProgramFiles") + "\\squishcoco"); + tryPath(envVar("ProgramFiles(x86)") + "\\squishcoco"); + } +} GlobalSettingsWidget::GlobalSettingsWidget(QFrame *parent) : QFrame(parent) { diff --git a/src/plugins/coco/globalsettings.h b/src/plugins/coco/globalsettings.h index 5bd4a1107f3..ce682e857e6 100644 --- a/src/plugins/coco/globalsettings.h +++ b/src/plugins/coco/globalsettings.h @@ -3,8 +3,6 @@ #pragma once -#include "cocoinstallation.h" - #include #include @@ -17,6 +15,32 @@ void save(); } // GlobalSettings +struct CocoInstallationPrivate; + +// Borg pattern: There are many instances of this class, but all are the same. +class CocoInstallation +{ +public: + CocoInstallation(); + + Utils::FilePath directory() const; + Utils::FilePath coverageBrowserPath() const; + void setDirectory(const Utils::FilePath &dir); + void findDefaultDirectory(); + + bool isValid() const; + QString errorMessage() const; + +private: + Utils::FilePath coverageScannerPath(const Utils::FilePath &cocoDir) const; + void logError(const QString &msg); + bool isCocoDirectory(const Utils::FilePath &cocoDir) const; + bool verifyCocoDirectory(); + void tryPath(const QString &path); + QString envVar(const QString &var) const; + + static CocoInstallationPrivate *d; +}; class GlobalSettingsWidget : public QFrame { From a221ce82ceb7e701c42aaf49120653487c349edf Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Dec 2024 07:59:08 +0100 Subject: [PATCH 407/989] Coco: Create a CocoSettings class ... out of CocoInstallation and the GlobalSettings namespace and use the usual static-in-function singleton access which incidentally can be used to get the same access CocoInstallation had as all CocoInstallation object shared the same data. Further plan is to move m_cocoPathAspect from GlobalSettingsWidget and simplify a bit. Change-Id: I3b7b38404c972b8510911a1e24723124cf8a85d0 Reviewed-by: Jarek Kobus --- src/plugins/coco/cocobuildstep.cpp | 3 +- src/plugins/coco/cocoplugin.cpp | 7 +- src/plugins/coco/cocoprojectwidget.cpp | 8 +- src/plugins/coco/cocoprojectwidget.h | 2 - src/plugins/coco/cocoqmakesettings.cpp | 3 +- src/plugins/coco/globalsettings.cpp | 133 ++++++++++++------------- src/plugins/coco/globalsettings.h | 24 ++--- 7 files changed, 84 insertions(+), 96 deletions(-) diff --git a/src/plugins/coco/cocobuildstep.cpp b/src/plugins/coco/cocobuildstep.cpp index dea41c52dee..941cbe7237f 100644 --- a/src/plugins/coco/cocobuildstep.cpp +++ b/src/plugins/coco/cocobuildstep.cpp @@ -97,8 +97,7 @@ QWidget *CocoBuildStep::createConfigWidget() void CocoBuildStep::updateDisplay() { - CocoInstallation coco; - if (!coco.isValid()) { + if (!cocoSettings().isValid()) { setSummaryText("" + Tr::tr("Coco Code Coverage: No working Coco installation") + ""); emit setButtonState(false); return; diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index 4162fc5a8af..e499efba2db 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -61,8 +61,7 @@ public: m_client->shutdown(); m_client = nullptr; - CocoInstallation coco; - if (coco.isValid()) { + if (cocoSettings().isValid()) { QDialog dialog(ICore::dialogParent()); dialog.setModal(true); auto layout = new QFormLayout(); @@ -83,7 +82,7 @@ public: QObject::connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); if (dialog.exec() == QDialog::Accepted) { - const FilePath cocoPath = coco.coverageBrowserPath(); + const FilePath cocoPath = cocoSettings().coverageBrowserPath(); const FilePath csmesPath = csmesChoser.filePath(); if (cocoPath.isExecutableFile() && csmesPath.exists()) { m_client = new CocoLanguageClient(cocoPath, csmesPath); @@ -117,7 +116,7 @@ void CocoPlugin::initialize() QCoreApplication::translate("Coco", "Coco"), ":/cocoplugin/images/SquishCoco_48x48.png"); - GlobalSettings::read(); + cocoSettings().read(); GlobalSettingsPage::instance().widget(); setupCocoProjectPanel(); diff --git a/src/plugins/coco/cocoprojectwidget.cpp b/src/plugins/coco/cocoprojectwidget.cpp index 88b0d78e321..9d101875c7c 100644 --- a/src/plugins/coco/cocoprojectwidget.cpp +++ b/src/plugins/coco/cocoprojectwidget.cpp @@ -105,11 +105,11 @@ void CocoProjectWidget::reloadSettings() setState(configDone); displayChanges(); - const bool valid = m_coco.isValid(); + const bool valid = cocoSettings().isValid(); m_configerrorLabel.setVisible(!valid); if (!valid) { m_configerrorLabel.setText( - Tr::tr("Coco is not installed correctly: \"%1\"").arg(m_coco.errorMessage())); + Tr::tr("Coco is not installed correctly: \"%1\"").arg(cocoSettings().errorMessage())); } } @@ -232,7 +232,7 @@ void Internal::CocoProjectWidget::onCoverageGroupBoxClicked() return; } - if (!m_coco.isValid()) { + if (!cocoSettings().isValid()) { m_coverageGroupBoxEnabled.setValue(false, Utils::BaseAspect::BeQuiet); QMessageBox box; @@ -245,7 +245,7 @@ void Internal::CocoProjectWidget::onCoverageGroupBoxClicked() if (box.clickedButton() == editButton) Core::ICore::showOptionsDialog(Constants::COCO_SETTINGS_PAGE_ID); - m_coverageGroupBoxEnabled.setValue(m_coco.isValid(), Utils::BaseAspect::BeQuiet); + m_coverageGroupBoxEnabled.setValue(cocoSettings().isValid(), Utils::BaseAspect::BeQuiet); } else m_buildSettings->setCoverage(checked); diff --git a/src/plugins/coco/cocoprojectwidget.h b/src/plugins/coco/cocoprojectwidget.h index ccc04fddc5d..30efb7e09eb 100644 --- a/src/plugins/coco/cocoprojectwidget.h +++ b/src/plugins/coco/cocoprojectwidget.h @@ -4,7 +4,6 @@ #pragma once #include "buildsettings.h" -#include "globalsettings.h" #include #include @@ -75,7 +74,6 @@ private: QString m_selectionDirectory; ConfigurationState m_configState = configDone; QString m_buildConfigurationName; - CocoInstallation m_coco; }; } // namespace Coco::Internal diff --git a/src/plugins/coco/cocoqmakesettings.cpp b/src/plugins/coco/cocoqmakesettings.cpp index 61115a8c01d..35012262802 100644 --- a/src/plugins/coco/cocoqmakesettings.cpp +++ b/src/plugins/coco/cocoqmakesettings.cpp @@ -50,7 +50,6 @@ private: bool cocoPathValid() const; QMakeFeatureFile m_featureFile; - CocoInstallation m_coco; }; void CocoQMakeSettings::read() @@ -179,7 +178,7 @@ void CocoQMakeSettings::write(const QString &options, const QString &tweaks) QString CocoQMakeSettings::pathAssignment() const { - return pathAssignmentPrefix + m_coco.directory().toUserOutput(); + return pathAssignmentPrefix + cocoSettings().directory().toUserOutput(); } bool CocoQMakeSettings::cocoPathValid() const diff --git a/src/plugins/coco/globalsettings.cpp b/src/plugins/coco/globalsettings.cpp index 7a83e3309c0..7a85e35ab4f 100644 --- a/src/plugins/coco/globalsettings.cpp +++ b/src/plugins/coco/globalsettings.cpp @@ -20,23 +20,34 @@ #include #include +using namespace Utils; + namespace Coco::Internal { -namespace GlobalSettings { static const char DIRECTORY[] = "CocoDirectory"; -void read() +CocoSettings &cocoSettings() +{ + static CocoSettings theCocoSettings; + return theCocoSettings; +} + +CocoSettings::CocoSettings() +{ + m_errorMessage = Tr::tr("Error: Coco installation directory not set. (This can't happen.)"); +} + +void CocoSettings::read() { - CocoInstallation coco; bool directoryInSettings = false; - Utils::QtcSettings *s = Core::ICore::settings(); + QtcSettings *s = Core::ICore::settings(); s->beginGroup(Constants::COCO_SETTINGS_GROUP); const QStringList keys = s->allKeys(); for (const QString &keyString : keys) { - Utils::Key key(keyString.toLatin1()); + Key key(keyString.toLatin1()); if (key == DIRECTORY) { - coco.setDirectory(Utils::FilePath::fromUserInput(s->value(key).toString())); + setDirectory(FilePath::fromUserInput(s->value(key).toString())); directoryInSettings = true; } else s->remove(key); @@ -44,74 +55,56 @@ void read() s->endGroup(); if (!directoryInSettings) - coco.findDefaultDirectory(); + findDefaultDirectory(); - GlobalSettings::save(); + save(); } -void save() +void CocoSettings::save() { - Utils::QtcSettings *s = Core::ICore::settings(); + QtcSettings *s = Core::ICore::settings(); s->beginGroup(Constants::COCO_SETTINGS_GROUP); - s->setValue(DIRECTORY, CocoInstallation().directory().toUserOutput()); + s->setValue(DIRECTORY, directory().toUserOutput()); s->endGroup(); } -} // namespace GlobalSettings - -struct CocoInstallationPrivate +FilePath CocoSettings::directory() const { - Utils::FilePath cocoPath; - bool isValid = false; - QString errorMessage = Tr::tr("Error: Coco installation directory not set. (This can't happen.)"); -}; - -CocoInstallationPrivate *CocoInstallation::d = nullptr; - -CocoInstallation::CocoInstallation() -{ - if (!d) - d = new CocoInstallationPrivate; + return m_cocoPath; } -Utils::FilePath CocoInstallation::directory() const -{ - return d->cocoPath; -} - -Utils::FilePath CocoInstallation::coverageBrowserPath() const +FilePath CocoSettings::coverageBrowserPath() const { QString browserPath; - if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost()) + if (HostOsInfo::isAnyUnixHost() || HostOsInfo::isMacHost()) browserPath = "bin/coveragebrowser"; else browserPath = "coveragebrowser.exe"; - return d->cocoPath.resolvePath(browserPath); + return m_cocoPath.resolvePath(browserPath); } -void CocoInstallation::setDirectory(const Utils::FilePath &dir) +void CocoSettings::setDirectory(const FilePath &dir) { if (isCocoDirectory(dir)) { - d->cocoPath = dir; - d->isValid = true; - d->errorMessage = ""; + m_cocoPath = dir; + m_isValid = true; + m_errorMessage.clear(); verifyCocoDirectory(); - } - else { - d->cocoPath = Utils::FilePath(); - d->isValid = false; - d->errorMessage + } else { + m_cocoPath = Utils::FilePath(); + m_isValid = false; + m_errorMessage = Tr::tr("Error: Coco installation directory not found at \"%1\".").arg(dir.nativePath()); } } -Utils::FilePath CocoInstallation::coverageScannerPath(const Utils::FilePath &cocoDir) const +FilePath CocoSettings::coverageScannerPath(const FilePath &cocoDir) const { QString scannerPath; - if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost()) + if (HostOsInfo::isAnyUnixHost() || HostOsInfo::isMacHost()) scannerPath = "bin/coveragescanner"; else scannerPath = "coveragescanner.exe"; @@ -119,21 +112,21 @@ Utils::FilePath CocoInstallation::coverageScannerPath(const Utils::FilePath &coc return cocoDir.resolvePath(scannerPath); } -bool CocoInstallation::isCocoDirectory(const Utils::FilePath &cocoDir) const +bool CocoSettings::isCocoDirectory(const Utils::FilePath &cocoDir) const { return coverageScannerPath(cocoDir).exists(); } -void CocoInstallation::logError(const QString &msg) +void CocoSettings::logError(const QString &msg) { logFlashing(msg); - d->isValid = false; - d->errorMessage = msg; + m_isValid = false; + m_errorMessage = msg; } -bool CocoInstallation::verifyCocoDirectory() +bool CocoSettings::verifyCocoDirectory() { - QString coveragescanner = coverageScannerPath(d->cocoPath).nativePath(); + QString coveragescanner = coverageScannerPath(m_cocoPath).nativePath(); QProcess proc; proc.setProgram(coveragescanner); @@ -170,19 +163,19 @@ bool CocoInstallation::verifyCocoDirectory() } } -bool CocoInstallation::isValid() const +bool CocoSettings::isValid() const { - return d->isValid; + return m_isValid; } -QString CocoInstallation::errorMessage() const +QString CocoSettings::errorMessage() const { - return d->errorMessage; + return m_errorMessage; } -void CocoInstallation::tryPath(const QString &path) +void CocoSettings::tryPath(const QString &path) { - if (d->isValid) + if (m_isValid) return; const auto fpath = Utils::FilePath::fromString(path); @@ -190,17 +183,18 @@ void CocoInstallation::tryPath(const QString &path) if (isCocoDirectory(fpath)) { logSilently(Tr::tr("Found Coco directory \"%1\".").arg(nativePath)); setDirectory(fpath); - GlobalSettings::save(); - } else + save(); + } else { logSilently(Tr::tr("Checked Coco directory \"%1\".").arg(nativePath)); + } } -QString CocoInstallation::envVar(const QString &var) const +QString CocoSettings::envVar(const QString &var) const { return QProcessEnvironment::systemEnvironment().value(var); } -void CocoInstallation::findDefaultDirectory() +void CocoSettings::findDefaultDirectory() { if (Utils::HostOsInfo::isMacHost()) tryPath("/Applications/SquishCoco"); @@ -216,10 +210,11 @@ void CocoInstallation::findDefaultDirectory() tryPath(envVar("ProgramFiles(x86)") + "\\squishcoco"); } } + GlobalSettingsWidget::GlobalSettingsWidget(QFrame *parent) : QFrame(parent) { - m_cocoPathAspect.setDefaultPathValue(m_coco.directory()); + m_cocoPathAspect.setDefaultPathValue(cocoSettings().directory()); m_cocoPathAspect.setExpectedKind(Utils::PathChooser::ExistingDirectory); m_cocoPathAspect.setPromptDialogTitle(Tr::tr("Coco Installation Directory")); @@ -245,13 +240,13 @@ void GlobalSettingsWidget::onCocoPathChanged() bool GlobalSettingsWidget::verifyCocoDirectory(const Utils::FilePath &cocoDir) { - m_coco.setDirectory(cocoDir); - m_messageLabel.setText(m_coco.errorMessage()); - if (m_coco.isValid()) + cocoSettings().setDirectory(cocoDir); + m_messageLabel.setText(cocoSettings().errorMessage()); + if (cocoSettings().isValid()) m_messageLabel.setIconType(Utils::InfoLabel::None); else m_messageLabel.setIconType(Utils::InfoLabel::Error); - return m_coco.isValid(); + return cocoSettings().isValid(); } void GlobalSettingsWidget::apply() @@ -259,21 +254,21 @@ void GlobalSettingsWidget::apply() if (!verifyCocoDirectory(widgetCocoDir())) return; - m_coco.setDirectory(widgetCocoDir()); - GlobalSettings::save(); + cocoSettings().setDirectory(widgetCocoDir()); + cocoSettings().save(); emit updateCocoDir(); } void GlobalSettingsWidget::cancel() { - m_coco.setDirectory(m_previousCocoDir); + cocoSettings().setDirectory(m_previousCocoDir); } void GlobalSettingsWidget::setVisible(bool visible) { QFrame::setVisible(visible); - m_previousCocoDir = m_coco.directory(); + m_previousCocoDir = cocoSettings().directory(); } Utils::FilePath GlobalSettingsWidget::widgetCocoDir() const diff --git a/src/plugins/coco/globalsettings.h b/src/plugins/coco/globalsettings.h index ce682e857e6..568d1400792 100644 --- a/src/plugins/coco/globalsettings.h +++ b/src/plugins/coco/globalsettings.h @@ -8,20 +8,15 @@ #include namespace Coco::Internal { -namespace GlobalSettings { -void read(); -void save(); - -} // GlobalSettings - -struct CocoInstallationPrivate; - -// Borg pattern: There are many instances of this class, but all are the same. -class CocoInstallation +class CocoSettings { + friend CocoSettings &cocoSettings(); + CocoSettings(); + public: - CocoInstallation(); + void read(); + void save(); Utils::FilePath directory() const; Utils::FilePath coverageBrowserPath() const; @@ -39,9 +34,13 @@ private: void tryPath(const QString &path); QString envVar(const QString &var) const; - static CocoInstallationPrivate *d; + Utils::FilePath m_cocoPath; + bool m_isValid = false; + QString m_errorMessage; }; +CocoSettings &cocoSettings(); + class GlobalSettingsWidget : public QFrame { Q_OBJECT @@ -67,7 +66,6 @@ private: Utils::FilePathAspect m_cocoPathAspect; Utils::TextDisplay m_messageLabel; - CocoInstallation m_coco; Utils::FilePath m_previousCocoDir; }; From fabcf8550822cdaed9e0d59f470fa4685eea843e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 12 Dec 2024 17:13:46 +0100 Subject: [PATCH 408/989] CmdBridge: Act on exceptions in Client::exit() Change-Id: I93b82d2e559366b67e7a9069fd3ff371d37988ad Reviewed-by: Marcus Tillmanns --- src/libs/gocmdbridge/client/cmdbridgeclient.cpp | 10 +++++----- src/libs/gocmdbridge/client/cmdbridgeclient.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/gocmdbridge/client/cmdbridgeclient.cpp b/src/libs/gocmdbridge/client/cmdbridgeclient.cpp index 754aac2251c..51f75c43f8b 100644 --- a/src/libs/gocmdbridge/client/cmdbridgeclient.cpp +++ b/src/libs/gocmdbridge/client/cmdbridgeclient.cpp @@ -244,10 +244,8 @@ Client::Client(const Utils::FilePath &remoteCmdBridgePath) Client::~Client() { - if (d->thread->isRunning()) { - exit(); + if (d->thread->isRunning() && exit()) d->thread->wait(); - } } expected_str> Client::start() @@ -856,12 +854,14 @@ Utils::expected_str> Client::signalProcess(int pid, Utils::Control "signalsuccess"); } -void Client::exit() +bool Client::exit() { try { createVoidJob(d.get(), QCborMap{{"Type", "exit"}}, "exitres")->waitForFinished(); + return true; } catch (...) { - return; + qCWarning(clientLog) << "Client::exit() caught exception"; + return false; } } diff --git a/src/libs/gocmdbridge/client/cmdbridgeclient.h b/src/libs/gocmdbridge/client/cmdbridgeclient.h index 1d6556d3234..07302131878 100644 --- a/src/libs/gocmdbridge/client/cmdbridgeclient.h +++ b/src/libs/gocmdbridge/client/cmdbridgeclient.h @@ -113,7 +113,7 @@ public: Utils::expected_str> signalProcess(int pid, Utils::ControlSignal signal); protected: - void exit(); + bool exit(); signals: void done(const Utils::ProcessResultData &resultData); From 661ceb6433a2a44208df7ce13701cb267e6f3ca2 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Dec 2024 11:36:37 +0100 Subject: [PATCH 409/989] CmdBridge: Make sure the wait ends when shutting down Change-Id: Ic56d7bf14246d51c2b729ea54da5541a29fa5e23 Reviewed-by: Marcus Tillmanns --- src/libs/gocmdbridge/client/cmdbridgeclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/gocmdbridge/client/cmdbridgeclient.cpp b/src/libs/gocmdbridge/client/cmdbridgeclient.cpp index 51f75c43f8b..21028853bf0 100644 --- a/src/libs/gocmdbridge/client/cmdbridgeclient.cpp +++ b/src/libs/gocmdbridge/client/cmdbridgeclient.cpp @@ -245,7 +245,7 @@ Client::Client(const Utils::FilePath &remoteCmdBridgePath) Client::~Client() { if (d->thread->isRunning() && exit()) - d->thread->wait(); + d->thread->wait(2000); } expected_str> Client::start() From 2b2ef52d806b1e63eeebec972ea0c8b06836a835 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Wed, 20 Nov 2024 16:01:33 +0100 Subject: [PATCH 410/989] qmlls: apply settings after the qt version change Restart qmlls when the qt kit was changed for a project, as different qt kits require different qmlls binaries and commandline. Fixes: QTCREATORBUG-32044 Change-Id: Ia234c496ea9b18ef3c7077376b6c9f2253fe209c Reviewed-by: David Schulz Reviewed-by: hjk --- src/plugins/qmljseditor/qmljseditorplugin.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp index b95c19f0689..f75ad084d89 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.cpp +++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp @@ -30,6 +30,8 @@ #include +#include + #include #include #include @@ -101,6 +103,12 @@ QmlJSEditorPluginPrivate::QmlJSEditorPluginPrivate() // recompute messages when project data changes (files added or removed) connect(modelManager, &QmlJS::ModelManagerInterface::projectInfoUpdated, &m_qmlTaskManager, &QmlTaskManager::updateMessages); + // restart qmlls when project data changes (qt kit changed, for example) + connect( + modelManager, + &QmlJS::ModelManagerInterface::projectInfoUpdated, + LanguageClient::LanguageClientManager::instance(), + []() { LanguageClient::LanguageClientManager::applySettings(qmllsSettings()); }); connect(modelManager, &QmlJS::ModelManagerInterface::aboutToRemoveFiles, &m_qmlTaskManager, From fe4838b46c0203672955d6d3761d7e5ca761723f Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 3 Dec 2024 12:44:57 +0100 Subject: [PATCH 411/989] Utils: Simplify FileReader interface It was either used with QIODevice::Text, or not. Moving the \r\n -> \n replacement to the result accessor make passing the flags unnecessary. Change-Id: I686f992a07734f1805617c245774b357c6d42025 Reviewed-by: Eike Ziller --- src/libs/qmljs/jsoncheck.cpp | 4 ++-- src/libs/qmljs/qmljsplugindumper.cpp | 4 ++-- src/libs/utils/fileutils.cpp | 23 ++++++++++--------- src/libs/utils/fileutils.h | 11 ++++----- src/plugins/android/androiddevice.cpp | 4 ++-- .../clangtools/clangtoolslogfilereader.cpp | 4 ++-- .../readexporteddiagnosticstest.cpp | 4 ++-- src/plugins/git/gitclient.cpp | 4 ++-- src/plugins/perforce/perforceplugin.cpp | 4 ++-- .../customwizard/customwizard.cpp | 6 ++--- .../jsonwizard/jsonwizardfilegenerator.cpp | 7 ++---- src/plugins/squish/objectsmapdocument.cpp | 4 ++-- src/plugins/texteditor/formattexteditor.cpp | 4 ++-- src/plugins/vcsbase/nicknamedialog.cpp | 4 ++-- src/plugins/vcsbase/submiteditorfile.cpp | 4 ++-- src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 4 ++-- 16 files changed, 44 insertions(+), 51 deletions(-) diff --git a/src/libs/qmljs/jsoncheck.cpp b/src/libs/qmljs/jsoncheck.cpp index 3cb44111f9d..c76152a4d34 100644 --- a/src/libs/qmljs/jsoncheck.cpp +++ b/src/libs/qmljs/jsoncheck.cpp @@ -1091,8 +1091,8 @@ JsonSchema *JsonSchemaManager::schemaByName(const QString &baseName) const JsonSchema *JsonSchemaManager::parseSchema(const QString &schemaFileName) const { FileReader reader; - if (reader.fetch(FilePath::fromString(schemaFileName), QIODevice::Text)) { - const QString &contents = QString::fromUtf8(reader.data()); + if (reader.fetch(FilePath::fromString(schemaFileName))) { + const QString &contents = QString::fromUtf8(reader.text()); JsonValue *json = JsonValue::create(contents, &m_pool); if (json && json->kind() == JsonValue::Object) return new JsonSchema(json->toObject(), this); diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index fa6358e4a2a..ad327cb5f85 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -332,7 +332,7 @@ QFuture PluginDumper::loadQmlTypeDescription(c for (const FilePath &p: paths) { Utils::FileReader reader; - if (!reader.fetch(p, QFile::Text)) { + if (!reader.fetch(p)) { result.errors += reader.errorString(); continue; } @@ -341,7 +341,7 @@ QFuture PluginDumper::loadQmlTypeDescription(c CppQmlTypesLoader::BuiltinObjects objs; QList apis; QStringList deps; - CppQmlTypesLoader::parseQmlTypeDescriptions(reader.data(), &objs, &apis, &deps, + CppQmlTypesLoader::parseQmlTypeDescriptions(reader.text(), &objs, &apis, &deps, &error, &warning, p.toString()); if (!error.isEmpty()) { result.errors += Tr::tr("Failed to parse \"%1\".\nError: %2").arg(p.toUserOutput(), error); diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index e20ebb853d6..885375fb172 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -56,26 +56,27 @@ QByteArray FileReader::fetchQrc(const QString &fileName) return file.readAll(); } -bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode) +bool FileReader::fetch(const FilePath &filePath) { - QTC_ASSERT(!(mode & ~(QIODevice::ReadOnly | QIODevice::Text)), return false); - const expected_str contents = filePath.fileContents(); if (!contents) { m_errorString = contents.error(); return false; } m_data = *contents; - - if (mode & QIODevice::Text) - m_data = m_data.replace("\r\n", "\n"); - return true; } -bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode, QString *errorString) +QByteArray FileReader::text() const { - if (fetch(filePath, mode)) + QByteArray res = m_data; + res = res.replace("\r\n", "\n"); + return res; +} + +bool FileReader::fetch(const FilePath &filePath, QString *errorString) +{ + if (fetch(filePath)) return true; if (errorString) *errorString = m_errorString; @@ -83,9 +84,9 @@ bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode, QStri } #ifdef QT_GUI_LIB -bool FileReader::fetch(const FilePath &filePath, QIODevice::OpenMode mode, QWidget *parent) +bool FileReader::fetch(const FilePath &filePath, QWidget *parent) { - if (fetch(filePath, mode)) + if (fetch(filePath)) return true; if (parent) QMessageBox::critical(parent, Tr::tr("File Error"), m_errorString); diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index a894d33a403..2f23277fef2 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -149,16 +149,13 @@ class QTCREATOR_UTILS_EXPORT FileReader { public: static QByteArray fetchQrc(const QString &fileName); // Only for internal resources - bool fetch(const FilePath &filePath, QIODevice::OpenMode mode = QIODevice::NotOpen); // QIODevice::ReadOnly is implicit - bool fetch(const FilePath &filePath, QIODevice::OpenMode mode, QString *errorString); - bool fetch(const FilePath &filePath, QString *errorString) - { return fetch(filePath, QIODevice::NotOpen, errorString); } + bool fetch(const FilePath &filePath); + bool fetch(const FilePath &filePath, QString *errorString); #ifdef QT_GUI_LIB - bool fetch(const FilePath &filePath, QIODevice::OpenMode mode, QWidget *parent); - bool fetch(const FilePath &filePath, QWidget *parent) - { return fetch(filePath, QIODevice::NotOpen, parent); } + bool fetch(const FilePath &filePath, QWidget *parent); #endif // QT_GUI_LIB const QByteArray &data() const { return m_data; } + QByteArray text() const; // data with replaced \r\n -> \n const QString &errorString() const { return m_errorString; } private: QByteArray m_data; diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 663cfe57470..94a9ee9ddee 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -750,11 +750,11 @@ static void modifyManufacturerTag(const FilePath &avdPath, TagModification modif const FilePath configFilePath = avdPath / "config.ini"; FileReader reader; - if (!reader.fetch(configFilePath, QIODevice::ReadOnly | QIODevice::Text)) + if (!reader.fetch(configFilePath)) return; FileSaver saver(configFilePath); - QTextStream textStream(reader.data()); + QTextStream textStream(reader.text()); while (!textStream.atEnd()) { QString line = textStream.readLine(); if (line.contains("hw.device.manufacturer")) { diff --git a/src/plugins/clangtools/clangtoolslogfilereader.cpp b/src/plugins/clangtools/clangtoolslogfilereader.cpp index 21f34f35c10..185dab40363 100644 --- a/src/plugins/clangtools/clangtoolslogfilereader.cpp +++ b/src/plugins/clangtools/clangtoolslogfilereader.cpp @@ -100,8 +100,8 @@ private: return {}; Utils::FileReader reader; - // Do not use QIODevice::Text as we have to deal with byte offsets. - if (reader.fetch(Utils::FilePath::fromString(filePath), QIODevice::ReadOnly)) + // Do not use FileReader::text as we have to deal with byte offsets. + if (reader.fetch(Utils::FilePath::fromString(filePath))) return reader.data(); return {}; diff --git a/src/plugins/clangtools/readexporteddiagnosticstest.cpp b/src/plugins/clangtools/readexporteddiagnosticstest.cpp index f6bf5e1118e..38bbee73908 100644 --- a/src/plugins/clangtools/readexporteddiagnosticstest.cpp +++ b/src/plugins/clangtools/readexporteddiagnosticstest.cpp @@ -264,8 +264,8 @@ FilePath ReadExportedDiagnosticsTest::createFile(const Utils::FilePath &yamlFile const FilePath newFileName = m_baseDir->filePath().resolvePath(yamlFilePath); FileReader reader; - if (QTC_GUARD(reader.fetch(yamlFilePath, QIODevice::ReadOnly | QIODevice::Text))) { - QByteArray contents = reader.data(); + if (QTC_GUARD(reader.fetch(yamlFilePath))) { + QByteArray contents = reader.text(); contents.replace("FILE_PATH", filePathToInject.toString().toLocal8Bit()); FileSaver fileSaver(newFileName, QIODevice::WriteOnly | QIODevice::Text); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 1e8b5c05bbf..85f8dbfd7a4 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2812,9 +2812,9 @@ bool GitClient::getCommitData(const FilePath &workingDirectory, if (!templateFile.isEmpty()) { templateFile = repoDirectory.resolvePath(templateFile); FileReader reader; - if (!reader.fetch(templateFile, QIODevice::Text, errorMessage)) + if (!reader.fetch(templateFile, errorMessage)) return false; - *commitTemplate = QString::fromLocal8Bit(reader.data()); + *commitTemplate = QString::fromLocal8Bit(reader.text()); } break; } diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 389879afe96..1cabd56984d 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -1416,7 +1416,7 @@ bool PerforcePluginPrivate::activateCommit() // Pipe file into p4 submit -i FileReader reader; - if (!reader.fetch(Utils::FilePath::fromString(m_commitMessageFileName), QIODevice::Text)) { + if (!reader.fetch(Utils::FilePath::fromString(m_commitMessageFileName))) { VcsOutputWindow::appendError(reader.errorString()); return false; } @@ -1425,7 +1425,7 @@ bool PerforcePluginPrivate::activateCommit() submitArgs << QLatin1String("submit") << QLatin1String("-i"); const PerforceResponse submitResponse = runP4Cmd(settings().topLevelSymLinkTarget(), submitArgs, LongTimeOut|RunFullySynchronous|CommandToWindow|StdErrToWindow|ErrorToWindow|ShowBusyCursor, - {}, reader.data()); + {}, reader.text()); if (submitResponse.error) return false; diff --git a/src/plugins/projectexplorer/customwizard/customwizard.cpp b/src/plugins/projectexplorer/customwizard/customwizard.cpp index fe81b3ba7e7..e79a454b06e 100644 --- a/src/plugins/projectexplorer/customwizard/customwizard.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizard.cpp @@ -176,10 +176,8 @@ static bool createFile(CustomWizardFile cwFile, qDebug() << "generating " << targetPath << sourcePath << fm; // Read contents of source file - const QFile::OpenMode openMode - = cwFile.binary ? QIODevice::ReadOnly : (QIODevice::ReadOnly|QIODevice::Text); FileReader reader; - if (!reader.fetch(FilePath::fromString(sourcePath), openMode, errorMessage)) + if (!reader.fetch(FilePath::fromString(sourcePath), errorMessage)) return false; GeneratedFile generatedFile; @@ -190,7 +188,7 @@ static bool createFile(CustomWizardFile cwFile, generatedFile.setBinaryContents(reader.data()); } else { // Template file: Preprocess. - const QString contentsIn = QString::fromLocal8Bit(reader.data()); + const QString contentsIn = QString::fromLocal8Bit(reader.text()); generatedFile.setContents(CustomWizardContext::processFile(fm, contentsIn)); } diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp index 1644257a971..340b91709ce 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfilegenerator.cpp @@ -118,11 +118,8 @@ Core::GeneratedFile JsonWizardFileGenerator::generateFile(const File &file, MacroExpander *expander, QString *errorMessage) { // Read contents of source file - const QFile::OpenMode openMode = file.isBinary.toBool() ? - QIODevice::ReadOnly : (QIODevice::ReadOnly|QIODevice::Text); - FileReader reader; - if (!reader.fetch(file.source, openMode, errorMessage)) + if (!reader.fetch(file.source, errorMessage)) return Core::GeneratedFile(); // Generate file information: @@ -155,7 +152,7 @@ Core::GeneratedFile JsonWizardFileGenerator::generateFile(const File &file, return expander->resolveMacro(n, ret); }); - gf.setContents(TemplateEngine::processText(&nested, QString::fromUtf8(reader.data()), + gf.setContents(TemplateEngine::processText(&nested, QString::fromUtf8(reader.text()), errorMessage)); if (!errorMessage->isEmpty()) { *errorMessage = Tr::tr("When processing \"%1\":
    %2") diff --git a/src/plugins/squish/objectsmapdocument.cpp b/src/plugins/squish/objectsmapdocument.cpp index 3cb7b5fd7c5..83816a1b64b 100644 --- a/src/plugins/squish/objectsmapdocument.cpp +++ b/src/plugins/squish/objectsmapdocument.cpp @@ -185,10 +185,10 @@ Core::IDocument::OpenResult ObjectsMapDocument::openImpl(QString *error, QByteArray text; if (realFileName.fileName() == "objects.map") { Utils::FileReader reader; - if (!reader.fetch(realFileName, QIODevice::Text, error)) + if (!reader.fetch(realFileName, error)) return OpenResult::ReadError; - text = reader.data(); + text = reader.text(); } else { const Utils::FilePath base = settings().squishPath(); if (base.isEmpty()) { diff --git a/src/plugins/texteditor/formattexteditor.cpp b/src/plugins/texteditor/formattexteditor.cpp index 20a7d9c8bc8..e28abd73663 100644 --- a/src/plugins/texteditor/formattexteditor.cpp +++ b/src/plugins/texteditor/formattexteditor.cpp @@ -88,11 +88,11 @@ static FormatOutput format(const FormatInput &input) // Read text back Utils::FileReader reader; - if (!reader.fetch(sourceFile.filePath(), QIODevice::Text)) { + if (!reader.fetch(sourceFile.filePath())) { return Utils::make_unexpected(Tr::tr("Cannot read file \"%1\": %2.") .arg(sourceFile.filePath().toUserOutput(), reader.errorString())); } - return QString::fromUtf8(reader.data()); + return QString::fromUtf8(reader.text()); } case Command::PipeProcessing: { diff --git a/src/plugins/vcsbase/nicknamedialog.cpp b/src/plugins/vcsbase/nicknamedialog.cpp index 39791dc7472..1efa23f584f 100644 --- a/src/plugins/vcsbase/nicknamedialog.cpp +++ b/src/plugins/vcsbase/nicknamedialog.cpp @@ -235,11 +235,11 @@ bool NickNameDialog::populateModelFromMailCapFile(const FilePath &fileName, if (fileName.isEmpty()) return true; FileReader reader; - if (!reader.fetch(fileName, QIODevice::Text, errorMessage)) + if (!reader.fetch(fileName, errorMessage)) return false; // Split into lines and read NickNameEntry entry; - const QStringList lines = QString::fromUtf8(reader.data()).trimmed().split(QLatin1Char('\n')); + const QStringList lines = QString::fromUtf8(reader.text()).trimmed().split(QLatin1Char('\n')); const int count = lines.size(); for (int i = 0; i < count; i++) { if (entry.parse(lines.at(i))) { diff --git a/src/plugins/vcsbase/submiteditorfile.cpp b/src/plugins/vcsbase/submiteditorfile.cpp index ebdd14bf0f9..e00f6080818 100644 --- a/src/plugins/vcsbase/submiteditorfile.cpp +++ b/src/plugins/vcsbase/submiteditorfile.cpp @@ -37,10 +37,10 @@ IDocument::OpenResult SubmitEditorFile::open(QString *errorString, const FilePat return OpenResult::ReadError; FileReader reader; - if (!reader.fetch(realFilePath, QIODevice::Text, errorString)) + if (!reader.fetch(realFilePath, errorString)) return OpenResult::ReadError; - const QString text = QString::fromLocal8Bit(reader.data()); + const QString text = QString::fromLocal8Bit(reader.text()); if (!m_editor->setFileContents(text.toUtf8())) return OpenResult::CannotHandle; diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 995fb5c848c..2c9b917240a 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -242,11 +242,11 @@ static inline QStringList fieldTexts(const QString &fileContents) void VcsBaseSubmitEditor::createUserFields(const FilePath &fieldConfigFile) { FileReader reader; - if (!reader.fetch(fieldConfigFile, QIODevice::Text, ICore::dialogParent())) + if (!reader.fetch(fieldConfigFile, ICore::dialogParent())) return; // Parse into fields - const QStringList fields = fieldTexts(QString::fromUtf8(reader.data())); + const QStringList fields = fieldTexts(QString::fromUtf8(reader.text())); if (fields.empty()) return; // Create a completer on user names From bbf5802148029b8f432b7cf45b2a56b1e0f5efe6 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Fri, 13 Dec 2024 13:51:00 +0100 Subject: [PATCH 412/989] qmlls: remove unused string constants Amends 68309a5e855ff13aa3614ff3d76befec74361b73 that forgot to remove the settings key used in project specific settings, that are now removed. Change-Id: I33a71187f22f796413f78addf9a92127f8682a8d Reviewed-by: hjk --- src/plugins/qmljseditor/qmljseditorsettings.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/qmljseditor/qmljseditorsettings.cpp b/src/plugins/qmljseditor/qmljseditorsettings.cpp index 87983730004..81df5392028 100644 --- a/src/plugins/qmljseditor/qmljseditorsettings.cpp +++ b/src/plugins/qmljseditor/qmljseditorsettings.cpp @@ -57,14 +57,11 @@ using namespace ProjectExplorer; namespace QmlJSEditor::Internal { -const char SETTINGS_KEY_MAIN[] = "QmlJSEditor"; const char AUTO_FORMAT_ON_SAVE[] = "QmlJSEditor.AutoFormatOnSave"; const char AUTO_FORMAT_ONLY_CURRENT_PROJECT[] = "QmlJSEditor.AutoFormatOnlyCurrentProject"; const char QML_CONTEXTPANE_KEY[] = "QmlJSEditor.ContextPaneEnabled"; const char QML_CONTEXTPANEPIN_KEY[] = "QmlJSEditor.ContextPanePinned"; const char FOLD_AUX_DATA[] = "QmlJSEditor.FoldAuxData"; -const char USE_GLOBAL_SETTINGS[] = "QmlJSEditor.UseGlobalSettings"; -const char USE_QMLLS[] = "QmlJSEditor.UseQmlls"; const char UIQML_OPEN_MODE[] = "QmlJSEditor.openUiQmlMode"; const char FORMAT_COMMAND[] = "QmlJSEditor.formatCommand"; const char FORMAT_COMMAND_OPTIONS[] = "QmlJSEditor.formatCommandOptions"; From 319a5ccd86be2c3030e948964217f178f94ce020 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 12 Dec 2024 16:58:25 +0100 Subject: [PATCH 413/989] CppEditor: Fix InsertVirtualMethods quickfix ... for base classes pulled in via using declarations. This is probably just a hack, like everything connected to the weird ClassOrNamespace class. Fixes: QTCREATORBUG-32162 Change-Id: Id7fbcf569fca231284ad0026cc040b16ac04960c Reviewed-by: Christian Stenger --- .../quickfixes/cppinsertvirtualmethods.cpp | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/plugins/cppeditor/quickfixes/cppinsertvirtualmethods.cpp b/src/plugins/cppeditor/quickfixes/cppinsertvirtualmethods.cpp index 25324bcd46d..005c3625928 100644 --- a/src/plugins/cppeditor/quickfixes/cppinsertvirtualmethods.cpp +++ b/src/plugins/cppeditor/quickfixes/cppinsertvirtualmethods.cpp @@ -559,9 +559,17 @@ public: while (!baseClassQueue.isEmpty()) { ClassOrNamespace *clazz = baseClassQueue.dequeue(); visitedBaseClasses.insert(clazz); - const QList bases = clazz->usings(); - for (const ClassOrNamespace *baseClass : bases) { + QList bases = clazz->usings(); + while (!bases.isEmpty()) { + const ClassOrNamespace *baseClass = bases.takeFirst(); const QList symbols = baseClass->symbols(); + + // See QTCREATORBUG-32162. + if (symbols.isEmpty() && baseClass->usings().size() == 1) { + bases.prepend(baseClass->usings().first()); + continue; + } + for (Symbol *symbol : symbols) { Class *base = symbol->asClass(); if (base @@ -1852,6 +1860,21 @@ void InsertVirtualMethodsTest::test_data() "};\n\n" "struct Derived2 : Derived1\n" "};\n"); + + QTest::newRow("base class via using") + << InsertVirtualMethodsDialog::ModeOnlyDeclarations << false << true + << _(R"cpp( + namespace A { struct Base { virtual void foo() = 0; }; } // namespace A + using A::Base; + struct @Derived : Base {};)cpp") + << _(R"cpp( + namespace A { struct Base { virtual void foo() = 0; }; } // namespace A + using A::Base; + struct @Derived : Base { + // Base interface + public: + void foo() override; + };)cpp"); } void InsertVirtualMethodsTest::test() From 6cdacdacef455a32aaa7979861340ce1e8486c69 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Fri, 13 Dec 2024 16:01:32 +0100 Subject: [PATCH 414/989] LSP: fix typo in condition Fix a typo in a condition that ended up always being true. Amends 1221a9678de22badd0a5f73dee452d9bbef9c4b8. Change-Id: Ib1b0151f5ba14d753fe1610f85e7d16f3c91184e Reviewed-by: David Schulz --- src/plugins/languageclient/languageclientmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index fc62f1e15aa..84070bc4638 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -323,7 +323,8 @@ void LanguageClientManager::applySettings(BaseSettings *setting) managerInstance->m_clientForDocument.remove(document); if (!setting->isValid()) return; - if (setting->m_startBehavior == BaseSettings::AlwaysOn || BaseSettings::RequiresFile) { + if (setting->m_startBehavior == BaseSettings::AlwaysOn + || setting->m_startBehavior == BaseSettings::RequiresFile) { if (!setting->m_enabled) return; auto ensureClient = [setting, client = static_cast(nullptr)]() mutable { From 08a66b778064ece5f01ee3323d8a5b5171b02c09 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 27 Nov 2024 15:13:04 +0100 Subject: [PATCH 415/989] Editor: use detected indentation by default This removes the undescribed Mixed tab settings option. It was unclear and undocumented what this option actually means. In theory this option tries to detect whether tabs or spaces are used for indentation around a specific position in the document. This now conflicts with the automatic auto detection which scans the complete document. That auto detection not just detects whether tabs are used but also the indent depth. Having a source document with a different indent depth is arguably a more common use case than a source file with mixed tabs and spaces for indentation. So in order to not confuse the user with to many unclear magic options that might interfere with each other the mixed tab settings option was removed in this change. Fixes: QTCREATORBUG-11575 Fixes: QTCREATORBUG-11675 Fixes: QTCREATORBUG-19576 Fixes: QTCREATORBUG-25628 Change-Id: Ib95662ade38d0384d503e9a7b99f54ea4b416f68 Reviewed-by: Christian Stenger --- .../clangformat/clangformatindenter.cpp | 5 +- src/plugins/clangformat/clangformatutils.cpp | 7 +- src/plugins/cppeditor/cpptoolssettings.cpp | 4 +- .../cppeditor/quickfixes/rewritecomment.cpp | 2 +- src/plugins/texteditor/tabsettings.cpp | 69 ++++++------------- src/plugins/texteditor/tabsettings.h | 8 +-- src/plugins/texteditor/tabsettingswidget.cpp | 19 +++-- src/plugins/texteditor/tabsettingswidget.h | 2 + src/plugins/texteditor/textdocument.cpp | 20 +++--- src/plugins/texteditor/texteditor.cpp | 8 +-- src/plugins/texteditor/texteditor_test.cpp | 3 - 11 files changed, 58 insertions(+), 89 deletions(-) diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index 5f30c77ebf9..21278e136aa 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -78,14 +78,11 @@ std::optional ClangFormatIndenter::tabSettings() const TabSettings tabSettings; switch (style.UseTab) { - case FormatStyle::UT_Never: - tabSettings.m_tabPolicy = TabSettings::SpacesOnlyTabPolicy; - break; case FormatStyle::UT_Always: tabSettings.m_tabPolicy = TabSettings::TabsOnlyTabPolicy; break; default: - tabSettings.m_tabPolicy = TabSettings::MixedTabPolicy; + tabSettings.m_tabPolicy = TabSettings::SpacesOnlyTabPolicy; } tabSettings.m_tabSize = static_cast(style.TabWidth); diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index dcc7cbc84c8..6a439e4138f 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -246,13 +246,10 @@ void fromTabSettings(clang::format::FormatStyle &style, const TextEditor::TabSet style.TabWidth = settings.m_tabSize; switch (settings.m_tabPolicy) { - case TextEditor::TabSettings::TabPolicy::MixedTabPolicy: - style.UseTab = FormatStyle::UT_ForContinuationAndIndentation; - break; - case TextEditor::TabSettings::TabPolicy::SpacesOnlyTabPolicy: + case TextEditor::TabSettings::SpacesOnlyTabPolicy: style.UseTab = FormatStyle::UT_Never; break; - case TextEditor::TabSettings::TabPolicy::TabsOnlyTabPolicy: + case TextEditor::TabSettings::TabsOnlyTabPolicy: style.UseTab = FormatStyle::UT_Always; break; } diff --git a/src/plugins/cppeditor/cpptoolssettings.cpp b/src/plugins/cppeditor/cpptoolssettings.cpp index 284b36d232a..abf2626bf33 100644 --- a/src/plugins/cppeditor/cpptoolssettings.cpp +++ b/src/plugins/cppeditor/cpptoolssettings.cpp @@ -106,8 +106,8 @@ CppToolsSettings::CppToolsSettings() gnuCodeStyle->setDisplayName(Tr::tr("GNU")); gnuCodeStyle->setReadOnly(true); TabSettings gnuTabSettings; - gnuTabSettings.m_tabPolicy = TabSettings::MixedTabPolicy; - gnuTabSettings.m_tabSize = 8; + gnuTabSettings.m_tabPolicy = TabSettings::TabsOnlyTabPolicy; + gnuTabSettings.m_tabSize = 2; gnuTabSettings.m_indentSize = 2; gnuTabSettings.m_continuationAlignBehavior = TabSettings::ContinuationAlignWithIndent; gnuCodeStyle->setTabSettings(gnuTabSettings); diff --git a/src/plugins/cppeditor/quickfixes/rewritecomment.cpp b/src/plugins/cppeditor/quickfixes/rewritecomment.cpp index 3ac7fede2c5..a7bea4c0471 100644 --- a/src/plugins/cppeditor/quickfixes/rewritecomment.cpp +++ b/src/plugins/cppeditor/quickfixes/rewritecomment.cpp @@ -324,7 +324,7 @@ private: int lineIndentColumn = sts.indentationColumn(text) + columnOffset; text.replace(0, TabSettings::firstNonSpace(text), - tts.indentationString(0, lineIndentColumn, 0, insertionBlock)); + tts.indentationString(0, lineIndentColumn, 0)); } functionDoc += text; } diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp index 54aa18f3c29..debc9e199ac 100644 --- a/src/plugins/texteditor/tabsettings.cpp +++ b/src/plugins/texteditor/tabsettings.cpp @@ -9,7 +9,7 @@ #include static const char spacesForTabsKey[] = "SpacesForTabs"; -static const char autoSpacesForTabsKey[] = "AutoSpacesForTabs"; +static const char autoDetectKey[] = "AutoDetect"; static const char tabSizeKey[] = "TabSize"; static const char indentSizeKey[] = "IndentSize"; static const char paddingModeKey[] = "PaddingMode"; @@ -33,7 +33,7 @@ Store TabSettings::toMap() const { return { {spacesForTabsKey, m_tabPolicy != TabsOnlyTabPolicy}, - {autoSpacesForTabsKey, m_tabPolicy == MixedTabPolicy}, + {autoDetectKey, m_autoDetect}, {tabSizeKey, m_tabSize}, {indentSizeKey, m_indentSize}, {paddingModeKey, m_continuationAlignBehavior} @@ -43,8 +43,8 @@ Store TabSettings::toMap() const void TabSettings::fromMap(const Store &map) { const bool spacesForTabs = map.value(spacesForTabsKey, true).toBool(); - const bool autoSpacesForTabs = map.value(autoSpacesForTabsKey, false).toBool(); - m_tabPolicy = spacesForTabs ? (autoSpacesForTabs ? MixedTabPolicy : SpacesOnlyTabPolicy) : TabsOnlyTabPolicy; + m_autoDetect = map.value(autoDetectKey, true).toBool(); + m_tabPolicy = spacesForTabs ? SpacesOnlyTabPolicy : TabsOnlyTabPolicy; m_tabSize = map.value(tabSizeKey, m_tabSize).toInt(); m_indentSize = map.value(indentSizeKey, m_indentSize).toInt(); m_continuationAlignBehavior = (ContinuationAlignBehavior) @@ -55,8 +55,7 @@ TabSettings TabSettings::autoDetect(const QTextDocument *document) const { QTC_ASSERT(document, return *this); - const int blockCount = document->blockCount(); - if (blockCount < 10) + if (!m_autoDetect) return *this; int totalIndentations = 0; @@ -64,16 +63,15 @@ TabSettings TabSettings::autoDetect(const QTextDocument *document) const QMap indentCount; auto checkText = - [this, &totalIndentations, &indentCount, &indentationWithTabs](const QTextBlock &block) { + [this, document, &totalIndentations, &indentCount, &indentationWithTabs](const QTextBlock &block) { if (block.length() == 0) return; - const QTextDocument *doc = block.document(); int pos = block.position(); bool hasTabs = false; int indentation = 0; // iterate ove the characters in the document is faster since we do not have to allocate // a string for each block text when we are only interested in the first few characters - QChar c = doc->characterAt(pos); + QChar c = document->characterAt(pos); while (c.isSpace() && c != QChar::ParagraphSeparator) { if (c == QChar::Tabulation) { hasTabs = true; @@ -81,7 +79,7 @@ TabSettings TabSettings::autoDetect(const QTextDocument *document) const } else { ++indentation; } - c = doc->characterAt(++pos); + c = document->characterAt(++pos); } // only track indentations that are at least 2 columns wide if (indentation > 1) { @@ -92,6 +90,7 @@ TabSettings TabSettings::autoDetect(const QTextDocument *document) const } }; + const int blockCount = document->blockCount(); if (blockCount < 200) { // check the indentation of all blocks if the document is shorter than 200 lines for (QTextBlock block = document->firstBlock(); block.isValid(); block = block.next()) @@ -118,6 +117,9 @@ TabSettings TabSettings::autoDetect(const QTextDocument *document) const } } + if (indentCount.size() < 3) + return *this; + // find the most common indent int mostCommonIndent = 0; int mostCommonIndentCount = 0; @@ -222,7 +224,6 @@ bool TabSettings::isIndentationClean(const QTextBlock &block, const int indent) int i = 0; int spaceCount = 0; QString text = block.text(); - bool spacesForTabs = guessSpacesForTabs(block); while (i < text.size()) { QChar c = text.at(i); if (!c.isSpace()) @@ -231,13 +232,13 @@ bool TabSettings::isIndentationClean(const QTextBlock &block, const int indent) if (c == QLatin1Char(' ')) { ++spaceCount; if (spaceCount == m_tabSize) - if (!spacesForTabs) + if (m_tabPolicy == TabsOnlyTabPolicy) if ((m_continuationAlignBehavior != ContinuationAlignWithSpaces) || (i < indent)) return false; if (spaceCount > indent && m_continuationAlignBehavior == NoContinuationAlign) return false; } else if (c == QLatin1Char('\t')) { - if (spacesForTabs || (spaceCount != 0)) + if (m_tabPolicy == SpacesOnlyTabPolicy || (spaceCount != 0)) return false; if ((m_continuationAlignBehavior != ContinuationAlignWithIndent) && ((i + 1) * m_tabSize > indent)) return false; @@ -316,41 +317,10 @@ int TabSettings::indentedColumn(int column, bool doIndent) const return qMax(0, aligned - m_indentSize); } -bool TabSettings::guessSpacesForTabs(const QTextBlock &block) const -{ - if (m_tabPolicy == MixedTabPolicy && block.isValid()) { - QTextBlock prev = block.previous(); - QTextBlock next = block.next(); - - auto checkFirstChar = - [doc = block.document()](const QTextBlock &block) -> std::optional { - if (block.length() > 0) { - const QChar firstChar = doc->characterAt(block.position()); - if (firstChar == QLatin1Char(' ')) - return true; - if (firstChar == QLatin1Char('\t')) - return false; - } - return {}; - }; - - for (int delta = 1; delta <= 100 && (prev.isValid() || next.isValid()); ++delta) { - if (auto result = checkFirstChar(prev)) - return *result; - if (auto result = checkFirstChar(next)) - return *result; - prev = prev.previous(); - next = next.next(); - } - } - return m_tabPolicy != TabsOnlyTabPolicy; -} - -QString TabSettings::indentationString(int startColumn, int targetColumn, int padding, - const QTextBlock &block) const +QString TabSettings::indentationString(int startColumn, int targetColumn, int padding) const { targetColumn = qMax(startColumn, targetColumn); - if (guessSpacesForTabs(block)) + if (m_tabPolicy == SpacesOnlyTabPolicy) return QString(targetColumn - startColumn, QLatin1Char(' ')); QString s; @@ -390,7 +360,7 @@ void TabSettings::indentLine(const QTextBlock &block, int newIndent, int padding // if (indentationColumn(text) == newIndent) // return; - const QString indentString = indentationString(0, newIndent, padding, block); + const QString indentString = indentationString(0, newIndent, padding); if (oldBlockLength == indentString.length() && text == indentString) return; @@ -419,7 +389,7 @@ void TabSettings::reindentLine(QTextBlock block, int delta) const // user likes tabs for spaces and uses tabs for indentation, preserve padding if (m_tabPolicy == TabsOnlyTabPolicy && m_tabSize == m_indentSize) padding = qMin(maximumPadding(text), newIndent); - const QString indentString = indentationString(0, newIndent, padding, block); + const QString indentString = indentationString(0, newIndent, padding); if (oldBlockLength == indentString.length() && text == indentString) return; @@ -434,7 +404,8 @@ void TabSettings::reindentLine(QTextBlock block, int delta) const bool TabSettings::equals(const TabSettings &ts) const { - return m_tabPolicy == ts.m_tabPolicy + return m_autoDetect == ts.m_autoDetect + && m_tabPolicy == ts.m_tabPolicy && m_tabSize == ts.m_tabSize && m_indentSize == ts.m_indentSize && m_continuationAlignBehavior == ts.m_continuationAlignBehavior; diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h index 4d28a3c05cd..f173cd0e68c 100644 --- a/src/plugins/texteditor/tabsettings.h +++ b/src/plugins/texteditor/tabsettings.h @@ -20,11 +20,9 @@ namespace TextEditor { class TEXTEDITORSUPPORT_EXPORT TabSettings { public: - enum TabPolicy { SpacesOnlyTabPolicy = 0, - TabsOnlyTabPolicy = 1, - MixedTabPolicy = 2 + TabsOnlyTabPolicy }; // This enum must match the indexes of continuationAlignBehavior widget @@ -49,7 +47,7 @@ public: int positionAtColumn(const QString &text, int column, int *offset = nullptr, bool allowOverstep = false) const; int columnCountForText(const QString &text, int startColumn = 0) const; int indentedColumn(int column, bool doIndent = true) const; - QString indentationString(int startColumn, int targetColumn, int padding, const QTextBlock ¤tBlock = QTextBlock()) const; + QString indentationString(int startColumn, int targetColumn, int padding) const; int indentationColumn(const QString &text) const; static int maximumPadding(const QString &text); @@ -57,7 +55,6 @@ public: void reindentLine(QTextBlock block, int delta) const; bool isIndentationClean(const QTextBlock &block, const int indent) const; - bool guessSpacesForTabs(const QTextBlock &block) const; friend bool operator==(const TabSettings &t1, const TabSettings &t2) { return t1.equals(t2); } friend bool operator!=(const TabSettings &t1, const TabSettings &t2) { return !t1.equals(t2); } @@ -70,6 +67,7 @@ public: static int trailingWhitespaces(const QString &text); static void removeTrailingWhitespace(QTextCursor cursor, QTextBlock &block); + bool m_autoDetect = true; TabPolicy m_tabPolicy = SpacesOnlyTabPolicy; int m_tabSize = 8; int m_indentSize = 4; diff --git a/src/plugins/texteditor/tabsettingswidget.cpp b/src/plugins/texteditor/tabsettingswidget.cpp index c796591ffc6..fb48fa7a6b8 100644 --- a/src/plugins/texteditor/tabsettingswidget.cpp +++ b/src/plugins/texteditor/tabsettingswidget.cpp @@ -7,6 +7,7 @@ #include "texteditortr.h" #include +#include #include #include #include @@ -60,17 +61,22 @@ TabSettingsWidget::TabSettingsWidget(QWidget *parent) : Tr::tr("The text editor indentation setting is used for non-code files only. See the C++ " "and Qt Quick coding style settings to configure indentation for code files.")); + m_autoDetect = new QCheckBox(Tr::tr("Auto detect"), this); + m_autoDetect->setToolTip( + Tr::tr("%1 tries to detect the indentation settings based on the file contents. It " + "will fallback to the settings below if the detection fails.") + .arg(QGuiApplication::applicationDisplayName())); + m_tabPolicy = new QComboBox(this); m_tabPolicy->addItem(Tr::tr("Spaces Only")); m_tabPolicy->addItem(Tr::tr("Tabs Only")); - m_tabPolicy->addItem(Tr::tr("Mixed")); auto tabSizeLabel = new QLabel(Tr::tr("Ta&b size:")); m_tabSize = new QSpinBox(this); m_tabSize->setRange(1, 20); - auto indentSizeLabel = new QLabel(Tr::tr("&Indent size:")); + auto indentSizeLabel = new QLabel(Tr::tr("Default &indent size:")); m_indentSize = new QSpinBox(this); m_indentSize->setRange(1, 20); @@ -89,15 +95,18 @@ TabSettingsWidget::TabSettingsWidget(QWidget *parent) : Row { Form { m_codingStyleWarning, br, - Tr::tr("Tab policy:"), m_tabPolicy, br, - tabSizeLabel, m_tabSize, br, + m_autoDetect, br, + Tr::tr("Default tab policy:"), m_tabPolicy, br, indentSizeLabel, m_indentSize, br, + tabSizeLabel, m_tabSize, br, Tr::tr("Align continuation lines:"), m_continuationAlignBehavior, br }, st }.attachTo(this); connect(m_codingStyleWarning, &QLabel::linkActivated, this, &TabSettingsWidget::codingStyleLinkActivated); + connect(m_autoDetect, &QCheckBox::stateChanged, + this, &TabSettingsWidget::slotSettingsChanged); connect(m_tabPolicy, &QComboBox::currentIndexChanged, this, &TabSettingsWidget::slotSettingsChanged); connect(m_tabSize, &QSpinBox::valueChanged, @@ -113,7 +122,7 @@ TabSettingsWidget::~TabSettingsWidget() = default; void TabSettingsWidget::setTabSettings(const TabSettings &s) { QSignalBlocker blocker(this); - m_tabPolicy->setCurrentIndex(s.m_tabPolicy); + m_tabPolicy->setCurrentIndex(int(s.m_tabPolicy)); m_tabSize->setValue(s.m_tabSize); m_indentSize->setValue(s.m_indentSize); m_continuationAlignBehavior->setCurrentIndex(s.m_continuationAlignBehavior); diff --git a/src/plugins/texteditor/tabsettingswidget.h b/src/plugins/texteditor/tabsettingswidget.h index 802dde8b075..3de6891f750 100644 --- a/src/plugins/texteditor/tabsettingswidget.h +++ b/src/plugins/texteditor/tabsettingswidget.h @@ -8,6 +8,7 @@ #include QT_BEGIN_NAMESPACE +class QCheckBox; class QComboBox; class QLabel; class QSpinBox; @@ -44,6 +45,7 @@ private: void codingStyleLinkActivated(const QString &linkString); QLabel *m_codingStyleWarning; + QCheckBox *m_autoDetect; QComboBox *m_tabPolicy; QSpinBox *m_tabSize; QSpinBox *m_indentSize; diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index b52dafc150d..ccc0cb216bb 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -153,7 +153,7 @@ MultiTextCursor TextDocumentPrivate::indentOrUnindent(const MultiTextCursor &cur = tabSettings.indentedColumn(tabSettings.columnAt(text, indentPosition), doIndent); cursor.setPosition(block.position() + indentPosition); - cursor.insertText(tabSettings.indentationString(0, targetColumn, 0, block)); + cursor.insertText(tabSettings.indentationString(0, targetColumn, 0)); cursor.setPosition(block.position()); cursor.setPosition(block.position() + indentPosition, QTextCursor::KeepAnchor); cursor.removeSelectedText(); @@ -184,7 +184,7 @@ MultiTextCursor TextDocumentPrivate::indentOrUnindent(const MultiTextCursor &cur QTextCursor::KeepAnchor); cursor.removeSelectedText(); cursor.insertText( - tabSettings.indentationString(startColumn, targetColumn, 0, startBlock)); + tabSettings.indentationString(startColumn, targetColumn, 0)); } cursor.endEditBlock(); @@ -367,13 +367,13 @@ const StorageSettings &TextDocument::storageSettings() const return d->m_storageSettings; } -void TextDocument::setTabSettings(const TabSettings &newTabSettings) +void TextDocument::setTabSettings(const TabSettings &tabSettings) { - if (newTabSettings == d->m_tabSettings) - return; - d->m_tabSettings = newTabSettings; - - emit tabSettingsChanged(); + if (const TabSettings candidate = tabSettings.autoDetect(document()); + candidate != d->m_tabSettings) { + d->m_tabSettings = candidate; + emit tabSettingsChanged(); + } } TabSettings TextDocument::tabSettings() const @@ -752,6 +752,7 @@ Core::IDocument::OpenResult TextDocument::open(QString *errorString, OpenResult success = openImpl(errorString, filePath, realFilePath, /*reload =*/ false); if (success == OpenResult::Success) { setMimeType(Utils::mimeTypeForFile(filePath, MimeMatchMode::MatchDefaultAndRemote).name()); + setTabSettings(d->m_tabSettings); emit openFinishedSuccessfully(); } return success; @@ -960,8 +961,7 @@ void TextDocument::cleanWhitespace(QTextCursor &cursor, bool inEntireDocument, } else { int column = currentTabSettings.columnAt(blockText, firstNonSpace); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace); - QString indentationString = currentTabSettings.indentationString(0, column, column - indent, block); - cursor.insertText(indentationString); + cursor.insertText(currentTabSettings.indentationString(0, column, column - indent)); } } } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 5ddc6f1dcc1..1fc21b2b22e 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -302,9 +302,6 @@ private: case TabSettings::TabsOnlyTabPolicy: policy = Tr::tr("Tabs"); break; - case TabSettings::MixedTabPolicy: - policy = Tr::tr("Mixed"); - break; } setText(QString("%1: %2").arg(policy).arg(ts.m_indentSize)); } @@ -321,6 +318,7 @@ private: [this](std::function modifier) { return [this, modifier]() { auto ts = m_doc->tabSettings(); + ts.m_autoDetect = false; modifier(ts); m_doc->setTabSettings(ts); }; @@ -328,7 +326,7 @@ private: documentSettings->addAction( Tr::tr("Auto detect"), modifyTabSettings([doc = m_doc->document()](TabSettings &tabSettings) { - tabSettings = tabSettings.autoDetect(doc); + tabSettings.m_autoDetect = true; })); auto tabSettings = documentSettings->addMenu(Tr::tr("Tab Settings")); tabSettings->addAction(Tr::tr("Spaces"), modifyTabSettings([](TabSettings &tabSettings) { @@ -8999,7 +8997,7 @@ void TextEditorWidget::rewrapParagraph() QString spacing; if (commonPrefix.isEmpty()) { - spacing = ts.indentationString(0, indentLevel, 0, textCursor().block()); + spacing = ts.indentationString(0, indentLevel, 0); } else { spacing = commonPrefix; indentLevel = ts.columnCountForText(spacing); diff --git a/src/plugins/texteditor/texteditor_test.cpp b/src/plugins/texteditor/texteditor_test.cpp index c82804ee992..604770e5e1d 100644 --- a/src/plugins/texteditor/texteditor_test.cpp +++ b/src/plugins/texteditor/texteditor_test.cpp @@ -17,8 +17,6 @@ static QString tabPolicyToString(TabSettings::TabPolicy policy) return QLatin1String("spacesOnlyPolicy"); case TabSettings::TabsOnlyTabPolicy: return QLatin1String("tabsOnlyPolicy"); - case TabSettings::MixedTabPolicy: - return QLatin1String("mixedIndentPolicy"); } return QString(); } @@ -49,7 +47,6 @@ static void generateTestRows(const QLatin1String &name, const QString &text, IsC const QVector allPolicies = { TabSettings::SpacesOnlyTabPolicy, TabSettings::TabsOnlyTabPolicy, - TabSettings::MixedTabPolicy }; const QVector allbehaviors = { TabSettings::NoContinuationAlign, From e1c08a3b2ad5ee6d750d1fbc636683aa55cc2eb4 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 3 Dec 2024 12:08:49 +0100 Subject: [PATCH 416/989] Editor: Add option to hide tab setting button Change-Id: Idba9e5d6c080f51342dde20bc6ab6e82f12e3cd5 Reviewed-by: Christian Stenger --- src/plugins/texteditor/displaysettings.cpp | 4 ++++ src/plugins/texteditor/displaysettings.h | 1 + src/plugins/texteditor/displaysettingspage.cpp | 5 +++++ src/plugins/texteditor/texteditor.cpp | 9 +++++++++ 4 files changed, 19 insertions(+) diff --git a/src/plugins/texteditor/displaysettings.cpp b/src/plugins/texteditor/displaysettings.cpp index fac753b5943..a6a9ecb581f 100644 --- a/src/plugins/texteditor/displaysettings.cpp +++ b/src/plugins/texteditor/displaysettings.cpp @@ -31,6 +31,7 @@ const char centerCursorOnScrollKey[] = "CenterCursorOnScroll"; const char openLinksInNextSplitKey[] = "OpenLinksInNextSplitKey"; const char displayFileEncodingKey[] = "DisplayFileEncoding"; const char displayFileLineEndingKey[] = "DisplayFileLineEnding"; +const char displayTabSettingsKey[] = "DisplayTabSettings"; const char scrollBarHighlightsKey[] = "ScrollBarHighlights"; const char animateNavigationWithinFileKey[] = "AnimateNavigationWithinFile"; const char animateWithinFileTimeMaxKey[] = "AnimateWithinFileTimeMax"; @@ -58,6 +59,7 @@ void DisplaySettings::toSettings(QtcSettings *s) const s->setValue(openLinksInNextSplitKey, m_openLinksInNextSplit); s->setValue(displayFileEncodingKey, m_displayFileEncoding); s->setValue(displayFileLineEndingKey, m_displayFileLineEnding); + s->setValue(displayTabSettingsKey, m_displayTabSettings); s->setValue(scrollBarHighlightsKey, m_scrollBarHighlights); s->setValue(animateNavigationWithinFileKey, m_animateNavigationWithinFile); s->setValue(displayAnnotationsKey, m_displayAnnotations); @@ -86,6 +88,7 @@ void DisplaySettings::fromSettings(QtcSettings *s) m_openLinksInNextSplit = s->value(openLinksInNextSplitKey, m_openLinksInNextSplit).toBool(); m_displayFileEncoding = s->value(displayFileEncodingKey, m_displayFileEncoding).toBool(); m_displayFileLineEnding = s->value(displayFileLineEndingKey, m_displayFileLineEnding).toBool(); + m_displayTabSettings = s->value(displayTabSettingsKey, m_displayTabSettings).toBool(); m_scrollBarHighlights = s->value(scrollBarHighlightsKey, m_scrollBarHighlights).toBool(); m_animateNavigationWithinFile = s->value(animateNavigationWithinFileKey, m_animateNavigationWithinFile).toBool(); m_animateWithinFileTimeMax = s->value(animateWithinFileTimeMaxKey, m_animateWithinFileTimeMax).toInt(); @@ -116,6 +119,7 @@ bool DisplaySettings::equals(const DisplaySettings &ds) const && m_forceOpenLinksInNextSplit == ds.m_forceOpenLinksInNextSplit && m_displayFileEncoding == ds.m_displayFileEncoding && m_displayFileLineEnding == ds.m_displayFileLineEnding + && m_displayTabSettings == ds.m_displayTabSettings && m_scrollBarHighlights == ds.m_scrollBarHighlights && m_animateNavigationWithinFile == ds.m_animateNavigationWithinFile && m_animateWithinFileTimeMax == ds.m_animateWithinFileTimeMax diff --git a/src/plugins/texteditor/displaysettings.h b/src/plugins/texteditor/displaysettings.h index bb42a9ac935..6aa15e9c950 100644 --- a/src/plugins/texteditor/displaysettings.h +++ b/src/plugins/texteditor/displaysettings.h @@ -50,6 +50,7 @@ public: bool m_forceOpenLinksInNextSplit = false; bool m_displayFileEncoding = false; bool m_displayFileLineEnding = true; + bool m_displayTabSettings = true; bool m_scrollBarHighlights = true; bool m_animateNavigationWithinFile = false; bool m_highlightSelection = true; diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index 84b73f3a625..05973aefc3f 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -92,6 +92,7 @@ public: visualizeIndent = new QCheckBox(Tr::tr("Visualize indent")); displayFileLineEnding = new QCheckBox(Tr::tr("Display file line ending")); displayFileEncoding = new QCheckBox(Tr::tr("Display file encoding")); + displayTabSettings = new QCheckBox(Tr::tr("Display tab settings")); openLinksInNextSplit = new QCheckBox(Tr::tr("Always open links in another split")); highlightMatchingParentheses = new QCheckBox(Tr::tr("&Highlight matching parentheses")); @@ -158,6 +159,7 @@ public: openLinksInNextSplit, displayFileEncoding, displayFileLineEnding, + displayTabSettings, st } } @@ -197,6 +199,7 @@ public: QCheckBox *visualizeIndent; QCheckBox *displayFileLineEnding; QCheckBox *displayFileEncoding; + QCheckBox *displayTabSettings; QCheckBox *openLinksInNextSplit; QCheckBox *highlightMatchingParentheses; QCheckBox *visualizeWhitespace; @@ -240,6 +243,7 @@ void DisplaySettingsWidget::settingsFromUI(DisplaySettings &displaySettings, displaySettings.m_centerCursorOnScroll = centerOnScroll->isChecked(); displaySettings.m_openLinksInNextSplit = openLinksInNextSplit->isChecked(); displaySettings.m_displayFileEncoding = displayFileEncoding->isChecked(); + displaySettings.m_displayTabSettings = displayTabSettings->isChecked(); displaySettings.m_displayFileLineEnding = displayFileLineEnding->isChecked(); displaySettings.m_scrollBarHighlights = scrollBarHighlights->isChecked(); displaySettings.m_animateNavigationWithinFile = animateNavigationWithinFile->isChecked(); @@ -280,6 +284,7 @@ void DisplaySettingsWidget::settingsToUI() openLinksInNextSplit->setChecked(displaySettings.m_openLinksInNextSplit); displayFileEncoding->setChecked(displaySettings.m_displayFileEncoding); displayFileLineEnding->setChecked(displaySettings.m_displayFileLineEnding); + displayTabSettings->setChecked(displaySettings.m_displayTabSettings); scrollBarHighlights->setChecked(displaySettings.m_scrollBarHighlights); animateNavigationWithinFile->setChecked(displaySettings.m_animateNavigationWithinFile); displayAnnotations->setChecked(displaySettings.m_displayAnnotations); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 1fc21b2b22e..ce8b9918297 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -853,6 +853,7 @@ public: void _q_animateUpdate(const QTextCursor &cursor, QPointF lastPos, QRectF rect); void updateCodeFoldingVisible(); void updateFileLineEndingVisible(); + void updateTabSettingsButtonVisible(); void reconfigure(); void updateSyntaxInfoBar(const HighlighterHelper::Definitions &definitions, const QString &fileName); @@ -1228,6 +1229,7 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent) m_tabSettingsButton = new TabSettingsButton(q); m_tabSettingsButton->setContentsMargins(spacing, 0, spacing, 0); m_toolBarWidget->layout()->addWidget(m_tabSettingsButton); + updateTabSettingsButtonVisible(); m_fileLineEnding = new QToolButton(q); m_fileLineEnding->setContentsMargins(spacing, 0, spacing, 0); @@ -3649,6 +3651,7 @@ bool TextEditorWidget::event(QEvent *e) } case QEvent::ReadOnlyChange: d->updateFileLineEndingVisible(); + d->updateTabSettingsButtonVisible(); if (isReadOnly()) setTextInteractionFlags(textInteractionFlags() | Qt::TextSelectableByKeyboard); d->updateActions(); @@ -3909,6 +3912,11 @@ void TextEditorWidgetPrivate::updateFileLineEndingVisible() m_fileLineEndingAction->setVisible(m_displaySettings.m_displayFileLineEnding && !q->isReadOnly()); } +void TextEditorWidgetPrivate::updateTabSettingsButtonVisible() +{ + m_tabSettingsButton->setVisible(m_displaySettings.m_displayTabSettings && !q->isReadOnly()); +} + void TextEditorWidgetPrivate::reconfigure() { m_document->setMimeType( @@ -9189,6 +9197,7 @@ void TextEditorWidget::setDisplaySettings(const DisplaySettings &ds) d->updateCodeFoldingVisible(); d->updateFileLineEndingVisible(); + d->updateTabSettingsButtonVisible(); d->updateHighlights(); d->setupScrollBar(); d->updateCursorSelections(); From 9157e9ddd7322b9dea52c8d6a5ca1c942106b3e7 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 16 Dec 2024 10:15:23 +0200 Subject: [PATCH 417/989] TextEditor: Respect and store autodetect setting Amends 08a66b778064ece5f01ee3323d8a5b5171b02c09. Change-Id: I250fa295cfd9270c1598bcda451bc5b6fd19804c Reviewed-by: David Schulz --- src/plugins/texteditor/tabsettingswidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/texteditor/tabsettingswidget.cpp b/src/plugins/texteditor/tabsettingswidget.cpp index fb48fa7a6b8..a7a025f0b87 100644 --- a/src/plugins/texteditor/tabsettingswidget.cpp +++ b/src/plugins/texteditor/tabsettingswidget.cpp @@ -122,6 +122,7 @@ TabSettingsWidget::~TabSettingsWidget() = default; void TabSettingsWidget::setTabSettings(const TabSettings &s) { QSignalBlocker blocker(this); + m_autoDetect->setChecked(s.m_autoDetect); m_tabPolicy->setCurrentIndex(int(s.m_tabPolicy)); m_tabSize->setValue(s.m_tabSize); m_indentSize->setValue(s.m_indentSize); @@ -132,6 +133,7 @@ TabSettings TabSettingsWidget::tabSettings() const { TabSettings set; + set.m_autoDetect = m_autoDetect->isChecked(); set.m_tabPolicy = TabSettings::TabPolicy(m_tabPolicy->currentIndex()); set.m_tabSize = m_tabSize->value(); set.m_indentSize = m_indentSize->value(); From 7f50b0a9efdf44af5bb4b95666e960259736b132 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Dec 2024 15:02:16 +0100 Subject: [PATCH 418/989] RemoteLinux: Use the 'local' executable as remote executable ... for real remote builds with build and run device the same. This brushes over the fact that the deployment data stays currently empty for remote cmake builds. Change-Id: I7bfa2907791306a66f8b94c5f8851498284539ca Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/remotelinuxrunconfiguration.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp index 0b74373c0e6..bb0050eb376 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp @@ -71,6 +71,11 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Id id) executable.setExecutable(runDevice->filePath(depFile.remoteFilePath())); symbolFile.setValue(localExecutable); + + // Hack for remote build == run: deploymentData is empty when the deploy step is disabled. + if (executable().isEmpty() && buildDevice == runDevice) + executable.setExecutable(localExecutable); + useLibraryPath.setEnabled(buildDevice == runDevice); }); From dc524987afcae42e56d5d57558129fc3c42ef259 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 3 Dec 2024 13:56:18 +0100 Subject: [PATCH 419/989] Utils: Merge one FileReader use in its only user Change-Id: Ie9ab42b33c0fe95bb17d82f07ad83a32324e459c Reviewed-by: Eike Ziller --- src/libs/utils/fileutils.cpp | 11 ----------- src/libs/utils/fileutils.h | 3 --- src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 4 +++- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 885375fb172..626b0e08fe8 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -83,17 +83,6 @@ bool FileReader::fetch(const FilePath &filePath, QString *errorString) return false; } -#ifdef QT_GUI_LIB -bool FileReader::fetch(const FilePath &filePath, QWidget *parent) -{ - if (fetch(filePath)) - return true; - if (parent) - QMessageBox::critical(parent, Tr::tr("File Error"), m_errorString); - return false; -} -#endif // QT_GUI_LIB - // FileSaver FileSaverBase::FileSaverBase() = default; diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 2f23277fef2..274535c2d3e 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -151,9 +151,6 @@ public: static QByteArray fetchQrc(const QString &fileName); // Only for internal resources bool fetch(const FilePath &filePath); bool fetch(const FilePath &filePath, QString *errorString); -#ifdef QT_GUI_LIB - bool fetch(const FilePath &filePath, QWidget *parent); -#endif // QT_GUI_LIB const QByteArray &data() const { return m_data; } QByteArray text() const; // data with replaced \r\n -> \n const QString &errorString() const { return m_errorString; } diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 2c9b917240a..54c7ed8da90 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -242,8 +242,10 @@ static inline QStringList fieldTexts(const QString &fileContents) void VcsBaseSubmitEditor::createUserFields(const FilePath &fieldConfigFile) { FileReader reader; - if (!reader.fetch(fieldConfigFile, ICore::dialogParent())) + if (!reader.fetch(fieldConfigFile)) { + QMessageBox::critical(ICore::dialogParent(), Tr::tr("File Error"), reader.errorString()); return; + } // Parse into fields const QStringList fields = fieldTexts(QString::fromUtf8(reader.text())); From 00f36bcfce22b401e1c857c5733296c72a2428d1 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 13 Dec 2024 10:45:25 +0100 Subject: [PATCH 420/989] TextEditor: avoid leaking the tab settings button menu Fixes: QTCREATORBUG-32161 Change-Id: I499a24d8ed80d710df8b45ad30fa5c68a4acfb20 Reviewed-by: Eike Ziller --- src/plugins/texteditor/texteditor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index ce8b9918297..bbd1354f768 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -309,8 +309,9 @@ private: void showMenu() { QTC_ASSERT(m_doc, return); - auto menu = new QMenu; + auto menu = new QMenu(this); menu->addAction(ActionManager::command(Constants::AUTO_INDENT_SELECTION)->action()); + menu->setAttribute(Qt::WA_DeleteOnClose); if (auto indenter = m_doc->indenter(); indenter && indenter->respectsTabSettings()) { auto documentSettings = menu->addMenu(Tr::tr("Document Settings")); From 59c66634c748296103c173b172afc83c6889fda9 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 13 Dec 2024 10:57:09 +0100 Subject: [PATCH 421/989] Editor: avoid leaking menu of file line ending button Change-Id: I6fa12cceb5b97764f958f203084f921ef9143f93 Reviewed-by: Eike Ziller --- src/plugins/texteditor/texteditor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index bbd1354f768..97b67e45248 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -1293,7 +1293,8 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent) q, &TextEditorWidget::selectEncoding); connect(m_fileLineEnding, &QToolButton::clicked, ActionManager::instance(), [this] { - QMenu *menu = new QMenu; + QMenu *menu = new QMenu(q); + menu->setAttribute(Qt::WA_DeleteOnClose); menu->addAction(Tr::tr("Unix Line Endings (LF)"), [this] { q->selectLineEnding(TextFileFormat::LFLineTerminator); }); menu->addAction(Tr::tr("Windows Line Endings (CRLF)"), From deaae35e986c28b491e231a27a28b40851125631 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 13 Dec 2024 10:57:41 +0100 Subject: [PATCH 422/989] LanguageClient: fix leaking menu of editor toolbar button Change-Id: Ie8b1fc5e48cd3e22d3c8eefa11a553d42afeb469 Reviewed-by: Eike Ziller --- src/plugins/languageclient/languageclientutils.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index a8c1a02c4ca..9679d07769d 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -249,8 +249,9 @@ void updateEditorToolBar(Core::IEditor *editor) const QIcon icon = Utils::Icon({{":/languageclient/images/languageclient.png", Utils::Theme::IconsBaseColor}}).icon(); extras->m_popupAction = widget->toolBar()->addAction( - icon, client->name(), [document = QPointer(document), client = QPointer(client)] { - auto menu = new QMenu; + icon, client->name(), [widget, document = QPointer(document), client = QPointer(client)] { + auto menu = new QMenu(widget); + menu->setAttribute(Qt::WA_DeleteOnClose); auto clientsGroup = new QActionGroup(menu); clientsGroup->setExclusive(true); for (auto client : LanguageClientManager::clientsSupportingDocument(document, false)) { From a4fd26cfa0d9fc15efd8c35d34f32f50a725f5cc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 13 Dec 2024 16:32:23 +0100 Subject: [PATCH 423/989] ICodeStylePreferences: Remove codeStyleSettingsChanged() signals ...from its subclasses. They are not used. Change-Id: I6204bf24d89481fb0a70ba48d9c378a1e802bef3 Reviewed-by: David Schulz --- src/plugins/cppeditor/cppcodestylepreferences.cpp | 1 - src/plugins/cppeditor/cppcodestylepreferences.h | 1 - src/plugins/qmljstools/qmljscodestylepreferences.cpp | 1 - src/plugins/qmljstools/qmljscodestylepreferences.h | 1 - 4 files changed, 4 deletions(-) diff --git a/src/plugins/cppeditor/cppcodestylepreferences.cpp b/src/plugins/cppeditor/cppcodestylepreferences.cpp index cb04d4e12cb..75ed819c3bd 100644 --- a/src/plugins/cppeditor/cppcodestylepreferences.cpp +++ b/src/plugins/cppeditor/cppcodestylepreferences.cpp @@ -48,7 +48,6 @@ void CppCodeStylePreferences::setCodeStyleSettings(const CppCodeStyleSettings &d QVariant v; v.setValue(data); emit valueChanged(v); - emit codeStyleSettingsChanged(m_data); if (!currentDelegate()) emit currentValueChanged(v); } diff --git a/src/plugins/cppeditor/cppcodestylepreferences.h b/src/plugins/cppeditor/cppcodestylepreferences.h index 6ee7d8fc136..79837fdf5c6 100644 --- a/src/plugins/cppeditor/cppcodestylepreferences.h +++ b/src/plugins/cppeditor/cppcodestylepreferences.h @@ -32,7 +32,6 @@ public slots: void setCodeStyleSettings(const CppCodeStyleSettings &data); signals: - void codeStyleSettingsChanged(const CppCodeStyleSettings &); void currentCodeStyleSettingsChanged(const CppCodeStyleSettings &); private: diff --git a/src/plugins/qmljstools/qmljscodestylepreferences.cpp b/src/plugins/qmljstools/qmljscodestylepreferences.cpp index 679dd561f09..16a2c5deba3 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferences.cpp +++ b/src/plugins/qmljstools/qmljscodestylepreferences.cpp @@ -48,7 +48,6 @@ void QmlJSCodeStylePreferences::setCodeStyleSettings(const QmlJSCodeStyleSetting QVariant v; v.setValue(data); emit valueChanged(v); - emit codeStyleSettingsChanged(m_data); if (!currentDelegate()) emit currentValueChanged(v); } diff --git a/src/plugins/qmljstools/qmljscodestylepreferences.h b/src/plugins/qmljstools/qmljscodestylepreferences.h index 7a8dcc83d86..8963a364db5 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferences.h +++ b/src/plugins/qmljstools/qmljscodestylepreferences.h @@ -32,7 +32,6 @@ public slots: void setCodeStyleSettings(const QmlJSCodeStyleSettings &data); signals: - void codeStyleSettingsChanged(const QmlJSCodeStyleSettings &); void currentCodeStyleSettingsChanged(const QmlJSCodeStyleSettings &); private: From cabb1bb42aee43d8de5ff197ca6ba058f9e2025d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 16 Dec 2024 08:50:56 +0100 Subject: [PATCH 424/989] ICodeStyleSettings: Remove currentCodeStyleSettingsChanged() signals ...from its subclasses. Reuse currentValueChanged() instead. Change-Id: Iea696717176cc1a9557cf8ec3f0a1cf139cad7ed Reviewed-by: David Schulz --- src/plugins/cppeditor/cppcodestylepreferences.cpp | 11 ----------- src/plugins/cppeditor/cppcodestylepreferences.h | 6 ------ src/plugins/cppeditor/cppcodestylesettingspage.cpp | 5 ++--- src/plugins/qmljstools/qmljscodestylepreferences.cpp | 11 ----------- src/plugins/qmljstools/qmljscodestylepreferences.h | 6 ------ .../qmljstools/qmljscodestylepreferenceswidget.cpp | 8 ++++---- src/plugins/qmljstools/qmljscodestylesettingspage.cpp | 2 +- .../qmljstools/qmljscodestylesettingswidget.cpp | 4 ++-- src/plugins/qmljstools/qmljscodestylesettingswidget.h | 2 +- 9 files changed, 10 insertions(+), 45 deletions(-) diff --git a/src/plugins/cppeditor/cppcodestylepreferences.cpp b/src/plugins/cppeditor/cppcodestylepreferences.cpp index 75ed819c3bd..c6afa32c26d 100644 --- a/src/plugins/cppeditor/cppcodestylepreferences.cpp +++ b/src/plugins/cppeditor/cppcodestylepreferences.cpp @@ -13,9 +13,6 @@ CppCodeStylePreferences::CppCodeStylePreferences(QObject *parent) : { setSettingsSuffix("CodeStyleSettings"); setGlobalSettingsCategory(Constants::CPP_CODE_STYLE_SETTINGS_ID); - - connect(this, &CppCodeStylePreferences::currentValueChanged, - this, &CppCodeStylePreferences::slotCurrentValueChanged); } QVariant CppCodeStylePreferences::value() const @@ -62,14 +59,6 @@ CppCodeStyleSettings CppCodeStylePreferences::currentCodeStyleSettings() const return v.value(); } -void CppCodeStylePreferences::slotCurrentValueChanged(const QVariant &value) -{ - if (!value.canConvert()) - return; - - emit currentCodeStyleSettingsChanged(value.value()); -} - Store CppCodeStylePreferences::toMap() const { Store map = ICodeStylePreferences::toMap(); diff --git a/src/plugins/cppeditor/cppcodestylepreferences.h b/src/plugins/cppeditor/cppcodestylepreferences.h index 79837fdf5c6..164271789fb 100644 --- a/src/plugins/cppeditor/cppcodestylepreferences.h +++ b/src/plugins/cppeditor/cppcodestylepreferences.h @@ -28,15 +28,9 @@ public: Utils::Store toMap() const override; void fromMap(const Utils::Store &map) override; -public slots: void setCodeStyleSettings(const CppCodeStyleSettings &data); -signals: - void currentCodeStyleSettingsChanged(const CppCodeStyleSettings &); - private: - void slotCurrentValueChanged(const QVariant &); - CppCodeStyleSettings m_data; }; diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.cpp b/src/plugins/cppeditor/cppcodestylesettingspage.cpp index 500b6ae9bdb..7edbeb10985 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.cpp +++ b/src/plugins/cppeditor/cppcodestylesettingspage.cpp @@ -356,9 +356,8 @@ void CppCodeStylePreferencesWidget::setCodeStyle(CppCodeStylePreferences *codeSt connect(m_preferences, &CppCodeStylePreferences::currentTabSettingsChanged, this, &CppCodeStylePreferencesWidget::setTabSettings); - connect(m_preferences, &CppCodeStylePreferences::currentCodeStyleSettingsChanged, - this, [this](const CppCodeStyleSettings &codeStyleSettings) { - setCodeStyleSettings(codeStyleSettings); + connect(m_preferences, &CppCodeStylePreferences::currentValueChanged, this, [this] { + setCodeStyleSettings(m_preferences->currentCodeStyleSettings()); }); connect(m_preferences, &ICodeStylePreferences::currentPreferencesChanged, diff --git a/src/plugins/qmljstools/qmljscodestylepreferences.cpp b/src/plugins/qmljstools/qmljscodestylepreferences.cpp index 16a2c5deba3..b5bc2bb5b24 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferences.cpp +++ b/src/plugins/qmljstools/qmljscodestylepreferences.cpp @@ -13,9 +13,6 @@ QmlJSCodeStylePreferences::QmlJSCodeStylePreferences(QObject *parent) : { setSettingsSuffix("CodeStyleSettings"); setGlobalSettingsCategory(Constants::QML_JS_CODE_STYLE_SETTINGS_ID); - - connect(this, &QmlJSCodeStylePreferences::currentValueChanged, - this, &QmlJSCodeStylePreferences::slotCurrentValueChanged); } QVariant QmlJSCodeStylePreferences::value() const @@ -62,14 +59,6 @@ QmlJSCodeStyleSettings QmlJSCodeStylePreferences::currentCodeStyleSettings() con return v.value(); } -void QmlJSCodeStylePreferences::slotCurrentValueChanged(const QVariant &value) -{ - if (!value.canConvert()) - return; - - emit currentCodeStyleSettingsChanged(value.value()); -} - Store QmlJSCodeStylePreferences::toMap() const { Store map = ICodeStylePreferences::toMap(); diff --git a/src/plugins/qmljstools/qmljscodestylepreferences.h b/src/plugins/qmljstools/qmljscodestylepreferences.h index 8963a364db5..038bff52120 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferences.h +++ b/src/plugins/qmljstools/qmljscodestylepreferences.h @@ -28,15 +28,9 @@ public: Utils::Store toMap() const override; void fromMap(const Utils::Store &map) override; -public slots: void setCodeStyleSettings(const QmlJSCodeStyleSettings &data); -signals: - void currentCodeStyleSettingsChanged(const QmlJSCodeStyleSettings &); - private: - void slotCurrentValueChanged(const QVariant &); - QmlJSCodeStyleSettings m_data; }; diff --git a/src/plugins/qmljstools/qmljscodestylepreferenceswidget.cpp b/src/plugins/qmljstools/qmljscodestylepreferenceswidget.cpp index 8cb727368c7..65a6a1de15b 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferenceswidget.cpp +++ b/src/plugins/qmljstools/qmljscodestylepreferenceswidget.cpp @@ -30,8 +30,7 @@ void QmlJSCodeStylePreferencesWidget::setPreferences(QmlJSCodeStylePreferences * // cleanup old if (m_preferences) { - disconnect(m_preferences, &QmlJSCodeStylePreferences::currentCodeStyleSettingsChanged, - m_codeStyleSettingsWidget, &QmlJSCodeStyleSettingsWidget::setCodeStyleSettings); + disconnect(m_preferences, &QmlJSCodeStylePreferences::currentValueChanged, this, nullptr); disconnect(m_preferences, &QmlJSCodeStylePreferences::currentPreferencesChanged, this, &QmlJSCodeStylePreferencesWidget::slotCurrentPreferencesChanged); disconnect(m_codeStyleSettingsWidget, &QmlJSCodeStyleSettingsWidget::settingsChanged, @@ -42,8 +41,9 @@ void QmlJSCodeStylePreferencesWidget::setPreferences(QmlJSCodeStylePreferences * if (m_preferences) { m_codeStyleSettingsWidget->setCodeStyleSettings(m_preferences->currentCodeStyleSettings()); - connect(m_preferences, &QmlJSCodeStylePreferences::currentCodeStyleSettingsChanged, - m_codeStyleSettingsWidget, &QmlJSCodeStyleSettingsWidget::setCodeStyleSettings); + connect(m_preferences, &QmlJSCodeStylePreferences::currentValueChanged, this, [this] { + m_codeStyleSettingsWidget->setCodeStyleSettings(m_preferences->currentCodeStyleSettings()); + }); connect(m_preferences, &QmlJSCodeStylePreferences::currentPreferencesChanged, this, &QmlJSCodeStylePreferencesWidget::slotCurrentPreferencesChanged); connect(m_codeStyleSettingsWidget, &QmlJSCodeStyleSettingsWidget::settingsChanged, diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp index 70420def1c4..8f1bcc7c45b 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp @@ -74,7 +74,7 @@ void QmlJSCodeStylePreferencesWidget::setPreferences(QmlJSCodeStylePreferences * { connect(m_preferences, &ICodeStylePreferences::currentTabSettingsChanged, this, &QmlJSCodeStylePreferencesWidget::slotSettingsChanged); - connect(m_preferences, &QmlJSCodeStylePreferences::currentCodeStyleSettingsChanged, + connect(m_preferences, &QmlJSCodeStylePreferences::currentValueChanged, this, &QmlJSCodeStylePreferencesWidget::slotSettingsChanged); } updatePreview(); diff --git a/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp b/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp index 9fee7205b3d..093fc3ff4f4 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp @@ -36,10 +36,10 @@ QmlJSCodeStyleSettingsWidget::QmlJSCodeStyleSettingsWidget(QWidget *parent) this, &QmlJSCodeStyleSettingsWidget::slotSettingsChanged); } -void QmlJSCodeStyleSettingsWidget::setCodeStyleSettings(const QmlJSCodeStyleSettings& s) +void QmlJSCodeStyleSettingsWidget::setCodeStyleSettings(const QmlJSCodeStyleSettings &settings) { QSignalBlocker blocker(this); - m_lineLengthSpinBox->setValue(s.lineLength); + m_lineLengthSpinBox->setValue(settings.lineLength); } QmlJSCodeStyleSettings QmlJSCodeStyleSettingsWidget::codeStyleSettings() const diff --git a/src/plugins/qmljstools/qmljscodestylesettingswidget.h b/src/plugins/qmljstools/qmljscodestylesettingswidget.h index 05297a4263f..3f08a52c402 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingswidget.h +++ b/src/plugins/qmljstools/qmljscodestylesettingswidget.h @@ -29,7 +29,7 @@ public: QmlJSCodeStyleSettings codeStyleSettings() const; void setCodingStyleWarningVisible(bool visible); - void setCodeStyleSettings(const QmlJSCodeStyleSettings& s); + void setCodeStyleSettings(const QmlJSCodeStyleSettings &settings); signals: void settingsChanged(const QmlJSCodeStyleSettings &); From 0dd875a7fb421916b85a8ece25770a80eaf2baf0 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 9 Dec 2024 16:20:50 +0100 Subject: [PATCH 425/989] RemoteLinux: Use GoCmdBridge This sets up the shell access as usual, and if that is successful tries to "upgrade" the file access to the cmdbridge, effectively leaving most of the setup logic as-is. Task-number: QTCREATORBUG-26870 Change-Id: Ibc20769810bd619a5c711ee70ef48b8cad47eda3 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/CMakeLists.txt | 2 +- src/plugins/remotelinux/linuxdevice.cpp | 30 +++++++++++++++++++------ src/plugins/remotelinux/remotelinux.qbs | 2 ++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/plugins/remotelinux/CMakeLists.txt b/src/plugins/remotelinux/CMakeLists.txt index d1d45cbe86c..81cb31e77f9 100644 --- a/src/plugins/remotelinux/CMakeLists.txt +++ b/src/plugins/remotelinux/CMakeLists.txt @@ -1,5 +1,5 @@ add_qtc_plugin(RemoteLinux - DEPENDS QmlDebug + DEPENDS QmlDebug CmdBridgeClient PLUGIN_DEPENDS Core Debugger ProjectExplorer SOURCES abstractremotelinuxdeploystep.cpp abstractremotelinuxdeploystep.h diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index bda9b9e6e10..4f065b1766d 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -16,6 +16,9 @@ #include #include +#include +#include + #include #include #include @@ -338,9 +341,11 @@ public: void invalidateEnvironmentCache(); LinuxDevice *q = nullptr; - LinuxDeviceAccess m_scriptAccess; - UnavailableDeviceFileAccess m_disconnectedAccess; + BoolAspect m_disconnected; + UnavailableDeviceFileAccess m_disconnectedAccess; + LinuxDeviceAccess m_scriptAccess; + CmdBridge::FileAccess m_cmdBridgeAccess; QReadWriteLock m_environmentCacheLock; std::optional m_environmentCache; @@ -1166,14 +1171,25 @@ Result LinuxDevicePrivate::setupShell(const SshParameters &sshParameters, bool a if (announce) unannounceConnectionAttempt(); - if (result) { - setupConnectedAccess(); - setOsTypeFromUnameResult(m_scriptAccess.m_handler->runInShell(unameCommand())); - } else { + if (!result) { setupDisconnectedAccess(); + return result; } - return result; + setupConnectedAccess(); + setOsTypeFromUnameResult(m_scriptAccess.m_handler->runInShell(unameCommand())); + + // We have good shell access now, try to get bridge access, too: + Result initResult = m_cmdBridgeAccess.deployAndInit(Core::ICore::libexecPath(), q->rootPath()); + if (initResult) { + qCDebug(linuxDeviceLog) << "Bridge ok to use"; + q->setFileAccess(&m_cmdBridgeAccess); + } else { + qCDebug(linuxDeviceLog) << "Failed to start CmdBridge:" << initResult.error() + << ", falling back to slow shell access"; + } + + return Result::Ok; // Both are fine. } RunResult LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &data) diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs index c2a91fd2e75..ab45593650f 100644 --- a/src/plugins/remotelinux/remotelinux.qbs +++ b/src/plugins/remotelinux/remotelinux.qbs @@ -2,6 +2,8 @@ QtcPlugin { name: "RemoteLinux" Depends { name: "Qt.widgets" } + + Depends { name: "CmdBridgeClient" } Depends { name: "QmlDebug" } Depends { name: "Utils" } From f429ffe029e0b7e9976c2eafafa87a7f29d8ce3a Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 13 Dec 2024 13:48:16 +0100 Subject: [PATCH 426/989] RemoteLinux: Drop GenericDeployStep's not-same-device restriction This is getting into the way for remote builds as it disabled the GenericCopy version which is in principle always usable. Make this even the preferred version for the build == run case, as this will end up in the fast path of FilePath::copyFile. As a collateral improvement this also removes the error message that was referring to rsync only. Change-Id: Ia27e3733b99f0de0161050c0355f135026b899f5 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/genericdeploystep.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/plugins/remotelinux/genericdeploystep.cpp b/src/plugins/remotelinux/genericdeploystep.cpp index 805c82fc5f3..b1faf9c6b39 100644 --- a/src/plugins/remotelinux/genericdeploystep.cpp +++ b/src/plugins/remotelinux/genericdeploystep.cpp @@ -55,12 +55,6 @@ public: method.addOption(Tr::tr("Use default transfer. This might be slow.")); setInternalInitializer([this]() -> expected_str { - if (BuildDeviceKitAspect::device(kit()) == RunDeviceKitAspect::device(kit())) { - // rsync transfer on the same device currently not implemented - // and typically not wanted. - return make_unexpected( - Tr::tr("rsync is only supported for transfers between different devices.")); - } return isDeploymentPossible(); }); } @@ -121,6 +115,8 @@ static FileTransferMethod effectiveTransferMethodFor(const FileToTransfer &fileT auto targetDevice = ProjectExplorer::DeviceManager::deviceForPath(fileToTransfer.m_target); if (!sourceDevice || !targetDevice) return FileTransferMethod::GenericCopy; + if (sourceDevice == targetDevice) + return FileTransferMethod::GenericCopy; const auto devicesSupportMethod = [&](Id method) { return sourceDevice->extraData(method).toBool() && targetDevice->extraData(method).toBool(); From 1cb8bcf538b20ec281e7786dc60ced4ef49e6e7d Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 16 Dec 2024 17:23:08 +0100 Subject: [PATCH 427/989] Qbs: Replace some .toUserOutput() with .nativePath() ... when constructing the build command line. From the tool's perspective, these need to be 'local', not remote-qualified. Change-Id: I62faa081a8ebd2589c68d9ae367212fbf001e048 Reviewed-by: Christian Kandeler --- src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp index 5bcce759105..a73f855cace 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp @@ -241,9 +241,9 @@ QString QbsBuildConfiguration::equivalentCommandLine(const QbsBuildStepData &ste CommandLine commandLine; commandLine.addArg(QDir::toNativeSeparators(QbsSettings::qbsExecutableFilePath().toString())); commandLine.addArg(stepData.command); - const QString buildDir = buildDirectory().toUserOutput(); + const QString buildDir = buildDirectory().nativePath(); commandLine.addArgs({"-d", buildDir}); - commandLine.addArgs({"-f", project()->projectFilePath().toUserOutput()}); + commandLine.addArgs({"-f", project()->projectFilePath().nativePath()}); if (QbsSettings::useCreatorSettingsDirForQbs()) { commandLine.addArgs({"--settings-dir", QDir::toNativeSeparators(QbsSettings::qbsSettingsBaseDir())}); @@ -273,9 +273,9 @@ QString QbsBuildConfiguration::equivalentCommandLine(const QbsBuildStepData &ste commandLine.addArg(QString(Constants::QBS_CONFIG_VARIANT_KEY) + ':' + buildVariant); const FilePath installRoot = stepData.installRoot; if (!installRoot.isEmpty()) { - commandLine.addArg(QString(Constants::QBS_INSTALL_ROOT_KEY) + ':' + installRoot.toUserOutput()); + commandLine.addArg(QString(Constants::QBS_INSTALL_ROOT_KEY) + ':' + installRoot.nativePath()); if (stepData.isInstallStep) - commandLine.addArgs({"--installRoot", installRoot.toUserOutput()}); + commandLine.addArgs({"--installRoot", installRoot.nativePath()}); } commandLine.addArg("profile:" + profileName); From 6531a1e20670e3a969a7e86ab8ccc217859da5ce Mon Sep 17 00:00:00 2001 From: Liu Zhangjian Date: Fri, 13 Dec 2024 11:24:45 +0800 Subject: [PATCH 428/989] fix: [Session] Improve session name sorting Update session name comparison in SessionModel::sort to use Utils::caseFriendlyCompare instead of direct string comparison. This ensures more intuitive sorting of session names regardless of their case. Change-Id: I8655f937f78d1b2c0d290106b76220127bede0de Reviewed-by: Christian Kandeler --- src/plugins/coreplugin/sessionmodel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/coreplugin/sessionmodel.cpp b/src/plugins/coreplugin/sessionmodel.cpp index d4f49874ac9..fb4bd43bc42 100644 --- a/src/plugins/coreplugin/sessionmodel.cpp +++ b/src/plugins/coreplugin/sessionmodel.cpp @@ -150,11 +150,11 @@ void SessionModel::sort(int column, Qt::SortOrder order) const auto cmp = [column, order](const QString &s1, const QString &s2) { bool isLess; if (column == 0) { - if (s1 == s2) + const int cmp = Utils::caseFriendlyCompare(s1, s2); + if (cmp == 0) return false; - isLess = s1 < s2; - } - else { + isLess = cmp < 0; + } else { const auto s1time = SessionManager::sessionDateTime(s1); const auto s2time = SessionManager::sessionDateTime(s2); if (s1time == s2time) From 0540a4bf5b4938f6cb94261d471531661d52a290 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 10 Dec 2024 13:15:58 +0100 Subject: [PATCH 429/989] Qmake: Remove one use of ProcessArgs::ArgIterator Change-Id: I9c3ffa927aab02abd31c0e5a5d1c0335ddbe5b71 Reviewed-by: Christian Stenger --- src/plugins/qmakeprojectmanager/qmakestep.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 1f34696df15..56736c61802 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -391,14 +391,14 @@ QStringList QMakeStep::parserArguments() QString QMakeStep::mkspec() const { - QString additionalArguments = userArguments(); - ProcessArgs::addArgs(&additionalArguments, m_extraArgs); - for (ProcessArgs::ArgIterator ait(&additionalArguments); ait.next(); ) { - if (ait.value() == "-spec") { - if (ait.next()) - return FilePath::fromUserInput(ait.value()).toString(); - } - } + CommandLine cmd; + cmd.addArgs(userArguments(), CommandLine::Raw); + cmd.addArgs(m_extraArgs); + + const QStringList args = cmd.splitArguments(); + const int pos = args.indexOf("-spec") + 1; + if (pos > 0 && pos < args.size()) + return FilePath::fromUserInput(args[pos]).toString(); return QmakeKitAspect::effectiveMkspec(target()->kit()); } From 2e6465de3e7be9bb502c2dc6b990f0b6b6608c86 Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Thu, 12 Dec 2024 16:16:47 +0100 Subject: [PATCH 430/989] Autodetect native DAP debuggers Enabled autodetection for C/C++ debuggers that support DAP mode. It is guarded by `QTC_ENABLE_NATIVE_DAP_DEBUGGERS` environment variable and is turned off by default (DAP mode is not exactly production ready). If enabled, autodetection adds DAP debuggers as separate entries in the debuggers list from where they one can use them just as any other debuggers. The old method of launching a DAP session with C/C++ debuggers is no longer there: it is now only possible to start CMake or Python sessions that way. A lot of misc refactoring as the code would have been a monstrosity otherwise (just to be clear, it is still far from being perfect). Change-Id: I7b8cc3697370a2938c9163c106b302c98a4bd94d Reviewed-by: hjk --- src/plugins/debugger/debuggeritem.cpp | 420 ++++++++++++------- src/plugins/debugger/debuggeritem.h | 23 +- src/plugins/debugger/debuggeritemmanager.cpp | 145 ++++++- src/plugins/debugger/debuggerplugin.cpp | 9 +- 4 files changed, 414 insertions(+), 183 deletions(-) diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index 98dac23f01d..7354b699b7b 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -22,23 +22,64 @@ #include +using namespace Debugger; using namespace Debugger::Internal; using namespace ProjectExplorer; using namespace Utils; -namespace Debugger { +static expected_str fetchVersionOutput(const FilePath &executable, Environment environment) +{ + // CDB only understands the single-dash -version, whereas GDB and LLDB are + // happy with both -version and --version. So use the "working" -version + // except for the experimental LLDB-MI which insists on --version. + QString version = "-version"; + if (executable.baseName().toLower().contains("lldb-mi") + || executable.baseName().startsWith("LLDBFrontend")) { // Comes with Android Studio + version = "--version"; + } -const char DEBUGGER_INFORMATION_COMMAND[] = "Binary"; -const char DEBUGGER_INFORMATION_DISPLAYNAME[] = "DisplayName"; -const char DEBUGGER_INFORMATION_ID[] = "Id"; -const char DEBUGGER_INFORMATION_ENGINETYPE[] = "EngineType"; -const char DEBUGGER_INFORMATION_AUTODETECTED[] = "AutoDetected"; // FIXME: Merge into DetectionSource -const char DEBUGGER_INFORMATION_DETECTION_SOURCE[] = "DetectionSource"; -const char DEBUGGER_INFORMATION_VERSION[] = "Version"; -const char DEBUGGER_INFORMATION_ABIS[] = "Abis"; -const char DEBUGGER_INFORMATION_LASTMODIFIED[] = "LastModified"; -const char DEBUGGER_INFORMATION_WORKINGDIRECTORY[] = "WorkingDirectory"; + // QNX gdb unconditionally checks whether the QNX_TARGET env variable is + // set and bails otherwise, even when it is not used by the specific + // codepath triggered by the --version and --configuration arguments. The + // hack below tricks it into giving us the information we want. + environment.set("QNX_TARGET", QString()); + // On Windows, we need to prevent the Windows Error Reporting dialog from + // popping up when a candidate is missing required DLLs. + const WindowsCrashDialogBlocker blocker; + + Process proc; + proc.setEnvironment(environment); + proc.setCommand({executable, {version}}); + proc.runBlocking(); + QString output = proc.allOutput().trimmed(); + if (proc.result() != ProcessResult::FinishedWithSuccess) + return make_unexpected(output); + + return output; +} + +static std::optional extractLldbVersion(const QString &fromOutput) +{ + // Self-build binaries also emit clang and llvm revision. + const QString line = fromOutput.split('\n')[0]; + + // Linux typically, or some Windows builds + const QString nonMacOSPrefix = "lldb version "; + if (line.contains(nonMacOSPrefix)) { + const qsizetype pos1 = line.indexOf(nonMacOSPrefix) + nonMacOSPrefix.length(); + const qsizetype pos2 = line.indexOf(' ', pos1); + return line.mid(pos1, pos2 - pos1); + } + + // Mac typically + const QString macOSPrefix = "lldb-"; + if (line.startsWith(macOSPrefix, Qt::CaseInsensitive)) { + return line.mid(macOSPrefix.length()); + } + + return {}; +} //! Return the configuration of gdb as a list of --key=value //! \note That the list will also contain some output not in this format. @@ -54,26 +95,186 @@ static QString getGdbConfiguration(const FilePath &command, const Environment &s //! Extract the target ABI identifier from GDB output //! \return QString() (aka Null) if unable to find something -static QString extractGdbTargetAbiStringFromGdbOutput(const QString &gdbOutput) +static std::optional extractGdbTargetAbiStringFromGdbOutput(const QString &gdbOutput) { const auto outputLines = gdbOutput.split('\n'); const auto whitespaceSeparatedTokens = outputLines.join(' ').split(' ', Qt::SkipEmptyParts); const QString targetKey{"--target="}; - const QString targetValue = Utils::findOrDefault(whitespaceSeparatedTokens, - [&targetKey](const QString &token) { return token.startsWith(targetKey); }); + const QString targetValue + = Utils::findOrDefault(whitespaceSeparatedTokens, [&targetKey](const QString &token) { + return token.startsWith(targetKey); + }); if (!targetValue.isEmpty()) return targetValue.mid(targetKey.size()); return {}; } +static std::optional extractGdbTargetAbi( + const FilePath &fromExecutable, const int version, const Environment &env) +{ + // ABI + const bool unableToFindAVersion = (0 == version); + const bool gdbSupportsConfigurationFlag = (version >= 70700); + if (!unableToFindAVersion && !gdbSupportsConfigurationFlag) + return {}; + + const std::optional gdbTargetAbiString = extractGdbTargetAbiStringFromGdbOutput( + getGdbConfiguration(fromExecutable, env)); + if (!gdbTargetAbiString) + return {}; + + return Abi::abiFromTargetTriplet(*gdbTargetAbiString); +} + +static std::optional extractLegacyGdbTargetAbi(const QString &fromOutput) +{ + // ABI: legacy: the target was removed from the output of --version with + // https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=c61b06a19a34baab66e3809c7b41b0c31009ed9f + std::optional legacyGdbTargetAbiString = extractGdbTargetAbiStringFromGdbOutput( + fromOutput); + if (!legacyGdbTargetAbiString) + return {}; + + legacyGdbTargetAbiString->chop(1); // remove trailing " + return Abi::abiFromTargetTriplet(*legacyGdbTargetAbiString); +} + +static Utils::expected_str extractLldbTechnicalData( + const FilePath &fromExecutable, const Environment &env, const QString &dapServerSuffix) +{ + // As of LLVM 19.1.4 `lldb-dap`/`lldb-vscode` has no `--version` switch + // so we cannot use that binary directly. + // However it should be pretty safe to assume that if there is an `lldb` binary + // next to it both are of the same version. + // It also makes sense that both follow the same naming scheme, + // so replacing the name should work. + QString binaryName = fromExecutable.fileName(); + binaryName.replace(dapServerSuffix, QString{}); + const FilePath lldb = fromExecutable.parentDir() / binaryName; + if (!lldb.exists()) { + return make_unexpected(QString{"%1 does not exist alongside %2"} + .arg(lldb.fileNameView(), fromExecutable.toUserOutput())); + } + if (!lldb.isExecutableFile()) { + return make_unexpected(QString{"%1 exists alongside %2 but is not executable"} + .arg(lldb.fileNameView(), fromExecutable.toUserOutput())); + } + + const expected_str output = fetchVersionOutput(lldb, env); + if (!output) + return make_unexpected(output.error()); + + return DebuggerItem::TechnicalData{ + .engineType = LldbDapEngineType, + .abis = Abi::abisOfBinary(fromExecutable), + .version = extractLldbVersion(*output).value_or(""), + }; +} + +namespace Debugger { + +const char DEBUGGER_INFORMATION_COMMAND[] = "Binary"; +const char DEBUGGER_INFORMATION_DISPLAYNAME[] = "DisplayName"; +const char DEBUGGER_INFORMATION_ID[] = "Id"; +const char DEBUGGER_INFORMATION_ENGINETYPE[] = "EngineType"; +const char DEBUGGER_INFORMATION_AUTODETECTED[] = "AutoDetected"; // FIXME: Merge into DetectionSource +const char DEBUGGER_INFORMATION_DETECTION_SOURCE[] = "DetectionSource"; +const char DEBUGGER_INFORMATION_VERSION[] = "Version"; +const char DEBUGGER_INFORMATION_ABIS[] = "Abis"; +const char DEBUGGER_INFORMATION_LASTMODIFIED[] = "LastModified"; +const char DEBUGGER_INFORMATION_WORKINGDIRECTORY[] = "WorkingDirectory"; // -------------------------------------------------------------------------- // DebuggerItem // -------------------------------------------------------------------------- -DebuggerItem::DebuggerItem() = default; +Utils::expected_str DebuggerItem::TechnicalData::extract( + const FilePath &fromExecutable, const std::optional &customEnvironment) +{ + Environment env = customEnvironment.value_or(fromExecutable.deviceEnvironment()); + DebuggerItem::addAndroidLldbPythonEnv(fromExecutable, env); + + if (qgetenv("QTC_ENABLE_NATIVE_DAP_DEBUGGERS").toInt() != 0) { + for (const auto &dapServerSuffix : {QString{"-dap"}, QString{"-vscode"}}) { + const QString dapServerName = QString{"lldb%1"}.arg(dapServerSuffix); + if (fromExecutable.fileName().startsWith(dapServerName, Qt::CaseInsensitive)) { + return extractLldbTechnicalData(fromExecutable, env, dapServerSuffix); + } + } + } + + // We don't need to start the uVision executable to determine its version. + if (HostOsInfo::isWindowsHost() && fromExecutable.baseName() == "UV4") { + QString errorMessage; + QString version = winGetDLLVersion( + WinDLLFileVersion, fromExecutable.absoluteFilePath().path(), &errorMessage); + + if (!errorMessage.isEmpty()) + return make_unexpected(std::move(errorMessage)); + + return DebuggerItem::TechnicalData{ + .engineType = UvscEngineType, + .abis = {}, + .version = std::move(version), + }; + } + + const expected_str output = fetchVersionOutput(fromExecutable, env); + if (!output) { + return make_unexpected(output.error()); + } + + if (output->contains("gdb")) { + // Version + bool isMacGdb = false; + bool isQnxGdb = false; + int version = 0; + int buildVersion = 0; + Debugger::Internal::extractGdbVersion(*output, &version, &buildVersion, &isMacGdb, &isQnxGdb); + QString versionStr = version != 0 ? QString::fromLatin1("%1.%2.%3") + .arg(version / 10000) + .arg((version / 100) % 100) + .arg(version % 100) + : ""; + Abis abis; + if (std::optional abi = extractGdbTargetAbi(fromExecutable, version, env)) { + abis = {std::move(*abi)}; + } else if (std::optional abi = extractLegacyGdbTargetAbi(*output)) { + abis = {std::move(*abi)}; + } else { + qWarning() << "Unable to determine gdb target ABI from" << *output; + } + + return DebuggerItem::TechnicalData{ + .engineType = GdbEngineType, .abis = abis, .version = std::move(versionStr)}; + } + + if (output->contains("lldb") || output->startsWith("LLDB")) { + return DebuggerItem::TechnicalData{ + .engineType = LldbEngineType, + .abis = Abi::abisOfBinary(fromExecutable), + .version = extractLldbVersion(*output).value_or(""), + }; + } + if (output->startsWith("cdb")) { + // "cdb version 6.2.9200.16384" + return DebuggerItem::TechnicalData{ + .engineType = CdbEngineType, + .abis = Abi::abisOfBinary(fromExecutable), + .version = output->section(' ', 2), + }; + } + + return make_unexpected( + QString{"Failed to determine debugger engine type from '%1'"}.arg(*output)); +} + +bool DebuggerItem::TechnicalData::isEmpty() const +{ + return version.isEmpty() && abis.isEmpty() && engineType == NoEngineType; +} DebuggerItem::DebuggerItem(const QVariant &id) { @@ -88,28 +289,28 @@ DebuggerItem::DebuggerItem(const Store &data) m_unexpandedDisplayName = data.value(DEBUGGER_INFORMATION_DISPLAYNAME).toString(); m_isAutoDetected = data.value(DEBUGGER_INFORMATION_AUTODETECTED, false).toBool(); m_detectionSource = data.value(DEBUGGER_INFORMATION_DETECTION_SOURCE).toString(); - m_version = data.value(DEBUGGER_INFORMATION_VERSION).toString(); - m_engineType = DebuggerEngineType(data.value(DEBUGGER_INFORMATION_ENGINETYPE, - static_cast(NoEngineType)).toInt()); + m_technicalData.version = data.value(DEBUGGER_INFORMATION_VERSION).toString(); + m_technicalData.engineType = DebuggerEngineType( + data.value(DEBUGGER_INFORMATION_ENGINETYPE, static_cast(NoEngineType)).toInt()); m_lastModified = data.value(DEBUGGER_INFORMATION_LASTMODIFIED).toDateTime(); const QStringList abis = data.value(DEBUGGER_INFORMATION_ABIS).toStringList(); for (const QString &a : abis) { Abi abi = Abi::fromString(a); if (!abi.isNull()) - m_abis.append(abi); + m_technicalData.abis.append(abi); } - bool mightBeAPreQnxSeparateOSQnxDebugger = m_command.fileName().startsWith("nto") - && m_abis.count() == 1 - && m_abis[0].os() == Abi::UnknownOS - && m_abis[0].osFlavor() == Abi::UnknownFlavor - && m_abis[0].binaryFormat() == Abi::UnknownFormat; + const Abis &validAbis = m_technicalData.abis; + const bool mightBeAPreQnxSeparateOSQnxDebugger = m_command.fileName().startsWith("nto") + && validAbis.count() == 1 + && validAbis.front().os() == Abi::UnknownOS + && validAbis.front().osFlavor() + == Abi::UnknownFlavor + && validAbis.front().binaryFormat() + == Abi::UnknownFormat; - bool needsReinitialization = m_version.isEmpty() && m_abis.isEmpty() - && m_engineType == NoEngineType; - - if (needsReinitialization || mightBeAPreQnxSeparateOSQnxDebugger) + if (m_technicalData.isEmpty() || mightBeAPreQnxSeparateOSQnxDebugger) reinitializeFromFile(); } @@ -124,118 +325,17 @@ void DebuggerItem::reinitializeFromFile(QString *error, Utils::Environment *cust if (isGeneric()) return; - // CDB only understands the single-dash -version, whereas GDB and LLDB are - // happy with both -version and --version. So use the "working" -version - // except for the experimental LLDB-MI which insists on --version. - QString version = "-version"; - m_lastModified = m_command.lastModified(); - if (m_command.baseName().toLower().contains("lldb-mi") - || m_command.baseName().startsWith("LLDBFrontend")) // Comes with Android Studio - version = "--version"; - - // We don't need to start the uVision executable to - // determine its version. - if (HostOsInfo::isWindowsHost() && m_command.baseName() == "UV4") { - QString errorMessage; - m_version = winGetDLLVersion(WinDLLFileVersion, - m_command.absoluteFilePath().path(), - &errorMessage); - m_engineType = UvscEngineType; - m_abis.clear(); - return; - } - - Environment env = customEnv ? *customEnv : m_command.deviceEnvironment(); - DebuggerItem::addAndroidLldbPythonEnv(m_command, env); - - // QNX gdb unconditionally checks whether the QNX_TARGET env variable is - // set and bails otherwise, even when it is not used by the specific - // codepath triggered by the --version and --configuration arguments. The - // hack below tricks it into giving us the information we want. - env.set("QNX_TARGET", QString()); - - // On Windows, we need to prevent the Windows Error Reporting dialog from - // popping up when a candidate is missing required DLLs. - WindowsCrashDialogBlocker blocker; - - Process proc; - proc.setEnvironment(env); - proc.setCommand({m_command, {version}}); - proc.runBlocking(); - const QString output = proc.allOutput().trimmed(); - if (proc.result() != ProcessResult::FinishedWithSuccess) { + auto env = customEnv ? std::optional{*customEnv} : std::optional{}; + expected_str technicalData = TechnicalData::extract(m_command, env); + if (!technicalData) { if (error) - *error = output; - m_engineType = NoEngineType; - return; - } - m_abis.clear(); - - if (output.contains("gdb")) { - m_engineType = GdbEngineType; - - // Version - bool isMacGdb, isQnxGdb; - int version = 0, buildVersion = 0; - Debugger::Internal::extractGdbVersion(output, - &version, &buildVersion, &isMacGdb, &isQnxGdb); - if (version) - m_version = QString::fromLatin1("%1.%2.%3") - .arg(version / 10000).arg((version / 100) % 100).arg(version % 100); - - // ABI - const bool unableToFindAVersion = (0 == version); - const bool gdbSupportsConfigurationFlag = (version >= 70700); - if (gdbSupportsConfigurationFlag || unableToFindAVersion) { - const QString gdbTargetAbiString = extractGdbTargetAbiStringFromGdbOutput( - getGdbConfiguration(m_command, env)); - if (!gdbTargetAbiString.isEmpty()) { - m_abis.append(Abi::abiFromTargetTriplet(gdbTargetAbiString)); - return; - } - } - - // ABI: legacy: the target was removed from the output of --version with - // https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=c61b06a19a34baab66e3809c7b41b0c31009ed9f - QString legacyGdbTargetAbiString = extractGdbTargetAbiStringFromGdbOutput(output); - if (!legacyGdbTargetAbiString.isEmpty()) { - legacyGdbTargetAbiString.chop(1); // remove trailing " - m_abis.append(Abi::abiFromTargetTriplet(legacyGdbTargetAbiString)); - return; - } - - qWarning() << "Unable to determine gdb target ABI via" << proc.commandLine().toUserOutput(); - //! \note If unable to determine the GDB ABI, no ABI is appended to m_abis here. + *error = technicalData.error(); + m_technicalData.engineType = NoEngineType; return; } - if (output.contains("lldb") || output.startsWith("LLDB")) { - m_engineType = LldbEngineType; - m_abis = Abi::abisOfBinary(m_command); - - // Version - // Self-build binaries also emit clang and llvm revision. - const QString line = output.split('\n')[0]; - const QString nonMacOSPrefix = "lldb version "; - if (line.contains(nonMacOSPrefix)) { // Linux typically, or some Windows builds. - int pos1 = line.indexOf(nonMacOSPrefix) + nonMacOSPrefix.length(); - int pos2 = line.indexOf(' ', pos1); - m_version = line.mid(pos1, pos2 - pos1); - } else if (line.startsWith("lldb-") || line.startsWith("LLDB-")) { // Mac typically. - m_version = line.mid(5); - } - return; - } - if (output.startsWith("cdb")) { - // "cdb version 6.2.9200.16384" - m_engineType = CdbEngineType; - m_abis = Abi::abisOfBinary(m_command); - m_version = output.section(' ', 2); - return; - } - if (error) - *error = output; - m_engineType = NoEngineType; + m_technicalData = std::move(*technicalData); + m_lastModified = m_command.lastModified(); } bool DebuggerItem::addAndroidLldbPythonEnv(const Utils::FilePath &lldbCmd, Utils::Environment &env) @@ -263,7 +363,7 @@ bool DebuggerItem::addAndroidLldbPythonEnv(const Utils::FilePath &lldbCmd, Utils QString DebuggerItem::engineTypeName() const { - switch (m_engineType) { + switch (m_technicalData.engineType) { case NoEngineType: return Tr::tr("Not recognized"); case GdbEngineType: @@ -296,7 +396,7 @@ bool DebuggerItem::isGeneric() const QStringList DebuggerItem::abiNames() const { QStringList list; - for (const Abi &abi : m_abis) + for (const Abi &abi : m_technicalData.abis) list.append(abi.toString()); return list; } @@ -306,11 +406,16 @@ QDateTime DebuggerItem::lastModified() const return m_lastModified; } +void DebuggerItem::setLastModified(const QDateTime ×tamp) +{ + m_lastModified = timestamp; +} + DebuggerItem::Problem DebuggerItem::problem() const { if (isGeneric() || !m_id.isValid()) // Id can only be invalid for the "none" item. return Problem::None; - if (m_engineType == NoEngineType) + if (m_technicalData.engineType == NoEngineType) return Problem::NoEngine; if (!m_command.isExecutableFile()) return Problem::InvalidCommand; @@ -365,10 +470,10 @@ Store DebuggerItem::toMap() const data.insert(DEBUGGER_INFORMATION_ID, m_id); data.insert(DEBUGGER_INFORMATION_COMMAND, m_command.toSettings()); data.insert(DEBUGGER_INFORMATION_WORKINGDIRECTORY, m_workingDirectory.toSettings()); - data.insert(DEBUGGER_INFORMATION_ENGINETYPE, int(m_engineType)); + data.insert(DEBUGGER_INFORMATION_ENGINETYPE, int(m_technicalData.engineType)); data.insert(DEBUGGER_INFORMATION_AUTODETECTED, m_isAutoDetected); data.insert(DEBUGGER_INFORMATION_DETECTION_SOURCE, m_detectionSource); - data.insert(DEBUGGER_INFORMATION_VERSION, m_version); + data.insert(DEBUGGER_INFORMATION_VERSION, m_technicalData.version); data.insert(DEBUGGER_INFORMATION_ABIS, abiNames()); data.insert(DEBUGGER_INFORMATION_LASTMODIFIED, m_lastModified); return data; @@ -380,12 +485,17 @@ QString DebuggerItem::displayName() const return m_unexpandedDisplayName; MacroExpander expander; - expander.registerVariable("Debugger:Type", Tr::tr("Type of Debugger Backend"), - [this] { return engineTypeName(); }); - expander.registerVariable("Debugger:Version", Tr::tr("Debugger"), - [this] { return !m_version.isEmpty() ? m_version : Tr::tr("Unknown debugger version"); }); - expander.registerVariable("Debugger:Abi", Tr::tr("Debugger"), - [this] { return !m_abis.isEmpty() ? abiNames().join(' ') : Tr::tr("Unknown debugger ABI"); }); + expander.registerVariable("Debugger:Type", Tr::tr("Type of Debugger Backend"), [this] { + return engineTypeName(); + }); + expander.registerVariable( + "Debugger:Version", Tr::tr("Debugger"), [&version = m_technicalData.version] { + return !version.isEmpty() ? version : Tr::tr("Unknown debugger version"); + }); + expander.registerVariable("Debugger:Abi", Tr::tr("Debugger"), [this] { + return !m_technicalData.abis.isEmpty() ? abiNames().join(' ') + : Tr::tr("Unknown debugger ABI"); + }); return expander.expand(m_unexpandedDisplayName); } @@ -396,7 +506,7 @@ void DebuggerItem::setUnexpandedDisplayName(const QString &displayName) void DebuggerItem::setEngineType(const DebuggerEngineType &engineType) { - m_engineType = engineType; + m_technicalData.engineType = engineType; } void DebuggerItem::setCommand(const FilePath &command) @@ -411,23 +521,23 @@ void DebuggerItem::setAutoDetected(bool isAutoDetected) QString DebuggerItem::version() const { - return m_version; + return m_technicalData.version; } void DebuggerItem::setVersion(const QString &version) { - m_version = version; + m_technicalData.version = version; } void DebuggerItem::setAbis(const Abis &abis) { - m_abis = abis; + m_technicalData.abis = abis; } void DebuggerItem::setAbi(const Abi &abi) { - m_abis.clear(); - m_abis.append(abi); + m_technicalData.abis.clear(); + m_technicalData.abis.append(abi); } static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &targetAbi, DebuggerEngineType engineType) @@ -486,8 +596,8 @@ static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &t DebuggerItem::MatchLevel DebuggerItem::matchTarget(const Abi &targetAbi) const { MatchLevel bestMatch = DoesNotMatch; - for (const Abi &debuggerAbi : m_abis) { - MatchLevel currentMatch = matchSingle(debuggerAbi, targetAbi, m_engineType); + for (const Abi &debuggerAbi : m_technicalData.abis) { + MatchLevel currentMatch = matchSingle(debuggerAbi, targetAbi, m_technicalData.engineType); if (currentMatch > bestMatch) bestMatch = currentMatch; } diff --git a/src/plugins/debugger/debuggeritem.h b/src/plugins/debugger/debuggeritem.h index 8b2fcb50ab3..ece9a872ceb 100644 --- a/src/plugins/debugger/debuggeritem.h +++ b/src/plugins/debugger/debuggeritem.h @@ -29,7 +29,19 @@ class DebuggerItemModel; class DEBUGGER_EXPORT DebuggerItem { public: - DebuggerItem(); + struct TechnicalData + { + static Utils::expected_str extract( + const Utils::FilePath &fromExecutable, + const std::optional &customEnvironment); + bool isEmpty() const; + + DebuggerEngineType engineType = NoEngineType; + ProjectExplorer::Abis abis; + QString version; + }; + + DebuggerItem() = default; DebuggerItem(const Utils::Store &data); void createId(); @@ -45,7 +57,7 @@ public: QString unexpandedDisplayName() const { return m_unexpandedDisplayName; } void setUnexpandedDisplayName(const QString &unexpandedDisplayName); - DebuggerEngineType engineType() const { return m_engineType; } + DebuggerEngineType engineType() const { return m_technicalData.engineType; } void setEngineType(const DebuggerEngineType &engineType); Utils::FilePath command() const { return m_command; } @@ -57,7 +69,7 @@ public: QString version() const; void setVersion(const QString &version); - const ProjectExplorer::Abis &abis() const { return m_abis; } + const ProjectExplorer::Abis &abis() const { return m_technicalData.abis; } void setAbis(const ProjectExplorer::Abis &abis); void setAbi(const ProjectExplorer::Abi &abi); @@ -66,6 +78,7 @@ public: QStringList abiNames() const; QDateTime lastModified() const; + void setLastModified(const QDateTime ×tamp); // Keep enum sorted ascending by goodness. enum class Problem { NoEngine, InvalidCommand, InvalidWorkingDir, None }; @@ -95,12 +108,10 @@ private: QVariant m_id; QString m_unexpandedDisplayName; - DebuggerEngineType m_engineType = NoEngineType; + TechnicalData m_technicalData; Utils::FilePath m_command; Utils::FilePath m_workingDirectory; bool m_isAutoDetected = false; - QString m_version; - ProjectExplorer::Abis m_abis; QDateTime m_lastModified; QString m_detectionSource; diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 6a162757bb3..62f5319c18e 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -45,11 +45,49 @@ #include #include +using namespace Debugger; using namespace Debugger::Internal; using namespace Core; using namespace ProjectExplorer; using namespace Utils; +static DebuggerItem makeAutoDetectedDebuggerItem( + const FilePath &command, + const DebuggerItem::TechnicalData &technicalData, + const QString &detectionSource) +{ + DebuggerItem item; + item.createId(); + item.setCommand(command); + item.setDetectionSource(detectionSource); + item.setAutoDetected(true); + item.setEngineType(technicalData.engineType); + item.setAbis(technicalData.abis); + item.setVersion(technicalData.version); + const QString name = detectionSource.isEmpty() ? Tr::tr("System %1 at %2") + : Tr::tr("Detected %1 at %2"); + item.setUnexpandedDisplayName(name.arg(item.engineTypeName()).arg(command.toUserOutput())); + item.setLastModified(command.lastModified()); + return item; +} + +static expected_str makeAutoDetectedDebuggerItem( + const FilePath &command, const QString &detectionSource) +{ + expected_str technicalData + = DebuggerItem::TechnicalData::extract(command, {}); + + if (!technicalData) + return make_unexpected(std::move(technicalData).error()); + + return makeAutoDetectedDebuggerItem(command, *technicalData, detectionSource); +} + +static bool doEnableNativeDapDebuggers() +{ + return qgetenv("QTC_ENABLE_NATIVE_DAP_DEBUGGERS").toInt() != 0; +} + namespace Debugger { namespace Internal { @@ -607,9 +645,28 @@ void DebuggerItemModel::autoDetectGdbOrLldbDebuggers(const FilePaths &searchPath const QString &detectionSource, QString *logMessage) { - const QStringList filters = {"gdb-i686-pc-mingw32", "gdb-i686-pc-mingw32.exe", "gdb", - "gdb.exe", "lldb", "lldb.exe", "lldb-[1-9]*", - "arm-none-eabi-gdb-py.exe", "*-*-*-gdb"}; + QStringList filters + = {"gdb-i686-pc-mingw32", + "gdb-i686-pc-mingw32.exe", + "gdb", + "gdb.exe", + "lldb", + "lldb.exe", + "lldb-[1-9]*", + "arm-none-eabi-gdb-py.exe", + "*-*-*-gdb"}; + + if (doEnableNativeDapDebuggers()) { + filters.append({ + "lldb-dap", + "lldb-dap.exe", + "lldb-dap-*", + // LLDB DAP server was named lldb-vscode prior LLVM 18.0.0 + "lldb-vscode", + "lldb-vscode.exe", + "lldb-vscode-*", + }); + } if (searchPaths.isEmpty()) return; @@ -651,24 +708,78 @@ void DebuggerItemModel::autoDetectGdbOrLldbDebuggers(const FilePaths &searchPath const auto commandMatches = [command](const DebuggerTreeItem *titem) { return titem->m_item.command() == command; }; - if (DebuggerTreeItem *existingItem = findItemAtLevel<2>(commandMatches)) { - if (command.lastModified() != existingItem->m_item.lastModified()) - existingItem->m_item.reinitializeFromFile(); + if (DebuggerTreeItem *existingTreeItem = findItemAtLevel<2>(commandMatches)) { + DebuggerItem &existingItem = existingTreeItem->m_item; + if (command.lastModified() != existingItem.lastModified()) + existingItem.reinitializeFromFile(); + + if (doEnableNativeDapDebuggers()) { + if (existingItem.engineType() != GdbEngineType) + continue; + + // GDB starting version 14.1.0 supports DAP interface, but unlike LLDB, + // it uses the same binary, hence this hack. + const QVersionNumber dapSupportMinVersion{14, 1, 0}; + if (QVersionNumber::fromString(existingItem.version()) < dapSupportMinVersion) + continue; + // This is the "update" path: there's already a capable GDB in the settings, + // we only need to add a corresponding DAP entry if it's missing. + const auto commandMatchesAndIsDap = [command, commandMatches]( + const DebuggerTreeItem *titem) { + return commandMatches(titem) && titem->m_item.engineType() == GdbDapEngineType; + }; + const DebuggerTreeItem *existingDapTreeItem = findItemAtLevel<2>( + commandMatchesAndIsDap); + if (existingDapTreeItem) + continue; + + const DebuggerItem dapItem = makeAutoDetectedDebuggerItem( + command, + { + .engineType = GdbDapEngineType, + .abis = existingItem.abis(), + .version = existingItem.version(), + }, + detectionSource); + addDebuggerItem(dapItem); + logMessages.append( + Tr::tr("Added a surrogate GDB DAP item for existing entry \"%1\"") + .arg(command.toUserOutput())); + } continue; } - DebuggerItem item; - item.createId(); - item.setDetectionSource(detectionSource); - item.setAutoDetected(true); - item.setCommand(command); - item.reinitializeFromFile(); - if (item.engineType() == NoEngineType) + + const expected_str item + = makeAutoDetectedDebuggerItem(command, detectionSource); + if (!item) { + logMessages.append(item.error()); continue; - //: %1: Debugger engine type (GDB, LLDB, CDB...), %2: Path - const QString name = detectionSource.isEmpty() ? Tr::tr("System %1 at %2") : Tr::tr("Detected %1 at %2"); - item.setUnexpandedDisplayName(name.arg(item.engineTypeName()).arg(command.toUserOutput())); - addDebuggerItem(item); + } + + addDebuggerItem(*item); logMessages.append(Tr::tr("Found: \"%1\"").arg(command.toUserOutput())); + if (doEnableNativeDapDebuggers()) { + if (item->engineType() != GdbEngineType) + continue; + + // GDB starting version 14.1.0 supports DAP interface, but unlike LLDB, + // it uses the same binary, hence this hack + const QVersionNumber dapSupportMinVersion{14, 1, 0}; + if (QVersionNumber::fromString(item->version()) < dapSupportMinVersion) + continue; + + const DebuggerItem dapItem = makeAutoDetectedDebuggerItem( + command, + { + .engineType = GdbDapEngineType, + .abis = item->abis(), + .version = item->version(), + }, + detectionSource); + addDebuggerItem(dapItem); + logMessages.append( + Tr::tr("Added a surrogate GDB DAP item for \"%1\"").arg(command.toUserOutput())); + } } if (logMessage) *logMessage = logMessages.join('\n'); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index af452f8bf94..b21924b9104 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1236,11 +1236,10 @@ void DebuggerPluginPrivate::createDapDebuggerPerspective(QWidget *globalLogWindo }; const QList perspectiveList = { - DapPerspective{Tr::tr("CMake Preset"), - ProjectExplorer::Constants::DAP_CMAKE_DEBUG_RUN_MODE, - /*forceSkipDeploy=*/true}, - DapPerspective{Tr::tr("GDB Preset"), ProjectExplorer::Constants::DAP_GDB_DEBUG_RUN_MODE}, - DapPerspective{Tr::tr("LLDB Preset"), ProjectExplorer::Constants::DAP_LLDB_DEBUG_RUN_MODE}, + DapPerspective{ + Tr::tr("CMake Preset"), + ProjectExplorer::Constants::DAP_CMAKE_DEBUG_RUN_MODE, + /*forceSkipDeploy=*/true}, DapPerspective{Tr::tr("Python Preset"), ProjectExplorer::Constants::DAP_PY_DEBUG_RUN_MODE}, }; From 8a5949d632e1abbf6a8860afbf8ba0be31ff094e Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 16 Dec 2024 15:40:13 +0100 Subject: [PATCH 431/989] QtcSeparateDebugInfo: Update from Qt Add VERBATIM option to add_custom_command calls 8adacba3e6970d784108645d5c0a70e5b9c1151e Change-Id: I352e561f5bbad23d7562f4629b0b705f17f702e3 Reviewed-by: Cristian Adam --- cmake/QtcSeparateDebugInfo.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/QtcSeparateDebugInfo.cmake b/cmake/QtcSeparateDebugInfo.cmake index 9fb4047223a..96e27ca219d 100644 --- a/cmake/QtcSeparateDebugInfo.cmake +++ b/cmake/QtcSeparateDebugInfo.cmake @@ -99,7 +99,7 @@ function(qtc_enable_separate_debug_info target installDestination) TARGET ${target} POST_BUILD ${commands} - ) + VERBATIM) endfunction() # Installs pdb files for given target into the specified install dir. From 1e2a1900e7ad8aedb8c22fe306905a17f566b38c Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 17 Dec 2024 08:33:22 +0100 Subject: [PATCH 432/989] QtcSeparateDebugInfo: Adopt dsym location change from Qt Fix install location of dSYM bundle for Qt apps a60d42d873e67281e5e30bcaa3daa2f8edffe7eb This actually doesn't change anything in the installation of Qt Creator, only the build-time location. We do not use the standard install target for app bundles of CMake, which just copies the app bundle, which is ugly if the app bundle contains the .dSYM directories. This change keeps the .dSYM out of the app bundle in the build directory, which is still a sensible thing to do. Change-Id: I42cc8875e1e123a79a810d2b2e5dde8c2e389c53 Reviewed-by: Cristian Adam --- cmake/QtcSeparateDebugInfo.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/QtcSeparateDebugInfo.cmake b/cmake/QtcSeparateDebugInfo.cmake index 96e27ca219d..9e6a0e04c7f 100644 --- a/cmake/QtcSeparateDebugInfo.cmake +++ b/cmake/QtcSeparateDebugInfo.cmake @@ -49,7 +49,8 @@ function(qtc_enable_separate_debug_info target installDestination) endif() if(APPLE) get_target_property(is_framework ${target} FRAMEWORK) - if(is_framework) + get_target_property(is_bundle ${target} MACOSX_BUNDLE) + if(is_framework OR is_bundle) set(debug_info_bundle_dir "$.${debug_info_suffix}") set(BUNDLE_ID Qt${target}) else() From 3e190f46e39d8bd5707a27dcff27c6f99cc49a33 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 16 Dec 2024 17:45:01 +0100 Subject: [PATCH 433/989] Qbs: Return FilePath from QbsSettings::qbsSettingsBaseDir Allows using .nativePath() with the right context when needed. Currently this does not change anything, and most users are ok with using .path() when .nativePath() would be "correct" anyway. This also needs some further thinking on where to pick up the settings when building remotely, but at least one explicit use of FilePath::toString() and one of QDir::toNativeSeparator() are removed without ill-affecting the current local use case. Change-Id: I23566d0909181b44737c381624ec4466854d4ce4 Reviewed-by: Christian Kandeler --- src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp | 6 ++---- src/plugins/qbsprojectmanager/qbsprofilemanager.cpp | 2 +- src/plugins/qbsprojectmanager/qbsprojectparser.cpp | 2 +- src/plugins/qbsprojectmanager/qbssession.cpp | 2 +- src/plugins/qbsprojectmanager/qbssettings.cpp | 4 ++-- src/plugins/qbsprojectmanager/qbssettings.h | 2 +- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp index a73f855cace..3f3858cbf0e 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp @@ -244,10 +244,8 @@ QString QbsBuildConfiguration::equivalentCommandLine(const QbsBuildStepData &ste const QString buildDir = buildDirectory().nativePath(); commandLine.addArgs({"-d", buildDir}); commandLine.addArgs({"-f", project()->projectFilePath().nativePath()}); - if (QbsSettings::useCreatorSettingsDirForQbs()) { - commandLine.addArgs({"--settings-dir", - QDir::toNativeSeparators(QbsSettings::qbsSettingsBaseDir())}); - } + if (QbsSettings::useCreatorSettingsDirForQbs()) + commandLine.addArgs({"--settings-dir", QbsSettings::qbsSettingsBaseDir().nativePath()}); if (stepData.dryRun) commandLine.addArg("--dry-run"); if (stepData.keepGoing) diff --git a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp index 8fea3e1a2ed..617672665c7 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp @@ -201,7 +201,7 @@ QString QbsProfileManager::runQbsConfig(QbsConfigOp op, const QString &key, cons { QStringList args; if (QbsSettings::useCreatorSettingsDirForQbs()) - args << "--settings-dir" << QbsSettings::qbsSettingsBaseDir(); + args << "--settings-dir" << QbsSettings::qbsSettingsBaseDir().path(); switch (op) { case QbsConfigOp::Get: args << key; diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp index dd69935e185..8363d28ce93 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp @@ -72,7 +72,7 @@ void QbsProjectParser::parse(const Store &config, const Environment &env, request.insert(Constants::QBS_RESTORE_BEHAVIOR_KEY, userConfig.take(Constants::QBS_RESTORE_BEHAVIOR_KEY).toString()); if (QbsSettings::useCreatorSettingsDirForQbs()) - request.insert("settings-directory", QbsSettings::qbsSettingsBaseDir()); + request.insert("settings-directory", QbsSettings::qbsSettingsBaseDir().path()); request.insert("overridden-properties", QJsonObject::fromVariantMap(mapFromStore(userConfig))); // People don't like it when files are created as a side effect of opening a project, diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index ac3ed5724ec..7219f9cadc0 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -415,7 +415,7 @@ QbsSession::BuildGraphInfo QbsSession::getBuildGraphInfo(const FilePath &bgFileP request.insert("restore-behavior", "restore-only"); request.insert("configuration-name", bgFi.completeBaseName()); if (QbsSettings::useCreatorSettingsDirForQbs()) - request.insert("settings-directory", QbsSettings::qbsSettingsBaseDir()); + request.insert("settings-directory", QbsSettings::qbsSettingsBaseDir().path()); request.insert("build-root", buildRoot.path()); request.insert("error-handling-mode", "relaxed"); request.insert("data-mode", "only-if-changed"); diff --git a/src/plugins/qbsprojectmanager/qbssettings.cpp b/src/plugins/qbsprojectmanager/qbssettings.cpp index b550a7b0168..074e22b933c 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.cpp +++ b/src/plugins/qbsprojectmanager/qbssettings.cpp @@ -105,9 +105,9 @@ bool QbsSettings::useCreatorSettingsDirForQbs() return instance().m_settings.useCreatorSettings; } -QString QbsSettings::qbsSettingsBaseDir() +FilePath QbsSettings::qbsSettingsBaseDir() { - return useCreatorSettingsDirForQbs() ? Core::ICore::userResourcePath().toString() : QString(); + return useCreatorSettingsDirForQbs() ? Core::ICore::userResourcePath() : FilePath(); } QVersionNumber QbsSettings::qbsVersion() diff --git a/src/plugins/qbsprojectmanager/qbssettings.h b/src/plugins/qbsprojectmanager/qbssettings.h index f996eb2e9a7..f71cfa3c7e6 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.h +++ b/src/plugins/qbsprojectmanager/qbssettings.h @@ -35,7 +35,7 @@ public: static bool hasQbsExecutable(); static QString defaultInstallDirTemplate(); static bool useCreatorSettingsDirForQbs(); - static QString qbsSettingsBaseDir(); + static Utils::FilePath qbsSettingsBaseDir(); static QVersionNumber qbsVersion(); static void setSettingsData(const QbsSettingsData &settings); From 6cea1741fbe14409e6e9592e6f736ff73ba0575e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 17 Dec 2024 10:28:46 +0100 Subject: [PATCH 434/989] Utils: Introduce SummaryWidget To avoid code repetition. Reuse it twice. Change-Id: I1ef456e2cd0325c4a37e9dc40592dad497c116f6 Reviewed-by: Alessandro Portale --- src/libs/utils/CMakeLists.txt | 1 + src/libs/utils/summarywidget.cpp | 87 +++++++++++++++ src/libs/utils/summarywidget.h | 52 +++++++++ src/libs/utils/utils.qbs | 2 + src/plugins/android/androidsettingswidget.cpp | 103 +---------------- .../projectexplorer/windowsappsdksettings.cpp | 104 +----------------- 6 files changed, 144 insertions(+), 205 deletions(-) create mode 100644 src/libs/utils/summarywidget.cpp create mode 100644 src/libs/utils/summarywidget.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index ac418d4b2e9..f048fd5a061 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -170,6 +170,7 @@ add_qtc_library(Utils styleanimator.cpp styleanimator.h styledbar.cpp styledbar.h stylehelper.cpp stylehelper.h + summarywidget.cpp summarywidget.h synchronizedvalue.h templateengine.cpp templateengine.h temporarydirectory.cpp temporarydirectory.h diff --git a/src/libs/utils/summarywidget.cpp b/src/libs/utils/summarywidget.cpp new file mode 100644 index 00000000000..523abef2164 --- /dev/null +++ b/src/libs/utils/summarywidget.cpp @@ -0,0 +1,87 @@ +// 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 "summarywidget.h" + +#include "qtcassert.h" +#include "utilsicons.h" + +#include + +namespace Utils { + +SummaryWidget::SummaryWidget(const QMap &validationPoints, const QString &validText, + const QString &invalidText, DetailsWidget *detailsWidget) + : QWidget(detailsWidget) + , m_validText(validText) + , m_invalidText(invalidText) + , m_detailsWidget(detailsWidget) +{ + QTC_CHECK(m_detailsWidget); + auto layout = new QVBoxLayout(this); + layout->setContentsMargins(22, 0, 0, 12); + layout->setSpacing(4); + for (auto itr = validationPoints.cbegin(); itr != validationPoints.cend(); ++itr) { + RowData data; + data.m_infoLabel = new InfoLabel(itr.value()); + data.m_validText = itr.value(); + layout->addWidget(data.m_infoLabel); + m_validationData[itr.key()] = data; + setPointValid(itr.key(), false); + } + m_detailsWidget->setWidget(this); + setContentsMargins(0, 0, 0, 0); +} + +void SummaryWidget::setPointValid(int key, bool valid, const QString errorText) +{ + if (!m_validationData.contains(key)) + return; + RowData &data = m_validationData[key]; + data.m_valid = valid; + data.m_infoLabel->setType(valid ? InfoLabel::Ok : InfoLabel::NotOk); + data.m_infoLabel->setText(valid || errorText.isEmpty() ? data.m_validText : errorText); + updateUi(); +} + +bool SummaryWidget::rowsOk(const QList &keys) const +{ + for (auto key : keys) { + if (!m_validationData[key].m_valid) + return false; + } + return true; +} + +bool SummaryWidget::allRowsOk() const +{ + return rowsOk(m_validationData.keys()); +} + +void SummaryWidget::setInfoText(const QString &text) +{ + m_infoText = text; + updateUi(); +} + +void SummaryWidget::setInProgressText(const QString &text) +{ + m_detailsWidget->setIcon({}); + m_detailsWidget->setSummaryText(QString("%1...").arg(text)); + m_detailsWidget->setState(DetailsWidget::Collapsed); +} + +void SummaryWidget::setSetupOk(bool ok) +{ + m_detailsWidget->setState(ok ? DetailsWidget::Collapsed : DetailsWidget::Expanded); +} + +void SummaryWidget::updateUi() +{ + bool ok = allRowsOk(); + m_detailsWidget->setIcon(ok ? Icons::OK.icon() : Icons::CRITICAL.icon()); + m_detailsWidget->setSummaryText(ok ? QString("%1 %2").arg(m_validText).arg(m_infoText) + : m_invalidText); +} + +} // namespace Utils diff --git a/src/libs/utils/summarywidget.h b/src/libs/utils/summarywidget.h new file mode 100644 index 00000000000..102a39f8a22 --- /dev/null +++ b/src/libs/utils/summarywidget.h @@ -0,0 +1,52 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "utils_global.h" + +#include "detailswidget.h" +#include "expected.h" +#include "infolabel.h" + +#include + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT SummaryWidget : public QWidget +{ +public: + SummaryWidget(const QMap &validationPoints, const QString &validText, + const QString &invalidText, DetailsWidget *detailsWidget); + + template + void setPointValid(int key, const expected_str &test) + { + setPointValid(key, test.has_value(), test.has_value() ? QString{} : test.error()); + } + + void setPointValid(int key, bool valid, const QString errorText = {}); + bool rowsOk(const QList &keys) const; + bool allRowsOk() const; + void setInfoText(const QString &text); + void setInProgressText(const QString &text); + void setSetupOk(bool ok); + +private: + void updateUi(); + + class RowData { + public: + InfoLabel *m_infoLabel = nullptr; + bool m_valid = false; + QString m_validText; + }; + + QString m_validText; + QString m_invalidText; + QString m_infoText; + DetailsWidget *m_detailsWidget = nullptr; + QMap m_validationData; +}; + +} // namespace Utils diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index d03387e71ee..f08279ab043 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -307,6 +307,8 @@ QtcLibrary { "styledbar.h", "stylehelper.cpp", "stylehelper.h", + "summarywidget.cpp", + "summarywidget.h", "synchronizedvalue.h", "templateengine.cpp", "templateengine.h", diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 4ae99b23aec..ce386f1bd1d 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -20,12 +20,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include @@ -53,107 +53,6 @@ namespace Android::Internal { static Q_LOGGING_CATEGORY(androidsettingswidget, "qtc.android.androidsettingswidget", QtWarningMsg); constexpr int requiredJavaMajorVersion = 17; -class SummaryWidget : public QWidget -{ - class RowData { - public: - InfoLabel *m_infoLabel = nullptr; - bool m_valid = false; - QString m_validText; - }; - -public: - SummaryWidget(const QMap &validationPoints, const QString &validText, - const QString &invalidText, DetailsWidget *detailsWidget) : - QWidget(detailsWidget), - m_validText(validText), - m_invalidText(invalidText), - m_detailsWidget(detailsWidget) - { - QTC_CHECK(m_detailsWidget); - auto layout = new QVBoxLayout(this); - layout->setContentsMargins(22, 0, 0, 12); - layout->setSpacing(4); - for (auto itr = validationPoints.cbegin(); itr != validationPoints.cend(); ++itr) { - RowData data; - data.m_infoLabel = new InfoLabel(itr.value()); - data.m_validText = itr.value(); - layout->addWidget(data.m_infoLabel); - m_validationData[itr.key()] = data; - setPointValid(itr.key(), false); - } - m_detailsWidget->setWidget(this); - setContentsMargins(0, 0, 0, 0); - } - - template - void setPointValid(int key, const expected_str &test) - { - setPointValid(key, test.has_value(), test.has_value() ? QString{} : test.error()); - } - - void setPointValid(int key, bool valid, const QString errorText = {}) - { - if (!m_validationData.contains(key)) - return; - RowData &data = m_validationData[key]; - data.m_valid = valid; - data.m_infoLabel->setType(valid ? InfoLabel::Ok : InfoLabel::NotOk); - data.m_infoLabel->setText(valid || errorText.isEmpty() ? data.m_validText : errorText); - updateUi(); - } - - bool rowsOk(const QList &keys) const - { - for (auto key : keys) { - if (!m_validationData[key].m_valid) - return false; - } - return true; - } - - bool allRowsOk() const - { - return rowsOk(m_validationData.keys()); - } - - void setInfoText(const QString &text) - { - m_infoText = text; - updateUi(); - } - - void setInProgressText(const QString &text) - { - m_detailsWidget->setIcon({}); - m_detailsWidget->setSummaryText(QString("%1...").arg(text)); - m_detailsWidget->setState(DetailsWidget::Collapsed); - } - - void setSetupOk(bool ok) - { - m_detailsWidget->setState(ok ? DetailsWidget::Collapsed : DetailsWidget::Expanded); - } - - void setState(DetailsWidget::State state) - { - m_detailsWidget->setState(state); - } - -private: - void updateUi() { - bool ok = allRowsOk(); - m_detailsWidget->setIcon(ok ? Icons::OK.icon() : Icons::CRITICAL.icon()); - m_detailsWidget->setSummaryText(ok ? QString("%1 %2").arg(m_validText).arg(m_infoText) - : m_invalidText); - } - QString m_validText; - QString m_invalidText; - QString m_infoText; - DetailsWidget *m_detailsWidget = nullptr; - QMap m_validationData; -}; - class AndroidSettingsWidget final : public Core::IOptionsPageWidget { public: diff --git a/src/plugins/projectexplorer/windowsappsdksettings.cpp b/src/plugins/projectexplorer/windowsappsdksettings.cpp index 556a30a2c4c..680cdf44435 100644 --- a/src/plugins/projectexplorer/windowsappsdksettings.cpp +++ b/src/plugins/projectexplorer/windowsappsdksettings.cpp @@ -17,13 +17,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include @@ -100,108 +100,6 @@ static std::optional saveToDisk(const FilePath &filename, QIODevice *da return {}; } -class SummaryWidget : public QWidget -{ - class RowData { - public: - InfoLabel *m_infoLabel = nullptr; - bool m_valid = false; - QString m_validText; - }; - -public: - SummaryWidget(const QMap &validationPoints, const QString &validText, - const QString &invalidText, DetailsWidget *detailsWidget) : - QWidget(detailsWidget), - m_validText(validText), - m_invalidText(invalidText), - m_detailsWidget(detailsWidget) - { - QTC_CHECK(m_detailsWidget); - auto layout = new QVBoxLayout(this); - layout->setContentsMargins(22, 0, 0, 12); - layout->setSpacing(4); - for (auto itr = validationPoints.cbegin(); itr != validationPoints.cend(); ++itr) { - RowData data; - data.m_infoLabel = new InfoLabel(itr.value()); - data.m_validText = itr.value(); - layout->addWidget(data.m_infoLabel); - m_validationData[itr.key()] = data; - setPointValid(itr.key(), false); - } - m_detailsWidget->setWidget(this); - setContentsMargins(0, 0, 0, 0); - } - - template - void setPointValid(int key, const expected_str &test) - { - setPointValid(key, test.has_value(), test.has_value() ? QString{} : test.error()); - } - - void setPointValid(int key, bool valid, const QString errorText = {}) - { - if (!m_validationData.contains(key)) - return; - RowData &data = m_validationData[key]; - data.m_valid = valid; - data.m_infoLabel->setType(valid ? InfoLabel::Ok : InfoLabel::NotOk); - data.m_infoLabel->setText(valid || errorText.isEmpty() ? data.m_validText : errorText); - updateUi(); - } - - bool rowsOk(const QList &keys) const - { - for (auto key : keys) { - if (!m_validationData[key].m_valid) - return false; - } - return true; - } - - bool allRowsOk() const - { - return rowsOk(m_validationData.keys()); - } - - void setInfoText(const QString &text) - { - m_infoText = text; - updateUi(); - } - - void setInProgressText(const QString &text) - { - m_detailsWidget->setIcon({}); - m_detailsWidget->setSummaryText(QString("%1...").arg(text)); - m_detailsWidget->setState(DetailsWidget::Collapsed); - } - - void setSetupOk(bool ok) - { - m_detailsWidget->setState(ok ? DetailsWidget::Collapsed : DetailsWidget::Expanded); - } - - void setState(DetailsWidget::State state) - { - m_detailsWidget->setState(state); - } - -private: - void updateUi() - { - bool ok = allRowsOk(); - m_detailsWidget->setIcon(ok ? Icons::OK.icon() : Icons::CRITICAL.icon()); - m_detailsWidget->setSummaryText(ok ? QString("%1 %2").arg(m_validText).arg(m_infoText) - : m_invalidText); - } - QString m_validText; - QString m_invalidText; - QString m_infoText; - DetailsWidget *m_detailsWidget = nullptr; - QMap m_validationData; -}; - class WindowsSettingsWidget final : public Core::IOptionsPageWidget { public: From e548f5a32bf01003a5bc0d4ab89e49ccc426659b Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 16 Dec 2024 16:37:23 +0100 Subject: [PATCH 435/989] ProjectExplorer: (Mostly) implement IDevice::filePath on top of rootPath Separate implementation led to mixed results depending on the exact path of creation, leading to confusion in the debugger when paths of files reported by the debugger were matched with already opened files in the EditorManager. DesktopDevice is the odd-one out due to the fixed C:\ rootPath() on Windows and filePath() not using (and possibly wanting) this. Change-Id: I02858747524107124189498c777cc79b546ecce9 Reviewed-by: Christian Kandeler --- src/plugins/docker/dockerdevice.cpp | 7 ------- src/plugins/docker/dockerdevice.h | 1 - .../projectexplorer/devicesupport/desktopdevice.cpp | 1 + src/plugins/projectexplorer/devicesupport/idevice.cpp | 4 ++-- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 73f8c59da6b..3eb9e37f2ae 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -1071,13 +1071,6 @@ DeviceTester *DockerDevice::createDeviceTester() return nullptr; } -FilePath DockerDevice::filePath(const QString &pathOnDevice) const -{ - return FilePath::fromParts(Constants::DOCKER_DEVICE_SCHEME, - repoAndTagEncoded(), - pathOnDevice); -} - bool DockerDevice::handlesFile(const FilePath &filePath) const { if (filePath.scheme() == u"device" && filePath.host() == id().toString()) diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index 0f929bdaf6c..ea2f0d21feb 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -37,7 +37,6 @@ public: ProjectExplorer::DeviceTester *createDeviceTester() override; Utils::FilePath rootPath() const override; - Utils::FilePath filePath(const QString &pathOnDevice) const override; bool canMount(const Utils::FilePath &filePath) const override { diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index b1299403486..d485aee2c92 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -120,6 +120,7 @@ expected_str DesktopDevice::systemEnvironmentWithError() const FilePath DesktopDevice::rootPath() const { + // FIXME: This is ugly as .filePath(xxx) and .rootPath().withNewPath(xxx) diverge here. if (id() == DESKTOP_DEVICE_ID) return HostOsInfo::root(); return IDevice::rootPath(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 411398bfdef..fb438b03034 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -261,8 +261,7 @@ DeviceFileAccess *IDevice::fileAccess() const FilePath IDevice::filePath(const QString &pathOnDevice) const { - // match DeviceManager::deviceForPath - return FilePath::fromParts(u"device", id().toString(), pathOnDevice); + return rootPath().withNewPath(pathOnDevice); } FilePath IDevice::debugServerPath() const @@ -682,6 +681,7 @@ void IDevice::setMachineType(MachineType machineType) FilePath IDevice::rootPath() const { + // match DeviceManager::deviceForPath return FilePath::fromParts(u"device", id().toString(), u"/"); } From ee83ab69e57f7bae26867af27645b2f05f4c977c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 13 Dec 2024 14:38:40 +0100 Subject: [PATCH 436/989] QbsProjectManager: Factor out some common code Change-Id: Id5a6d74d9cef4f2d7696e8f9931a9ac931848367 Reviewed-by: Christian Stenger --- src/plugins/qbsprojectmanager/qbsproject.cpp | 5 +---- src/plugins/qbsprojectmanager/qbssession.cpp | 23 +++++++------------- src/plugins/qbsprojectmanager/qbssession.h | 2 ++ 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 508d9eac36a..51a57e0de3a 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -682,10 +682,7 @@ void QbsBuildSystem::updateAfterBuild() void QbsBuildSystem::generateErrors(const ErrorInfo &e) { - for (const ErrorInfoItem &item : e.items) { - TaskHub::addTask(BuildSystemTask(Task::Error, item.description, - item.filePath, item.line)); - } + e.generateTasks(Task::Error); } void QbsBuildSystem::prepareForParsing() diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index 7219f9cadc0..8964100bfaf 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -11,7 +11,6 @@ #include "qbssettings.h" #include -#include #include #include #include @@ -493,13 +492,7 @@ void QbsSession::handlePacket(const QJsonObject &packet) } else if (type == "log-data") { Core::MessageManager::writeSilently("[qbs] " + packet.value("message").toString()); } else if (type == "warning") { - const ErrorInfo errorInfo = ErrorInfo(packet.value("warning").toObject()); - - // TODO: This loop occurs a lot. Factor it out. - for (const ErrorInfoItem &item : errorInfo.items) { - TaskHub::addTask(BuildSystemTask(Task::Warning, item.description, - item.filePath, item.line)); - } + ErrorInfo(packet.value("warning").toObject()).generateTasks(Task::Warning); } else if (type == "task-started") { emit taskStarted(packet.value("description").toString(), packet.value("max-progress").toInt()); @@ -536,13 +529,7 @@ void QbsSession::handlePacket(const QJsonObject &packet) d->reply = packet; d->eventLoop.quit(); } else if (type == "protocol-error") { - const ErrorInfo errorInfo = ErrorInfo(packet.value("error").toObject()); - - // TODO: This loop occurs a lot. Factor it out. - for (const ErrorInfoItem &item : errorInfo.items) { - TaskHub::addTask(BuildSystemTask(Task::Error, item.description, - item.filePath, item.line)); - } + ErrorInfo(packet.value("error").toObject()).generateTasks(Task::Error); setError(Error::ProtocolError); } } @@ -703,6 +690,12 @@ QString ErrorInfo::toString() const .join('\n'); } +void ErrorInfo::generateTasks(ProjectExplorer::Task::TaskType type) const +{ + for (const ErrorInfoItem &item : items) + TaskHub::addTask(BuildSystemTask(type, item.description, item.filePath, item.line)); +} + void forAllProducts(const QJsonObject &project, const WorkerFunction &productFunction) { for (const QJsonValue &p : project.value("products").toArray()) diff --git a/src/plugins/qbsprojectmanager/qbssession.h b/src/plugins/qbsprojectmanager/qbssession.h index 2f0d906ee42..93724827b8b 100644 --- a/src/plugins/qbsprojectmanager/qbssession.h +++ b/src/plugins/qbsprojectmanager/qbssession.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include @@ -45,6 +46,7 @@ public: QString toString() const; bool hasError() const { return !items.isEmpty(); } + void generateTasks(ProjectExplorer::Task::TaskType type) const; QList items; }; From 6b452d5cf270cfdea1a269ed83fa30ba284fd988 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 17 Dec 2024 16:33:01 +0100 Subject: [PATCH 437/989] QbsProjectManager: Prefer profile settings page for devicification Change-Id: Ifff6d4eea81bc0741495dfb8e062580afa4e3db3 Reviewed-by: hjk --- .../qbsprofilessettingspage.cpp | 80 ++++++++++++------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp index c7d2f504239..ace5c60eeb3 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp @@ -7,11 +7,11 @@ #include "qbsprojectmanagerconstants.h" #include "qbsprojectmanagertr.h" -#include +#include +#include #include #include #include -#include #include #include #include @@ -53,36 +53,51 @@ private: class ProfileModel : public Utils::TreeModel { public: - ProfileModel() : TreeModel(static_cast(nullptr)) + ProfileModel(const QList &validKits) : TreeModel(static_cast(nullptr)) { setHeader(QStringList{Tr::tr("Key"), Tr::tr("Value")}); - reload(); + reload(validKits); } - void reload() + void reload(const QList &validKits) { ProfileTreeItem * const newRoot = new ProfileTreeItem(QString(), QString()); QHash itemMap; - const QStringList output = QbsProfileManager::runQbsConfig( - QbsProfileManager::QbsConfigOp::Get, "profiles").split('\n', Qt::SkipEmptyParts); - for (QString line : output) { - line = line.trimmed(); - line = line.mid(QString("profiles.").length()); - const int colonIndex = line.indexOf(':'); - if (colonIndex == -1) - continue; - const QStringList key = line.left(colonIndex).trimmed().split('.', Qt::SkipEmptyParts); - const QString value = line.mid(colonIndex + 1).trimmed(); - QStringList partialKey; - ProfileTreeItem *parent = newRoot; - for (const QString &keyComponent : key) { - partialKey << keyComponent; - ProfileTreeItem *&item = itemMap[partialKey]; - if (!item) { - item = new ProfileTreeItem(keyComponent, partialKey == key ? value : QString()); - parent->appendChild(item); + QHash> kitsPerBuildDevice; + for (const Kit * const k : validKits) { + if (const IDeviceConstPtr dev = BuildDeviceKitAspect::device(k)) + kitsPerBuildDevice[dev.get()] << k; + } + for (auto it = kitsPerBuildDevice.cbegin(); it != kitsPerBuildDevice.cend(); ++it) { + const QStringList output + = QbsProfileManager::runQbsConfig(QbsProfileManager::QbsConfigOp::Get, "profiles") + .split('\n', Qt::SkipEmptyParts); + const QStringList profileNames = Utils::transform(it.value(), [](const Kit *k) { + return QbsProfileManager::profileNameForKit(k); + }); + for (QString line : output) { + line = line.trimmed(); + line = line.mid(QString("profiles.").length()); + const int colonIndex = line.indexOf(':'); + if (colonIndex == -1) + continue; + const QStringList key + = line.left(colonIndex).trimmed().split('.', Qt::SkipEmptyParts); + if (key.isEmpty() || !profileNames.contains(key.first())) + continue; + const QString value = line.mid(colonIndex + 1).trimmed(); + QStringList partialKey; + ProfileTreeItem *parent = newRoot; + for (const QString &keyComponent : key) { + partialKey << keyComponent; + ProfileTreeItem *&item = itemMap[partialKey]; + if (!item) { + item = new ProfileTreeItem( + keyComponent, partialKey == key ? value : QString()); + parent->appendChild(item); + } + parent = item; } - parent = item; } } setRootItem(newRoot); @@ -99,8 +114,9 @@ private: void refreshKitsList(); void displayCurrentProfile(); + const QList validKits() const; - ProfileModel m_model; + ProfileModel m_model{validKits()}; QComboBox *m_kitsComboBox; QLabel *m_profileValueLabel; QTreeView *m_propertiesView; @@ -153,17 +169,16 @@ void QbsProfilesSettingsWidget::refreshKitsList() { m_kitsComboBox->disconnect(this); m_propertiesView->setModel(nullptr); - m_model.reload(); + const QList kits = validKits(); + m_model.reload(validKits()); m_profileValueLabel->clear(); Utils::Id currentId; if (m_kitsComboBox->count() > 0) currentId = Utils::Id::fromSetting(m_kitsComboBox->currentData()); m_kitsComboBox->clear(); int newCurrentIndex = -1; - QList validKits = KitManager::kits(); - Utils::erase(validKits, [](const Kit *k) { return !k->isValid(); }); - const bool hasKits = !validKits.isEmpty(); - for (const Kit * const kit : std::as_const(validKits)) { + const bool hasKits = !kits.isEmpty(); + for (const Kit * const kit : kits) { if (kit->id() == currentId) newCurrentIndex = m_kitsComboBox->count(); m_kitsComboBox->addItem(kit->displayName(), kit->id().toSetting()); @@ -198,4 +213,9 @@ void QbsProfilesSettingsWidget::displayCurrentProfile() } } +const QList QbsProfilesSettingsWidget::validKits() const +{ + return Utils::filtered(KitManager::kits(), [](const Kit *k) { return k->isValid(); }); +} + } // QbsProjectManager::Internal From 34ab9710740268ee3a071704491f2dbf404738bc Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Dec 2024 16:26:36 +0100 Subject: [PATCH 438/989] ProjectExplorer: Save a check before assigning The check can be more expensive then the assignment. Change-Id: Ibcdb37a575769d8614f5014cfbc172017bd0ff7f Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/projectnodes.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index 414c123086c..03c7d33edc5 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -132,11 +132,8 @@ void Node::setIsGenerated(bool g) m_flags = static_cast(m_flags & ~FlagIsGenerated); } -void Node::setAbsoluteFilePathAndLine(const Utils::FilePath &path, int line) +void Node::setAbsoluteFilePathAndLine(const FilePath &path, int line) { - if (m_filePath == path && m_line == line) - return; - m_filePath = path; m_line = line; } From c5eba3869cfa600fa2efed6e3a396b73391ec7ec Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 17 Dec 2024 14:31:39 +0100 Subject: [PATCH 439/989] Revert "ProjectExplorer: Fix offset calculation of links inside tasks" Align the offset calculation of the formats in OutputTaskParser::setDetailsFormat and Task::addLinkDetail revert the fix for the wrong offset calculation of 0bc70fdac141cff05fe27e22f50bd910486cadee. Fixes: QTCREATORBUG-32181 Change-Id: Ic4c5273e389f163b17c3636c7bc83aeaf9432823 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/task.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp index 91788306b82..a3fa35eff3d 100644 --- a/src/plugins/projectexplorer/task.cpp +++ b/src/plugins/projectexplorer/task.cpp @@ -136,7 +136,7 @@ QString Task::formattedDescription(DescriptionTags tags, const QString &extraHea return {}; QString text = description(tags); - const int offset = (tags & WithSummary) ? summary.size() + 1 : 0; + const int offset = (tags & WithSummary) ? 0 : summary.size() + 1; static const QString linkTagStartPlaceholder("__QTC_LINK_TAG_START__"); static const QString linkTagEndPlaceholder("__QTC_LINK_TAG_END__"); static const QString linkEndPlaceholder("__QTC_LINK_END__"); @@ -169,7 +169,8 @@ void Task::addLinkDetail(const QString &link) QTextCharFormat format; format.setAnchor(true); format.setAnchorHref(link); - formats << QTextLayout::FormatRange{0, int(link.length()), format}; + const int offset = summary.length() + 1; + formats << QTextLayout::FormatRange{offset, int(link.length()), format}; } // From c6feb2b30e386c9aa201ff16bde1c1844e672abc Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Dec 2024 15:42:18 +0100 Subject: [PATCH 440/989] Qbs: Some code cosmetics in qbsnodetreebuilder.* Remove unused #include, use C++17 namespaces and convert the class with a static function to a free function. Change-Id: Iaeed2b2583786c7b85fd9a2e5bcfe7eabb492866 Reviewed-by: Christian Kandeler --- .../qbsprojectmanager/qbsnodetreebuilder.cpp | 18 +++++++---------- .../qbsprojectmanager/qbsnodetreebuilder.h | 20 ++++++------------- src/plugins/qbsprojectmanager/qbsproject.cpp | 2 +- 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp index 82e896e77a8..83d08470586 100644 --- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp @@ -4,7 +4,6 @@ #include "qbsnodetreebuilder.h" #include "qbsnodes.h" -#include "qbsproject.h" #include "qbsprojectmanagertr.h" #include "qbssession.h" @@ -20,8 +19,7 @@ using namespace ProjectExplorer; using namespace Utils; -namespace QbsProjectManager { -namespace Internal { +namespace QbsProjectManager::Internal { static FileType fileType(const QJsonObject &artifact) { @@ -49,7 +47,7 @@ static FileType fileType(const QJsonObject &artifact) return FileType::Unknown; } -void setupArtifact(FolderNode *root, const QJsonObject &artifact) +static void setupArtifact(FolderNode *root, const QJsonObject &artifact) { const FilePath path = FilePath::fromString(artifact.value("file-path").toString()); const FileType type = fileType(artifact); @@ -83,7 +81,6 @@ static void setupGeneratedArtifacts(FolderNode *root, const QJsonObject &product root->compress(); } - static std::unique_ptr buildGroupNodeTree(const QJsonObject &grp) { const Location location = locationFromObject(grp); @@ -179,10 +176,10 @@ static QStringList unreferencedBuildSystemFiles(const QJsonObject &project) return unreferenced; } -QbsProjectNode *QbsNodeTreeBuilder::buildTree(const QString &projectName, - const Utils::FilePath &projectFile, - const Utils::FilePath &projectDir, - const QJsonObject &projectData) +QbsProjectNode *buildQbsProjectTree(const QString &projectName, + const FilePath &projectFile, + const FilePath &projectDir, + const QJsonObject &projectData) { auto root = std::make_unique(projectData); @@ -219,5 +216,4 @@ QbsProjectNode *QbsNodeTreeBuilder::buildTree(const QString &projectName, return root.release(); } -} // namespace Internal -} // namespace QbsProjectManager +} // namespace QbsProjectManager::Internal diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.h b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.h index 4527b4f39da..bee9df03ef1 100644 --- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.h +++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.h @@ -5,8 +5,6 @@ #include -#include - QT_BEGIN_NAMESPACE class QJsonObject; class QString; @@ -14,19 +12,13 @@ QT_END_NAMESPACE namespace Utils { class FilePath; } -namespace QbsProjectManager { -namespace Internal { +namespace QbsProjectManager::Internal { class QbsProjectNode; -class QbsNodeTreeBuilder -{ -public: - static QbsProjectNode *buildTree(const QString &projectName, - const Utils::FilePath &projectFile, - const Utils::FilePath &projectDir, - const QJsonObject &projectData); -}; +QbsProjectNode *buildQbsProjectTree(const QString &projectName, + const Utils::FilePath &projectFile, + const Utils::FilePath &projectDir, + const QJsonObject &projectData); -} // namespace Internal -} // namespace QbsProjectManager +} // namespace QbsProjectManager::Internal diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 51a57e0de3a..5e206a77cce 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -522,7 +522,7 @@ void QbsBuildSystem::updateProjectNodes(const std::function &continuati continuation(); }); m_treeCreationWatcher->setFuture(Utils::asyncRun(ProjectExplorerPlugin::sharedThreadPool(), - QThread::LowPriority, &QbsNodeTreeBuilder::buildTree, + QThread::LowPriority, &buildQbsProjectTree, project()->displayName(), project()->projectFilePath(), project()->projectDirectory(), projectData())); } From fb72cc9c94d40fb54bbd18d4be999a9fd55fbf74 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 17 Dec 2024 16:07:35 +0100 Subject: [PATCH 441/989] Qbs: Pass top project dir around when building project tree This way the various nodes can be created with the right remote name in the remote case. This makes opening file nodes from the tree work also for remote files. Change-Id: I48e9e80d3101b2d568ff2c8383b0a502c6da1bfc Reviewed-by: Christian Kandeler --- .../qbsprojectmanager/qbsnodetreebuilder.cpp | 49 ++++++++++--------- src/plugins/qbsprojectmanager/qbssession.cpp | 4 +- src/plugins/qbsprojectmanager/qbssession.h | 3 +- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp index 83d08470586..24661ac3255 100644 --- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp @@ -47,9 +47,9 @@ static FileType fileType(const QJsonObject &artifact) return FileType::Unknown; } -static void setupArtifact(FolderNode *root, const QJsonObject &artifact) +static void setupArtifact(FolderNode *root, const QJsonObject &artifact, const FilePath &top) { - const FilePath path = FilePath::fromString(artifact.value("file-path").toString()); + const FilePath path = top.withNewPath(artifact.value("file-path").toString()); const FileType type = fileType(artifact); const bool isGenerated = artifact.value("is-generated").toBool(); @@ -68,22 +68,25 @@ static void setupArtifact(FolderNode *root, const QJsonObject &artifact) root->addNestedNode(std::move(node)); } -static void setupArtifactsForGroup(FolderNode *root, const QJsonObject &group) +static void setupArtifactsForGroup(FolderNode *root, const QJsonObject &group, const FilePath &top) { - forAllArtifacts(group, [root](const QJsonObject &artifact) { setupArtifact(root, artifact); }); + forAllArtifacts(group, [root, top](const QJsonObject &artifact) { + setupArtifact(root, artifact, top); + }); root->compress(); } -static void setupGeneratedArtifacts(FolderNode *root, const QJsonObject &product) +static void setupGeneratedArtifacts(FolderNode *root, const QJsonObject &product, const FilePath &top) { - forAllArtifacts(product, ArtifactType::Generated, - [root](const QJsonObject &artifact) { setupArtifact(root, artifact); }); + forAllArtifacts(product, ArtifactType::Generated, [root, top](const QJsonObject &artifact) { + setupArtifact(root, artifact, top); + }); root->compress(); } -static std::unique_ptr buildGroupNodeTree(const QJsonObject &grp) +static std::unique_ptr buildGroupNodeTree(const QJsonObject &grp, const FilePath &top) { - const Location location = locationFromObject(grp); + const Location location = locationFromObject(grp, top); FilePath baseDir = location.filePath.parentDir(); QString prefix = grp.value("prefix").toString(); if (prefix.endsWith('/')) { @@ -98,13 +101,13 @@ static std::unique_ptr buildGroupNodeTree(const QJsonObject &grp) auto fileNode = std::make_unique(FilePath(), FileType::Project); fileNode->setAbsoluteFilePathAndLine(location.filePath, location.line); result->addNode(std::move(fileNode)); - setupArtifactsForGroup(result.get(), grp); + setupArtifactsForGroup(result.get(), grp, top); return result; } -static std::unique_ptr buildProductNodeTree(const QJsonObject &prd) +static std::unique_ptr buildProductNodeTree(const QJsonObject &prd, const FilePath &top) { - const Location location = locationFromObject(prd); + const Location location = locationFromObject(prd, top); auto result = std::make_unique(prd); result->setAbsoluteFilePathAndLine(location.filePath.parentDir(), -1); auto fileNode = std::make_unique(FilePath(), FileType::Project); @@ -115,24 +118,24 @@ static std::unique_ptr buildProductNodeTree(const QJsonObject &p if (grp.value("name") == prd.value("name") && grp.value("location") == prd.value("location")) { // Set implicit product group right onto this node: - setupArtifactsForGroup(result.get(), grp); + setupArtifactsForGroup(result.get(), grp, top); continue; } - result->addNode(buildGroupNodeTree(grp)); + result->addNode(buildGroupNodeTree(grp, top)); } // Add "Generated Files" Node: auto genFiles = std::make_unique( - FilePath::fromString(prd.value("build-directory").toString())); + top.withNewPath(prd.value("build-directory").toString())); genFiles->setDisplayName(::QbsProjectManager::Tr::tr("Generated files")); - setupGeneratedArtifacts(genFiles.get(), prd); + setupGeneratedArtifacts(genFiles.get(), prd, top); result->addNode(std::move(genFiles)); return result; } -static void setupProjectNode(QbsProjectNode *node) +static void setupProjectNode(QbsProjectNode *node, const FilePath &top) { - const Location loc = locationFromObject(node->projectData()); + const Location loc = locationFromObject(node->projectData(), top); node->setAbsoluteFilePathAndLine(loc.filePath.parentDir(), -1); auto fileNode = std::make_unique(node->filePath(), FileType::Project); fileNode->setAbsoluteFilePathAndLine(loc.filePath, loc.line); @@ -140,12 +143,12 @@ static void setupProjectNode(QbsProjectNode *node) for (const QJsonValue &v : node->projectData().value("sub-projects").toArray()) { auto subProject = std::make_unique(v.toObject()); - setupProjectNode(subProject.get()); + setupProjectNode(subProject.get(), top); node->addNode(std::move(subProject)); } for (const QJsonValue &v : node->projectData().value("products").toArray()) - node->addNode(buildProductNodeTree(v.toObject())); + node->addNode(buildProductNodeTree(v.toObject(), top)); } static QSet referencedBuildSystemFiles(const QJsonObject &prjData) @@ -189,7 +192,7 @@ QbsProjectNode *buildQbsProjectTree(const QString &projectName, auto fileNode = std::make_unique(projectFile, FileType::Project); root->addNode(std::move(fileNode)); } else { - setupProjectNode(root.get()); + setupProjectNode(root.get(), projectDir); } if (root->displayName().isEmpty()) @@ -200,10 +203,10 @@ QbsProjectNode *buildQbsProjectTree(const QString &projectName, auto buildSystemFiles = std::make_unique(projectDir); buildSystemFiles->setDisplayName(Tr::tr("Qbs files")); - const FilePath buildDir = FilePath::fromString(projectData.value("build-directory").toString()); + const FilePath buildDir = projectFile.withNewPath(projectData.value("build-directory").toString()); const QStringList files = unreferencedBuildSystemFiles(projectData); for (const QString &f : files) { - const FilePath filePath = FilePath::fromString(f); + const FilePath filePath = projectFile.withNewPath(f); if (filePath.isChildOf(projectDir)) { auto fileNode = std::make_unique(filePath, FileType::Project); fileNode->setIsGenerated(filePath.isChildOf(buildDir)); diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index 8964100bfaf..7fcbd75713e 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -725,10 +725,10 @@ void forAllArtifacts(const QJsonObject &group, const WorkerFunction &artifactFun artifactFunction(v.toObject()); } -Location locationFromObject(const QJsonObject &o) +Location locationFromObject(const QJsonObject &o, const FilePath &projectDir) { const QJsonObject loc = o.value("location").toObject(); - return Location(FilePath::fromString(loc.value("file-path").toString()), + return Location(projectDir.withNewPath(loc.value("file-path").toString()), loc.value("line").toInt()); } diff --git a/src/plugins/qbsprojectmanager/qbssession.h b/src/plugins/qbsprojectmanager/qbssession.h index 93724827b8b..71f88bfbe36 100644 --- a/src/plugins/qbsprojectmanager/qbssession.h +++ b/src/plugins/qbsprojectmanager/qbssession.h @@ -95,7 +95,8 @@ public: const Utils::FilePath filePath; const int line; }; -Location locationFromObject(const QJsonObject &o); // Project, Product or Group +// Project, Product or Group +Location locationFromObject(const QJsonObject &o, const Utils::FilePath &projectDir); class QbsSession : public QObject { From 8225bbc07cb0b50c317ef8bcb0795ee13cac6a0e Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 18 Dec 2024 10:19:53 +0100 Subject: [PATCH 442/989] Android: Check device when creating information from it Also, paddle back to the more common use of shared ptr in connection to devices. Change-Id: Ic7ffe9efff7314a7e44e66dcdfcdc39da1bdd5bd Reviewed-by: Jarek Kobus --- src/plugins/android/androiddeployqtstep.cpp | 6 +++--- src/plugins/android/androiddevice.cpp | 3 ++- src/plugins/android/androiddevice.h | 2 +- src/plugins/android/androidrunner.cpp | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 0a0717d26cd..a5a1c22241a 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -208,14 +208,14 @@ bool AndroidDeployQtStep::init() if (selectedAbis.isEmpty()) selectedAbis.append(bs->extraData(buildKey, Constants::AndroidAbi).toString()); - const auto dev = dynamic_cast(RunDeviceKitAspect::device(kit()).get()); + const auto dev = std::dynamic_pointer_cast(RunDeviceKitAspect::device(kit())); if (!dev) { reportWarningOrError(Tr::tr("No valid deployment device is set."), Task::Error); return false; } // TODO: use AndroidDevice directly instead of AndroidDeviceInfo. - const AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(dev); + const AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromDevice(dev); if (!info.isValid()) { reportWarningOrError(Tr::tr("The deployment device \"%1\" is invalid.") @@ -548,7 +548,7 @@ QWidget *AndroidDeployQtStep::createConfigWidget() return; const IDevice::ConstPtr device = RunDeviceKitAspect::device(currentTarget->kit()); - const AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(device.get()); + const AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromDevice(device); if (!info.isValid()) // aborted return; diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 94a9ee9ddee..d29f149f5b7 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -459,8 +459,9 @@ IDevice::Ptr AndroidDevice::create() return IDevice::Ptr(new AndroidDevice); } -AndroidDeviceInfo AndroidDevice::androidDeviceInfoFromIDevice(const IDevice *dev) +AndroidDeviceInfo AndroidDevice::androidDeviceInfoFromDevice(const ConstPtr &dev) { + QTC_ASSERT(dev, return {}); AndroidDeviceInfo info; info.state = dev->deviceState(); info.avdName = dev->extraData(Constants::AndroidAvdName).toString(); diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index 975ec932362..a53686d22d3 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -21,7 +21,7 @@ public: AndroidDevice(); static IDevice::Ptr create(); - static AndroidDeviceInfo androidDeviceInfoFromIDevice(const IDevice *dev); + static AndroidDeviceInfo androidDeviceInfoFromDevice(const IDevice::ConstPtr &dev); static Utils::Id idFromDeviceInfo(const AndroidDeviceInfo &info); static Utils::Id idFromAvdInfo(const CreateAvdInfo &info); diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 07a4f079368..2da1492e8d8 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -60,7 +60,7 @@ void AndroidRunner::start() qCDebug(androidRunnerLog) << "Run without deployment"; const IDevice::ConstPtr device = RunDeviceKitAspect::device(target->kit()); - AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(device.get()); + AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromDevice(device); setDeviceSerialNumber(target, info.serialNumber); deviceSerialNumber = info.serialNumber; apiLevel = info.sdk; From a39f8398ba68b570ad4f016baff6ced88f407f8f Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 18 Dec 2024 12:37:08 +0100 Subject: [PATCH 443/989] Themes: Update color tokens Primitive color palette has updated color values and some changed color names. Light and dark tokens have updated mappings to primitive colors. Change-Id: I764a57241bf310e0e0225eb9c750b0bef9adc31b Reviewed-by: Cristian Adam --- share/qtcreator/themes/dark.figmatokens | 10 +- share/qtcreator/themes/light.figmatokens | 8 +- share/qtcreator/themes/primitive-colors.inc | 184 ++++++++------------ 3 files changed, 79 insertions(+), 123 deletions(-) diff --git a/share/qtcreator/themes/dark.figmatokens b/share/qtcreator/themes/dark.figmatokens index f9deb3e3757..bd3cfd30848 100644 --- a/share/qtcreator/themes/dark.figmatokens +++ b/share/qtcreator/themes/dark.figmatokens @@ -30,11 +30,11 @@ Token_Stroke_Subtle=Primitive-Neutral-650 Token_Notification_Alert_Default=Primitive-Yellow-400 Token_Notification_Alert_Muted=Primitive-Yellow-600 -Token_Notification_Alert_Subtle=Primitive-Yellow-1000 +Token_Notification_Alert_Subtle=Primitive-Yellow-900 -Token_Notification_Neutral_Default=Primitive-QAMidnight-300 -Token_Notification_Neutral_Muted=Primitive-QAMidnight-600 -Token_Notification_Neutral_Subtle=Primitive-QAMidnight-900 +Token_Notification_Neutral_Default=Primitive-Blue-400 +Token_Notification_Neutral_Muted=Primitive-Blue-500 +Token_Notification_Neutral_Subtle=Primitive-Blue-900 Token_Notification_Danger_Default=Primitive-Red-400 Token_Notification_Danger_Muted=Primitive-Red-600 @@ -44,7 +44,7 @@ Token_Notification_Success_Default=Primitive-Neon-500 Token_Notification_Success_Muted=Primitive-Neon-700 Token_Notification_Success_Subtle=Primitive-Neon-1000 -Token_Gradient01_Start=Primitive-Pine-700 +Token_Gradient01_Start=Primitive-Pine-1000 Token_Gradient01_End=Primitive-Neon-600 Token_Gradient02_Start=Primitive-Neutral-600 Token_Gradient02_End=Primitive-Neutral-450 diff --git a/share/qtcreator/themes/light.figmatokens b/share/qtcreator/themes/light.figmatokens index 657da85ce32..64b6a25101f 100644 --- a/share/qtcreator/themes/light.figmatokens +++ b/share/qtcreator/themes/light.figmatokens @@ -32,9 +32,9 @@ Token_Notification_Alert_Default=Primitive-Yellow-600 Token_Notification_Alert_Muted=Primitive-Yellow-500 Token_Notification_Alert_Subtle=Primitive-Yellow-100 -Token_Notification_Neutral_Default=Primitive-QAMidnight-700 -Token_Notification_Neutral_Muted=Primitive-QAMidnight-600 -Token_Notification_Neutral_Subtle=Primitive-QAMidnight-100 +Token_Notification_Neutral_Default=Primitive-Blue-600 +Token_Notification_Neutral_Muted=Primitive-Blue-400 +Token_Notification_Neutral_Subtle=Primitive-Blue-100 Token_Notification_Danger_Default=Primitive-Red-600 Token_Notification_Danger_Muted=Primitive-Red-500 @@ -45,6 +45,6 @@ Token_Notification_Success_Muted=Primitive-Neon-600 Token_Notification_Success_Subtle=Primitive-Neon-100 Token_Gradient01_Start=Primitive-Neon-500 -Token_Gradient01_End=Primitive-Pine-600 +Token_Gradient01_End=Primitive-Pine-800 Token_Gradient02_Start=Primitive-Neutral-400 Token_Gradient02_End=Primitive-Neutral-550 diff --git a/share/qtcreator/themes/primitive-colors.inc b/share/qtcreator/themes/primitive-colors.inc index eaf28a82bb2..ef7eb97abdc 100644 --- a/share/qtcreator/themes/primitive-colors.inc +++ b/share/qtcreator/themes/primitive-colors.inc @@ -1,121 +1,77 @@ [Colors] -Primitive-Neutral-000=ffffffff -Primitive-Neutral-100=fffcfcfc -Primitive-Neutral-150=fff2f2f2 -Primitive-Neutral-200=ffe3e3e3 -Primitive-Neutral-250=ffcdcdcd -Primitive-Neutral-300=ffbebebe -Primitive-Neutral-350=ffaeaeae -Primitive-Neutral-400=ff9d9d9d -Primitive-Neutral-450=ff909090 -Primitive-Neutral-500=ff737373 -Primitive-Neutral-550=ff595959 -Primitive-Neutral-600=ff4a4a4a -Primitive-Neutral-650=ff3f3f3f -Primitive-Neutral-700=ff353535 -Primitive-Neutral-750=ff2d2d2d -Primitive-Neutral-800=ff262626 -Primitive-Neutral-850=ff1f1f1f -Primitive-Neutral-900=ff181818 -Primitive-Neutral-950=ff121212 -Primitive-Neutral-1000=ff000000 +Primitive-Neutral-000=FFFFFFFF +Primitive-Neutral-100=FFFCFCFC +Primitive-Neutral-150=FFF2F2F2 +Primitive-Neutral-200=FFE3E3E3 +Primitive-Neutral-250=FFCDCDCD +Primitive-Neutral-300=FFBEBEBE +Primitive-Neutral-350=FFAEAEAE +Primitive-Neutral-400=FF9D9D9D +Primitive-Neutral-450=FF909090 +Primitive-Neutral-500=FF737373 +Primitive-Neutral-550=FF595959 +Primitive-Neutral-600=FF4A4A4A +Primitive-Neutral-650=FF3F3F3F +Primitive-Neutral-700=FF353535 +Primitive-Neutral-750=FF2D2D2D +Primitive-Neutral-800=FF262626 +Primitive-Neutral-850=FF1F1F1F +Primitive-Neutral-900=FF181818 +Primitive-Neutral-950=FF121212 +Primitive-Neutral-1000=FF000000 -Primitive-Neon-100=ffdffced -Primitive-Neon-200=ffc2f8da -Primitive-Neon-300=ff96f0bc -Primitive-Neon-400=ff5cdc8a -Primitive-Neon-500=ff4fc779 -Primitive-Neon-600=ff3fa561 -Primitive-Neon-700=ff32824e -Primitive-Neon-800=ff296640 -Primitive-Neon-900=ff194229 -Primitive-Neon-1000=ff102c1c +Primitive-Neon-100=FFDBFDEC +Primitive-Neon-200=FFB9F9D9 +Primitive-Neon-300=FF83F2BA +Primitive-Neon-400=FF2CDE85 +Primitive-Neon-500=FF1EC974 +Primitive-Neon-600=FF12A75D +Primitive-Neon-700=FF12834B +Primitive-Neon-800=FF14673E +Primitive-Neon-900=FF0D4328 +Primitive-Neon-1000=FF092C1B -Primitive-Pine-100=ffe3f4fc -Primitive-Pine-200=ffc2eafa -Primitive-Pine-300=ff8fdcf7 -Primitive-Pine-400=ff5cc9f1 -Primitive-Pine-500=ff44b4e1 -Primitive-Pine-600=ff3492c0 -Primitive-Pine-700=ff297595 -Primitive-Pine-800=ff236176 -Primitive-Pine-900=ff1e4e5e -Primitive-Pine-1000=ff124149 +Primitive-Red-100=FFFACED9 +Primitive-Red-200=FFF0A4B7 +Primitive-Red-300=FFEA718E +Primitive-Red-400=FFE34269 +Primitive-Red-500=FFDC1343 +Primitive-Red-600=FFB00F36 +Primitive-Red-700=FF840B28 +Primitive-Red-800=FF561020 +Primitive-Red-900=FF411721 +Primitive-Red-1000=FF33161C -Primitive-Lemon-100=fff4f6ca -Primitive-Lemon-200=ffeef1a0 -Primitive-Lemon-300=ffebf074 -Primitive-Lemon-400=ffe3ec4e -Primitive-Lemon-500=ffdde83b -Primitive-Lemon-600=ffd0da37 -Primitive-Lemon-700=ffb5be2f -Primitive-Lemon-800=ff9aa327 -Primitive-Lemon-900=ff848b1f -Primitive-Lemon-1000=ff6f7419 +Primitive-Pine-100=FFE1F4FD +Primitive-Pine-200=FFBCEAFB +Primitive-Pine-300=FF80DBF9 +Primitive-Pine-400=FF3CC8F4 +Primitive-Pine-500=FF13B2E4 +Primitive-Pine-600=FF0690C3 +Primitive-Pine-700=FF077497 +Primitive-Pine-800=FF0A6078 +Primitive-Pine-900=FF0E4E5F +Primitive-Pine-1000=FF00414A -Primitive-Moss-100=ffeaecdb -Primitive-Moss-200=ffd7ddba -Primitive-Moss-300=ffbcc792 -Primitive-Moss-400=ffa2af6f -Primitive-Moss-500=ff859452 -Primitive-Moss-600=ff67753f -Primitive-Moss-700=ff515b32 -Primitive-Moss-800=ff41492c -Primitive-Moss-900=ff383e28 -Primitive-Moss-1000=ff1d2014 +Primitive-Yellow-100=FFFFEBCD +Primitive-Yellow-200=FFF7D6A5 +Primitive-Yellow-300=FFF3C279 +Primitive-Yellow-400=FFEFAD4C +Primitive-Yellow-500=FFEB991F +Primitive-Yellow-600=FFBC7A19 +Primitive-Yellow-700=FF8D5C13 +Primitive-Yellow-800=FF5E3D0C +Primitive-Yellow-900=FF3F2C11 +Primitive-Yellow-1000=FF31240F -Primitive-DS-100=ffbee8f6 -Primitive-DS-200=ffaae0f2 -Primitive-DS-300=ff81d2ed -Primitive-DS-400=ff5ec2e6 -Primitive-DS-500=ff44b4e1 -Primitive-DS-600=ff368fb4 -Primitive-DS-700=ff276c87 -Primitive-DS-800=ff19485a -Primitive-DS-900=ff123543 -Primitive-DS-1000=ff0a242d - -Primitive-QAViolet-100=ffefe9fe -Primitive-QAViolet-200=ffe2d6fd -Primitive-QAViolet-300=ffcab3fc -Primitive-QAViolet-400=ffad88fa -Primitive-QAViolet-500=ff8f5ff4 -Primitive-QAViolet-600=ff7843e7 -Primitive-QAViolet-700=ff6434cb -Primitive-QAViolet-800=ff562da6 -Primitive-QAViolet-900=ff482585 -Primitive-QAViolet-1000=ff2d1262 - -Primitive-QAMidnight-100=ffd8d3f7 -Primitive-QAMidnight-200=ffb6aef1 -Primitive-QAMidnight-300=ff8478e7 -Primitive-QAMidnight-400=ff6357cf -Primitive-QAMidnight-500=ff443aac -Primitive-QAMidnight-600=ff352ca7 -Primitive-QAMidnight-700=ff262088 -Primitive-QAMidnight-800=ff231d6d -Primitive-QAMidnight-900=ff1d184e -Primitive-QAMidnight-1000=ff181439 - -Primitive-Yellow-100=fffdeacf -Primitive-Yellow-200=fff3d5a9 -Primitive-Yellow-300=ffeec080 -Primitive-Yellow-400=ffe8ab58 -Primitive-Yellow-500=ffe39736 -Primitive-Yellow-600=ffb6792a -Primitive-Yellow-700=ff885b1f -Primitive-Yellow-800=ff5b3c14 -Primitive-Yellow-900=ff3d2c14 -Primitive-Yellow-1000=ff302411 - -Primitive-Red-100=fff5cfd9 -Primitive-Red-200=ffe9a5b7 -Primitive-Red-300=ffe0738f -Primitive-Red-400=ffd8456a -Primitive-Red-500=ffd01a46 -Primitive-Red-600=ffa71439 -Primitive-Red-700=ff7d0f2a -Primitive-Red-800=ff511121 -Primitive-Red-900=ff3e1821 -Primitive-Red-1000=ff31161c +Primitive-Blue-100=FFD9D2F9 +Primitive-Blue-200=FFB7ABF4 +Primitive-Blue-300=FF8671EC +Primitive-Blue-400=FF654FD4 +Primitive-Blue-500=FF4530B0 +Primitive-Blue-600=FF361EAB +Primitive-Blue-700=FF27138B +Primitive-Blue-800=FF241570 +Primitive-Blue-900=FF1E1450 +Primitive-Blue-1000=FF18123A From 6981f54f366429a348d1142b5ee2b29b8ae33194 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 18 Dec 2024 14:42:38 +0100 Subject: [PATCH 444/989] QtSupport: Make product name in linkingPurposeText dynamic Change-Id: I76f2bed36e7a169ccbea3843f6eddd0433b3db4f Reviewed-by: Eike Ziller --- share/qtcreator/translations/qtcreator_de.ts | 4 ++-- share/qtcreator/translations/qtcreator_fr.ts | 4 ++-- share/qtcreator/translations/qtcreator_pl.ts | 2 +- share/qtcreator/translations/qtcreator_zh_CN.ts | 2 +- src/plugins/qtsupport/qtoptionspage.cpp | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index d84cc17aa7c..24e629a2023 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -49912,8 +49912,8 @@ wirklich entfernen? Die ausgewählte Qt-Version muss dem Gerät entsprechen. - Linking with a Qt installation automatically registers Qt versions and kits, and other tools that were installed with that Qt installer, in this Qt Creator installation. Other Qt Creator installations are not affected. - Das Verknüpfen mit einer Qt-Installation registriert Qt-Versionen, Kits und andere mit dem Qt-Installationsprogramm installierte Werkzeuge automatisch in dieser Qt Creator-Installation. Dies hat keine Auswirkung auf andere Qt Creator-Installationen. + Linking with a Qt installation automatically registers Qt versions and kits, and other tools that were installed with that Qt installer, in this %1 installation. Other %1 installations are not affected. + Das Verknüpfen mit einer Qt-Installation registriert Qt-Versionen, Kits und andere mit dem Qt-Installationsprogramm installierte Werkzeuge automatisch in dieser %1-Installation. Dies hat keine Auswirkung auf andere %1-Installationen. %1's resource directory is not writable. diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index cc92aaa752d..eaf627ab4ea 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -50241,8 +50241,8 @@ Le déploiement vers ce répertoire entrainera la suppression des fichiers déj L’exécutable qmake %1 n’a pas pu être ajouté : %2 - Linking with a Qt installation automatically registers Qt versions and kits, and other tools that were installed with that Qt installer, in this Qt Creator installation. Other Qt Creator installations are not affected. - L’établissement d’un lien avec une installation de Qt enregistre automatiquement les versions et les kits de Qt, ainsi que les autres outils qui ont été installés avec ce programme d’installation de Qt, dans cette installation de Qt Creator. Les autres installations de Qt Creator ne sont pas concernées. + Linking with a Qt installation automatically registers Qt versions and kits, and other tools that were installed with that Qt installer, in this %1 installation. Other %1 installations are not affected. + L’établissement d’un lien avec une installation de Qt enregistre automatiquement les versions et les kits de Qt, ainsi que les autres outils qui ont été installés avec ce programme d’installation de Qt, dans cette installation de %1. Les autres installations de %1 ne sont pas concernées. %1's resource directory is not writable. diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index 00278fb998f..fd634e9cae6 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -47548,7 +47548,7 @@ Are you sure you want to continue? Nie można dodać pliku wykonywalnego qmake %1: %2 - Linking with a Qt installation automatically registers Qt versions and kits, and other tools that were installed with that Qt installer, in this Qt Creator installation. Other Qt Creator installations are not affected. + Linking with a Qt installation automatically registers Qt versions and kits, and other tools that were installed with that Qt installer, in this %1 installation. Other %1 installations are not affected. diff --git a/share/qtcreator/translations/qtcreator_zh_CN.ts b/share/qtcreator/translations/qtcreator_zh_CN.ts index 66a622a4259..e99999ac614 100644 --- a/share/qtcreator/translations/qtcreator_zh_CN.ts +++ b/share/qtcreator/translations/qtcreator_zh_CN.ts @@ -38550,7 +38550,7 @@ For more details, see /etc/sysctl.d/10-ptrace.conf - Linking with a Qt installation automatically registers Qt versions and kits, and other tools that were installed with that Qt installer, in this Qt Creator installation. Other Qt Creator installations are not affected. + Linking with a Qt installation automatically registers Qt versions and kits, and other tools that were installed with that Qt installer, in this %1 installation. Other %1 installations are not affected. diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 3c9be77128e..ec6b3b720ef 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -899,8 +899,8 @@ static QString linkingPurposeText() { return Tr::tr( "Linking with a Qt installation automatically registers Qt versions and kits, and other " - "tools that were installed with that Qt installer, in this Qt Creator installation. Other " - "Qt Creator installations are not affected."); + "tools that were installed with that Qt installer, in this %1 installation. Other %1 " + "installations are not affected.").arg(QGuiApplication::applicationDisplayName()); } static bool canLinkWithQt(QString *toolTip) From 9d74bd337db1497b7e7378acbceb8c15baa25049 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 18 Dec 2024 16:03:57 +0100 Subject: [PATCH 445/989] QbsProfileManager: Support remote qbs Change-Id: I3bb352b0338beb8a3b36316af1a9bd67f7502b52 Reviewed-by: hjk --- .../defaultpropertyprovider.cpp | 2 +- .../qbsbuildconfiguration.cpp | 10 +- .../qbsprojectmanager/qbslanguageclient.cpp | 9 +- .../qbsprojectmanager/qbsprofilemanager.cpp | 100 ++++++++++-------- .../qbsprojectmanager/qbsprofilemanager.h | 8 +- .../qbsprofilessettingspage.cpp | 10 +- src/plugins/qbsprojectmanager/qbsproject.cpp | 13 ++- .../qbsprojectmanager/qbsprojectparser.cpp | 12 ++- .../qbsprojectmanager/qbsprojectparser.h | 2 + src/plugins/qbsprojectmanager/qbssession.cpp | 25 +++-- src/plugins/qbsprojectmanager/qbssession.h | 3 +- src/plugins/qbsprojectmanager/qbssettings.cpp | 57 ++++++---- src/plugins/qbsprojectmanager/qbssettings.h | 17 +-- 13 files changed, 162 insertions(+), 106 deletions(-) diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index ebf6d5e80e2..957ae83ec58 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -347,7 +347,7 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor Core::MessageManager::writeFlashing( Tr::tr("C and C++ compiler paths differ. C compiler may not work.")); } - data.insert(QLatin1String(CPP_TOOLCHAINPATH), mainFilePath.absolutePath().toString()); + data.insert(QLatin1String(CPP_TOOLCHAINPATH), mainFilePath.absolutePath().path()); if (auto gcc = mainTc->asGccToolchain()) { QStringList compilerFlags = gcc->platformCodeGenFlags(); diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp index 3f3858cbf0e..8e67f24ae50 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -238,14 +239,17 @@ QStringList QbsBuildConfiguration::products() const QString QbsBuildConfiguration::equivalentCommandLine(const QbsBuildStepData &stepData) const { + const IDeviceConstPtr dev = BuildDeviceKitAspect::device(kit()); + if (!dev) + return Tr::tr(""); CommandLine commandLine; - commandLine.addArg(QDir::toNativeSeparators(QbsSettings::qbsExecutableFilePath().toString())); + commandLine.addArg(QbsSettings::qbsExecutableFilePath(dev).nativePath()); commandLine.addArg(stepData.command); const QString buildDir = buildDirectory().nativePath(); commandLine.addArgs({"-d", buildDir}); commandLine.addArgs({"-f", project()->projectFilePath().nativePath()}); - if (QbsSettings::useCreatorSettingsDirForQbs()) - commandLine.addArgs({"--settings-dir", QbsSettings::qbsSettingsBaseDir().nativePath()}); + if (QbsSettings::useCreatorSettingsDirForQbs(dev)) + commandLine.addArgs({"--settings-dir", QbsSettings::qbsSettingsBaseDir(dev).nativePath()}); if (stepData.dryRun) commandLine.addArg("--dry-run"); if (stepData.keepGoing) diff --git a/src/plugins/qbsprojectmanager/qbslanguageclient.cpp b/src/plugins/qbsprojectmanager/qbslanguageclient.cpp index e067d4ae37f..4f2461f82b0 100644 --- a/src/plugins/qbsprojectmanager/qbslanguageclient.cpp +++ b/src/plugins/qbsprojectmanager/qbslanguageclient.cpp @@ -27,9 +27,9 @@ namespace QbsProjectManager::Internal { class QbsLanguageClientInterface : public LocalSocketClientInterface { public: - QbsLanguageClientInterface(const QString &serverPath) + QbsLanguageClientInterface(const QString &serverPath, const FilePath &qbsExecutable) : LocalSocketClientInterface(serverPath), - m_qbsExecutable(QbsSettings::qbsExecutableFilePath()) {} + m_qbsExecutable(qbsExecutable) {} private: Utils::FilePath serverDeviceTemplate() const override{ return m_qbsExecutable; }; @@ -48,9 +48,10 @@ public: QPointer buildSystem; }; - QbsLanguageClient::QbsLanguageClient(const QString &serverPath, QbsBuildSystem *buildSystem) - : Client(new QbsLanguageClientInterface(serverPath)), d(new Private(this)) + : Client(new QbsLanguageClientInterface( + serverPath, QbsSettings::qbsExecutableFilePath(*buildSystem->kit()))) + , d(new Private(this)) { d->buildSystem = buildSystem; setName(QString::fromLatin1("qbs@%1").arg(serverPath)); diff --git a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp index 617672665c7..c07993b5549 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp @@ -7,12 +7,11 @@ #include "qbsprojectmanagertr.h" #include "qbssettings.h" -#include #include +#include +#include #include #include -#include -#include #include #include #include @@ -24,6 +23,8 @@ #include #include +using namespace ProjectExplorer; + namespace QbsProjectManager { static QList g_propertyProviders; @@ -94,7 +95,7 @@ static PropertyProvider &defaultPropertyProvider() return theDefaultPropertyProvider; } -static QString kitNameKeyInQbsSettings(const ProjectExplorer::Kit *kit) +static QString kitNameKeyInQbsSettings(const Kit *kit) { return "preferences.qtcreator.kit." + kit->id().toString(); } @@ -103,17 +104,17 @@ QbsProfileManager::QbsProfileManager() { setObjectName(QLatin1String("QbsProjectManager")); - if (ProjectExplorer::KitManager::instance()->isLoaded()) { - m_kitsToBeSetupForQbs = ProjectExplorer::KitManager::kits(); + if (KitManager::instance()->isLoaded()) { + m_kitsToBeSetupForQbs = KitManager::kits(); } else { - connect(ProjectExplorer::KitManager::instance(), &ProjectExplorer::KitManager::kitsLoaded, - this, [this] { m_kitsToBeSetupForQbs = ProjectExplorer::KitManager::kits(); } ); + connect(KitManager::instance(), &KitManager::kitsLoaded, + this, [this] { m_kitsToBeSetupForQbs = KitManager::kits(); } ); } - connect(ProjectExplorer::KitManager::instance(), &ProjectExplorer::KitManager::kitAdded, this, + connect(KitManager::instance(), &KitManager::kitAdded, this, &QbsProfileManager::addProfileFromKit); - connect(ProjectExplorer::KitManager::instance(), &ProjectExplorer::KitManager::kitUpdated, this, + connect(KitManager::instance(), &KitManager::kitUpdated, this, &QbsProfileManager::handleKitUpdate); - connect(ProjectExplorer::KitManager::instance(), &ProjectExplorer::KitManager::kitRemoved, this, + connect(KitManager::instance(), &KitManager::kitRemoved, this, &QbsProfileManager::handleKitRemoval); connect(&QbsSettings::instance(), &QbsSettings::settingsChanged, this, &QbsProfileManager::updateAllProfiles); @@ -127,7 +128,7 @@ QbsProfileManager *QbsProfileManager::instance() return &theQbsProfileManager; } -QString QbsProfileManager::ensureProfileForKit(const ProjectExplorer::Kit *k) +QString QbsProfileManager::ensureProfileForKit(const Kit *k) { if (!k) return QString(); @@ -135,60 +136,64 @@ QString QbsProfileManager::ensureProfileForKit(const ProjectExplorer::Kit *k) return profileNameForKit(k); } -void QbsProfileManager::updateProfileIfNecessary(const ProjectExplorer::Kit *kit) +void QbsProfileManager::updateProfileIfNecessary(const Kit *kit) { // kit in list <=> profile update is necessary // Note that the const_cast is safe, as we do not call any non-const methods on the object. - if (instance()->m_kitsToBeSetupForQbs.removeOne(const_cast(kit))) + if (instance()->m_kitsToBeSetupForQbs.removeOne(const_cast(kit))) instance()->addProfileFromKit(kit); } void QbsProfileManager::updateAllProfiles() { - for (const auto * const kit : ProjectExplorer::KitManager::kits()) + for (const auto * const kit : KitManager::kits()) addProfileFromKit(kit); } -void QbsProfileManager::addProfileFromKit(const ProjectExplorer::Kit *k) +void QbsProfileManager::addProfileFromKit(const Kit *k) { - const QString name = profileNameForKit(k); - runQbsConfig(QbsConfigOp::Unset, "profiles." + name); - runQbsConfig(QbsConfigOp::Set, kitNameKeyInQbsSettings(k), name); + if (const IDeviceConstPtr dev = BuildDeviceKitAspect::device(k)) { + const QString name = profileNameForKit(k); + runQbsConfig(dev, QbsConfigOp::Unset, "profiles." + name); + runQbsConfig(dev, QbsConfigOp::Set, kitNameKeyInQbsSettings(k), name); - // set up properties: - QVariantMap data = defaultPropertyProvider().properties(k, QVariantMap()); - for (PropertyProvider *provider : std::as_const(g_propertyProviders)) { - if (provider->canHandle(k)) - data = provider->properties(k, data); - } - if (const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(k)) - data.insert("moduleProviders.Qt.qmakeFilePaths", qt->qmakeFilePath().toString()); + // set up properties: + QVariantMap data = defaultPropertyProvider().properties(k, QVariantMap()); + for (PropertyProvider *provider : std::as_const(g_propertyProviders)) { + if (provider->canHandle(k)) + data = provider->properties(k, data); + } + if (const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(k)) + data.insert("moduleProviders.Qt.qmakeFilePaths", qt->qmakeFilePath().toString()); - if (QbsSettings::qbsVersion() < QVersionNumber({1, 20})) { - const QString keyPrefix = "profiles." + name + "."; - for (auto it = data.begin(); it != data.end(); ++it) - runQbsConfig(QbsConfigOp::Set, keyPrefix + it.key(), it.value()); - } else { - runQbsConfig(QbsConfigOp::AddProfile, name, data); + if (QbsSettings::qbsVersion(dev) < QVersionNumber({1, 20})) { + const QString keyPrefix = "profiles." + name + "."; + for (auto it = data.begin(); it != data.end(); ++it) + runQbsConfig(dev, QbsConfigOp::Set, keyPrefix + it.key(), it.value()); + } else { + runQbsConfig(dev, QbsConfigOp::AddProfile, name, data); + } } emit qbsProfilesUpdated(); } -void QbsProfileManager::handleKitUpdate(ProjectExplorer::Kit *kit) +void QbsProfileManager::handleKitUpdate(Kit *kit) { if (!m_kitsToBeSetupForQbs.contains(kit)) addProfileFromKit(kit); } -void QbsProfileManager::handleKitRemoval(ProjectExplorer::Kit *kit) +void QbsProfileManager::handleKitRemoval(Kit *kit) { m_kitsToBeSetupForQbs.removeOne(kit); - runQbsConfig(QbsConfigOp::Unset, kitNameKeyInQbsSettings(kit)); - runQbsConfig(QbsConfigOp::Unset, "profiles." + profileNameForKit(kit)); + if (const IDeviceConstPtr dev = BuildDeviceKitAspect::device(kit)) { + runQbsConfig(dev, QbsConfigOp::Unset, kitNameKeyInQbsSettings(kit)); + runQbsConfig(dev, QbsConfigOp::Unset, "profiles." + profileNameForKit(kit)); + } emit qbsProfilesUpdated(); } -QString QbsProfileManager::profileNameForKit(const ProjectExplorer::Kit *kit) +QString QbsProfileManager::profileNameForKit(const Kit *kit) { if (!kit) return QString(); @@ -197,11 +202,16 @@ QString QbsProfileManager::profileNameForKit(const ProjectExplorer::Kit *kit) kit->id().name(), QCryptographicHash::Sha1).toHex().left(8))); } -QString QbsProfileManager::runQbsConfig(QbsConfigOp op, const QString &key, const QVariant &value) +QString QbsProfileManager::runQbsConfig( + const IDeviceConstPtr &device, + QbsConfigOp op, + const QString &key, + const QVariant &value) { + QTC_ASSERT(device, return {}); QStringList args; - if (QbsSettings::useCreatorSettingsDirForQbs()) - args << "--settings-dir" << QbsSettings::qbsSettingsBaseDir().path(); + if (QbsSettings::useCreatorSettingsDirForQbs(device)) + args << "--settings-dir" << QbsSettings::qbsSettingsBaseDir(device).path(); switch (op) { case QbsConfigOp::Get: args << key; @@ -222,23 +232,23 @@ QString QbsProfileManager::runQbsConfig(QbsConfigOp op, const QString &key, cons break; } } - const Utils::FilePath qbsConfigExe = QbsSettings::qbsConfigFilePath(); + const Utils::FilePath qbsConfigExe = QbsSettings::qbsConfigFilePath(device); if (qbsConfigExe.isEmpty() || !qbsConfigExe.exists()) return {}; Utils::Process qbsConfig; - qbsConfig.setEnvironment(QbsSettings::qbsProcessEnvironment()); + qbsConfig.setEnvironment(QbsSettings::qbsProcessEnvironment(device)); qbsConfig.setCommand({qbsConfigExe, args}); qbsConfig.start(); using namespace std::chrono_literals; if (!qbsConfig.waitForFinished(5s)) { Core::MessageManager::writeFlashing( - Tr::tr("Failed to run qbs config: %1").arg(qbsConfig.errorString())); + Tr::tr("Failed to run qbs config: %1").arg(qbsConfig.exitMessage())); } else if (qbsConfig.exitCode() != 0) { Core::MessageManager::writeFlashing( Tr::tr("Failed to run qbs config: %1") .arg(QString::fromLocal8Bit(qbsConfig.rawStdErr()))); } - return QString::fromLocal8Bit(qbsConfig.rawStdOut()).trimmed(); + return qbsConfig.stdOut().trimmed(); } QVariant fromJSLiteral(const QString &str) diff --git a/src/plugins/qbsprojectmanager/qbsprofilemanager.h b/src/plugins/qbsprojectmanager/qbsprofilemanager.h index 5e9dacea819..06e09ca6b32 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilemanager.h +++ b/src/plugins/qbsprojectmanager/qbsprofilemanager.h @@ -3,7 +3,7 @@ #pragma once -#include "qbsprojectmanager_global.h" +#include #include #include @@ -30,7 +30,11 @@ public: static QString profileNameForKit(const ProjectExplorer::Kit *kit); static void updateProfileIfNecessary(const ProjectExplorer::Kit *kit); enum class QbsConfigOp { Get, Set, Unset, AddProfile }; - static QString runQbsConfig(QbsConfigOp op, const QString &key, const QVariant &value = {}); + static QString runQbsConfig( + const ProjectExplorer::IDeviceConstPtr &device, + QbsConfigOp op, + const QString &key, + const QVariant &value = {}); signals: void qbsProfilesUpdated(); diff --git a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp index ace5c60eeb3..9886e8aad2c 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp @@ -63,15 +63,15 @@ public: { ProfileTreeItem * const newRoot = new ProfileTreeItem(QString(), QString()); QHash itemMap; - QHash> kitsPerBuildDevice; + QHash> kitsPerBuildDevice; for (const Kit * const k : validKits) { if (const IDeviceConstPtr dev = BuildDeviceKitAspect::device(k)) - kitsPerBuildDevice[dev.get()] << k; + kitsPerBuildDevice[dev] << k; } for (auto it = kitsPerBuildDevice.cbegin(); it != kitsPerBuildDevice.cend(); ++it) { - const QStringList output - = QbsProfileManager::runQbsConfig(QbsProfileManager::QbsConfigOp::Get, "profiles") - .split('\n', Qt::SkipEmptyParts); + const QStringList output = QbsProfileManager::runQbsConfig( + it.key(), QbsProfileManager::QbsConfigOp::Get, "profiles") + .split('\n', Qt::SkipEmptyParts); const QStringList profileNames = Utils::transform(it.value(), [](const Kit *k) { return QbsProfileManager::profileNameForKit(k); }); diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 5e206a77cce..2f60adba562 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -152,7 +153,7 @@ static bool supportsNodeAction(ProjectAction action, const Node *node) QbsBuildSystem::QbsBuildSystem(QbsBuildConfiguration *bc) : BuildSystem(bc->target()), - m_session(new QbsSession(this)), + m_session(new QbsSession(this, BuildDeviceKitAspect::device(bc->kit()))), m_cppCodeModelUpdater( ProjectUpdaterFactory::createProjectUpdater(ProjectExplorer::Constants::CXX_LANGUAGE_ID)), m_buildConfiguration(bc) @@ -627,16 +628,18 @@ void QbsBuildSystem::startParsing(const QVariantMap &extraConfig) { QTC_ASSERT(!m_qbsProjectParser, return); + FilePath dir = m_buildConfiguration->buildDirectory(); Store config = m_buildConfiguration->qbsConfiguration(); - if (!config.contains(Constants::QBS_INSTALL_ROOT_KEY)) { - config.insert(Constants::QBS_INSTALL_ROOT_KEY, m_buildConfiguration->macroExpander() - ->expand(QbsSettings::defaultInstallDirTemplate())); + QString installRoot = config.value(Constants::QBS_INSTALL_ROOT_KEY).toString(); + if (installRoot.isEmpty()) { + installRoot = m_buildConfiguration->macroExpander()->expand( + QbsSettings::defaultInstallDirTemplate()); } + config.insert(Constants::QBS_INSTALL_ROOT_KEY, FilePath::fromString(installRoot).path()); config.insert(Constants::QBS_RESTORE_BEHAVIOR_KEY, "restore-and-track-changes"); for (auto it = extraConfig.begin(); it != extraConfig.end(); ++it) config.insert(keyFromString(it.key()), it.value()); Environment env = m_buildConfiguration->environment(); - FilePath dir = m_buildConfiguration->buildDirectory(); m_guard = guardParsingRun(); diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp index 8363d28ce93..28913182941 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp @@ -9,6 +9,8 @@ #include "qbssettings.h" #include +#include +#include #include #include @@ -16,6 +18,7 @@ #include #include +using namespace ProjectExplorer; using namespace Utils; namespace QbsProjectManager::Internal { @@ -26,7 +29,8 @@ namespace QbsProjectManager::Internal { QbsProjectParser::QbsProjectParser(QbsBuildSystem *buildSystem) : m_projectFilePath(buildSystem->project()->projectFilePath()), - m_session(buildSystem->session()) + m_session(buildSystem->session()), + m_device(BuildDeviceKitAspect::device(buildSystem->kit())) { m_fi = new QFutureInterface(); m_fi->setProgressRange(0, 0); @@ -71,8 +75,10 @@ void QbsProjectParser::parse(const Store &config, const Environment &env, userConfig.take(Constants::QBS_FORCE_PROBES_KEY).toBool()); request.insert(Constants::QBS_RESTORE_BEHAVIOR_KEY, userConfig.take(Constants::QBS_RESTORE_BEHAVIOR_KEY).toString()); - if (QbsSettings::useCreatorSettingsDirForQbs()) - request.insert("settings-directory", QbsSettings::qbsSettingsBaseDir().path()); + const IDeviceConstPtr device = m_device.lock(); + QTC_ASSERT(device, return); + if (QbsSettings::useCreatorSettingsDirForQbs(device)) + request.insert("settings-directory", QbsSettings::qbsSettingsBaseDir(device).path()); request.insert("overridden-properties", QJsonObject::fromVariantMap(mapFromStore(userConfig))); // People don't like it when files are created as a side effect of opening a project, diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.h b/src/plugins/qbsprojectmanager/qbsprojectparser.h index 4e7e041eaf8..0e79c68f846 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.h +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.h @@ -5,6 +5,7 @@ #include "qbssession.h" +#include #include #include @@ -44,6 +45,7 @@ private: Utils::Environment m_environment; const Utils::FilePath m_projectFilePath; QbsSession * const m_session; + const ProjectExplorer::DeviceConstRef m_device; ErrorInfo m_error; QJsonObject m_projectData; bool m_parsing = false; diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index 7fcbd75713e..309c1777895 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -11,6 +11,8 @@ #include "qbssettings.h" #include +#include +#include #include #include #include @@ -130,6 +132,9 @@ private: class QbsSession::Private { public: + Private(const IDeviceConstPtr &dev) : device(dev) {} + + DeviceConstRef device; Process *qbsProcess = nullptr; QbsLanguageClient *languageClient = nullptr; PacketReader *packetReader = nullptr; @@ -145,7 +150,8 @@ public: bool fileUpdatePossible = true; }; -QbsSession::QbsSession(QbsBuildSystem *buildSystem) : QObject(buildSystem), d(new Private) +QbsSession::QbsSession(QbsBuildSystem *buildSystem, const IDeviceConstPtr &device) + : QObject(buildSystem), d(new Private(device)) { initialize(); } @@ -191,7 +197,9 @@ void QbsSession::initialize() }); connect(d->packetReader, &PacketReader::packetReceived, this, &QbsSession::handlePacket); d->state = State::Initializing; - const FilePath qbsExe = QbsSettings::qbsExecutableFilePath(); + const IDeviceConstPtr device = d->device.lock(); + QTC_ASSERT(device, return); + const FilePath qbsExe = QbsSettings::qbsExecutableFilePath(device); if (qbsExe.isEmpty()) { QTimer::singleShot(0, this, [this] { setError(Error::NoQbsPath); }); return; @@ -200,7 +208,7 @@ void QbsSession::initialize() QTimer::singleShot(0, this, [this] { setError(Error::InvalidQbsExecutable); }); return; } - d->qbsProcess->setEnvironment(QbsSettings::qbsProcessEnvironment()); + d->qbsProcess->setEnvironment(QbsSettings::qbsProcessEnvironment(device)); d->qbsProcess->setCommand({qbsExe, {"session"}}); d->qbsProcess->start(); } @@ -238,8 +246,7 @@ QString QbsSession::errorString(QbsSession::Error error) return Tr::tr("No qbs executable was found, please set the path in the settings."); case Error::InvalidQbsExecutable: return Tr::tr("The qbs executable was not found at the specified path, or it is not " - "executable (\"%1\").") - .arg(QbsSettings::qbsExecutableFilePath().toUserOutput()); + "executable."); case Error::QbsQuit: return Tr::tr("The qbs process quit unexpectedly."); case Error::QbsFailedToStart: @@ -406,6 +413,8 @@ void QbsSession::insertRequestedModuleProperties(QJsonObject &request) QbsSession::BuildGraphInfo QbsSession::getBuildGraphInfo(const FilePath &bgFilePath, const QStringList &requestedProperties) { + const IDeviceConstPtr device = DeviceManager::deviceForPath(bgFilePath); + QTC_ASSERT(device, return {}); const QFileInfo bgFi = bgFilePath.toFileInfo(); QDir buildRoot = bgFi.dir(); buildRoot.cdUp(); @@ -413,13 +422,13 @@ QbsSession::BuildGraphInfo QbsSession::getBuildGraphInfo(const FilePath &bgFileP request.insert("type", "resolve-project"); request.insert("restore-behavior", "restore-only"); request.insert("configuration-name", bgFi.completeBaseName()); - if (QbsSettings::useCreatorSettingsDirForQbs()) - request.insert("settings-directory", QbsSettings::qbsSettingsBaseDir().path()); + if (QbsSettings::useCreatorSettingsDirForQbs(device)) + request.insert("settings-directory", QbsSettings::qbsSettingsBaseDir(device).path()); request.insert("build-root", buildRoot.path()); request.insert("error-handling-mode", "relaxed"); request.insert("data-mode", "only-if-changed"); request.insert("module-properties", QJsonArray::fromStringList(requestedProperties)); - QbsSession session(nullptr); + QbsSession session(nullptr, device); session.sendRequest(request); QJsonObject reply; BuildGraphInfo bgInfo; diff --git a/src/plugins/qbsprojectmanager/qbssession.h b/src/plugins/qbsprojectmanager/qbssession.h index 71f88bfbe36..d252f2e0a29 100644 --- a/src/plugins/qbsprojectmanager/qbssession.h +++ b/src/plugins/qbsprojectmanager/qbssession.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include @@ -102,7 +103,7 @@ class QbsSession : public QObject { Q_OBJECT public: - explicit QbsSession(QbsBuildSystem *buildSystem); + explicit QbsSession(QbsBuildSystem *buildSystem, const ProjectExplorer::IDeviceConstPtr &device); ~QbsSession() override; enum class State { Initializing, Active, Inactive }; diff --git a/src/plugins/qbsprojectmanager/qbssettings.cpp b/src/plugins/qbsprojectmanager/qbssettings.cpp index 074e22b933c..947f39e4cb6 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.cpp +++ b/src/plugins/qbsprojectmanager/qbssettings.cpp @@ -7,6 +7,9 @@ #include "qbsprojectmanagertr.h" #include +#include +#include +#include #include #include #include @@ -20,6 +23,7 @@ #include #include +using namespace ProjectExplorer; using namespace Utils; namespace QbsProjectManager::Internal { @@ -60,12 +64,22 @@ static bool operator!=(const QbsSettingsData &s1, const QbsSettingsData &s2) return !(s1 == s2); } -FilePath QbsSettings::qbsExecutableFilePath() +FilePath QbsSettings::qbsExecutableFilePath(const Kit &kit) { - FilePath candidate = instance().m_settings.qbsExecutableFilePath; - if (!candidate.exists()) - candidate = defaultQbsExecutableFilePath(); - return candidate; + return qbsExecutableFilePath(BuildDeviceKitAspect::device(&kit)); +} + +FilePath QbsSettings::qbsExecutableFilePath(const IDeviceConstPtr &device) +{ + if (!device) + return {}; + if (device->id() == ProjectExplorer::Constants::DESKTOP_DEVICE_ID) { + FilePath candidate = instance().m_settings.qbsExecutableFilePath; + if (!candidate.exists()) + candidate = defaultQbsExecutableFilePath(); + return candidate; + } + return device->searchExecutableInPath("qbs"); } FilePath QbsSettings::defaultQbsExecutableFilePath() @@ -78,9 +92,9 @@ FilePath QbsSettings::defaultQbsExecutableFilePath() return candidate; } -FilePath QbsSettings::qbsConfigFilePath() +FilePath QbsSettings::qbsConfigFilePath(const IDeviceConstPtr &device) { - const FilePath qbsExe = qbsExecutableFilePath(); + const FilePath qbsExe = qbsExecutableFilePath(device); if (!qbsExe.isExecutableFile()) return {}; const FilePath qbsConfig = qbsExe.absolutePath().pathAppended("qbs-config") @@ -90,9 +104,9 @@ FilePath QbsSettings::qbsConfigFilePath() return qbsConfig; } -Environment QbsSettings::qbsProcessEnvironment() +Environment QbsSettings::qbsProcessEnvironment(const IDeviceConstPtr &device) { - return getQbsProcessEnvironment(qbsExecutableFilePath()); + return getQbsProcessEnvironment(qbsExecutableFilePath(device)); } QString QbsSettings::defaultInstallDirTemplate() @@ -100,22 +114,21 @@ QString QbsSettings::defaultInstallDirTemplate() return instance().m_settings.defaultInstallDirTemplate; } -bool QbsSettings::useCreatorSettingsDirForQbs() +bool QbsSettings::useCreatorSettingsDirForQbs(const IDeviceConstPtr &device) { + if (!device || device->id() != ProjectExplorer::Constants::DESKTOP_DEVICE_ID) + return false; return instance().m_settings.useCreatorSettings; } -FilePath QbsSettings::qbsSettingsBaseDir() +FilePath QbsSettings::qbsSettingsBaseDir(const IDeviceConstPtr &device) { - return useCreatorSettingsDirForQbs() ? Core::ICore::userResourcePath() : FilePath(); + return useCreatorSettingsDirForQbs(device) ? Core::ICore::userResourcePath() : FilePath(); } -QVersionNumber QbsSettings::qbsVersion() +QVersionNumber QbsSettings::qbsVersion(const IDeviceConstPtr &device) { - if (instance().m_settings.qbsVersion.isNull()) - instance().m_settings.qbsVersion = QVersionNumber::fromString( - getQbsVersion(qbsExecutableFilePath())); - return instance().m_settings.qbsVersion; + return QVersionNumber::fromString(getQbsVersion(qbsExecutableFilePath(device))); } QbsSettings &QbsSettings::instance() @@ -168,14 +181,15 @@ public: QbsSettingsPageWidget() { m_qbsExePathChooser.setExpectedKind(PathChooser::ExistingCommand); - m_qbsExePathChooser.setFilePath(QbsSettings::qbsExecutableFilePath()); + const IDeviceConstPtr desktopDevice = DeviceManager::defaultDesktopDevice(); + m_qbsExePathChooser.setFilePath(QbsSettings::qbsExecutableFilePath(desktopDevice)); m_resetQbsExeButton.setText(Tr::tr("Reset")); m_defaultInstallDirLineEdit.setText(QbsSettings::defaultInstallDirTemplate()); m_versionLabel.setText(getQbsVersionString()); //: %1 == "Qt Creator" or "Qt Design Studio" m_settingsDirCheckBox.setText(Tr::tr("Use %1 settings directory for Qbs") .arg(QGuiApplication::applicationDisplayName())); - m_settingsDirCheckBox.setChecked(QbsSettings::useCreatorSettingsDirForQbs()); + m_settingsDirCheckBox.setChecked(QbsSettings::useCreatorSettingsDirForQbs(desktopDevice)); const auto layout = new QFormLayout(this); layout->addRow(&m_settingsDirCheckBox); @@ -197,11 +211,12 @@ public: void apply() final { QbsSettingsData settings = QbsSettings::rawSettingsData(); - if (m_qbsExePathChooser.filePath() != QbsSettings::qbsExecutableFilePath()) + if (m_qbsExePathChooser.filePath() + != QbsSettings::qbsExecutableFilePath(DeviceManager::defaultDesktopDevice())) { settings.qbsExecutableFilePath = m_qbsExePathChooser.filePath(); + } settings.defaultInstallDirTemplate = m_defaultInstallDirLineEdit.text(); settings.useCreatorSettings = m_settingsDirCheckBox.isChecked(); - settings.qbsVersion = {}; QbsSettings::setSettingsData(settings); } diff --git a/src/plugins/qbsprojectmanager/qbssettings.h b/src/plugins/qbsprojectmanager/qbssettings.h index f71cfa3c7e6..de89fd55e3f 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.h +++ b/src/plugins/qbsprojectmanager/qbssettings.h @@ -4,11 +4,12 @@ #pragma once #include - +#include #include #include +namespace ProjectExplorer { class Kit; } namespace Utils { class Environment; } namespace QbsProjectManager::Internal { @@ -18,7 +19,6 @@ class QbsSettingsData public: Utils::FilePath qbsExecutableFilePath; QString defaultInstallDirTemplate; - QVersionNumber qbsVersion; // Ephemeral bool useCreatorSettings = true; }; @@ -28,15 +28,16 @@ class QbsSettings : public QObject public: static QbsSettings &instance(); - static Utils::FilePath qbsExecutableFilePath(); + static Utils::FilePath qbsExecutableFilePath(const ProjectExplorer::Kit &kit); + static Utils::FilePath qbsExecutableFilePath(const ProjectExplorer::IDeviceConstPtr &device); static Utils::FilePath defaultQbsExecutableFilePath(); - static Utils::FilePath qbsConfigFilePath(); - static Utils::Environment qbsProcessEnvironment(); + static Utils::FilePath qbsConfigFilePath(const ProjectExplorer::IDeviceConstPtr &device); + static Utils::Environment qbsProcessEnvironment(const ProjectExplorer::IDeviceConstPtr &device); static bool hasQbsExecutable(); static QString defaultInstallDirTemplate(); - static bool useCreatorSettingsDirForQbs(); - static Utils::FilePath qbsSettingsBaseDir(); - static QVersionNumber qbsVersion(); + static bool useCreatorSettingsDirForQbs(const ProjectExplorer::IDeviceConstPtr &device); + static Utils::FilePath qbsSettingsBaseDir(const ProjectExplorer::IDeviceConstPtr &device); + static QVersionNumber qbsVersion(const ProjectExplorer::IDeviceConstPtr &device); static void setSettingsData(const QbsSettingsData &settings); static QbsSettingsData rawSettingsData(); From e7586024ff6325592376e419a6159b328b2e2092 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 16 Dec 2024 17:13:10 +0100 Subject: [PATCH 446/989] Android: Don't show version of selected NDK in status summary When opening the options page, the first entry in the NDK list widget got automatically selected. The version of that NDK entry was displayed in the status summary, and the status summary got updated when the selection changed. That gave the impression that the selection of an NDK entry has an influence on the configuration of kits. That is not the case, though. The NDK list widget is there to explore and manage available NDKs, and the kit generation mechanism has its own criteria to determine which of those NDKs to use for which kit. This change removes the automatic selection of the first NDK entry, as- well as the displaying of the NDK version in the status summary. The translations of the status summary string are also adapted. Fixes: QTCREATORBUG-31900 Change-Id: Ia5e8d8401bf4e3e76093dc7341198cc8c8678214 Reviewed-by: Jarek Kobus --- share/qtcreator/translations/qtcreator_da.ts | 4 ++-- share/qtcreator/translations/qtcreator_de.ts | 4 ++-- share/qtcreator/translations/qtcreator_fr.ts | 4 ++-- share/qtcreator/translations/qtcreator_hr.ts | 2 +- share/qtcreator/translations/qtcreator_ja.ts | 4 ++-- share/qtcreator/translations/qtcreator_pl.ts | 4 ++-- share/qtcreator/translations/qtcreator_ru.ts | 4 ++-- share/qtcreator/translations/qtcreator_zh_CN.ts | 4 ++-- src/plugins/android/androidsettingswidget.cpp | 11 +++-------- 9 files changed, 18 insertions(+), 23 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 53c0246ee3c..3d7958efe4e 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -1020,8 +1020,8 @@ To add the Qt version, select Options > Build & Run > Qt Versions. - (SDK Version: %1, NDK Version: %2) - (SDK version: %1, NDK version: %2) + (SDK Version: %1) + (SDK version: %1) Select JDK Path diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 24e629a2023..efff9d28f66 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -10902,8 +10902,8 @@ Locked components cannot be modified or selected. URL zum Herunterladen öffnen - (SDK Version: %1, NDK Version: %2) - (SDK-Version: %1, NDK-Version: %2) + (SDK Version: %1) + (SDK-Version: %1) Download and install Android SDK Tools to %1? diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index eaf627ab4ea..56ad2edae26 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -11238,8 +11238,8 @@ dans le navigateur système pour un téléchargement manuel. L'outil git n'est peut-être pas installé correctement sur votre système. - (SDK Version: %1, NDK Version: %2) - (Version du SDK : %1, version du NDK : %2) + (SDK Version: %1) + (Version du SDK : %1) Unset Default diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 93848c19411..87f45ecfcda 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -13803,7 +13803,7 @@ The minimum API level required by the kit is %1. - (SDK Version: %1, NDK Version: %2) + (SDK Version: %1) diff --git a/share/qtcreator/translations/qtcreator_ja.ts b/share/qtcreator/translations/qtcreator_ja.ts index 22f040580f6..a2d7c11b980 100644 --- a/share/qtcreator/translations/qtcreator_ja.ts +++ b/share/qtcreator/translations/qtcreator_ja.ts @@ -11605,8 +11605,8 @@ in the system's browser for manual download. エミュレータのコマンドライン起動オプション(<a href="%1">Help Web Page</a>): - (SDK Version: %1, NDK Version: %2) - (SDK バージョン: %1, NDK バージョン: %2) + (SDK Version: %1) + (SDK バージョン: %1) The selected path already has a valid SDK Tools package. diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index fd634e9cae6..dc2cf55d441 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -9973,8 +9973,8 @@ in the system's browser for manual download. - (SDK Version: %1, NDK Version: %2) - (Wersja SDK: %1, wersja NDK: %2) + (SDK Version: %1) + (Wersja SDK: %1) Unset Default diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 44f5dfa5823..6c2ee7d5551 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -1738,8 +1738,8 @@ Prefix with : if the process is private, use a lowercase name if the process is Программа git, возможно, установлена некорректно в этой системе. - (SDK Version: %1, NDK Version: %2) - (Версия SDK: %1, Версия NDK: %2) + (SDK Version: %1) + (Версия SDK: %1) All essential packages installed for all installed Qt versions. diff --git a/share/qtcreator/translations/qtcreator_zh_CN.ts b/share/qtcreator/translations/qtcreator_zh_CN.ts index e99999ac614..e91db454ce9 100644 --- a/share/qtcreator/translations/qtcreator_zh_CN.ts +++ b/share/qtcreator/translations/qtcreator_zh_CN.ts @@ -1956,8 +1956,8 @@ in the system's browser for manual download. Git 工具可能没有正确安装。 - (SDK Version: %1, NDK Version: %2) - (SDK 版本:%1, NDK 版本:%2) + (SDK Version: %1) + (SDK 版本:%1) Unset Default diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index ce386f1bd1d..c72ce476d34 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -443,8 +443,6 @@ void AndroidSettingsWidget::updateNdkList() } } - m_ndkListWidget->setCurrentRow(0); - updateUI(); } @@ -688,11 +686,8 @@ void AndroidSettingsWidget::updateUI() const bool androidSetupOk = m_androidSummary->allRowsOk(); const bool openSslOk = m_openSslSummary->allRowsOk(); - const QListWidgetItem *currentItem = m_ndkListWidget->currentItem(); - const FilePath currentNdk = FilePath::fromUserInput(currentItem ? currentItem->text() : ""); - const QString infoText = Tr::tr("(SDK Version: %1, NDK Version: %2)") - .arg(AndroidConfig::sdkToolsVersion().toString()) - .arg(currentNdk.isEmpty() ? "" : AndroidConfig::ndkVersion(currentNdk).toString()); + const QString infoText = Tr::tr("(SDK Version: %1)") + .arg(AndroidConfig::sdkToolsVersion().toString()); m_androidSummary->setInfoText(androidSetupOk ? infoText : ""); m_androidSummary->setSetupOk(androidSetupOk); @@ -711,7 +706,7 @@ void AndroidSettingsWidget::updateUI() } } - m_makeDefaultNdkButton->setEnabled(m_ndkListWidget->count() > 0); + m_makeDefaultNdkButton->setEnabled(m_ndkListWidget->currentItem() != nullptr); m_makeDefaultNdkButton->setText(isDefaultNdkSelected() ? Tr::tr("Unset Default") : Tr::tr("Make Default")); } From 3521b06c64067a994e44bea778e7874fed796a0c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 18 Dec 2024 14:31:20 +0100 Subject: [PATCH 447/989] ProjectExplorer: fix resetting gcc install dir If m_installDir was not empty when GccToolchain::resetToolchain gets called the install dir was not reset since GccToolchain::installDir would just return m_installDir in that case. But since the install dir is not needed in GccToolchain::resetToolchain we can just clear the install dir and rely on the fact that it gets autodected when GccToolchain::installDir gets called. This reduces the startup time of Qt Creator by around 700 ms on some machines since the android toolchain code relies on calling GccToolchain::resetToolchain in order to pick up JDK changes. Change-Id: Ic69bca3946a91388b793317050a0b53dbf0cea2d Reviewed-by: Christian Kandeler Reviewed-by: Alessandro Portale --- src/plugins/projectexplorer/gcctoolchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 60271688a51..109b3a1f8bc 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1006,7 +1006,7 @@ void GccToolchain::resetToolchain(const FilePath &path) const DetectedAbisResult detectedAbis = detectSupportedAbis(); m_supportedAbis = detectedAbis.supportedAbis; m_originalTargetTriple = detectedAbis.originalTargetTriple; - m_installDir = installDir(); + m_installDir.clear(); if (m_supportedAbis.isEmpty()) setTargetAbiNoSignal(Abi()); From 8513c3e82a079aedcd14bf792a001b008ca9589a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 16 Dec 2024 09:10:47 +0100 Subject: [PATCH 448/989] StyleSettings: Introduce settingsId() Reuse it in ICodeStylePreferences subclasses. Change-Id: I23f0e816bd643b1ce0e6d0e0652173152f62fcba Reviewed-by: David Schulz --- src/plugins/cppeditor/cppcodestylepreferences.cpp | 3 +-- src/plugins/cppeditor/cppcodestylesettings.cpp | 5 +++++ src/plugins/cppeditor/cppcodestylesettings.h | 4 +++- src/plugins/qmljstools/qmljscodestylepreferences.cpp | 3 +-- src/plugins/qmljstools/qmljscodestylesettings.cpp | 6 ++++++ src/plugins/qmljstools/qmljscodestylesettings.h | 4 ++-- 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/plugins/cppeditor/cppcodestylepreferences.cpp b/src/plugins/cppeditor/cppcodestylepreferences.cpp index c6afa32c26d..b832a483bb9 100644 --- a/src/plugins/cppeditor/cppcodestylepreferences.cpp +++ b/src/plugins/cppeditor/cppcodestylepreferences.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "cppcodestylepreferences.h" -#include "cppeditorconstants.h" using namespace Utils; @@ -12,7 +11,7 @@ CppCodeStylePreferences::CppCodeStylePreferences(QObject *parent) : ICodeStylePreferences(parent) { setSettingsSuffix("CodeStyleSettings"); - setGlobalSettingsCategory(Constants::CPP_CODE_STYLE_SETTINGS_ID); + setGlobalSettingsCategory(CppCodeStyleSettings::settingsId()); } QVariant CppCodeStylePreferences::value() const diff --git a/src/plugins/cppeditor/cppcodestylesettings.cpp b/src/plugins/cppeditor/cppcodestylesettings.cpp index 5499005c62b..f273e3165f8 100644 --- a/src/plugins/cppeditor/cppcodestylesettings.cpp +++ b/src/plugins/cppeditor/cppcodestylesettings.cpp @@ -230,4 +230,9 @@ CPlusPlus::Overview CppCodeStyleSettings::currentGlobalCodeStyleOverview() return overview; } +Id CppCodeStyleSettings::settingsId() +{ + return Constants::CPP_CODE_STYLE_SETTINGS_ID; +} + } // namespace CppEditor diff --git a/src/plugins/cppeditor/cppcodestylesettings.h b/src/plugins/cppeditor/cppcodestylesettings.h index a798ca7434d..25a7e139fda 100644 --- a/src/plugins/cppeditor/cppcodestylesettings.h +++ b/src/plugins/cppeditor/cppcodestylesettings.h @@ -8,8 +8,9 @@ #include namespace CPlusPlus { class Overview; } -namespace TextEditor { class TabSettings; } namespace ProjectExplorer { class Project; } +namespace TextEditor { class TabSettings; } +namespace Utils { class Id; } namespace CppEditor { @@ -93,6 +94,7 @@ public: default constructed Overview is returned. */ static CPlusPlus::Overview currentGlobalCodeStyleOverview(); + static Utils::Id settingsId(); }; } // namespace CppEditor diff --git a/src/plugins/qmljstools/qmljscodestylepreferences.cpp b/src/plugins/qmljstools/qmljscodestylepreferences.cpp index b5bc2bb5b24..c8ecf425fb6 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferences.cpp +++ b/src/plugins/qmljstools/qmljscodestylepreferences.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qmljscodestylepreferences.h" -#include "qmljstoolsconstants.h" using namespace Utils; @@ -12,7 +11,7 @@ QmlJSCodeStylePreferences::QmlJSCodeStylePreferences(QObject *parent) : ICodeStylePreferences(parent) { setSettingsSuffix("CodeStyleSettings"); - setGlobalSettingsCategory(Constants::QML_JS_CODE_STYLE_SETTINGS_ID); + setGlobalSettingsCategory(QmlJSCodeStyleSettings::settingsId()); } QVariant QmlJSCodeStylePreferences::value() const diff --git a/src/plugins/qmljstools/qmljscodestylesettings.cpp b/src/plugins/qmljstools/qmljscodestylesettings.cpp index c03501ac016..11fedd5a10a 100644 --- a/src/plugins/qmljstools/qmljscodestylesettings.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettings.cpp @@ -4,6 +4,7 @@ #include "qmljscodestylesettings.h" #include "qmljscodestylepreferences.h" +#include "qmljstoolsconstants.h" #include "qmljstoolssettings.h" #include @@ -59,4 +60,9 @@ TextEditor::TabSettings QmlJSCodeStyleSettings::currentGlobalTabSettings() return QmlJSCodeStylePreferences->currentTabSettings(); } +Id QmlJSCodeStyleSettings::settingsId() +{ + return Constants::QML_JS_CODE_STYLE_SETTINGS_ID; +} + } // namespace QmlJSTools diff --git a/src/plugins/qmljstools/qmljscodestylesettings.h b/src/plugins/qmljstools/qmljscodestylesettings.h index a97cd5a5b9f..5f71f16e550 100644 --- a/src/plugins/qmljstools/qmljscodestylesettings.h +++ b/src/plugins/qmljstools/qmljscodestylesettings.h @@ -7,9 +7,8 @@ #include -#include - namespace TextEditor { class TabSettings; } +namespace Utils { class Id; } namespace QmlJSTools { @@ -29,6 +28,7 @@ public: static QmlJSCodeStyleSettings currentGlobalCodeStyle(); static TextEditor::TabSettings currentGlobalTabSettings(); + static Utils::Id settingsId(); }; } // namespace CppEditor From e7aabf876218834af8b3003462913177806ddb19 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 16 Dec 2024 09:25:28 +0100 Subject: [PATCH 449/989] ICodeStylePreferences: Introduce TypedCodeStylePreferences This is going to replace CppCodeStylePreferences and QmlJsCodeStylePreferences. Change-Id: Ica5c63555ffd1e00454ee804bf3237c66b6fb14f Reviewed-by: David Schulz --- .../texteditor/icodestylepreferences.h | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/plugins/texteditor/icodestylepreferences.h b/src/plugins/texteditor/icodestylepreferences.h index 49f63f2c609..4b6d2911504 100644 --- a/src/plugins/texteditor/icodestylepreferences.h +++ b/src/plugins/texteditor/icodestylepreferences.h @@ -97,5 +97,77 @@ private: Internal::ICodeStylePreferencesPrivate *d; }; +template +class TypedCodeStylePreferences : public ICodeStylePreferences +{ +public: + TypedCodeStylePreferences(QObject *parent = nullptr) + : ICodeStylePreferences(parent) + { + setSettingsSuffix("CodeStyleSettings"); + setGlobalSettingsCategory(T::settingsId()); + } + + QVariant value() const final + { + QVariant v; + v.setValue(codeStyleSettings()); + return v; + } + void setValue(const QVariant &data) final + { + if (!data.canConvert()) + return; + + setCodeStyleSettings(data.value()); + } + + T codeStyleSettings() const { return m_data; } + + // Tracks parent hierarchy until currentParentSettings is null. TODO: return optional? + T currentCodeStyleSettings() const + { + QVariant v = currentValue(); + if (!v.canConvert()) { + // warning + return {}; + } + return v.value(); + } + + Utils::Store toMap() const override + { + Utils::Store map = ICodeStylePreferences::toMap(); + if (!currentDelegate()) { + const Utils::Store dataMap = m_data.toMap(); + for (auto it = dataMap.begin(), end = dataMap.end(); it != end; ++it) + map.insert(it.key(), it.value()); + } + return map; + } + void fromMap(const Utils::Store &map) override + { + ICodeStylePreferences::fromMap(map); + if (!currentDelegate()) + m_data.fromMap(map); + } + + void setCodeStyleSettings(const T &data) + { + if (m_data == data) + return; + + m_data = data; + + QVariant v; + v.setValue(data); + emit valueChanged(v); + if (!currentDelegate()) + emit currentValueChanged(v); + } + +private: + T m_data; +}; } // namespace TextEditor From 7402613ca7cd0a65b986b54d94f89ec2a60e9fb4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 16 Dec 2024 10:06:00 +0100 Subject: [PATCH 450/989] ICodeStylePreferences: Reuse TypedCodeStylePreferences Make CppCodeStylePreferences and QmlJsCodeStylePreferences typedefs to TypedCodeStylePreferences. Change-Id: I8d0ae7d07c1286d74fcdb68041faec5c6e76db40 Reviewed-by: David Schulz --- .../clangformat/clangformatconfigwidget.cpp | 1 - src/plugins/clangformat/clangformatfile.cpp | 1 - .../clangformat/clangformatindenter.cpp | 2 - src/plugins/clangformat/clangformatutils.cpp | 1 - src/plugins/cppeditor/CMakeLists.txt | 1 - .../cppeditor/cppcodestylepreferences.cpp | 79 ------------------- .../cppeditor/cppcodestylepreferences.h | 37 --------- .../cppcodestylepreferencesfactory.cpp | 6 +- .../cppeditor/cppcodestylesettings.cpp | 2 +- src/plugins/cppeditor/cppcodestylesettings.h | 4 + .../cppeditor/cppcodestylesettingspage.cpp | 7 +- .../cppeditor/cppcodestylesettingspage.h | 1 - src/plugins/cppeditor/cppeditor.qbs | 2 - src/plugins/cppeditor/cppqtstyleindenter.cpp | 4 +- src/plugins/cppeditor/cpptoolssettings.cpp | 2 +- src/plugins/cppeditor/cpptoolssettings.h | 4 +- .../cppeditor/quickfixes/cppquickfix_test.cpp | 1 - .../cppeditor/quickfixes/cppquickfix_test.h | 2 +- .../quickfixes/insertfunctiondefinition.cpp | 1 - src/plugins/glsleditor/glslindenter.cpp | 1 - .../textmodifier/basetexteditmodifier.cpp | 3 - .../indentingtexteditormodifier.cpp | 1 - src/plugins/qmljseditor/qmljseditorplugin.cpp | 1 - src/plugins/qmljstools/CMakeLists.txt | 1 - .../qmljstools/qmljscodestylepreferences.cpp | 79 ------------------- .../qmljstools/qmljscodestylepreferences.h | 37 --------- .../qmljscodestylepreferencesfactory.cpp | 6 +- .../qmljscodestylepreferenceswidget.cpp | 3 +- .../qmljscodestylepreferenceswidget.h | 8 +- .../qmljstools/qmljscodestylesettings.cpp | 2 +- .../qmljstools/qmljscodestylesettings.h | 6 +- .../qmljstools/qmljscodestylesettingspage.cpp | 2 +- .../qmljstools/qmljscodestylesettingspage.h | 3 +- src/plugins/qmljstools/qmljstools.qbs | 2 - src/plugins/qmljstools/qmljstoolssettings.cpp | 3 +- src/plugins/qmljstools/qmljstoolssettings.h | 3 +- 36 files changed, 36 insertions(+), 283 deletions(-) delete mode 100644 src/plugins/cppeditor/cppcodestylepreferences.cpp delete mode 100644 src/plugins/cppeditor/cppcodestylepreferences.h delete mode 100644 src/plugins/qmljstools/qmljscodestylepreferences.cpp delete mode 100644 src/plugins/qmljstools/qmljscodestylepreferences.h diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index 9d65daadcee..021afe667d3 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/src/plugins/clangformat/clangformatfile.cpp b/src/plugins/clangformat/clangformatfile.cpp index 8b89eed027f..bb573732bbc 100644 --- a/src/plugins/clangformat/clangformatfile.cpp +++ b/src/plugins/clangformat/clangformatfile.cpp @@ -4,7 +4,6 @@ #include "clangformatfile.h" #include "clangformatutils.h" -#include #include #include diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index 21278e136aa..5e2ef127e0a 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -7,8 +7,6 @@ #include -#include -#include #include #include diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 6a439e4138f..bc347813720 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -7,7 +7,6 @@ #include -#include #include #include diff --git a/src/plugins/cppeditor/CMakeLists.txt b/src/plugins/cppeditor/CMakeLists.txt index a541310f868..f0d3135fed4 100644 --- a/src/plugins/cppeditor/CMakeLists.txt +++ b/src/plugins/cppeditor/CMakeLists.txt @@ -24,7 +24,6 @@ add_qtc_plugin(CppEditor cppcodemodelinspectordialog.cpp cppcodemodelinspectordialog.h cppcodemodelinspectordumper.cpp cppcodemodelinspectordumper.h cppcodemodelsettings.cpp cppcodemodelsettings.h - cppcodestylepreferences.cpp cppcodestylepreferences.h cppcodestylepreferencesfactory.cpp cppcodestylepreferencesfactory.h cppcodestylesettings.cpp cppcodestylesettings.h cppcodestylesettingspage.cpp cppcodestylesettingspage.h diff --git a/src/plugins/cppeditor/cppcodestylepreferences.cpp b/src/plugins/cppeditor/cppcodestylepreferences.cpp deleted file mode 100644 index b832a483bb9..00000000000 --- a/src/plugins/cppeditor/cppcodestylepreferences.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "cppcodestylepreferences.h" - -using namespace Utils; - -namespace CppEditor { - -CppCodeStylePreferences::CppCodeStylePreferences(QObject *parent) : - ICodeStylePreferences(parent) -{ - setSettingsSuffix("CodeStyleSettings"); - setGlobalSettingsCategory(CppCodeStyleSettings::settingsId()); -} - -QVariant CppCodeStylePreferences::value() const -{ - QVariant v; - v.setValue(codeStyleSettings()); - return v; -} - -void CppCodeStylePreferences::setValue(const QVariant &data) -{ - if (!data.canConvert()) - return; - - setCodeStyleSettings(data.value()); -} - -CppCodeStyleSettings CppCodeStylePreferences::codeStyleSettings() const -{ - return m_data; -} - -void CppCodeStylePreferences::setCodeStyleSettings(const CppCodeStyleSettings &data) -{ - if (m_data == data) - return; - - m_data = data; - - QVariant v; - v.setValue(data); - emit valueChanged(v); - if (!currentDelegate()) - emit currentValueChanged(v); -} - -CppCodeStyleSettings CppCodeStylePreferences::currentCodeStyleSettings() const -{ - QVariant v = currentValue(); - if (!v.canConvert()) { - // warning - return {}; - } - return v.value(); -} - -Store CppCodeStylePreferences::toMap() const -{ - Store map = ICodeStylePreferences::toMap(); - if (!currentDelegate()) { - const Store dataMap = m_data.toMap(); - for (auto it = dataMap.begin(), end = dataMap.end(); it != end; ++it) - map.insert(it.key(), it.value()); - } - return map; -} - -void CppCodeStylePreferences::fromMap(const Store &map) -{ - ICodeStylePreferences::fromMap(map); - if (!currentDelegate()) - m_data.fromMap(map); -} - -} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppcodestylepreferences.h b/src/plugins/cppeditor/cppcodestylepreferences.h deleted file mode 100644 index 164271789fb..00000000000 --- a/src/plugins/cppeditor/cppcodestylepreferences.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "cppeditor_global.h" -#include "cppcodestylesettings.h" - -#include - -namespace CppEditor { - -class CPPEDITOR_EXPORT CppCodeStylePreferences : public TextEditor::ICodeStylePreferences -{ - Q_OBJECT -public: - explicit CppCodeStylePreferences( - QObject *parent = nullptr); - - QVariant value() const override; - void setValue(const QVariant &) override; - - CppCodeStyleSettings codeStyleSettings() const; - - // tracks parent hierarchy until currentParentSettings is null - CppCodeStyleSettings currentCodeStyleSettings() const; - - Utils::Store toMap() const override; - void fromMap(const Utils::Store &map) override; - - void setCodeStyleSettings(const CppCodeStyleSettings &data); - -private: - CppCodeStyleSettings m_data; -}; - -} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppcodestylepreferencesfactory.cpp b/src/plugins/cppeditor/cppcodestylepreferencesfactory.cpp index a24c5c26c91..053a4109cd5 100644 --- a/src/plugins/cppeditor/cppcodestylepreferencesfactory.cpp +++ b/src/plugins/cppeditor/cppcodestylepreferencesfactory.cpp @@ -3,7 +3,7 @@ #include "cppcodestylepreferencesfactory.h" -#include "cppcodestylepreferences.h" +#include "cppcodestylesettings.h" #include "cppcodestylesettingspage.h" #include "cppeditorconstants.h" #include "cppeditortr.h" @@ -73,7 +73,7 @@ QString CppCodeStylePreferencesFactory::displayName() TextEditor::ICodeStylePreferences *CppCodeStylePreferencesFactory::createCodeStyle() const { - return new CppCodeStylePreferences(); + return new CppCodeStylePreferences; } TextEditor::CodeStyleEditorWidget *CppCodeStylePreferencesFactory::createEditor( @@ -81,7 +81,7 @@ TextEditor::CodeStyleEditorWidget *CppCodeStylePreferencesFactory::createEditor( ProjectExplorer::Project *project, QWidget *parent) const { - auto cppPreferences = qobject_cast(preferences); + auto cppPreferences = dynamic_cast(preferences); if (!cppPreferences) return nullptr; auto widget = new Internal::CppCodeStylePreferencesWidget(parent); diff --git a/src/plugins/cppeditor/cppcodestylesettings.cpp b/src/plugins/cppeditor/cppcodestylesettings.cpp index f273e3165f8..e3324520f65 100644 --- a/src/plugins/cppeditor/cppcodestylesettings.cpp +++ b/src/plugins/cppeditor/cppcodestylesettings.cpp @@ -3,7 +3,7 @@ #include "cppcodestylesettings.h" -#include "cppcodestylepreferences.h" +#include "cppcodestylesettings.h" #include "cppeditorconstants.h" #include "cpptoolssettings.h" diff --git a/src/plugins/cppeditor/cppcodestylesettings.h b/src/plugins/cppeditor/cppcodestylesettings.h index 25a7e139fda..bbf4e2a25fb 100644 --- a/src/plugins/cppeditor/cppcodestylesettings.h +++ b/src/plugins/cppeditor/cppcodestylesettings.h @@ -5,6 +5,8 @@ #include "cppeditor_global.h" +#include + #include namespace CPlusPlus { class Overview; } @@ -97,6 +99,8 @@ public: static Utils::Id settingsId(); }; +using CppCodeStylePreferences = TextEditor::TypedCodeStylePreferences; + } // namespace CppEditor Q_DECLARE_METATYPE(CppEditor::CppCodeStyleSettings) diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.cpp b/src/plugins/cppeditor/cppcodestylesettingspage.cpp index 7edbeb10985..08c4a9bef26 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.cpp +++ b/src/plugins/cppeditor/cppcodestylesettingspage.cpp @@ -4,7 +4,6 @@ #include "cppcodestylesettingspage.h" #include "cppcodeformatter.h" -#include "cppcodestylepreferences.h" #include "cppcodestylesnippets.h" #include "cppeditorconstants.h" #include "cppeditortr.h" @@ -472,7 +471,7 @@ void CppCodeStylePreferencesWidget::slotCodeStyleSettingsChanged() return; if (m_preferences) { - auto current = qobject_cast(m_preferences->currentPreferences()); + auto current = dynamic_cast(m_preferences->currentPreferences()); if (current) current->setCodeStyleSettings(cppCodeStyleSettings()); } @@ -487,7 +486,7 @@ void CppCodeStylePreferencesWidget::slotTabSettingsChanged(const TabSettings &se return; if (m_preferences) { - auto current = qobject_cast(m_preferences->currentPreferences()); + auto current = dynamic_cast(m_preferences->currentPreferences()); if (current) current->setTabSettings(settings); } @@ -569,7 +568,7 @@ void CppCodeStylePreferencesWidget::apply() void CppCodeStylePreferencesWidget::finish() { if (m_preferences) { - auto current = qobject_cast(m_preferences->currentDelegate()); + auto current = dynamic_cast(m_preferences->currentDelegate()); if (current) { current->setCodeStyleSettings(m_originalCppCodeStyleSettings); current->setTabSettings(m_originalTabSettings); diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.h b/src/plugins/cppeditor/cppcodestylesettingspage.h index 2a8bce064c8..279cf72ec1f 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.h +++ b/src/plugins/cppeditor/cppcodestylesettingspage.h @@ -20,7 +20,6 @@ namespace TextEditor { } namespace CppEditor { -class CppCodeStylePreferences; namespace Internal { diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index 9331055b944..2fc478c7443 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -67,8 +67,6 @@ QtcPlugin { "cppcodemodelinspectordumper.h", "cppcodemodelsettings.cpp", "cppcodemodelsettings.h", - "cppcodestylepreferences.cpp", - "cppcodestylepreferences.h", "cppcodestylepreferencesfactory.cpp", "cppcodestylepreferencesfactory.h", "cppcodestylesettings.cpp", diff --git a/src/plugins/cppeditor/cppqtstyleindenter.cpp b/src/plugins/cppeditor/cppqtstyleindenter.cpp index acc84b15643..bde3bfcad6f 100644 --- a/src/plugins/cppeditor/cppqtstyleindenter.cpp +++ b/src/plugins/cppeditor/cppqtstyleindenter.cpp @@ -5,7 +5,7 @@ #include "cppcodeformatter.h" #include "cpptoolssettings.h" -#include "cppcodestylepreferences.h" +#include "cppcodestylesettings.h" #include #include @@ -162,7 +162,7 @@ void CppQtStyleIndenter::indent(const QTextCursor &cursor, void CppQtStyleIndenter::setCodeStylePreferences(ICodeStylePreferences *preferences) { - auto cppCodeStylePreferences = qobject_cast(preferences); + auto cppCodeStylePreferences = dynamic_cast(preferences); if (cppCodeStylePreferences) m_cppCodeStylePreferences = cppCodeStylePreferences; } diff --git a/src/plugins/cppeditor/cpptoolssettings.cpp b/src/plugins/cppeditor/cpptoolssettings.cpp index abf2626bf33..2eb920c1416 100644 --- a/src/plugins/cppeditor/cpptoolssettings.cpp +++ b/src/plugins/cppeditor/cpptoolssettings.cpp @@ -5,8 +5,8 @@ #include "cppeditorconstants.h" #include "cppeditortr.h" -#include "cppcodestylepreferences.h" #include "cppcodestylepreferencesfactory.h" +#include "cppcodestylesettings.h" #include diff --git a/src/plugins/cppeditor/cpptoolssettings.h b/src/plugins/cppeditor/cpptoolssettings.h index 6f8d9c8bbe9..ebdf154e472 100644 --- a/src/plugins/cppeditor/cpptoolssettings.h +++ b/src/plugins/cppeditor/cpptoolssettings.h @@ -5,12 +5,12 @@ #include "cppeditor_global.h" +#include "cppcodestylesettings.h" + #include namespace CppEditor { -class CppCodeStylePreferences; - // This class is meant to go away. class CPPEDITOR_EXPORT CppToolsSettings : public QObject diff --git a/src/plugins/cppeditor/quickfixes/cppquickfix_test.cpp b/src/plugins/cppeditor/quickfixes/cppquickfix_test.cpp index 8107ce0baf4..f764b4c07da 100644 --- a/src/plugins/cppeditor/quickfixes/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/quickfixes/cppquickfix_test.cpp @@ -3,7 +3,6 @@ #include "cppquickfix_test.h" -#include "../cppcodestylepreferences.h" #include "../cppeditorwidget.h" #include "../cppmodelmanager.h" #include "../cppsourceprocessertesthelper.h" diff --git a/src/plugins/cppeditor/quickfixes/cppquickfix_test.h b/src/plugins/cppeditor/quickfixes/cppquickfix_test.h index b6d3030ef31..0a3a86bdebe 100644 --- a/src/plugins/cppeditor/quickfixes/cppquickfix_test.h +++ b/src/plugins/cppeditor/quickfixes/cppquickfix_test.h @@ -4,6 +4,7 @@ #pragma once #include "../cpptoolstestcase.h" +#include "../cppcodestylesettings.h" #include "cppquickfix.h" #include "cppquickfixsettings.h" @@ -18,7 +19,6 @@ namespace TextEditor { class QuickFixOperation; } namespace CppEditor { -class CppCodeStylePreferences; namespace Internal { namespace Tests { diff --git a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp index 5bb8eb9f56c..3d95fc21f8e 100644 --- a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp +++ b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp @@ -3,7 +3,6 @@ #include "insertfunctiondefinition.h" -#include "../cppcodestylepreferences.h" #include "../cppcodestylesettings.h" #include "../cppeditortr.h" #include "../cppeditorwidget.h" diff --git a/src/plugins/glsleditor/glslindenter.cpp b/src/plugins/glsleditor/glslindenter.cpp index 8a14112327d..2a16a942d03 100644 --- a/src/plugins/glsleditor/glslindenter.cpp +++ b/src/plugins/glsleditor/glslindenter.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/src/plugins/qmldesigner/textmodifier/basetexteditmodifier.cpp b/src/plugins/qmldesigner/textmodifier/basetexteditmodifier.cpp index d3799e997bf..5ae82c06b39 100644 --- a/src/plugins/qmldesigner/textmodifier/basetexteditmodifier.cpp +++ b/src/plugins/qmldesigner/textmodifier/basetexteditmodifier.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -15,8 +14,6 @@ #include #include -#include - using namespace QmlDesigner; BaseTextEditModifier::BaseTextEditModifier(TextEditor::TextEditorWidget *textEdit) diff --git a/src/plugins/qmldesigner/textmodifier/indentingtexteditormodifier.cpp b/src/plugins/qmldesigner/textmodifier/indentingtexteditormodifier.cpp index f0f80200ac9..dac94707607 100644 --- a/src/plugins/qmldesigner/textmodifier/indentingtexteditormodifier.cpp +++ b/src/plugins/qmldesigner/textmodifier/indentingtexteditormodifier.cpp @@ -3,7 +3,6 @@ #include "indentingtexteditormodifier.h" -#include #include #include diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp index f75ad084d89..0678d79b383 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.cpp +++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include diff --git a/src/plugins/qmljstools/CMakeLists.txt b/src/plugins/qmljstools/CMakeLists.txt index 5f1342abbbc..34a11b53247 100644 --- a/src/plugins/qmljstools/CMakeLists.txt +++ b/src/plugins/qmljstools/CMakeLists.txt @@ -5,7 +5,6 @@ add_qtc_plugin(QmlJSTools SOURCES qmljsbundleprovider.cpp qmljsbundleprovider.h qmljscodestylepreferencesfactory.cpp qmljscodestylepreferencesfactory.h - qmljscodestylepreferences.cpp qmljscodestylepreferences.h qmljscodestylepreferenceswidget.cpp qmljscodestylepreferenceswidget.h qmljscodestylesettings.cpp qmljscodestylesettings.h qmljscodestylesettingswidget.cpp qmljscodestylesettingswidget.h diff --git a/src/plugins/qmljstools/qmljscodestylepreferences.cpp b/src/plugins/qmljstools/qmljscodestylepreferences.cpp deleted file mode 100644 index c8ecf425fb6..00000000000 --- a/src/plugins/qmljstools/qmljscodestylepreferences.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qmljscodestylepreferences.h" - -using namespace Utils; - -namespace QmlJSTools { - -QmlJSCodeStylePreferences::QmlJSCodeStylePreferences(QObject *parent) : - ICodeStylePreferences(parent) -{ - setSettingsSuffix("CodeStyleSettings"); - setGlobalSettingsCategory(QmlJSCodeStyleSettings::settingsId()); -} - -QVariant QmlJSCodeStylePreferences::value() const -{ - QVariant v; - v.setValue(codeStyleSettings()); - return v; -} - -void QmlJSCodeStylePreferences::setValue(const QVariant &data) -{ - if (!data.canConvert()) - return; - - setCodeStyleSettings(data.value()); -} - -QmlJSCodeStyleSettings QmlJSCodeStylePreferences::codeStyleSettings() const -{ - return m_data; -} - -void QmlJSCodeStylePreferences::setCodeStyleSettings(const QmlJSCodeStyleSettings &data) -{ - if (m_data == data) - return; - - m_data = data; - - QVariant v; - v.setValue(data); - emit valueChanged(v); - if (!currentDelegate()) - emit currentValueChanged(v); -} - -QmlJSCodeStyleSettings QmlJSCodeStylePreferences::currentCodeStyleSettings() const -{ - QVariant v = currentValue(); - if (!v.canConvert()) { - // warning - return {}; - } - return v.value(); -} - -Store QmlJSCodeStylePreferences::toMap() const -{ - Store map = ICodeStylePreferences::toMap(); - if (!currentDelegate()) { - const Store dataMap = m_data.toMap(); - for (auto it = dataMap.begin(), end = dataMap.end(); it != end; ++it) - map.insert(it.key(), it.value()); - } - return map; -} - -void QmlJSCodeStylePreferences::fromMap(const Store &map) -{ - ICodeStylePreferences::fromMap(map); - if (!currentDelegate()) - m_data.fromMap(map); -} - -} // namespace QmlJSTools diff --git a/src/plugins/qmljstools/qmljscodestylepreferences.h b/src/plugins/qmljstools/qmljscodestylepreferences.h deleted file mode 100644 index 038bff52120..00000000000 --- a/src/plugins/qmljstools/qmljscodestylepreferences.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "qmljstools_global.h" - -#include "qmljscodestylesettings.h" - -#include - -namespace QmlJSTools { - -class QMLJSTOOLS_EXPORT QmlJSCodeStylePreferences : public TextEditor::ICodeStylePreferences -{ - Q_OBJECT -public: - explicit QmlJSCodeStylePreferences(QObject *parent = nullptr); - - QVariant value() const override; - void setValue(const QVariant &) override; - - QmlJSCodeStyleSettings codeStyleSettings() const; - - // tracks parent hierarchy until currentParentSettings is null - QmlJSCodeStyleSettings currentCodeStyleSettings() const; - - Utils::Store toMap() const override; - void fromMap(const Utils::Store &map) override; - - void setCodeStyleSettings(const QmlJSCodeStyleSettings &data); - -private: - QmlJSCodeStyleSettings m_data; -}; - -} // namespace QmlJSTools diff --git a/src/plugins/qmljstools/qmljscodestylepreferencesfactory.cpp b/src/plugins/qmljstools/qmljscodestylepreferencesfactory.cpp index a1eeb7b1ace..96f77fb6702 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferencesfactory.cpp +++ b/src/plugins/qmljstools/qmljscodestylepreferencesfactory.cpp @@ -3,7 +3,7 @@ #include "qmljscodestylepreferencesfactory.h" -#include "qmljscodestylepreferences.h" +#include "qmljscodestylesettings.h" #include "qmljscodestylesettingspage.h" #include "qmljsindenter.h" #include "qmljstoolsconstants.h" @@ -45,7 +45,7 @@ QString QmlJSCodeStylePreferencesFactory::displayName() TextEditor::ICodeStylePreferences *QmlJSCodeStylePreferencesFactory::createCodeStyle() const { - return new QmlJSCodeStylePreferences(); + return new QmlJSCodeStylePreferences; } TextEditor::CodeStyleEditorWidget *QmlJSCodeStylePreferencesFactory::createEditor( @@ -54,7 +54,7 @@ TextEditor::CodeStyleEditorWidget *QmlJSCodeStylePreferencesFactory::createEdito QWidget *parent) const { Q_UNUSED(project) - auto qmlJSPreferences = qobject_cast(preferences); + auto qmlJSPreferences = dynamic_cast(preferences); if (!qmlJSPreferences) return nullptr; auto widget = new Internal::QmlJSCodeStylePreferencesWidget(this, parent); diff --git a/src/plugins/qmljstools/qmljscodestylepreferenceswidget.cpp b/src/plugins/qmljstools/qmljscodestylepreferenceswidget.cpp index 65a6a1de15b..c341757b657 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferenceswidget.cpp +++ b/src/plugins/qmljstools/qmljscodestylepreferenceswidget.cpp @@ -3,7 +3,6 @@ #include "qmljscodestylepreferenceswidget.h" -#include "qmljscodestylepreferences.h" #include "qmljscodestylesettings.h" #include "qmljscodestylesettingswidget.h" @@ -62,7 +61,7 @@ void QmlJSCodeStylePreferencesWidget::slotSettingsChanged(const QmlJSCodeStyleSe if (!m_preferences) return; - QmlJSCodeStylePreferences *current = qobject_cast(m_preferences->currentPreferences()); + QmlJSCodeStylePreferences *current = dynamic_cast(m_preferences->currentPreferences()); if (!current) return; diff --git a/src/plugins/qmljstools/qmljscodestylepreferenceswidget.h b/src/plugins/qmljstools/qmljscodestylepreferenceswidget.h index 4770877a40b..a8a2f770dd4 100644 --- a/src/plugins/qmljstools/qmljscodestylepreferenceswidget.h +++ b/src/plugins/qmljstools/qmljscodestylepreferenceswidget.h @@ -5,16 +5,12 @@ #include "qmljstools_global.h" +#include "qmljscodestylesettings.h" + #include -namespace TextEditor { -class ICodeStylePreferences; -} - namespace QmlJSTools { -class QmlJSCodeStyleSettings; class QmlJSCodeStyleSettingsWidget; -class QmlJSCodeStylePreferences; class QMLJSTOOLS_EXPORT QmlJSCodeStylePreferencesWidget : public QWidget { diff --git a/src/plugins/qmljstools/qmljscodestylesettings.cpp b/src/plugins/qmljstools/qmljscodestylesettings.cpp index 11fedd5a10a..dacf9fb92e1 100644 --- a/src/plugins/qmljstools/qmljscodestylesettings.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettings.cpp @@ -3,7 +3,7 @@ #include "qmljscodestylesettings.h" -#include "qmljscodestylepreferences.h" +#include "qmljscodestylesettings.h" #include "qmljstoolsconstants.h" #include "qmljstoolssettings.h" diff --git a/src/plugins/qmljstools/qmljscodestylesettings.h b/src/plugins/qmljstools/qmljscodestylesettings.h index 5f71f16e550..fe0483324b9 100644 --- a/src/plugins/qmljstools/qmljscodestylesettings.h +++ b/src/plugins/qmljstools/qmljscodestylesettings.h @@ -5,6 +5,8 @@ #include "qmljstools_global.h" +#include + #include namespace TextEditor { class TabSettings; } @@ -31,6 +33,8 @@ public: static Utils::Id settingsId(); }; -} // namespace CppEditor +using QmlJSCodeStylePreferences = TextEditor::TypedCodeStylePreferences; + +} // namespace QmlJSTools Q_DECLARE_METATYPE(QmlJSTools::QmlJSCodeStyleSettings) diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp index 8f1bcc7c45b..e436f6c4c91 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp @@ -3,8 +3,8 @@ #include "qmljscodestylesettingspage.h" -#include "qmljscodestylepreferences.h" #include "qmljscodestylepreferenceswidget.h" +#include "qmljscodestylesettings.h" #include "qmljsqtstylecodeformatter.h" #include "qmljstoolsconstants.h" #include "qmljstoolssettings.h" diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.h b/src/plugins/qmljstools/qmljscodestylesettingspage.h index 853d482b95e..5defa7e89bb 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.h +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.h @@ -3,6 +3,8 @@ #pragma once +#include "qmljscodestylesettings.h" + #include #include @@ -13,7 +15,6 @@ namespace TextEditor { } namespace QmlJSTools { -class QmlJSCodeStylePreferences; class QmlJSCodeStylePreferencesWidget; class QmlJSCodeStyleSettings; diff --git a/src/plugins/qmljstools/qmljstools.qbs b/src/plugins/qmljstools/qmljstools.qbs index b866329d513..40459125f4f 100644 --- a/src/plugins/qmljstools/qmljstools.qbs +++ b/src/plugins/qmljstools/qmljstools.qbs @@ -19,8 +19,6 @@ QtcPlugin { files: [ "qmljsbundleprovider.cpp", "qmljsbundleprovider.h", - "qmljscodestylepreferences.cpp", - "qmljscodestylepreferences.h", "qmljscodestylepreferencesfactory.cpp", "qmljscodestylepreferencesfactory.h", "qmljscodestylepreferenceswidget.cpp", diff --git a/src/plugins/qmljstools/qmljstoolssettings.cpp b/src/plugins/qmljstools/qmljstoolssettings.cpp index 6ba30acb424..ff8667e8913 100644 --- a/src/plugins/qmljstools/qmljstoolssettings.cpp +++ b/src/plugins/qmljstools/qmljstoolssettings.cpp @@ -1,7 +1,8 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "qmljscodestylepreferences.h" +#include "qmljscodestylesettings.h" + #include "qmljscodestylepreferencesfactory.h" #include "qmljstoolsconstants.h" #include "qmljstoolssettings.h" diff --git a/src/plugins/qmljstools/qmljstoolssettings.h b/src/plugins/qmljstools/qmljstoolssettings.h index 419117a0d48..c60c3c8a5f9 100644 --- a/src/plugins/qmljstools/qmljstoolssettings.h +++ b/src/plugins/qmljstools/qmljstoolssettings.h @@ -5,10 +5,11 @@ #include "qmljstools_global.h" +#include "qmljscodestylesettings.h" + #include namespace QmlJSTools { -class QmlJSCodeStylePreferences; /** * This class provides a central place for cpp tools settings. From 56742be835a3104d0306b177d40a69417f9cdace Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 17 Dec 2024 18:01:14 +0100 Subject: [PATCH 451/989] CppEditor: Remove unused method Change-Id: I874e5d30a4679e17e17dda7b388f8fcbf19976dd Reviewed-by: David Schulz --- src/plugins/cppeditor/cppcodeformatter.cpp | 6 ------ src/plugins/cppeditor/cppcodeformatter.h | 1 - 2 files changed, 7 deletions(-) diff --git a/src/plugins/cppeditor/cppcodeformatter.cpp b/src/plugins/cppeditor/cppcodeformatter.cpp index 85c841e2c72..168e4d8e73e 100644 --- a/src/plugins/cppeditor/cppcodeformatter.cpp +++ b/src/plugins/cppeditor/cppcodeformatter.cpp @@ -1153,12 +1153,6 @@ QtStyleCodeFormatter::QtStyleCodeFormatter(const TabSettings &tabSettings, setStatementMacros(m_styleSettings.statementMacros); } -void QtStyleCodeFormatter::setTabSettings(const TabSettings &tabSettings) -{ - m_tabSettings = tabSettings; - setTabSize(tabSettings.m_tabSize); -} - void QtStyleCodeFormatter::setCodeStyleSettings(const CppCodeStyleSettings &settings) { m_styleSettings = settings; diff --git a/src/plugins/cppeditor/cppcodeformatter.h b/src/plugins/cppeditor/cppcodeformatter.h index f3d69422ee0..6f1daddc674 100644 --- a/src/plugins/cppeditor/cppcodeformatter.h +++ b/src/plugins/cppeditor/cppcodeformatter.h @@ -241,7 +241,6 @@ public: QtStyleCodeFormatter(const TextEditor::TabSettings &tabSettings, const CppCodeStyleSettings &settings); - void setTabSettings(const TextEditor::TabSettings &tabSettings); void setCodeStyleSettings(const CppCodeStyleSettings &settings); protected: From 737be781b9a70c9c4feca0d2319a9664ff3da9f7 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 9 Dec 2024 11:58:57 +0100 Subject: [PATCH 452/989] Core: Introduce a TextDocument::setCodec(QByteArray) overload Taking the codec's name. This allows some caller paths to not explicitly use the deprecated QTextCodec class. Change-Id: If7093c0c6d78bdcb5bbbc5a0a02eac930529fdaa Reviewed-by: David Schulz --- .../coreplugin/dialogs/codecselector.cpp | 2 +- src/plugins/coreplugin/textdocument.cpp | 24 +++++++++++++++++-- src/plugins/coreplugin/textdocument.h | 5 +++- src/plugins/designer/formwindowfile.cpp | 10 ++++---- src/plugins/designer/formwindowfile.h | 2 +- .../qmljseditor/qmljseditordocument.cpp | 7 +++--- src/plugins/qmljseditor/qmljseditordocument.h | 2 +- .../scxmleditor/scxmleditordocument.cpp | 7 +++--- src/plugins/scxmleditor/scxmleditordocument.h | 2 +- 9 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/codecselector.cpp b/src/plugins/coreplugin/dialogs/codecselector.cpp index 3ef225490ad..20289358962 100644 --- a/src/plugins/coreplugin/dialogs/codecselector.cpp +++ b/src/plugins/coreplugin/dialogs/codecselector.cpp @@ -91,7 +91,7 @@ CodecSelector::CodecSelector(QWidget *parent, Core::BaseTextDocument *doc) int currentIndex = -1; for (const int mib : std::as_const(sortedMibs)) { QTextCodec *c = QTextCodec::codecForMib(mib); - if (!doc->supportsCodec(c)) + if (!doc->supportsCodec(c ? c->name() : QByteArray())) continue; if (!buf.isEmpty()) { diff --git a/src/plugins/coreplugin/textdocument.cpp b/src/plugins/coreplugin/textdocument.cpp index cf4dd82939e..10828f9f566 100644 --- a/src/plugins/coreplugin/textdocument.cpp +++ b/src/plugins/coreplugin/textdocument.cpp @@ -107,6 +107,18 @@ void BaseTextDocument::setLineTerminationMode(Utils::TextFileFormat::LineTermina d->m_format.lineTerminationMode = mode; } +bool BaseTextDocument::isUtf8Codec(const QByteArray &name) +{ + static const auto utf8Codecs = []() -> QList { + QTextCodec *codec = QTextCodec::codecForName("UTF-8"); + if (QTC_GUARD(codec)) + return QList{codec->name()} + codec->aliases(); + return {"UTF-8"}; + }(); + + return utf8Codecs.contains(name); +} + /*! Autodetects file format and reads the text file specified by \a filePath into a list of strings specified by \a plainTextList. @@ -162,11 +174,19 @@ void BaseTextDocument::setCodec(const QTextCodec *codec) { if (debug) qDebug() << Q_FUNC_INFO << this << (codec ? codec->name() : QByteArray()); - if (supportsCodec(codec)) + if (supportsCodec(codec ? codec->name() : QByteArray())) d->m_format.codec = codec; } -bool BaseTextDocument::supportsCodec(const QTextCodec *) const +void BaseTextDocument::setCodec(const QByteArray &name) +{ + if (debug) + qDebug() << Q_FUNC_INFO << this << name; + if (supportsCodec(name)) + d->m_format.codec = QTextCodec::codecForName(name); +} + +bool BaseTextDocument::supportsCodec(const QByteArray &) const { return true; } diff --git a/src/plugins/coreplugin/textdocument.h b/src/plugins/coreplugin/textdocument.h index 4eac04e62cc..73ce64f41b4 100644 --- a/src/plugins/coreplugin/textdocument.h +++ b/src/plugins/coreplugin/textdocument.h @@ -24,7 +24,8 @@ public: Utils::TextFileFormat format() const; const QTextCodec *codec() const; void setCodec(const QTextCodec *); - virtual bool supportsCodec(const QTextCodec *) const; + void setCodec(const QByteArray &name); + virtual bool supportsCodec(const QByteArray &) const; void switchUtf8Bom(); bool supportsUtf8Bom() const; Utils::TextFileFormat::LineTerminationMode lineTerminationMode() const; @@ -41,6 +42,8 @@ public: void setSupportsUtf8Bom(bool value); void setLineTerminationMode(Utils::TextFileFormat::LineTerminationMode mode); + static bool isUtf8Codec(const QByteArray &name); + private: Internal::TextDocumentPrivate *d; }; diff --git a/src/plugins/designer/formwindowfile.cpp b/src/plugins/designer/formwindowfile.cpp index 9672488db15..def031c13cf 100644 --- a/src/plugins/designer/formwindowfile.cpp +++ b/src/plugins/designer/formwindowfile.cpp @@ -12,14 +12,12 @@ #include #include +#include #include #include #include #include #include -#include -#include -#include using namespace Utils; @@ -33,7 +31,7 @@ FormWindowFile::FormWindowFile(QDesignerFormWindowInterface *form, QObject *pare setParent(parent); setId(Utils::Id(Designer::Constants::K_DESIGNER_XML_EDITOR_ID)); // Designer needs UTF-8 regardless of settings. - setCodec(QTextCodec::codecForName("UTF-8")); + setCodec("UTF-8"); connect(m_formWindow->core()->formWindowManager(), &QDesignerFormWindowManagerInterface::formWindowRemoved, this, &FormWindowFile::slotFormWindowRemoved); connect(m_formWindow->commandHistory(), &QUndoStack::indexChanged, @@ -224,9 +222,9 @@ QString FormWindowFile::fallbackSaveAsFileName() const return m_suggestedName; } -bool FormWindowFile::supportsCodec(const QTextCodec *codec) const +bool FormWindowFile::supportsCodec(const QByteArray &codec) const { - return codec == QTextCodec::codecForName("UTF-8"); + return TextEditor::TextDocument::isUtf8Codec(codec); } bool FormWindowFile::writeFile(const Utils::FilePath &filePath, QString *errorString) const diff --git a/src/plugins/designer/formwindowfile.h b/src/plugins/designer/formwindowfile.h index 4c86ad5fde4..1e6372e1005 100644 --- a/src/plugins/designer/formwindowfile.h +++ b/src/plugins/designer/formwindowfile.h @@ -35,7 +35,7 @@ public: bool isSaveAsAllowed() const override; Utils::Result reload(ReloadFlag flag, ChangeType type) override; QString fallbackSaveAsFileName() const override; - bool supportsCodec(const QTextCodec *codec) const override; + bool supportsCodec(const QByteArray &codec) const override; // Internal void setFallbackSaveAsFileName(const QString &fileName); diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp index 266867ac6ca..74f8657f8f7 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.cpp +++ b/src/plugins/qmljseditor/qmljseditordocument.cpp @@ -30,7 +30,6 @@ #include #include -#include const char QML_UI_FILE_WARNING[] = "QmlJSEditor.QmlUiFileWarning"; @@ -739,13 +738,13 @@ QmlJSEditorDocument::QmlJSEditorDocument(Utils::Id id) connect(this, &TextEditor::TextDocument::tabSettingsChanged, d, &Internal::QmlJSEditorDocumentPrivate::invalidateFormatterCache); resetSyntaxHighlighter([] { return new QmlJSHighlighter(); }); - setCodec(QTextCodec::codecForName("UTF-8")); // qml files are defined to be utf-8 + setCodec("UTF-8"); // qml files are defined to be utf-8 setIndenter(createQmlJsIndenter(document())); } -bool QmlJSEditorDocument::supportsCodec(const QTextCodec *codec) const +bool QmlJSEditorDocument::supportsCodec(const QByteArray &codec) const { - return codec == QTextCodec::codecForName("UTF-8"); + return TextEditor::TextDocument::isUtf8Codec(codec); } QmlJSEditorDocument::~QmlJSEditorDocument() diff --git a/src/plugins/qmljseditor/qmljseditordocument.h b/src/plugins/qmljseditor/qmljseditordocument.h index 0334cb6336b..a1bef52e341 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.h +++ b/src/plugins/qmljseditor/qmljseditordocument.h @@ -25,7 +25,7 @@ public: QmlJSEditorDocument(Utils::Id id); ~QmlJSEditorDocument() override; - bool supportsCodec(const QTextCodec *codec) const override; + bool supportsCodec(const QByteArray &codec) const override; const QmlJSTools::SemanticInfo &semanticInfo() const; bool isSemanticInfoOutdated() const; diff --git a/src/plugins/scxmleditor/scxmleditordocument.cpp b/src/plugins/scxmleditor/scxmleditordocument.cpp index 9c4e5c83b6d..8d8fa25e0d3 100644 --- a/src/plugins/scxmleditor/scxmleditordocument.cpp +++ b/src/plugins/scxmleditor/scxmleditordocument.cpp @@ -13,7 +13,6 @@ #include #include -#include #include using namespace Utils; @@ -29,7 +28,7 @@ ScxmlEditorDocument::ScxmlEditorDocument(MainWidget *designWidget, QObject *pare setId(Utils::Id(ScxmlEditor::Constants::K_SCXML_EDITOR_ID)); // Designer needs UTF-8 regardless of settings. - setCodec(QTextCodec::codecForName("UTF-8")); + setCodec("UTF-8"); connect(m_designWidget.data(), &Common::MainWidget::dirtyChanged, this, [this]{ emit changed(); }); @@ -124,9 +123,9 @@ Result ScxmlEditorDocument::reload(ReloadFlag flag, ChangeType type) return Result(success, errorString); } -bool ScxmlEditorDocument::supportsCodec(const QTextCodec *codec) const +bool ScxmlEditorDocument::supportsCodec(const QByteArray &codec) const { - return codec == QTextCodec::codecForName("UTF-8"); + return TextEditor::TextDocument::isUtf8Codec(codec); } QString ScxmlEditorDocument::designWidgetContents() const diff --git a/src/plugins/scxmleditor/scxmleditordocument.h b/src/plugins/scxmleditor/scxmleditordocument.h index 9121313647d..631a3c6300f 100644 --- a/src/plugins/scxmleditor/scxmleditordocument.h +++ b/src/plugins/scxmleditor/scxmleditordocument.h @@ -34,7 +34,7 @@ public: bool isSaveAsAllowed() const override; bool isModified() const override; Utils::Result reload(ReloadFlag flag, ChangeType type) override; - bool supportsCodec(const QTextCodec *codec) const override; + bool supportsCodec(const QByteArray &codec) const override; // Internal Common::MainWidget *designWidget() const; From 360a3fe27e1eb6abfff69ef5b7c92300c78ebba5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 9 Dec 2024 12:39:08 +0100 Subject: [PATCH 453/989] ProjectExplorer, Texteditor: Remove a few explicit uses of QTextCodec Change-Id: I6b57099cf3bb674ec9a0ad2fbfb9d68b168d8fc5 Reviewed-by: David Schulz --- src/plugins/bineditor/bineditorplugin.cpp | 9 ++++---- .../editormanager/editormanager.cpp | 6 ++++++ .../coreplugin/editormanager/editormanager.h | 1 + .../projectexplorer/allprojectsfind.cpp | 7 ++++--- .../projectexplorer/editorconfiguration.cpp | 21 +++++++++---------- .../projectexplorer/editorconfiguration.h | 8 ++----- .../texteditor/behaviorsettingspage.cpp | 2 +- .../texteditor/behaviorsettingswidget.cpp | 4 ++-- .../texteditor/behaviorsettingswidget.h | 8 ++----- src/plugins/texteditor/codecchooser.cpp | 8 +++---- src/plugins/texteditor/codecchooser.h | 6 +++--- src/plugins/vcsbase/vcsbaseeditor.cpp | 2 +- 12 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp index 3f8a23ec94f..b952c1e3ae3 100644 --- a/src/plugins/bineditor/bineditorplugin.cpp +++ b/src/plugins/bineditor/bineditorplugin.cpp @@ -247,7 +247,7 @@ public: void copy(bool raw = false); void setMarkup(const QList &markup); void setNewWindowRequestAllowed(bool c) { m_canRequestNewWindow = c; } - void setCodec(QTextCodec *codec); + void setCodec(const QByteArray &codec); QByteArray toByteArray(const QString &s) const; void clearMarkup() { m_markup.clear(); } @@ -392,7 +392,7 @@ BinEditorWidget::BinEditorWidget(const std::shared_ptr &doc) const QByteArray setting = ICore::settings()->value(C_ENCODING_SETTING).toByteArray(); if (!setting.isEmpty()) - setCodec(QTextCodec::codecForName(setting)); + setCodec(setting); m_addressEdit = new QLineEdit; auto addressValidator = new QRegularExpressionValidator(QRegularExpression("[0-9a-fA-F]{1,16}"), m_addressEdit); @@ -1888,12 +1888,13 @@ void BinEditorWidget::jumpToAddress(quint64 address) m_doc->requestNewRange(address); } -void BinEditorWidget::setCodec(QTextCodec *codec) +void BinEditorWidget::setCodec(const QByteArray &codecName) { + QTextCodec *codec = QTextCodec::codecForName(codecName); if (codec == m_codec) return; m_codec = codec; - ICore::settings()->setValue(C_ENCODING_SETTING, codec ? codec->name() : QByteArray()); + ICore::settings()->setValue(C_ENCODING_SETTING, codecName); viewport()->update(); } diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 937f4b2082c..abab9654be8 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -3821,6 +3821,12 @@ QTextCodec *EditorManager::defaultTextCodec() return QTextCodec::codecForLocale(); } +QByteArray EditorManager::defaultTextCodecName() +{ + QTextCodec *codec = defaultTextCodec(); + return codec ? codec->name() : QByteArray(); +} + /*! Returns the default line ending as the user specified in the settings. */ diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index 5dd26f857c0..c98500f879c 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -130,6 +130,7 @@ public: static bool autoSaveAfterRefactoring(); static QTextCodec *defaultTextCodec(); + static QByteArray defaultTextCodecName(); static Utils::TextFileFormat::LineTerminationMode defaultLineEnding(); diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp index b20ebe3dc5e..2709d558a6e 100644 --- a/src/plugins/projectexplorer/allprojectsfind.cpp +++ b/src/plugins/projectexplorer/allprojectsfind.cpp @@ -17,6 +17,7 @@ #include #include +#include using namespace ProjectExplorer; using namespace ProjectExplorer::Internal; @@ -62,14 +63,14 @@ FileContainer AllProjectsFind::filesForProjects(const QStringList &nameFilters, QMap encodings; for (const Project *project : projects) { const EditorConfiguration *config = project->editorConfiguration(); - QTextCodec *projectCodec = config->useGlobalSettings() - ? Core::EditorManager::defaultTextCodec() + QByteArray projectCodec = config->useGlobalSettings() + ? Core::EditorManager::defaultTextCodecName() : config->textCodec(); const FilePaths filteredFiles = filterFiles(project->files(Project::SourceFiles)); for (const FilePath &fileName : filteredFiles) { QTextCodec *codec = openEditorEncodings.value(fileName); if (!codec) - codec = projectCodec; + codec = QTextCodec::codecForName(projectCodec); encodings.insert(fileName, codec); } } diff --git a/src/plugins/projectexplorer/editorconfiguration.cpp b/src/plugins/projectexplorer/editorconfiguration.cpp index f67db95cd67..00bd0fb2860 100644 --- a/src/plugins/projectexplorer/editorconfiguration.cpp +++ b/src/plugins/projectexplorer/editorconfiguration.cpp @@ -24,7 +24,6 @@ #include #include -#include #include using namespace TextEditor; @@ -45,7 +44,7 @@ struct EditorConfigurationPrivate m_storageSettings(globalStorageSettings()), m_behaviorSettings(globalBehaviorSettings()), m_extraEncodingSettings(globalExtraEncodingSettings()), - m_textCodec(Core::EditorManager::defaultTextCodec()) + m_textCodec(Core::EditorManager::defaultTextCodecName()) { } ICodeStylePreferences *m_defaultCodeStyle = nullptr; @@ -55,7 +54,7 @@ struct EditorConfigurationPrivate bool m_useGlobal = true; ExtraEncodingSettings m_extraEncodingSettings; MarginSettings m_marginSettings; - QTextCodec *m_textCodec; + QByteArray m_textCodec; QMap m_languageCodeStylePreferences; QList m_editors; @@ -111,10 +110,10 @@ void EditorConfiguration::cloneGlobalSettings() setBehaviorSettings(globalBehaviorSettings()); setExtraEncodingSettings(globalExtraEncodingSettings()); setMarginSettings(TextEditorSettings::marginSettings()); - d->m_textCodec = Core::EditorManager::defaultTextCodec(); + d->m_textCodec = Core::EditorManager::defaultTextCodecName(); } -QTextCodec *EditorConfiguration::textCodec() const +QByteArray EditorConfiguration::textCodec() const { return d->m_textCodec; } @@ -169,7 +168,7 @@ Store EditorConfiguration::toMap() const { Store map = { {kUseGlobal, d->m_useGlobal}, - {kCodec, d->m_textCodec->name()}, + {kCodec, d->m_textCodec}, {kCodeStyleCount, d->m_languageCodeStylePreferences.count()} }; @@ -197,10 +196,10 @@ Store EditorConfiguration::toMap() const void EditorConfiguration::fromMap(const Store &map) { - const QByteArray &codecName = map.value(kCodec, d->m_textCodec->name()).toByteArray(); - d->m_textCodec = QTextCodec::codecForName(codecName); - if (!d->m_textCodec) - d->m_textCodec = Core::EditorManager::defaultTextCodec(); + const QByteArray &codecName = map.value(kCodec, d->m_textCodec).toByteArray(); + d->m_textCodec = codecName; + if (d->m_textCodec.isEmpty()) + d->m_textCodec = Core::EditorManager::defaultTextCodecName(); const int codeStyleCount = map.value(kCodeStyleCount, 0).toInt(); for (int i = 0; i < codeStyleCount; ++i) { @@ -349,7 +348,7 @@ void EditorConfiguration::setMarginSettings(const MarginSettings &settings) } } -void EditorConfiguration::setTextCodec(QTextCodec *textCodec) +void EditorConfiguration::setTextCodec(const QByteArray &textCodec) { d->m_textCodec = textCodec; } diff --git a/src/plugins/projectexplorer/editorconfiguration.h b/src/plugins/projectexplorer/editorconfiguration.h index 7c7791f7cd4..a6befe99946 100644 --- a/src/plugins/projectexplorer/editorconfiguration.h +++ b/src/plugins/projectexplorer/editorconfiguration.h @@ -12,10 +12,6 @@ #include -QT_BEGIN_NAMESPACE -class QTextCodec; -QT_END_NAMESPACE - namespace TextEditor { class BaseTextEditor; class TextEditorWidget; @@ -50,7 +46,7 @@ public: void cloneGlobalSettings(); // The default codec is returned in the case the project doesn't override it. - QTextCodec *textCodec() const; + QByteArray textCodec() const; const TextEditor::TypingSettings &typingSettings() const; const TextEditor::StorageSettings &storageSettings() const; @@ -79,7 +75,7 @@ public: void setUseIndenter(bool onoff); void setWrapColumn(int column); - void setTextCodec(QTextCodec *textCodec); + void setTextCodec(const QByteArray &textCodec); void slotAboutToRemoveProject(ProjectExplorer::Project *project); diff --git a/src/plugins/texteditor/behaviorsettingspage.cpp b/src/plugins/texteditor/behaviorsettingspage.cpp index eb2917aaccd..a6883b8960f 100644 --- a/src/plugins/texteditor/behaviorsettingspage.cpp +++ b/src/plugins/texteditor/behaviorsettingspage.cpp @@ -101,7 +101,7 @@ public: d->m_behaviorWidget->setAssignedStorageSettings(globalStorageSettings()); d->m_behaviorWidget->setAssignedBehaviorSettings(globalBehaviorSettings()); d->m_behaviorWidget->setAssignedExtraEncodingSettings(globalExtraEncodingSettings()); - d->m_behaviorWidget->setAssignedCodec(Core::EditorManager::defaultTextCodec()); + d->m_behaviorWidget->setAssignedCodec(Core::EditorManager::defaultTextCodecName()); d->m_behaviorWidget->setAssignedLineEnding(Core::EditorManager::defaultLineEnding()); } diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp index 5a702e5b33e..9bdc7ff444a 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.cpp +++ b/src/plugins/texteditor/behaviorsettingswidget.cpp @@ -316,11 +316,11 @@ void BehaviorSettingsWidget::setActive(bool active) d->groupBoxStorageSettings->setEnabled(active); } -void BehaviorSettingsWidget::setAssignedCodec(QTextCodec *codec) +void BehaviorSettingsWidget::setAssignedCodec(const QByteArray &codec) { const QString codecName = Core::ICore::settings()->value( Core::Constants::SETTINGS_DEFAULTTEXTENCODING).toString(); - d->encodingBox->setAssignedCodec(codec, codecName); + d->encodingBox->setAssignedCodec(QTextCodec::codecForName(codec), codecName); } QByteArray BehaviorSettingsWidget::assignedCodecName() const diff --git a/src/plugins/texteditor/behaviorsettingswidget.h b/src/plugins/texteditor/behaviorsettingswidget.h index 60b9c686a6b..03411c73fb0 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.h +++ b/src/plugins/texteditor/behaviorsettingswidget.h @@ -7,10 +7,6 @@ #include -QT_BEGIN_NAMESPACE -class QTextCodec; -QT_END_NAMESPACE - namespace TextEditor { class ICodeStylePreferences; @@ -32,7 +28,7 @@ public: void setActive(bool active); - void setAssignedCodec(QTextCodec *codec); + void setAssignedCodec(const QByteArray &codec); QByteArray assignedCodecName() const; void setCodeStyle(ICodeStylePreferences *preferences); @@ -59,7 +55,7 @@ signals: void storageSettingsChanged(const TextEditor::StorageSettings &settings); void behaviorSettingsChanged(const TextEditor::BehaviorSettings &settings); void extraEncodingSettingsChanged(const TextEditor::ExtraEncodingSettings &settings); - void textCodecChanged(QTextCodec *codec); + void textCodecChanged(const QByteArray &codec); private: void slotTypingSettingsChanged(); diff --git a/src/plugins/texteditor/codecchooser.cpp b/src/plugins/texteditor/codecchooser.cpp index 57cc2d23f39..4a7e0196e27 100644 --- a/src/plugins/texteditor/codecchooser.cpp +++ b/src/plugins/texteditor/codecchooser.cpp @@ -42,7 +42,7 @@ CodecChooser::CodecChooser(Filter filter) } } connect(this, &QComboBox::currentIndexChanged, - this, [this](int index) { emit codecChanged(m_codecs.at(index)); }); + this, [this](int index) { emit codecChanged(codecAt(index)); }); } void CodecChooser::prependNone() @@ -51,16 +51,16 @@ void CodecChooser::prependNone() m_codecs.prepend(nullptr); } -QTextCodec *CodecChooser::currentCodec() const +QByteArray CodecChooser::currentCodec() const { return codecAt(currentIndex()); } -QTextCodec *CodecChooser::codecAt(int index) const +QByteArray CodecChooser::codecAt(int index) const { if (index < 0) index = 0; - return m_codecs[index]; + return m_codecs[index] ? m_codecs[index]->name() : QByteArray(); } void CodecChooser::setAssignedCodec(QTextCodec *codec, const QString &name) diff --git a/src/plugins/texteditor/codecchooser.h b/src/plugins/texteditor/codecchooser.h index a56cb38660d..a1e33366d18 100644 --- a/src/plugins/texteditor/codecchooser.h +++ b/src/plugins/texteditor/codecchooser.h @@ -21,15 +21,15 @@ public: enum class Filter { All, SingleByte }; explicit CodecChooser(Filter filter = Filter::All); void prependNone(); - QTextCodec *currentCodec() const; - QTextCodec *codecAt(int index) const; + QByteArray currentCodec() const; void setAssignedCodec(QTextCodec *codec, const QString &name = {}); QByteArray assignedCodecName() const; signals: - void codecChanged(QTextCodec *codec); + void codecChanged(const QByteArray &codec); private: + QByteArray codecAt(int index) const; QList m_codecs; }; diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 8be8a5b752b..12d9d28163b 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -1260,7 +1260,7 @@ static QTextCodec *findProjectCodec(const FilePath &dirPath) const auto projects = ProjectExplorer::ProjectManager::projects(); const auto *p = findOrDefault(projects, equal(&ProjectExplorer::Project::projectDirectory, dirPath)); - return p ? p->editorConfiguration()->textCodec() : nullptr; + return p ? QTextCodec::codecForName(p->editorConfiguration()->textCodec()) : nullptr; } QTextCodec *VcsBaseEditor::getCodec(const FilePath &source) From a4c05e2f05ef7a5fc25a978260b5d7a818ae3906 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 9 Dec 2024 13:43:03 +0100 Subject: [PATCH 454/989] TextEditor: Avoid some direct QTextCodec use in TextDocument::reload() Change-Id: If36e76e2e003462dad7438a1b7fdd8a73ec329c8 Reviewed-by: David Schulz --- src/plugins/coreplugin/dialogs/codecselector.cpp | 11 ++++++----- src/plugins/coreplugin/dialogs/codecselector.h | 3 +-- src/plugins/texteditor/textdocument.cpp | 4 ++-- src/plugins/texteditor/textdocument.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/codecselector.cpp b/src/plugins/coreplugin/dialogs/codecselector.cpp index 20289358962..299837123ec 100644 --- a/src/plugins/coreplugin/dialogs/codecselector.cpp +++ b/src/plugins/coreplugin/dialogs/codecselector.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -28,7 +29,7 @@ public: CodecSelector(QWidget *parent, Core::BaseTextDocument *doc); ~CodecSelector() override; - QTextCodec *selectedCodec() const; + QByteArray selectedCodec() const; private: void updateButtons(); @@ -142,17 +143,17 @@ void CodecSelector::updateButtons() m_saveButton->setEnabled(!m_hasDecodingError && hasCodec); } -QTextCodec *CodecSelector::selectedCodec() const +QByteArray CodecSelector::selectedCodec() const { if (QListWidgetItem *item = m_listWidget->currentItem()) { if (!item->isSelected()) - return nullptr; + return {}; QString codecName = item->text(); if (codecName.contains(QLatin1String(" / "))) codecName = codecName.left(codecName.indexOf(QLatin1String(" / "))); - return QTextCodec::codecForName(codecName.toLatin1()); + return codecName.toLatin1(); } - return nullptr; + return {}; } void CodecSelector::buttonClicked(QAbstractButton *button) diff --git a/src/plugins/coreplugin/dialogs/codecselector.h b/src/plugins/coreplugin/dialogs/codecselector.h index 4ec22c8960d..a5319b756fc 100644 --- a/src/plugins/coreplugin/dialogs/codecselector.h +++ b/src/plugins/coreplugin/dialogs/codecselector.h @@ -5,7 +5,6 @@ #include "../core_global.h" -#include #include namespace Core { @@ -18,7 +17,7 @@ struct CORE_EXPORT CodecSelectorResult { enum Action { Cancel, Reload, Save }; Action action; - QTextCodec *codec; + QByteArray codec; }; CORE_EXPORT CodecSelectorResult askForCodec(QWidget *parent, Core::BaseTextDocument *doc); diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index ccc0cb216bb..ba815a4caf6 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -823,9 +823,9 @@ Core::IDocument::OpenResult TextDocument::openImpl(QString *errorString, return OpenResult::Success; } -Result TextDocument::reload(QTextCodec *codec) +Result TextDocument::reload(const QByteArray &codec) { - QTC_ASSERT(codec, return Result::Error("No codec given")); + QTC_ASSERT(!codec.isEmpty(), return Result::Error("No codec given")); setCodec(codec); return reload(); } diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index 55a4e75c0bb..9046702b78d 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -127,7 +127,7 @@ public: void resetSyntaxHighlighter(const SyntaxHighLighterCreator &creator); SyntaxHighlighter *syntaxHighlighter() const; - Utils::Result reload(QTextCodec *codec); + Utils::Result reload(const QByteArray &codec); void cleanWhitespace(const QTextCursor &cursor); virtual void triggerPendingUpdates(); From 37584f022d0ef5d47cc979f0f0e0e6ab1197d00c Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 9 Dec 2024 13:30:59 +0100 Subject: [PATCH 455/989] TextEditor: Protect access to TextFileFormat::[m_]codec This makes it easier to transform the using code. Change-Id: I4dfc44cb56d1588361cedb601b7e2a7acbb3d6de Reviewed-by: David Schulz --- src/libs/utils/textfileformat.cpp | 57 +++++++++++++------ src/libs/utils/textfileformat.h | 11 +++- .../clangfixitsrefactoringchanges.cpp | 4 +- src/plugins/coreplugin/fileutils.cpp | 6 +- src/plugins/coreplugin/generatedfile.cpp | 2 +- src/plugins/coreplugin/outputwindow.cpp | 2 +- src/plugins/coreplugin/textdocument.cpp | 6 +- src/plugins/diffeditor/diffeditorplugin.cpp | 12 ++-- .../qmakeprojectmanager/qmakeparsernodes.cpp | 2 +- src/plugins/qmldesigner/documentmanager.cpp | 2 +- .../resourceeditor/qrceditor/resourcefile.cpp | 2 +- src/plugins/texteditor/refactoringchanges.cpp | 6 +- src/plugins/texteditor/textdocument.cpp | 2 +- 13 files changed, 72 insertions(+), 42 deletions(-) diff --git a/src/libs/utils/textfileformat.cpp b/src/libs/utils/textfileformat.cpp index fa0e81572c8..fdbe5fece66 100644 --- a/src/libs/utils/textfileformat.cpp +++ b/src/libs/utils/textfileformat.cpp @@ -18,9 +18,9 @@ QDebug operator<<(QDebug d, const TextFileFormat &format) { QDebug nsp = d.nospace(); nsp << "TextFileFormat: "; - if (format.codec) { - nsp << format.codec->name(); - const QList aliases = format.codec->aliases(); + if (format.codec()) { + nsp << format.codecName(); + const QList aliases = format.codec()->aliases(); for (const QByteArray &alias : aliases) nsp << ' ' << alias; } else { @@ -65,12 +65,12 @@ TextFileFormat TextFileFormat::detect(const QByteArray &data) // code taken from qtextstream if (bytesRead >= 4 && ((buf[0] == 0xff && buf[1] == 0xfe && buf[2] == 0 && buf[3] == 0) || (buf[0] == 0 && buf[1] == 0 && buf[2] == 0xfe && buf[3] == 0xff))) { - result.codec = QTextCodec::codecForName("UTF-32"); + result.m_codec = QTextCodec::codecForName("UTF-32"); } else if (bytesRead >= 2 && ((buf[0] == 0xff && buf[1] == 0xfe) || (buf[0] == 0xfe && buf[1] == 0xff))) { - result.codec = QTextCodec::codecForName("UTF-16"); + result.m_codec = QTextCodec::codecForName("UTF-16"); } else if (bytesRead >= 3 && ((buf[0] == 0xef && buf[1] == 0xbb) && buf[2] == 0xbf)) { - result.codec = QTextCodec::codecForName("UTF-8"); + result.m_codec = QTextCodec::codecForName("UTF-8"); result.hasUtf8Bom = true; } // end code taken from qtextstream @@ -95,6 +95,26 @@ QByteArray TextFileFormat::decodingErrorSample(const QByteArray &data) return p < 0 ? data : data.left(p); } +const QTextCodec *TextFileFormat::codec() const +{ + return m_codec; +} + +QByteArray TextFileFormat::codecName() const +{ + return m_codec ? m_codec->name() : QByteArray(); +} + +void TextFileFormat::setCodecName(const QByteArray &codec) +{ + m_codec = QTextCodec::codecForName(codec); +} + +void TextFileFormat::setCodec(const QTextCodec *codec) +{ + m_codec = codec; +} + enum { textChunkSize = 65536 }; static bool verifyDecodingError(const QString &text, const QTextCodec *codec, @@ -119,7 +139,8 @@ bool decodeTextFileContent(const QByteArray &dataBA, Target *target, void (Target::*appendFunction)(const QString &)) { - QTC_ASSERT(format.codec, return false); + const QTextCodec *codec = format.codec(); + QTC_ASSERT(codec, return false); QTextCodec::ConverterState state; bool hasDecodingError = false; @@ -133,18 +154,18 @@ bool decodeTextFileContent(const QByteArray &dataBA, for (const char *data = start; data < end; ) { const char *chunkStart = data; const int chunkSize = qMin(int(textChunkSize), int(end - chunkStart)); - QString text = format.codec->toUnicode(chunkStart, chunkSize, &state); + QString text = codec->toUnicode(chunkStart, chunkSize, &state); data += chunkSize; // Process until the end of the current multi-byte character. Remaining might // actually contain more than needed so try one-be-one. If EOF is reached with // and characters remain->encoding error. for ( ; state.remainingChars && data < end ; ++data) - text.append(format.codec->toUnicode(data, 1, &state)); + text.append(codec->toUnicode(data, 1, &state)); if (state.remainingChars) hasDecodingError = true; if (!hasDecodingError) hasDecodingError = - verifyDecodingError(text, format.codec, chunkStart, data - chunkStart, + verifyDecodingError(text, codec, chunkStart, data - chunkStart, chunkStart == start); if (format.lineTerminationMode == TextFileFormat::CRLFLineTerminator) text.remove(QLatin1Char('\r')); @@ -203,8 +224,8 @@ TextFileFormat::ReadResult readTextFile(const FilePath &filePath, const QTextCod if (!data.isEmpty()) *format = TextFileFormat::detect(data); - if (!format->codec) - format->codec = defaultCodec ? defaultCodec : QTextCodec::codecForLocale(); + if (!format->codec()) + format->setCodec(defaultCodec ? defaultCodec : QTextCodec::codecForLocale()); if (!format->decode(data, target)) { if (errorString) @@ -280,10 +301,10 @@ TextFileFormat::ReadResult TextFileFormat::readFileUTF8(const FilePath &filePath } TextFileFormat format = TextFileFormat::detect(data); - if (!format.codec) - format.codec = defaultCodec ? defaultCodec : QTextCodec::codecForLocale(); + if (!format.m_codec) + format.m_codec = defaultCodec ? defaultCodec : QTextCodec::codecForLocale(); QString target; - if (format.codec->name() == "UTF-8" || !format.decode(data, &target)) { + if (format.m_codec->name() == "UTF-8" || !format.decode(data, &target)) { if (format.hasUtf8Bom) data.remove(0, 3); if (format.lineTerminationMode == TextFileFormat::CRLFLineTerminator) @@ -317,7 +338,7 @@ TextFileFormat::readFile(const FilePath &filePath, const QTextCodec *defaultCode bool TextFileFormat::writeFile(const FilePath &filePath, QString plainText, QString *errorString) const { - QTC_ASSERT(codec, return false); + QTC_ASSERT(m_codec, return false); // Does the user want CRLF? If that is native, // do not let QFile do the work, because it replaces the line ending after the text was encoded, @@ -328,9 +349,9 @@ bool TextFileFormat::writeFile(const FilePath &filePath, QString plainText, QStr FileSaver saver(filePath, fileMode); if (!saver.hasError()) { - if (hasUtf8Bom && codec->name() == "UTF-8") + if (hasUtf8Bom && m_codec->name() == "UTF-8") saver.write("\xef\xbb\xbf", 3); - saver.write(codec->fromUnicode(plainText)); + saver.write(m_codec->fromUnicode(plainText)); } const bool ok = saver.finalize(errorString); if (debug) diff --git a/src/libs/utils/textfileformat.h b/src/libs/utils/textfileformat.h index 4cd67abec8e..a4225c05633 100644 --- a/src/libs/utils/textfileformat.h +++ b/src/libs/utils/textfileformat.h @@ -64,7 +64,16 @@ public: LineTerminationMode lineTerminationMode = NativeLineTerminator; bool hasUtf8Bom = false; - const QTextCodec *codec = nullptr; + + QByteArray codecName() const; + void setCodecName(const QByteArray &codec); + + // FIXME: Avoid. + const QTextCodec *codec() const; + void setCodec(const QTextCodec *codec); + +private: + const QTextCodec *m_codec = nullptr; }; } // namespace Utils diff --git a/src/plugins/clangtools/clangfixitsrefactoringchanges.cpp b/src/plugins/clangtools/clangfixitsrefactoringchanges.cpp index 52c33c70d53..d1662908f2e 100644 --- a/src/plugins/clangtools/clangfixitsrefactoringchanges.cpp +++ b/src/plugins/clangtools/clangfixitsrefactoringchanges.cpp @@ -97,7 +97,7 @@ bool FixitsRefactoringFile::apply() } // Write file - if (!m_textFileFormat.codec) + if (!m_textFileFormat.codec()) return false; // Error reading file QString error; @@ -151,7 +151,7 @@ QTextDocument *FixitsRefactoringFile::document(const FilePath &filePath) const if (result != TextFileFormat::ReadSuccess) { qCDebug(fixitsLog) << "ERROR: Could not read " << filePath.toUserOutput() << ":" << error; - m_textFileFormat.codec = nullptr; + m_textFileFormat.setCodec(nullptr); } } // always make a QTextDocument to avoid excessive null checks diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 85915cd8f0d..527b384ba7c 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -191,8 +191,8 @@ static bool updateHeaderFileGuardAfterRename(const QString &headerPath, headerFile.close(); auto headerFileTextFormat = TextFileFormat::detect(data); - if (!headerFileTextFormat.codec) - headerFileTextFormat.codec = EditorManager::defaultTextCodec(); + if (!headerFileTextFormat.codec()) + headerFileTextFormat.setCodecName(EditorManager::defaultTextCodecName()); QString stringContent; if (!headerFileTextFormat.decode(data, &stringContent)) return false; @@ -298,7 +298,7 @@ static bool updateHeaderFileGuardAfterRename(const QString &headerPath, } lineCounter++; } - tmpHeader.write(headerFileTextFormat.codec->fromUnicode(outString)); + tmpHeader.write(headerFileTextFormat.codec()->fromUnicode(outString)); tmpHeader.close(); } else { // if opening the temp file failed report error diff --git a/src/plugins/coreplugin/generatedfile.cpp b/src/plugins/coreplugin/generatedfile.cpp index 3c9a7165f06..c4285ec7ebb 100644 --- a/src/plugins/coreplugin/generatedfile.cpp +++ b/src/plugins/coreplugin/generatedfile.cpp @@ -160,7 +160,7 @@ bool GeneratedFilePrivate::writeContents(QString *errorMessage) const } TextFileFormat format; - format.codec = EditorManager::defaultTextCodec(); + format.setCodecName(EditorManager::defaultTextCodecName()); format.lineTerminationMode = EditorManager::defaultLineEnding(); return format.writeFile(path, QString::fromUtf8(contents), errorMessage); } diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index e6f9fad6712..95e148225c4 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -309,7 +309,7 @@ void OutputWindow::contextMenuEvent(QContextMenuEvent *event) if (!file.isEmpty()) { QString error; Utils::TextFileFormat format; - format.codec = EditorManager::defaultTextCodec(); + format.setCodecName(EditorManager::defaultTextCodecName()); format.lineTerminationMode = EditorManager::defaultLineEnding(); if (!format.writeFile(file, toPlainText(), &error)) MessageManager::writeDisrupting(error); diff --git a/src/plugins/coreplugin/textdocument.cpp b/src/plugins/coreplugin/textdocument.cpp index 10828f9f566..1c251a57e29 100644 --- a/src/plugins/coreplugin/textdocument.cpp +++ b/src/plugins/coreplugin/textdocument.cpp @@ -167,7 +167,7 @@ BaseTextDocument::ReadResult BaseTextDocument::read(const Utils::FilePath &fileP const QTextCodec *BaseTextDocument::codec() const { - return d->m_format.codec; + return d->m_format.codec(); } void BaseTextDocument::setCodec(const QTextCodec *codec) @@ -175,7 +175,7 @@ void BaseTextDocument::setCodec(const QTextCodec *codec) if (debug) qDebug() << Q_FUNC_INFO << this << (codec ? codec->name() : QByteArray()); if (supportsCodec(codec ? codec->name() : QByteArray())) - d->m_format.codec = codec; + d->m_format.setCodec(codec); } void BaseTextDocument::setCodec(const QByteArray &name) @@ -183,7 +183,7 @@ void BaseTextDocument::setCodec(const QByteArray &name) if (debug) qDebug() << Q_FUNC_INFO << this << name; if (supportsCodec(name)) - d->m_format.codec = QTextCodec::codecForName(name); + d->m_format.setCodecName(name); } bool BaseTextDocument::supportsCodec(const QByteArray &) const diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index dd750efef6e..26e614accd6 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -183,7 +183,7 @@ QList DiffCurrentFileController::reloadInputList() const QString leftText; const TextFileFormat::ReadResult leftResult = TextFileFormat::readFile( - FilePath::fromString(m_fileName), format.codec, &leftText, &format, &errorString); + FilePath::fromString(m_fileName), format.codec(), &leftText, &format, &errorString); const QString rightText = textDocument->plainText(); @@ -232,7 +232,7 @@ QList DiffOpenFilesController::reloadInputList() const QString leftText; const QString fileName = textDocument->filePath().toString(); const TextFileFormat::ReadResult leftResult = TextFileFormat::readFile( - FilePath::fromString(fileName), format.codec, &leftText, &format, &errorString); + FilePath::fromString(fileName), format.codec(), &leftText, &format, &errorString); const QString rightText = textDocument->plainText(); @@ -285,7 +285,7 @@ QList DiffModifiedFilesController::reloadInputList() const QString leftText; const QString fileName = textDocument->filePath().toString(); const TextFileFormat::ReadResult leftResult = TextFileFormat::readFile( - FilePath::fromString(fileName), format.codec, &leftText, &format, &errorString); + FilePath::fromString(fileName), format.codec(), &leftText, &format, &errorString); const QString rightText = textDocument->plainText(); @@ -330,15 +330,15 @@ QList DiffExternalFilesController::reloadInputList() const { QString errorString; TextFileFormat format; - format.codec = EditorManager::defaultTextCodec(); + format.setCodecName(EditorManager::defaultTextCodecName()); QString leftText; QString rightText; const TextFileFormat::ReadResult leftResult = TextFileFormat::readFile( - FilePath::fromString(m_leftFileName), format.codec, &leftText, &format, &errorString); + FilePath::fromString(m_leftFileName), format.codec(), &leftText, &format, &errorString); const TextFileFormat::ReadResult rightResult = TextFileFormat::readFile( - FilePath::fromString(m_rightFileName), format.codec, &rightText, &format, &errorString); + FilePath::fromString(m_rightFileName), format.codec(), &rightText, &format, &errorString); ReloadInput reloadInput; reloadInput.text = {leftText, rightText}; diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index 6e804f70b30..67275b7ed72 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -913,7 +913,7 @@ bool QmakePriFile::setProVariable(const QString &var, const QStringList &values, void QmakePriFile::save(const QStringList &lines) { { - QTC_ASSERT(m_textFormat.codec, return); + QTC_ASSERT(m_textFormat.codec(), return); FileChangeBlocker changeGuard(filePath()); QString errorMsg; if (!m_textFormat.writeFile(filePath(), lines.join('\n'), &errorMsg)) { diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp index 8530743d5fb..9fbb7e5ef84 100644 --- a/src/plugins/qmldesigner/documentmanager.cpp +++ b/src/plugins/qmldesigner/documentmanager.cpp @@ -315,7 +315,7 @@ void DocumentManager::goIntoComponent(const QString &fileName) bool DocumentManager::createFile(const QString &filePath, const QString &contents) { Utils::TextFileFormat textFileFormat; - textFileFormat.codec = Core::EditorManager::defaultTextCodec(); + textFileFormat.setCodecName(Core::EditorManager::defaultTextCodecName()); QString errorMessage; return textFileFormat.writeFile(Utils::FilePath::fromString(filePath), contents, &errorMessage); diff --git a/src/plugins/resourceeditor/qrceditor/resourcefile.cpp b/src/plugins/resourceeditor/qrceditor/resourcefile.cpp index 15c3d71d337..9b6c78a92eb 100644 --- a/src/plugins/resourceeditor/qrceditor/resourcefile.cpp +++ b/src/plugins/resourceeditor/qrceditor/resourcefile.cpp @@ -114,7 +114,7 @@ Core::IDocument::OpenResult ResourceFile::load() // Detect line ending style m_textFileFormat = TextFileFormat::detect(data); // we always write UTF-8 when saving - m_textFileFormat.codec = QTextCodec::codecForName("UTF-8"); + m_textFileFormat.setCodecName("UTF-8"); file.close(); QString error_msg; diff --git a/src/plugins/texteditor/refactoringchanges.cpp b/src/plugins/texteditor/refactoringchanges.cpp index 7dfe6f4c662..416aea74a6a 100644 --- a/src/plugins/texteditor/refactoringchanges.cpp +++ b/src/plugins/texteditor/refactoringchanges.cpp @@ -72,7 +72,7 @@ bool RefactoringFile::create(const QString &contents, bool reindent, bool openIn // Write the file to disk: TextFileFormat format; - format.codec = EditorManager::defaultTextCodec(); + format.setCodecName(EditorManager::defaultTextCodecName()); QString error; bool saveOk = format.writeFile(m_filePath, m_document->toPlainText(), &error); delete m_document; @@ -121,7 +121,7 @@ QTextDocument *RefactoringFile::mutableDocument() const &error); if (result != TextFileFormat::ReadSuccess) { qWarning() << "Could not read " << m_filePath << ". Error: " << error; - m_textFileFormat.codec = nullptr; + m_textFileFormat.setCodec(nullptr); } } // always make a QTextDocument to avoid excessive null checks @@ -264,7 +264,7 @@ bool RefactoringFile::apply() c.endEditBlock(); // if this document doesn't have an editor, write the result to a file - if (!m_editor && m_textFileFormat.codec) { + if (!m_editor && m_textFileFormat.codec()) { QTC_ASSERT(!m_filePath.isEmpty(), return false); QString error; // suppress "file has changed" warnings if the file is open in a read-only editor diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index ba815a4caf6..a8ab2d79944 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -662,7 +662,7 @@ Result TextDocument::saveImpl(const FilePath &filePath, bool autoSave) // check if UTF8-BOM has to be added or removed Utils::TextFileFormat saveFormat = format(); - if (saveFormat.codec->name() == "UTF-8" && supportsUtf8Bom()) { + if (saveFormat.codecName() == "UTF-8" && supportsUtf8Bom()) { switch (d->m_extraEncodingSettings.m_utf8BomSetting) { case ExtraEncodingSettings::AlwaysAdd: saveFormat.hasUtf8Bom = true; From 0e1b64860c0cb2ec096da7a5b079af83e8c431f1 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 13:41:41 +0100 Subject: [PATCH 456/989] Debugger: Fix a crash in DebuggerToolTipManager Editors with tooltips can be dead before the event filter gets a chance to handle their move events. Change-Id: I833d3f606cc05f2a9bea4af5dc9f4b8e6e00aca5 Reviewed-by: David Schulz Reviewed-by: Andrii Semkiv --- src/plugins/debugger/debuggertooltipmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index e3e4879c923..08ffe94ac68 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -1060,7 +1060,7 @@ bool DebuggerToolTipManagerPrivate::eventFilter(QObject *o, QEvent *e) purgeClosedToolTips(); QList> affectedTooltips; for (auto &[editor, tooltips] : m_tooltips) { - if (editor->window() == o) + if (editor && editor->window() == o) affectedTooltips.append(tooltips); } for (const QPointer &tooltip : std::as_const(affectedTooltips)) { From d22e757532b13e7ad0b5dca0dad1c9a753e575cb Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 18 Dec 2024 15:24:27 +0100 Subject: [PATCH 457/989] Android: Modernize AndroidDevice a bit Hidden friends for comparison etc. Change-Id: Ife6fc2b0c231f2f3174d86267cd39f8974b8dfe3 Reviewed-by: Jarek Kobus --- src/plugins/android/androiddeviceinfo.cpp | 31 ++++++++----------- src/plugins/android/androiddeviceinfo.h | 20 ++++++------ .../android/avdmanageroutputparser.cpp | 1 + .../android/tst_avdmanageroutputparser.cpp | 1 + 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/plugins/android/androiddeviceinfo.cpp b/src/plugins/android/androiddeviceinfo.cpp index 2c79ced2c0f..a489065a94b 100644 --- a/src/plugins/android/androiddeviceinfo.cpp +++ b/src/plugins/android/androiddeviceinfo.cpp @@ -3,33 +3,28 @@ #include "androiddeviceinfo.h" +using namespace ProjectExplorer; + namespace Android::Internal { -bool AndroidDeviceInfo::operator<(const AndroidDeviceInfo &other) const +bool operator<(const AndroidDeviceInfo &lhs, const AndroidDeviceInfo &rhs) { - if (serialNumber.contains("????") != other.serialNumber.contains("????")) - return !serialNumber.contains("????"); - if (type != other.type) - return type == ProjectExplorer::IDevice::Hardware; - if (sdk != other.sdk) - return sdk < other.sdk; - if (avdName != other.avdName) - return avdName < other.avdName; + if (lhs.serialNumber.contains("????") != rhs.serialNumber.contains("????")) + return !lhs.serialNumber.contains("????"); + if (lhs.type != rhs.type) + return lhs.type == IDevice::Hardware; + if (lhs.sdk != rhs.sdk) + return lhs.sdk < rhs.sdk; + if (lhs.avdName != rhs.avdName) + return lhs.avdName < rhs.avdName; - return serialNumber < other.serialNumber; -} - -bool AndroidDeviceInfo::operator==(const AndroidDeviceInfo &other) const -{ - return serialNumber == other.serialNumber && avdName == other.avdName - && avdPath == other.avdPath && cpuAbi == other.cpuAbi - && sdk == other.sdk && state == other.state && type == other.type; + return lhs.serialNumber < rhs.serialNumber; } QDebug &operator<<(QDebug &stream, const AndroidDeviceInfo &device) { stream.nospace() - << "Type:" << (device.type == ProjectExplorer::IDevice::Emulator ? "Emulator" : "Device") + << "Type:" << (device.type == IDevice::Emulator ? "Emulator" : "Device") << ", ABI:" << device.cpuAbi << ", Serial:" << device.serialNumber << ", Name:" << device.avdName << ", API:" << device.sdk << ", Authorised:" << (device.state == IDevice::DeviceReadyToUse); diff --git a/src/plugins/android/androiddeviceinfo.h b/src/plugins/android/androiddeviceinfo.h index 6a66e821218..cca9bc9609c 100644 --- a/src/plugins/android/androiddeviceinfo.h +++ b/src/plugins/android/androiddeviceinfo.h @@ -10,29 +10,29 @@ #include -using namespace ProjectExplorer; - namespace Android::Internal { class AndroidDeviceInfo { public: + bool isValid() const { return !serialNumber.isEmpty() || !avdName.isEmpty(); } + QString serialNumber; QString avdName; QStringList cpuAbi; int sdk = -1; - IDevice::DeviceState state = IDevice::DeviceDisconnected; - IDevice::MachineType type = IDevice::Emulator; + ProjectExplorer::IDevice::DeviceState state = ProjectExplorer::IDevice::DeviceDisconnected; + ProjectExplorer::IDevice::MachineType type = ProjectExplorer::IDevice::Emulator; Utils::FilePath avdPath; - bool isValid() const { return !serialNumber.isEmpty() || !avdName.isEmpty(); } - bool operator<(const AndroidDeviceInfo &other) const; - bool operator==(const AndroidDeviceInfo &other) const; // should be = default with C++20 - bool operator!=(const AndroidDeviceInfo &other) const { return !(*this == other); } +private: + friend bool operator<(const AndroidDeviceInfo &lhs, const AndroidDeviceInfo &rhs); + friend bool operator==(const AndroidDeviceInfo &lhs, const AndroidDeviceInfo &rhs) = default; + friend bool operator!=(const AndroidDeviceInfo &lhs, const AndroidDeviceInfo &rhs) = default; + friend QDebug &operator<<(QDebug &stream, const AndroidDeviceInfo &device); }; -using AndroidDeviceInfoList = QList; -QDebug &operator<<(QDebug &stream, const AndroidDeviceInfo &device); +using AndroidDeviceInfoList = QList; } // namespace Android::Internal diff --git a/src/plugins/android/avdmanageroutputparser.cpp b/src/plugins/android/avdmanageroutputparser.cpp index 2357b90dfe1..fc43df72420 100644 --- a/src/plugins/android/avdmanageroutputparser.cpp +++ b/src/plugins/android/avdmanageroutputparser.cpp @@ -15,6 +15,7 @@ #include #include +using namespace ProjectExplorer; using namespace Utils; namespace Android::Internal { diff --git a/tests/auto/android/tst_avdmanageroutputparser.cpp b/tests/auto/android/tst_avdmanageroutputparser.cpp index e65a2bb15a4..22038729ce3 100644 --- a/tests/auto/android/tst_avdmanageroutputparser.cpp +++ b/tests/auto/android/tst_avdmanageroutputparser.cpp @@ -7,6 +7,7 @@ using namespace Android; using namespace Android::Internal; +using namespace ProjectExplorer; class tst_AvdManagerOutputParser : public QObject { From 50f2c424ad5baa63e8650857c4ac1b72e3c3a564 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 19 Dec 2024 13:12:12 +0100 Subject: [PATCH 458/989] PE: Return Result from canRunStartupProject() Simplify usages a bit. Change-Id: I33e4b910437964d64ae18bab87c4f1e33e37f705 Reviewed-by: hjk Reviewed-by: Christian Kandeler --- src/plugins/debugger/debuggerplugin.cpp | 10 +++---- src/plugins/lua/bindings/project.cpp | 2 +- src/plugins/perfprofiler/perfprofilertool.cpp | 2 +- .../projectexplorer/projectexplorer.cpp | 28 +++++++++---------- src/plugins/projectexplorer/projectexplorer.h | 8 ++---- src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +- src/plugins/valgrind/callgrindtool.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 4 +-- 8 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index b21924b9104..29741cc8936 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1516,11 +1516,11 @@ void DebuggerPluginPrivate::updatePresetState() if (!currentEngine) { // No engine running -- or -- we have a running engine but it does not // correspond to the current start up project. - m_startAction.setEnabled(bool(canRun)); + m_startAction.setEnabled(canRun); m_startAction.setIcon(startIcon(true)); m_startAction.setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_startAction.setVisible(true); - m_debugWithoutDeployAction.setEnabled(bool(canRun)); + m_debugWithoutDeployAction.setEnabled(canRun); m_visibleStartAction.setAction(&m_startAction); m_hiddenStopAction.setAction(&m_undisturbableAction); return; @@ -1534,7 +1534,7 @@ void DebuggerPluginPrivate::updatePresetState() m_startAction.setEnabled(false); m_startAction.setVisible(false); - m_debugWithoutDeployAction.setEnabled(bool(canRun)); + m_debugWithoutDeployAction.setEnabled(canRun); const DebuggerState state = currentEngine->state(); @@ -1552,8 +1552,8 @@ void DebuggerPluginPrivate::updatePresetState() m_hiddenStopAction.setAction(ActionManager::command(Constants::INTERRUPT)->action()); } else if (state == DebuggerFinished) { // We don't want to do anything anymore. - m_startAction.setEnabled(bool(canRun)); - m_debugWithoutDeployAction.setEnabled(bool(canRun)); + m_startAction.setEnabled(canRun); + m_debugWithoutDeployAction.setEnabled(canRun); m_visibleStartAction.setAction(ActionManager::command(DEBUGGER_START)->action()); m_hiddenStopAction.setAction(&m_undisturbableAction); } else if (state == InferiorUnrunnable) { diff --git a/src/plugins/lua/bindings/project.cpp b/src/plugins/lua/bindings/project.cpp index 40cbc2f0e54..6f83bcd3642 100644 --- a/src/plugins/lua/bindings/project.cpp +++ b/src/plugins/lua/bindings/project.cpp @@ -59,7 +59,7 @@ void setupProjectModule() result["canRunStartupProject"] = [](const QString &mode) -> std::pair> { - auto result = ProjectExplorerPlugin::canRunStartupProject(Id::fromString(mode)); + const auto result = ProjectExplorerPlugin::canRunStartupProject(Id::fromString(mode)); if (result) return std::make_pair(true, sol::lua_nil); return std::make_pair(false, result.error()); diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index 731b5f0c7c9..524aaf64faf 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -439,7 +439,7 @@ void PerfProfilerTool::updateRunActions() const auto canRun = ProjectExplorerPlugin::canRunStartupProject( ProjectExplorer::Constants::PERFPROFILER_RUN_MODE); m_startAction->setToolTip(canRun ? Tr::tr("Start a performance analysis.") : canRun.error()); - m_startAction->setEnabled(bool(canRun)); + m_startAction->setEnabled(canRun); m_loadPerfData->setEnabled(true); m_loadTrace->setEnabled(true); } diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index c1cba541107..3914c805952 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3175,32 +3175,32 @@ void ProjectExplorerPluginPrivate::updateDeployActions() doUpdateRunActions(); } -expected_str ProjectExplorerPlugin::canRunStartupProject(Utils::Id runMode) +Result ProjectExplorerPlugin::canRunStartupProject(Utils::Id runMode) { Project *project = ProjectManager::startupProject(); if (!project) - return make_unexpected(Tr::tr("No active project.")); + return Result::Error(Tr::tr("No active project.")); if (project->needsConfiguration()) { - return make_unexpected(Tr::tr("The project \"%1\" is not configured.") + return Result::Error(Tr::tr("The project \"%1\" is not configured.") .arg(project->displayName())); } Target *target = project->activeTarget(); if (!target) { - return make_unexpected(Tr::tr("The project \"%1\" has no active kit.") + return Result::Error(Tr::tr("The project \"%1\" has no active kit.") .arg(project->displayName())); } RunConfiguration *activeRC = target->activeRunConfiguration(); if (!activeRC) { - return make_unexpected( + return Result::Error( Tr::tr("The kit \"%1\" for the project \"%2\" has no active run configuration.") .arg(target->displayName(), project->displayName())); } if (!activeRC->isEnabled(runMode)) - return make_unexpected(activeRC->disabledReason(runMode)); + return Result::Error(activeRC->disabledReason(runMode)); if (projectExplorerSettings().buildBeforeDeploy != BuildBeforeRunMode::Off && projectExplorerSettings().deployBeforeRun @@ -3208,30 +3208,30 @@ expected_str ProjectExplorerPlugin::canRunStartupProject(Utils::Id runMode && hasBuildSettings(project)) { QPair buildState = dd->buildSettingsEnabled(project); if (!buildState.first) - return make_unexpected(buildState.second); + return Result::Error(buildState.second); if (BuildManager::isBuilding()) - return make_unexpected(Tr::tr("A build is still in progress.")); + return Result::Error(Tr::tr("A build is still in progress.")); } // shouldn't actually be shown to the user... if (!RunControl::canRun(runMode, RunDeviceTypeKitAspect::deviceTypeId(target->kit()), activeRC->id())) { - return make_unexpected(Tr::tr("Cannot run \"%1\".").arg(activeRC->displayName())); + return Result::Error(Tr::tr("Cannot run \"%1\".").arg(activeRC->displayName())); } if (dd->m_delayedRunConfiguration && dd->m_delayedRunConfiguration->project() == project) - return make_unexpected(Tr::tr("A run action is already scheduled for the active project.")); + return Result::Error(Tr::tr("A run action is already scheduled for the active project.")); - return {}; + return Result::Ok; } void ProjectExplorerPluginPrivate::doUpdateRunActions() { const auto canRun = ProjectExplorerPlugin::canRunStartupProject(Constants::NORMAL_RUN_MODE); - m_runAction->setEnabled(bool(canRun)); - m_runAction->setToolTip(canRun ? QString() : canRun.error()); - m_runWithoutDeployAction->setEnabled(bool(canRun)); + m_runAction->setEnabled(canRun); + m_runAction->setToolTip(canRun.error()); + m_runWithoutDeployAction->setEnabled(canRun); emit m_instance->runActionsUpdated(); } diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index fdb8edbc2e9..aebb14f8d25 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -7,13 +7,9 @@ #include -#include #include #include - -#include - -#include +#include QT_BEGIN_NAMESPACE class QPoint; @@ -138,7 +134,7 @@ public: static void renameFilesForSymbol(const QString &oldSymbolName, const QString &newSymbolName, const Utils::FilePaths &files, bool preferLowerCaseFileNames); - static Utils::expected_str canRunStartupProject(Utils::Id runMode); + static Utils::Result canRunStartupProject(Utils::Id runMode); static void runProject(Project *pro, Utils::Id, const bool forceSkipDeploy = false); static void runStartupProject(Utils::Id runMode, bool forceSkipDeploy = false); static void runRunConfiguration(RunConfiguration *rc, Utils::Id runMode, diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index e7834d1209e..e729c58c3c8 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -345,7 +345,7 @@ void QmlProfilerTool::updateRunActions() ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); d->m_startAction->setToolTip(canRun ? Tr::tr("Start QML Profiler analysis.") : canRun.error()); - d->m_startAction->setEnabled(bool(canRun)); + d->m_startAction->setEnabled(canRun); d->m_stopAction->setEnabled(false); } } diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index abab7340e6d..ea6c594710c 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -756,7 +756,7 @@ void CallgrindTool::updateRunActions() const auto canRun = ProjectExplorerPlugin::canRunStartupProject(CALLGRIND_RUN_MODE); m_startAction->setToolTip(canRun ? Tr::tr("Start a Valgrind Callgrind analysis.") : canRun.error()); - m_startAction->setEnabled(bool(canRun)); + m_startAction->setEnabled(canRun); m_stopAction->setEnabled(false); } } diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 5323e45e547..0bf925d9853 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -855,12 +855,12 @@ void MemcheckTool::updateRunActions() const auto canRun = ProjectExplorerPlugin::canRunStartupProject(MEMCHECK_RUN_MODE); m_startAction->setToolTip(canRun ? Tr::tr("Start a Valgrind Memcheck analysis.") : canRun.error()); - m_startAction->setEnabled(bool(canRun)); + m_startAction->setEnabled(canRun); const auto canRunGdb = ProjectExplorerPlugin::canRunStartupProject( MEMCHECK_WITH_GDB_RUN_MODE); m_startWithGdbAction->setToolTip( canRunGdb ? Tr::tr("Start a Valgrind Memcheck with GDB analysis.") : canRunGdb.error()); - m_startWithGdbAction->setEnabled(bool(canRunGdb)); + m_startWithGdbAction->setEnabled(canRunGdb); m_stopAction->setEnabled(false); } } From 9a7840b758c339b9daffdf67a716a70357f737d8 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 9 Dec 2024 13:54:14 +0100 Subject: [PATCH 459/989] TextEditor: Return codec names from openedTextDocumentEncodings() And adapt called and calling code. Change-Id: I043a1c14ca1abbfcbbbeb066d99c70576c3cd4e6 Reviewed-by: David Schulz --- src/plugins/coreplugin/textdocument.cpp | 5 +++++ src/plugins/coreplugin/textdocument.h | 1 + src/plugins/projectexplorer/allprojectsfind.cpp | 10 +++++----- src/plugins/texteditor/findincurrentfile.cpp | 11 ++++++----- src/plugins/texteditor/findinopenfiles.cpp | 12 +++++++----- src/plugins/texteditor/textdocument.cpp | 6 +++--- src/plugins/texteditor/textdocument.h | 2 +- 7 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/plugins/coreplugin/textdocument.cpp b/src/plugins/coreplugin/textdocument.cpp index 1c251a57e29..593344fe0d9 100644 --- a/src/plugins/coreplugin/textdocument.cpp +++ b/src/plugins/coreplugin/textdocument.cpp @@ -170,6 +170,11 @@ const QTextCodec *BaseTextDocument::codec() const return d->m_format.codec(); } +QByteArray BaseTextDocument::codecName() const +{ + return d->m_format.codecName(); +} + void BaseTextDocument::setCodec(const QTextCodec *codec) { if (debug) diff --git a/src/plugins/coreplugin/textdocument.h b/src/plugins/coreplugin/textdocument.h index 73ce64f41b4..a7113d216b0 100644 --- a/src/plugins/coreplugin/textdocument.h +++ b/src/plugins/coreplugin/textdocument.h @@ -23,6 +23,7 @@ public: Utils::TextFileFormat format() const; const QTextCodec *codec() const; + QByteArray codecName() const; void setCodec(const QTextCodec *); void setCodec(const QByteArray &name); virtual bool supportsCodec(const QByteArray &) const; diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp index 2709d558a6e..6b30fa44606 100644 --- a/src/plugins/projectexplorer/allprojectsfind.cpp +++ b/src/plugins/projectexplorer/allprojectsfind.cpp @@ -58,7 +58,7 @@ FileContainer AllProjectsFind::filesForProjects(const QStringList &nameFilters, { const FilterFilesFunction filterFiles = Utils::filterFilesFunction(nameFilters, exclusionFilters); - const QMap openEditorEncodings + const QMap openEditorEncodings = TextDocument::openedTextDocumentEncodings(); QMap encodings; for (const Project *project : projects) { @@ -68,10 +68,10 @@ FileContainer AllProjectsFind::filesForProjects(const QStringList &nameFilters, : config->textCodec(); const FilePaths filteredFiles = filterFiles(project->files(Project::SourceFiles)); for (const FilePath &fileName : filteredFiles) { - QTextCodec *codec = openEditorEncodings.value(fileName); - if (!codec) - codec = QTextCodec::codecForName(projectCodec); - encodings.insert(fileName, codec); + QByteArray codec = openEditorEncodings.value(fileName); + if (codec.isEmpty()) + codec = projectCodec; + encodings.insert(fileName, QTextCodec::codecForName(codec)); } } return FileListContainer(encodings.keys(), encodings.values()); diff --git a/src/plugins/texteditor/findincurrentfile.cpp b/src/plugins/texteditor/findincurrentfile.cpp index f68eb33247e..9d4bb111c3c 100644 --- a/src/plugins/texteditor/findincurrentfile.cpp +++ b/src/plugins/texteditor/findincurrentfile.cpp @@ -13,6 +13,7 @@ #include #include +#include using namespace Utils; @@ -67,11 +68,11 @@ QString FindInCurrentFile::displayName() const FileContainerProvider FindInCurrentFile::fileContainerProvider() const { return [fileName = m_currentDocument->filePath()] { - const QMap encodings = TextDocument::openedTextDocumentEncodings(); - QTextCodec *codec = encodings.value(fileName); - if (!codec) - codec = Core::EditorManager::defaultTextCodec(); - return FileListContainer({fileName}, {codec}); + const QMap encodings = TextDocument::openedTextDocumentEncodings(); + QByteArray codec = encodings.value(fileName); + if (codec.isEmpty()) + codec = Core::EditorManager::defaultTextCodecName(); + return FileListContainer({fileName}, {QTextCodec::codecForName(codec)}); }; } diff --git a/src/plugins/texteditor/findinopenfiles.cpp b/src/plugins/texteditor/findinopenfiles.cpp index deeb66e9f5f..117e44822a2 100644 --- a/src/plugins/texteditor/findinopenfiles.cpp +++ b/src/plugins/texteditor/findinopenfiles.cpp @@ -12,6 +12,8 @@ #include +#include + using namespace Utils; namespace TextEditor::Internal { @@ -59,7 +61,7 @@ QString FindInOpenFiles::displayName() const FileContainerProvider FindInOpenFiles::fileContainerProvider() const { return [] { - const QMap encodings = TextDocument::openedTextDocumentEncodings(); + const QMap encodings = TextDocument::openedTextDocumentEncodings(); FilePaths fileNames; QList codecs; const QList entries = Core::DocumentModel::entries(); @@ -67,10 +69,10 @@ FileContainerProvider FindInOpenFiles::fileContainerProvider() const const FilePath fileName = entry->filePath(); if (!fileName.isEmpty()) { fileNames.append(fileName); - QTextCodec *codec = encodings.value(fileName); - if (!codec) - codec = Core::EditorManager::defaultTextCodec(); - codecs.append(codec); + QByteArray codec = encodings.value(fileName); + if (codec.isEmpty()) + codec = Core::EditorManager::defaultTextCodecName(); + codecs.append(QTextCodec::codecForName(codec)); } } return FileListContainer(fileNames, codecs); diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index a8ab2d79944..0e88e78b9ee 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -272,16 +272,16 @@ QMap TextDocument::openedTextDocumentContents() return workingCopy; } -QMap TextDocument::openedTextDocumentEncodings() +QMap TextDocument::openedTextDocumentEncodings() { - QMap workingCopy; + QMap workingCopy; const QList documents = DocumentModel::openedDocuments(); for (IDocument *document : documents) { auto textEditorDocument = qobject_cast(document); if (!textEditorDocument) continue; const FilePath fileName = textEditorDocument->filePath(); - workingCopy[fileName] = const_cast(textEditorDocument->codec()); + workingCopy[fileName] = textEditorDocument->codecName(); } return workingCopy; } diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index 9046702b78d..8c08e0bc942 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -51,7 +51,7 @@ public: ~TextDocument() override; static QMap openedTextDocumentContents(); - static QMap openedTextDocumentEncodings(); + static QMap openedTextDocumentEncodings(); static TextDocument *currentTextDocument(); static TextDocument *textDocumentForFilePath(const Utils::FilePath &filePath); static QString convertToPlainText(const QString &rawText); From 41c3285de06386b9cd5c6129f91c6fd42e2c389a Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 16:12:45 +0100 Subject: [PATCH 460/989] Debugger: Remove some unused leftovers From an earlier attempt at using some internal terminal. Change-Id: Iaf9bc2e84ad192f28dc4ab6a4f5ec7e96fe4378c Reviewed-by: Andrii Semkiv Reviewed-by: hjk --- src/plugins/debugger/debuggerengine.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 50ab3ba5d22..a00ca94af64 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -592,19 +592,6 @@ void DebuggerEnginePrivate::setupViews() QTC_ASSERT(m_state == DebuggerNotReady || m_state == DebuggerFinished, qDebug() << m_state); m_progress.setProgressValue(200); -// m_terminal.setup(); -// if (m_terminal.isUsable()) { -// connect(&m_terminal, &Terminal::stdOutReady, [this](const QString &msg) { -// m_engine->showMessage(msg, Utils::StdOutFormatSameLine); -// }); -// connect(&m_terminal, &Terminal::stdErrReady, [this](const QString &msg) { -// m_engine->showMessage(msg, Utils::StdErrFormatSameLine); -// }); -// connect(&m_terminal, &Terminal::error, [this](const QString &msg) { -// m_engine->showMessage(msg, Utils::ErrorMessageFormat); -// }); -// } - connect(&m_locationTimer, &QTimer::timeout, this, &DebuggerEnginePrivate::resetLocation); From f6831d0645a01170ab5fa800c4be3fb524c94db5 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 11 Dec 2024 13:35:34 +0100 Subject: [PATCH 461/989] Raise Qt requirement for building Qt Creator to Qt 6.5.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And remove some version checks. Qt 6.8 is released and Qt 6.5 and 6.8 are LTS. This enables us to use some newer APIs like Qt::ColorScheme. Change-Id: Ibdeeb933bb8e9fa2d1a02fba3e3f0b868747e763 Reviewed-by: Orgad Shaneh Reviewed-by: Robert Löhning Reviewed-by: hjk Reviewed-by: André Hartmann --- README.md | 6 +++--- cmake/QtCreatorAPI.cmake | 2 +- cmake/QtCreatorAPIInternal.cmake | 2 -- coin/instructions/common_environment.yaml | 2 +- src/app/main.cpp | 3 +-- src/libs/utils/async.h | 5 ----- src/libs/utils/persistentsettings.cpp | 4 ---- src/plugins/terminal/shortcutmap.cpp | 4 ---- 8 files changed, 6 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 14a08075fc2..96da4ba0e5a 100644 --- a/README.md +++ b/README.md @@ -40,16 +40,16 @@ https://doc.qt.io/qtcreator-extending/coding-style.html Prerequisites: -* Qt 6.4.3 or later. The Qt version that you use to build Qt Creator defines the +* Qt 6.5.3 or later. The Qt version that you use to build Qt Creator defines the minimum platform versions that the result supports - (Windows 10, RHEL/CentOS 8.4, Ubuntu 20.04, macOS 10.15 for Qt 6.4.3). + (Windows 10, RHEL/CentOS 8.8, Ubuntu 22.04, macOS 11 for Qt 6.5.3). * Qt WebEngine module for QtWebEngine based help viewer * On Windows: * MinGW with GCC 11.2 or Visual Studio 2019 or later * Python 3.8 or later (optional, needed for the python enabled debug helper) * Debugging Tools for Windows (optional, for MSVC debugging support with CDB) * On macOS: latest Xcode -* On Linux: GCC 9 or later +* On Linux: GCC 10 or later * LLVM/Clang 14 or later (optional, LLVM/Clang 17 is recommended. See [instructions](#getting-llvmclang-for-the-clang-code-model) on how to get LLVM. diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index e05a48563bc..e213eb73ce0 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -3,7 +3,7 @@ if(QT_CREATOR_API_DEFINED) endif() set(QT_CREATOR_API_DEFINED TRUE) -set(IDE_QT_VERSION_MIN "6.4.3") +set(IDE_QT_VERSION_MIN "6.5.3") include(${CMAKE_CURRENT_LIST_DIR}/QtCreatorAPIInternal.cmake) include(${CMAKE_CURRENT_LIST_DIR}/QtcSeparateDebugInfo.cmake) diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index ef7b55ff830..2d1b104c2c7 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -22,9 +22,7 @@ list(APPEND DEFAULT_DEFINES QT_CREATOR QT_NO_JAVA_STYLE_ITERATORS QT_NO_CAST_TO_ASCII QT_RESTRICTED_CAST_FROM_ASCII QT_NO_FOREACH - QT_DISABLE_DEPRECATED_BEFORE=0x050900 QT_DISABLE_DEPRECATED_UP_TO=0x050900 - QT_WARN_DEPRECATED_BEFORE=0x060400 QT_WARN_DEPRECATED_UP_TO=0x060400 QT_USE_QSTRINGBUILDER ) diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml index dedcbaf2fc5..b36a480a57d 100644 --- a/coin/instructions/common_environment.yaml +++ b/coin/instructions/common_environment.yaml @@ -20,7 +20,7 @@ instructions: instructions: - type: EnvironmentVariable variableName: QTC_QT_BASE_URL - variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/qt/6.4.3/release_content/" + variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/qt/6.5.3/release_content/" - type: EnvironmentVariable variableName: MACOSX_DEPLOYMENT_TARGET variableValue: 11.0 diff --git a/src/app/main.cpp b/src/app/main.cpp index 42b28ea500c..e993b4609be 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -485,8 +485,7 @@ private: // Show some kind of GUI with collected messages before exiting. // For Windows, Qt already uses a dialog. if (HostOsInfo::isLinuxHost()) { -#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) && QT_VERSION < QT_VERSION_CHECK(6, 5, 3)) \ - || (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) && QT_VERSION < QT_VERSION_CHECK(6, 6, 1)) +#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) && QT_VERSION < QT_VERSION_CHECK(6, 6, 1)) // Information about potentially missing libxcb-cursor0 is printed by Qt since Qt 6.5.3 and Qt 6.6.1 // Add it manually for other versions >= 6.5.0 instance->messages.prepend("From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to " diff --git a/src/libs/utils/async.h b/src/libs/utils/async.h index 4643ea161bb..76e4f01aa40 100644 --- a/src/libs/utils/async.h +++ b/src/libs/utils/async.h @@ -171,12 +171,7 @@ public: QFuture future() const { return m_watcher.future(); } ResultType result() const { return m_watcher.result(); } -#if QT_VERSION > QT_VERSION_CHECK(6, 5, 2) - // takeResult is buggy before QTBUG-112513 as it resets the future state to "NoState". - // This in turn causes the FutureSynchronizer to deadlock in "waitForFinished", as the - // future is not in the finished state anymore. ResultType takeResult() const { return m_watcher.future().takeResult(); } -#endif ResultType resultAt(int index) const { return m_watcher.resultAt(index); } QList results() const { return future().results(); } bool isResultAvailable() const { return future().resultCount(); } diff --git a/src/libs/utils/persistentsettings.cpp b/src/libs/utils/persistentsettings.cpp index 2b65aa0ce58..90454ca0dd1 100644 --- a/src/libs/utils/persistentsettings.cpp +++ b/src/libs/utils/persistentsettings.cpp @@ -330,11 +330,7 @@ FilePath PersistentSettingsReader::filePath() \sa Utils::PersistentSettingsReader */ -#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) static QString xmlAttrFromKey(const QString &key) { return key; } -#else -static QString xmlAttrFromKey(const QString &key) { return key; } -#endif static void writeVariantValue(QXmlStreamWriter &w, const QVariant &variant, const QString &key = {}) { diff --git a/src/plugins/terminal/shortcutmap.cpp b/src/plugins/terminal/shortcutmap.cpp index 4e17f0c35e4..31dd9ba604b 100644 --- a/src/plugins/terminal/shortcutmap.cpp +++ b/src/plugins/terminal/shortcutmap.cpp @@ -237,11 +237,7 @@ bool ShortcutMap::tryShortcut(QKeyEvent *e) return dispatchEvent(e); } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) Q_UNREACHABLE_RETURN(false); -#else - return false; -#endif } /*! \internal From 019fa3b42e9c59ff8a2f842d9c1dd9eb1037063b Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 19 Dec 2024 14:43:24 +0100 Subject: [PATCH 462/989] QbsProjectManager: More file path translations Among other things, this fixes a bogus "file not part of project" message for sources in remote projects. Change-Id: If0cdec787792f17413ad568f2de480e8f7fe8c63 Reviewed-by: hjk --- src/plugins/qbsprojectmanager/qbsproject.cpp | 49 ++++++++++++-------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 2f60adba562..73c9165951e 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -871,6 +871,7 @@ static void getExpandedCompilerFlags(QStringList &cFlags, QStringList &cxxFlags, } static RawProjectPart generateProjectPart( + const FilePath &refFile, const QJsonObject &product, const QJsonObject &group, const std::shared_ptr &cToolchain, @@ -918,12 +919,12 @@ static RawProjectPart generateProjectPart( list.append(arrayToStringList(props.value("cpp.systemFrameworkPaths"))); list.removeDuplicates(); for (const QString &p : std::as_const(list)) - headerPaths += HeaderPath::makeFramework(FilePath::fromUserInput(p)); + headerPaths += HeaderPath::makeFramework(refFile.withNewPath(p)); rpp.setHeaderPaths(headerPaths); rpp.setDisplayName(groupName); const QJsonObject location = groupOrProduct.value("location").toObject(); rpp.setProjectFileLocation( - FilePath::fromUserInput(location.value("file-path").toString()), + refFile.withNewPath(location.value("file-path").toString()), location.value("line").toInt(), location.value("column").toInt()); rpp.setBuildSystemTarget(QbsProductNode::getBuildKey(product)); @@ -946,8 +947,10 @@ static RawProjectPart generateProjectPart( bool hasObjcFiles = false; bool hasObjcxxFiles = false; const auto artifactWorker = [&](const QJsonObject &source) { - const QString filePath = source.value("file-path").toString(); - filePathToSourceArtifact.insert(filePath, source); + const QString filePath = refFile.withNewPath(source.value("file-path").toString()).toString(); + QJsonObject translatedSource = source; + translatedSource.insert("file-path", filePath); + filePathToSourceArtifact.insert(filePath, translatedSource); for (const QJsonValue &tag : source.value("file-tags").toArray()) { if (tag == "c") hasCFiles = true; @@ -988,7 +991,10 @@ static RawProjectPart generateProjectPart( qCWarning(qbsPmLog) << "Expect problems with code model"; } rpp.setPreCompiledHeaders(Utils::toList(pchFiles)); - rpp.setIncludedFiles(arrayToStringList(props.value("cpp.prefixHeaders"))); + rpp.setIncludedFiles( + Utils::transform(arrayToStringList(props.value("cpp.prefixHeaders")), [&](const QString &f) { + return refFile.withNewPath(f).toString(); + })); rpp.setFiles(filePathToSourceArtifact.keys(), {}, [filePathToSourceArtifact](const QString &filePath) { // Keep this lambda thread-safe! @@ -998,6 +1004,7 @@ static RawProjectPart generateProjectPart( } static RawProjectParts generateProjectParts( + const FilePath &refFile, const QJsonObject &projectData, const std::shared_ptr &cToolchain, const std::shared_ptr &cxxToolchain, @@ -1005,21 +1012,25 @@ static RawProjectParts generateProjectParts( ) { RawProjectParts rpps; + const auto translatedPath = [&](const QJsonValue &v) { + QTC_ASSERT(v.isString(), return QString()); + return refFile.withNewPath(v.toString()).toString(); + }; forAllProducts(projectData, [&](const QJsonObject &prd) { QString cPch; QString cxxPch; QString objcPch; QString objcxxPch; - const auto &pchFinder = [&cPch, &cxxPch, &objcPch, &objcxxPch](const QJsonObject &artifact) { + const auto &pchFinder = [&](const QJsonObject &artifact) { const QJsonArray fileTags = artifact.value("file-tags").toArray(); if (fileTags.contains("c_pch_src")) - cPch = artifact.value("file-path").toString(); + cPch = translatedPath(artifact.value("file-path")); if (fileTags.contains("cpp_pch_src")) - cxxPch = artifact.value("file-path").toString(); + cxxPch = translatedPath(artifact.value("file-path")); if (fileTags.contains("objc_pch_src")) - objcPch = artifact.value("file-path").toString(); + objcPch = translatedPath(artifact.value("file-path")); if (fileTags.contains("objcpp_pch_src")) - objcxxPch = artifact.value("file-path").toString(); + objcxxPch = translatedPath(artifact.value("file-path")); }; forAllArtifacts(prd, ArtifactType::All, pchFinder); const Utils::QtMajorVersion qtVersionForPart @@ -1033,11 +1044,11 @@ static RawProjectParts generateProjectParts( }; for (const QJsonValue &g : groups) { appendIfNotEmpty(generateProjectPart( - prd, g.toObject(), cToolchain, cxxToolchain, qtVersionForPart, + refFile, prd, g.toObject(), cToolchain, cxxToolchain, qtVersionForPart, cPch, cxxPch, objcPch, objcxxPch)); } appendIfNotEmpty(generateProjectPart( - prd, {}, cToolchain, cxxToolchain, qtVersionForPart, + refFile, prd, {}, cToolchain, cxxToolchain, qtVersionForPart, cPch, cxxPch, objcPch, objcxxPch)); }); return rpps; @@ -1058,8 +1069,8 @@ void QbsBuildSystem::updateCppCodeModel() ? kitInfo.cxxToolchain->clone() : nullptr); m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), {}, - [projectData, kitInfo, cToolchain, cxxToolchain] { - return generateProjectParts(projectData, cToolchain, cxxToolchain, + [projectData, kitInfo, cToolchain, cxxToolchain, refFile = project()->projectFilePath()] { + return generateProjectParts(refFile, projectData, cToolchain, cxxToolchain, kitInfo.projectPartQtVersion); }}); } @@ -1146,8 +1157,8 @@ void QbsBuildSystem::updateApplicationTargets() } BuildTargetInfo bti; bti.buildKey = QbsProductNode::getBuildKey(productData); - bti.targetFilePath = FilePath::fromString(targetFile); - bti.projectFilePath = FilePath::fromString(projectFile); + bti.targetFilePath = projectFilePath().withNewPath(targetFile); + bti.projectFilePath = projectFilePath().withNewPath(projectFile); bti.isQtcRunnable = isQtcRunnable; // Fixed up below. bti.usesTerminal = usesTerminal; bti.displayName = productData.value("full-display-name").toString(); @@ -1196,12 +1207,12 @@ void QbsBuildSystem::updateDeploymentInfo() if (session()->projectData().isEmpty()) return; DeploymentData deploymentData; - forAllProducts(session()->projectData(), [&deploymentData](const QJsonObject &product) { - forAllArtifacts(product, ArtifactType::All, [&deploymentData](const QJsonObject &artifact) { + forAllProducts(session()->projectData(), [&](const QJsonObject &product) { + forAllArtifacts(product, ArtifactType::All, [&](const QJsonObject &artifact) { const QJsonObject installData = artifact.value("install-data").toObject(); if (installData.value("is-installable").toBool()) { deploymentData.addFile( - FilePath::fromSettings(artifact.value("file-path")), + projectFilePath().withNewPath(artifact.value("file-path").toString()), QFileInfo(installData.value("install-file-path").toString()).path(), artifact.value("is-executable").toBool() ? DeployableFile::TypeExecutable : DeployableFile::TypeNormal); From 248061deb279f197d8b5ef740461e466c4a7ee30 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 16:32:50 +0100 Subject: [PATCH 463/989] Utils: Allow remote paths in MacroExpander::registerFileVariable Change-Id: I5156366b3009f119ab4524b7078fa72f23b2b251 Reviewed-by: Christian Kandeler --- src/libs/utils/macroexpander.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index 082c88f6f4f..3037caf383e 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -514,13 +514,13 @@ void MacroExpander::registerFileVariables(const QByteArray &prefix, registerVariable( prefix + kFilePathPostfix, Tr::tr("%1: Full path including file name.").arg(heading), - [base] { return base().path(); }, + [base] { return base().toFSPathString(); }, visibleInChooser); registerVariable( prefix + kPathPostfix, Tr::tr("%1: Full path excluding file name.").arg(heading), - [base] { return base().parentDir().path(); }, + [base] { return base().parentDir().toFSPathString(); }, visibleInChooser); registerVariable( From 84f8e7f55fe77e04afe15efda32c0b3f8ab9f007 Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Thu, 19 Dec 2024 12:16:47 +0100 Subject: [PATCH 464/989] Debugger: Attach to Unstarted... dlg positioning The last position of Attach to Unstarted Application... dialog will be remembered and restored when the dialog is shown again after being closed or the debugging finishing. Fixes: QTCREATORBUG-32185 Change-Id: Ib2827116da80bb909d8d3f5fe7208ab6305debb9 Reviewed-by: hjk --- src/plugins/debugger/debuggerplugin.cpp | 10 ++++++++-- src/plugins/debugger/unstartedappwatcherdialog.cpp | 13 ++++++++++--- src/plugins/debugger/unstartedappwatcherdialog.h | 3 ++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 29741cc8936..ea608f30904 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -702,6 +702,8 @@ public: DebuggerRunWorkerFactory debuggerWorkerFactory; + std::optional attachToUnstartedApplicationDialogLastPosition; + // FIXME: Needed? // QString mainScript = runConfig->property("mainScript").toString(); // const bool isDebuggableScript = mainScript.endsWith(".py"); // Only Python for now. @@ -1750,9 +1752,13 @@ void DebuggerPluginPrivate::attachToRunningApplication() void DebuggerPluginPrivate::attachToUnstartedApplicationDialog() { - auto dlg = new UnstartedAppWatcherDialog(ICore::dialogParent()); + auto dlg = new UnstartedAppWatcherDialog( + attachToUnstartedApplicationDialogLastPosition, ICore::dialogParent()); - connect(dlg, &QDialog::finished, dlg, &QObject::deleteLater); + connect(dlg, &QDialog::finished, this, [this, dlg]() { + this->attachToUnstartedApplicationDialogLastPosition = dlg->pos(); + dlg->deleteLater(); + }); connect(dlg, &UnstartedAppWatcherDialog::processFound, this, [this, dlg] { RunControl *rc = attachToRunningProcess(dlg->currentKit(), dlg->currentProcess(), diff --git a/src/plugins/debugger/unstartedappwatcherdialog.cpp b/src/plugins/debugger/unstartedappwatcherdialog.cpp index cc1c13c5415..1644483d8d1 100644 --- a/src/plugins/debugger/unstartedappwatcherdialog.cpp +++ b/src/plugins/debugger/unstartedappwatcherdialog.cpp @@ -65,9 +65,12 @@ static bool isLocal(RunConfiguration *runConfiguration) scripts can restart application several times during tests. */ -UnstartedAppWatcherDialog::UnstartedAppWatcherDialog(QWidget *parent) +UnstartedAppWatcherDialog::UnstartedAppWatcherDialog(std::optional pos, QWidget *parent) : QDialog(parent) + , m_lastPosition(pos) { + if (pos) + move(*pos); setWindowTitle(Tr::tr("Attach to Process Not Yet Started")); m_kitChooser = new KitChooser(this); @@ -197,6 +200,8 @@ void UnstartedAppWatcherDialog::selectExecutable() void UnstartedAppWatcherDialog::startWatching() { + if (m_lastPosition) + move(*m_lastPosition); show(); if (checkExecutableString()) { setWaitingState(WatchingState); @@ -212,10 +217,12 @@ void UnstartedAppWatcherDialog::pidFound(const ProcessInfo &p) startStopTimer(false); m_process = p; - if (hideOnAttach()) + if (hideOnAttach()) { + m_lastPosition = pos(); hide(); - else + } else { accept(); + } emit processFound(); } diff --git a/src/plugins/debugger/unstartedappwatcherdialog.h b/src/plugins/debugger/unstartedappwatcherdialog.h index c5acb6dcb7c..719a6ef39fd 100644 --- a/src/plugins/debugger/unstartedappwatcherdialog.h +++ b/src/plugins/debugger/unstartedappwatcherdialog.h @@ -28,7 +28,7 @@ class UnstartedAppWatcherDialog : public QDialog Q_OBJECT public: - explicit UnstartedAppWatcherDialog(QWidget *parent = nullptr); + UnstartedAppWatcherDialog(std::optional pos, QWidget *parent = nullptr); ProjectExplorer::Kit *currentKit() const; Utils::ProcessInfo currentProcess() const; @@ -70,6 +70,7 @@ private: Utils::ProcessInfo m_process; QSet m_excluded; QTimer m_timer; + std::optional m_lastPosition; }; } // Debugger::Internal From 9dc91be3d61070830a4c23f1b3b01547f1e7ef40 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 12:32:30 +0100 Subject: [PATCH 465/989] RemoteLinux: Source .profile etc when retrieving remote env When requested. Otherwise, the user PATH settings are not picked up. Change-Id: Iaeb2af524832d3e5f393527140c72b298d6250f8 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/linuxdevice.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 4f065b1766d..4dd20618a07 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -371,8 +371,18 @@ Environment LinuxDevicePrivate::getEnvironment() if (m_disconnected()) return {}; + const bool sourceProfile = q->extraData(Constants::SourceProfile).toBool(); + + CommandLine cmd; + if (sourceProfile) { + cmd.setExecutable(q->filePath("sh")); + cmd.addArgs({"-c", ". /etc/profile ; . ~/.profile ; env"}); + } else { + cmd.setExecutable(q->filePath("env")); + } + Process getEnvProc; - getEnvProc.setCommand(CommandLine{q->filePath("env")}); + getEnvProc.setCommand(cmd); using namespace std::chrono; getEnvProc.runBlocking(5s); From 07d04a182af7cc68fabaa3617ed87ccab1bc37d0 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 19 Dec 2024 17:45:15 +0100 Subject: [PATCH 466/989] QbsProjectManager: Fix adding/removing files to/from a project Change-Id: I6c57c138bb05c2a505f1bac13161352417bd8fe4 Reviewed-by: hjk --- src/plugins/qbsprojectmanager/qbsproject.cpp | 69 +++++++++++--------- src/plugins/qbsprojectmanager/qbsproject.h | 4 +- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 73c9165951e..7d472a2255a 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -348,20 +348,19 @@ bool QbsBuildSystem::isProjectEditable() const return !isParsing() && !BuildManager::isBuilding(target()); } -bool QbsBuildSystem::ensureWriteableQbsFile(const QString &file) +// Ensure that the file is not read only +bool QbsBuildSystem::ensureWriteableQbsFile(const FilePath &file) { - // Ensure that the file is not read only - QFileInfo fi(file); - if (!fi.isWritable()) { + if (!file.isWritableFile()) { // Try via vcs manager IVersionControl *versionControl = - VcsManager::findVersionControlForDirectory(FilePath::fromString(fi.absolutePath())); - if (!versionControl || !versionControl->vcsOpen(FilePath::fromString(file))) { - bool makeWritable = QFile::setPermissions(file, fi.permissions() | QFile::WriteUser); + VcsManager::findVersionControlForDirectory(file.parentDir()); + if (!versionControl || !versionControl->vcsOpen(file)) { + bool makeWritable = file.setPermissions(file.permissions() | QFile::WriteUser); if (!makeWritable) { QMessageBox::warning(ICore::dialogParent(), Tr::tr("Failed"), - Tr::tr("Could not write project file %1.").arg(file)); + Tr::tr("Could not write project file %1.").arg(file.toUserOutput())); return false; } } @@ -375,10 +374,9 @@ bool QbsBuildSystem::addFilesToProduct( const QJsonObject &group, FilePaths *notAdded) { - const QString groupFilePath = group.value("location").toObject().value("file-path").toString(); - ensureWriteableQbsFile(groupFilePath); + ensureWriteableQbsFile(groupFilePath(group)); const FileChangeResult result = session()->addFiles( - Utils::transform(filePaths, &FilePath::toString), + Utils::transform(filePaths, &FilePath::path), product.value("full-display-name").toString(), group.value("name").toString()); if (result.error().hasError()) { @@ -394,27 +392,27 @@ RemovedFilesFromProject QbsBuildSystem::removeFilesFromProduct( const QJsonObject &group, FilePaths *notRemoved) { - const auto allWildcardsInGroup = transform( + const auto allWildcardsInGroup = transform( group.value("source-artifacts-from-wildcards").toArray(), - [](const QJsonValue &v) { return v.toObject().value("file-path").toString(); }); + [this](const QJsonValue &v) { return locationFilePath(v.toObject()); }); FilePaths wildcardFiles; - QStringList nonWildcardFiles; + FilePaths nonWildcardFiles; for (const FilePath &filePath : filePaths) { - if (allWildcardsInGroup.contains(filePath.toString())) + if (allWildcardsInGroup.contains(filePath)) wildcardFiles << filePath; else - nonWildcardFiles << filePath.toString(); + nonWildcardFiles << filePath; } - const QString groupFilePath = group.value("location") - .toObject().value("file-path").toString(); - ensureWriteableQbsFile(groupFilePath); + ensureWriteableQbsFile(groupFilePath(group)); const FileChangeResult result = session()->removeFiles( - nonWildcardFiles, + Utils::transform(nonWildcardFiles, &FilePath::path), product.value("name").toString(), group.value("name").toString()); - *notRemoved = FileUtils::toFilePathList(result.failedFiles()); + *notRemoved = Utils::transform(result.failedFiles(), [this](const QString &f) { + return projectFilePath().withNewPath(f); + }); if (result.error().hasError()) MessageManager::writeDisrupting(result.error().toString()); const bool success = notRemoved->isEmpty(); @@ -450,29 +448,26 @@ bool QbsBuildSystem::renameFilesInProduct( const QJsonObject &group, Utils::FilePaths *notRenamed) { - const auto allWildcardsInGroup = transform( + const auto allWildcardsInGroup = transform( group.value("source-artifacts-from-wildcards").toArray(), - [](const QJsonValue &v) { return v.toObject().value("file-path").toString(); }); + [this](const QJsonValue &v) { return locationFilePath(v.toObject()); }); using FileStringPair = std::pair; using FileStringPairs = QList; - const FileStringPairs filesAsStrings = Utils::transform(files, [](const FilePair &fp) { - return std::make_pair(fp.first.path(), fp.second.path()); - }); FileStringPairs nonWildcardFiles; - for (const FileStringPair &file : filesAsStrings) { + for (const FilePair &file : files) { if (!allWildcardsInGroup.contains(file.first)) - nonWildcardFiles << file; + nonWildcardFiles << std::make_pair(file.first.path(), file.second.path()); } - const QString groupFilePath = group.value("location") - .toObject().value("file-path").toString(); - ensureWriteableQbsFile(groupFilePath); + ensureWriteableQbsFile(groupFilePath(group)); const FileChangeResult result = session()->renameFiles( nonWildcardFiles, product.value("name").toString(), group.value("name").toString()); - *notRenamed = FileUtils::toFilePathList(result.failedFiles()); + *notRenamed = Utils::transform(result.failedFiles(), [this](const QString &f) { + return projectFilePath().withNewPath(f); + }); if (result.error().hasError()) MessageManager::writeDisrupting(result.error().toString()); return notRenamed->isEmpty(); @@ -528,6 +523,16 @@ void QbsBuildSystem::updateProjectNodes(const std::function &continuati projectData())); } +FilePath QbsBuildSystem::locationFilePath(const QJsonObject &loc) const +{ + return projectDirectory().withNewPath(loc.value("file-path").toString()); +} + +FilePath QbsBuildSystem::groupFilePath(const QJsonObject &group) const +{ + return locationFilePath(group.value("location").toObject()); +} + FilePath QbsBuildSystem::installRoot() { const auto dc = target()->activeDeployConfiguration(); diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 0edb7e67c41..0fa1e43c0ee 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -129,8 +129,10 @@ private: void updateAfterParse(); void updateProjectNodes(const std::function &continuation); Utils::FilePath installRoot(); + Utils::FilePath locationFilePath(const QJsonObject &loc) const; + Utils::FilePath groupFilePath(const QJsonObject &group) const; - static bool ensureWriteableQbsFile(const QString &file); + static bool ensureWriteableQbsFile(const Utils::FilePath &file); QbsSession * const m_session; QSet m_qbsDocuments; From 10df9d9b6b0c81b117a2ed3bc1c2282036db0382 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 19 Dec 2024 17:05:10 +0100 Subject: [PATCH 467/989] Android: Remove unused signal Change-Id: I1205bdffe7c3bf8fa2bb4a24f2e1c5747e4b231b Reviewed-by: hjk --- src/plugins/android/androidrunner.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 2739fbf87ae..f135837cbe4 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -26,7 +26,6 @@ public: signals: void canceled(); - void avdDetected(); private: void remoteStarted(const Utils::Port &debugServerPort, qint64 pid); From 56901780383af8fe5fcbc32c5e4cff74eabf0f05 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 19 Dec 2024 10:27:24 +0100 Subject: [PATCH 468/989] Editor: use member initialization in TextBlockUserData Change-Id: If51077870a8a60791cfe975bddd7314c954f2266 Reviewed-by: Eike Ziller --- src/plugins/texteditor/textdocumentlayout.h | 24 +++++++-------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index 3c5640c26a5..61176278111 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -48,15 +48,7 @@ class TEXTEDITOR_EXPORT TextBlockUserData : public QTextBlockUserData { public: - inline TextBlockUserData() - : m_foldingIndent(0) - , m_lexerState(0) - , m_folded(false) - , m_ifdefedOut(false) - , m_foldingStartIncluded(false) - , m_foldingEndIncluded(false) - , m_codeFormatterData(nullptr) - {} + TextBlockUserData() = default; ~TextBlockUserData() override; inline TextMarks marks() const { return m_marks; } @@ -141,15 +133,15 @@ public: private: TextMarks m_marks; - int m_foldingIndent : 16; - int m_lexerState : 8; - uint m_folded : 1; - uint m_ifdefedOut : 1; - uint m_foldingStartIncluded : 1; - uint m_foldingEndIncluded : 1; + int m_foldingIndent : 16 = 0; + int m_lexerState : 8 = 0; + uint m_folded : 1 = false; + uint m_ifdefedOut : 1 = false; + uint m_foldingStartIncluded : 1 = false; + uint m_foldingEndIncluded : 1 = false; int m_additionalAnnotationHeight = 0; Parentheses m_parentheses; - CodeFormatterData *m_codeFormatterData; + CodeFormatterData *m_codeFormatterData = nullptr; KSyntaxHighlighting::State m_syntaxState; QByteArray m_expectedRawStringSuffix; // A bit C++-specific, but let's be pragmatic. std::unique_ptr m_replacement; From 3311bc5f09a4fbd9d24d0564b85a4a609c5cad78 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 18 Dec 2024 13:16:55 +0100 Subject: [PATCH 469/989] ProjectExplorer: compress rebuild contents of TargetGroupItem An updated toolchain can affect multiple kits and for each kit the content of the TargetGroupItem got rebuilt which in turn completely rebuilds the project panel. Taking up to 5 seconds in the main thread on some machines after loading a session. Do the Rebuild only once per eventloop roundtrip reduces this to 300ms. Change-Id: I2c2006b280c8d046ac79e8f016e2080eb0796796 Reviewed-by: Christian Kandeler --- .../projectexplorer/targetsettingspanel.cpp | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp index 1daf0b95b12..bbb0ec91a99 100644 --- a/src/plugins/projectexplorer/targetsettingspanel.cpp +++ b/src/plugins/projectexplorer/targetsettingspanel.cpp @@ -157,15 +157,14 @@ public: TargetGroupItemPrivate(TargetGroupItem *q, Project *project); ~TargetGroupItemPrivate() override; - void handleRemovedKit(Kit *kit); void handleAddedKit(Kit *kit); - void handleUpdatedKit(Kit *kit); void handleTargetAdded(Target *target); void handleTargetRemoved(Target *target); void handleTargetChanged(Target *target); void ensureWidget(); + void scheduleRebuildContents(); void rebuildContents(); void ensureShowMoreItem(); @@ -184,6 +183,7 @@ public: TargetGroupItem *q; QString m_displayName; Project *m_project; + bool m_rebuildScheduled = false; QPointer m_noKitLabel; QPointer m_configurePage; @@ -689,13 +689,13 @@ TargetGroupItemPrivate::TargetGroupItemPrivate(TargetGroupItem *q, Project *proj connect(KitManager::instance(), &KitManager::kitAdded, this, &TargetGroupItemPrivate::handleAddedKit); connect(KitManager::instance(), &KitManager::kitRemoved, - this, &TargetGroupItemPrivate::handleRemovedKit); + this, &TargetGroupItemPrivate::scheduleRebuildContents); connect(KitManager::instance(), &KitManager::kitUpdated, - this, &TargetGroupItemPrivate::handleUpdatedKit); - connect(KitManager::instance(), &KitManager::kitsChanged, - this, &TargetGroupItemPrivate::rebuildContents); + this, &TargetGroupItemPrivate::scheduleRebuildContents); + connect(KitManager::instance(), &KitManager::kitsLoaded, + this, &TargetGroupItemPrivate::scheduleRebuildContents); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, - this, &TargetGroupItemPrivate::rebuildContents); + this, &TargetGroupItemPrivate::scheduleRebuildContents); rebuildContents(); } @@ -762,18 +762,6 @@ ITargetItem *TargetGroupItem::targetItem(Target *target) const return nullptr; } -void TargetGroupItemPrivate::handleRemovedKit(Kit *kit) -{ - Q_UNUSED(kit) - rebuildContents(); -} - -void TargetGroupItemPrivate::handleUpdatedKit(Kit *kit) -{ - Q_UNUSED(kit) - rebuildContents(); -} - void TargetGroupItemPrivate::handleAddedKit(Kit *kit) { q->appendChild(new TargetItem(m_project, kit->id(), m_project->projectIssues(kit))); @@ -799,8 +787,17 @@ void TargetGroupItemPrivate::ensureShowMoreItem() q->appendChild(new ShowMoreItem(this)); } +void TargetGroupItemPrivate::scheduleRebuildContents() +{ + if (m_rebuildScheduled) + return; + m_rebuildScheduled = true; + QMetaObject::invokeMethod(this, &TargetGroupItemPrivate::rebuildContents, Qt::QueuedConnection); +} + void TargetGroupItemPrivate::rebuildContents() { + m_rebuildScheduled = false; QGuiApplication::setOverrideCursor(Qt::WaitCursor); const auto sortedKits = KitManager::sortedKits(); bool isAnyKitNotEnabled = std::any_of(sortedKits.begin(), sortedKits.end(), [this](Kit *kit) { From 0a0183938bec19c29bbf4ad38bf03a7f5fe02255 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 10:52:50 +0100 Subject: [PATCH 470/989] Utils: Introduce TypedSelectionAspect template Can be used to produce properly typed value() etc and remove the need to static_cast<> or similar on the user side. Change-Id: Idb1d5d5daaf81e3964b2cc80dbe1b2af11368088 Reviewed-by: David Schulz --- src/libs/utils/aspects.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 1e3fba25052..21e3f474867 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -581,6 +581,18 @@ protected: std::unique_ptr d; }; +template +class TypedSelectionAspect : public SelectionAspect +{ +public: + using SelectionAspect::SelectionAspect; + + ValueType operator()() const { return static_cast(SelectionAspect::operator()()); } + ValueType value() const { return static_cast(SelectionAspect::value()); } + ValueType defaultValue() const { return static_cast(SelectionAspect::defaultValue()); } + ValueType volatileValue() const { return static_cast(SelectionAspect::volatileValue()); } +}; + class QTCREATOR_UTILS_EXPORT MultiSelectionAspect : public TypedAspect { Q_OBJECT From ed694123dcb16002e8a3183a3ec5f398d5788f41 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 17:04:03 +0100 Subject: [PATCH 471/989] Debugger: Merge analyzermanager.h into analyzerutils.h ... and put everything into namespace Debugger. The analyzer/debugger separation is long gone. Change-Id: Ife819b0bc4add4a6f7a81b0a8a20dcbf7282125f Reviewed-by: Jarek Kobus --- src/plugins/clangtools/clangtool.cpp | 4 +- .../cmakeprojectmanager.cpp | 2 +- src/plugins/debugger/CMakeLists.txt | 1 - .../debugger/analyzer/analyzermanager.h | 48 ------------------- .../debugger/analyzer/analyzerutils.cpp | 16 +++++-- src/plugins/debugger/analyzer/analyzerutils.h | 42 ++++++++++++++-- src/plugins/debugger/debugger.qbs | 1 - src/plugins/debugger/debuggerplugin.cpp | 2 +- src/plugins/perfprofiler/perfprofilertool.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +- .../qmlprofiler/qmlprofilertraceview.cpp | 2 +- .../qmlprofiler/qmlprofilerviewmanager.cpp | 3 +- .../tests/localqmlprofilerrunner_test.cpp | 2 +- src/plugins/squish/squishperspective.cpp | 2 +- src/plugins/valgrind/callgrindengine.cpp | 2 +- src/plugins/valgrind/callgrindtool.cpp | 5 +- src/plugins/valgrind/memchecktool.cpp | 3 +- 17 files changed, 67 insertions(+), 72 deletions(-) delete mode 100644 src/plugins/debugger/analyzer/analyzermanager.h diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index e4d993b7d9c..99a053f8096 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -24,7 +24,9 @@ #include -#include +#include +#include +#include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index d4b5602c4d6..3dc42a9a316 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/debugger/CMakeLists.txt b/src/plugins/debugger/CMakeLists.txt index 82267c18f7f..3bcc96bf536 100644 --- a/src/plugins/debugger/CMakeLists.txt +++ b/src/plugins/debugger/CMakeLists.txt @@ -9,7 +9,6 @@ add_qtc_plugin(Debugger analyzer/analyzerbase.qrc analyzer/analyzerconstants.h analyzer/analyzericons.h - analyzer/analyzermanager.h analyzer/analyzerrunconfigwidget.cpp analyzer/analyzerrunconfigwidget.h analyzer/analyzerutils.cpp analyzer/analyzerutils.h analyzer/detailederrorview.cpp analyzer/detailederrorview.h diff --git a/src/plugins/debugger/analyzer/analyzermanager.h b/src/plugins/debugger/analyzer/analyzermanager.h deleted file mode 100644 index ca8b1e54c89..00000000000 --- a/src/plugins/debugger/analyzer/analyzermanager.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "analyzerconstants.h" - -#include "../debuggermainwindow.h" - -#include - -#include -#include - -#include - -namespace Debugger { - -/** - * The mode in which this tool should preferably be run - * - * Debugging tools which try to show stack traces as close as possible to what the source code - * looks like will prefer SymbolsMode. Profiling tools which need optimized code for realistic - * performance, but still want to show analytical output that depends on debug symbols, will prefer - * ProfileMode. - */ -enum ToolMode { - DebugMode = 0x1, - ProfileMode = 0x2, - ReleaseMode = 0x4, - SymbolsMode = DebugMode | ProfileMode, - OptimizedMode = ProfileMode | ReleaseMode, - //AnyMode = DebugMode | ProfileMode | ReleaseMode -}; - -// FIXME: Merge with something sensible. -DEBUGGER_EXPORT bool wantRunTool(ToolMode toolMode, const QString &toolName); -DEBUGGER_EXPORT void showCannotStartDialog(const QString &toolName); - -DEBUGGER_EXPORT void enableMainWindow(bool on); - -// Convenience functions. -DEBUGGER_EXPORT void showPermanentStatusMessage(const QString &message); - -DEBUGGER_EXPORT QAction *createStartAction(); -DEBUGGER_EXPORT QAction *createStopAction(); - -} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/analyzerutils.cpp b/src/plugins/debugger/analyzer/analyzerutils.cpp index a2ea231755b..c07e55ab2ca 100644 --- a/src/plugins/debugger/analyzer/analyzerutils.cpp +++ b/src/plugins/debugger/analyzer/analyzerutils.cpp @@ -3,20 +3,23 @@ #include "analyzerutils.h" +#include +#include + #include + #include #include #include -#include -#include - #include using namespace Core; using namespace ProjectExplorer; +namespace Debugger { + static void moveCursorToEndOfName(QTextCursor *tc) { QTextDocument *doc = tc->document(); @@ -31,8 +34,9 @@ static void moveCursorToEndOfName(QTextCursor *tc) } // TODO: Can this be improved? This code is ripped from CppEditor, especially CppElementEvaluater -// We cannot depend on this since CppEditor plugin code is internal and requires building the implementation files ourselves -CPlusPlus::Symbol *AnalyzerUtils::findSymbolUnderCursor() +// We cannot depend on this since CppEditor plugin code is internal +// and requires building the implementation files ourselves +CPlusPlus::Symbol *findSymbolUnderCursor() { TextEditor::TextEditorWidget *widget = TextEditor::TextEditorWidget::currentTextEditorWidget(); if (!widget) @@ -63,3 +67,5 @@ CPlusPlus::Symbol *AnalyzerUtils::findSymbolUnderCursor() const CPlusPlus::LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate. return lookupItem.declaration(); } + +} // Debugger diff --git a/src/plugins/debugger/analyzer/analyzerutils.h b/src/plugins/debugger/analyzer/analyzerutils.h index dc39ae53d25..727efbfeece 100644 --- a/src/plugins/debugger/analyzer/analyzerutils.h +++ b/src/plugins/debugger/analyzer/analyzerutils.h @@ -5,9 +5,43 @@ #include +QT_BEGIN_NAMESPACE +class QAction; +QT_END_NAMESPACE + namespace CPlusPlus { class Symbol; } -namespace AnalyzerUtils -{ - DEBUGGER_EXPORT CPlusPlus::Symbol *findSymbolUnderCursor(); -} +namespace Debugger { + +/** + * The mode in which this tool should preferably be run + * + * Debugging tools which try to show stack traces as close as possible to what the source code + * looks like will prefer SymbolsMode. Profiling tools which need optimized code for realistic + * performance, but still want to show analytical output that depends on debug symbols, will prefer + * ProfileMode. + */ +enum ToolMode { + DebugMode = 0x1, + ProfileMode = 0x2, + ReleaseMode = 0x4, + SymbolsMode = DebugMode | ProfileMode, + OptimizedMode = ProfileMode | ReleaseMode, + //AnyMode = DebugMode | ProfileMode | ReleaseMode +}; + +DEBUGGER_EXPORT bool wantRunTool(ToolMode toolMode, const QString &toolName); +DEBUGGER_EXPORT void showCannotStartDialog(const QString &toolName); + +DEBUGGER_EXPORT void enableMainWindow(bool on); + +// Convenience functions. +DEBUGGER_EXPORT void showPermanentStatusMessage(const QString &message); + +DEBUGGER_EXPORT QAction *createStartAction(); +DEBUGGER_EXPORT QAction *createStopAction(); + + +DEBUGGER_EXPORT CPlusPlus::Symbol *findSymbolUnderCursor(); + +} // Debugger diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index cf409d355bd..b42bb313741 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -232,7 +232,6 @@ QtcPlugin { "analyzerbase.qrc", "analyzerconstants.h", "analyzericons.h", - "analyzermanager.h", "analyzerrunconfigwidget.cpp", "analyzerrunconfigwidget.h", "analyzerutils.cpp", diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index ea608f30904..f77ac759669 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -27,7 +27,7 @@ #include "console/console.h" #include "analyzer/analyzerconstants.h" -#include "analyzer/analyzermanager.h" +#include "analyzer/analyzerutils.h" #include #include diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index 524aaf64faf..4241d535925 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index e729c58c3c8..945df939bb8 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp index ac24343a9c7..0f1adf54dd6 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp @@ -30,7 +30,7 @@ #include // Needed for the load&save actions in the context menu -#include +#include #include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp b/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp index c4dc0449184..78d57cc02d4 100644 --- a/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp @@ -6,7 +6,8 @@ #include "qmlprofilertr.h" #include "qmlprofilerviewmanager.h" -#include +#include +#include #include diff --git a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp index 94ea38a8fe7..78e47ae747b 100644 --- a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp +++ b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp @@ -3,7 +3,7 @@ #include "localqmlprofilerrunner_test.h" -#include +#include #include diff --git a/src/plugins/squish/squishperspective.cpp b/src/plugins/squish/squishperspective.cpp index 4eb63cbb7eb..36f6d5f7fe5 100644 --- a/src/plugins/squish/squishperspective.cpp +++ b/src/plugins/squish/squishperspective.cpp @@ -7,7 +7,7 @@ #include "squishtr.h" #include "squishxmloutputhandler.h" -#include +#include #include #include diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index 4d6c911df60..66aeaf07efe 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -6,7 +6,7 @@ #include "callgrind/callgrindparser.h" #include "valgrindtr.h" -#include +#include #include #include diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index ea6c594710c..f6fbacac2de 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -32,7 +32,8 @@ #include #include -#include +#include +#include #include #include @@ -829,7 +830,7 @@ void CallgrindTool::requestContextMenu(TextEditorWidget *widget, int line, QMenu void CallgrindTool::handleShowCostsOfFunction() { - CPlusPlus::Symbol *symbol = AnalyzerUtils::findSymbolUnderCursor(); + CPlusPlus::Symbol *symbol = Debugger::findSymbolUnderCursor(); if (!symbol) return; diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 0bf925d9853..5989b54093a 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -25,9 +25,10 @@ #include #include +#include #include #include -#include +#include #include #include From 1704b89b401f1746c4996af9a41e560611fb3a02 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 17:28:57 +0100 Subject: [PATCH 472/989] Debugger: Merge analyzerconstants.h into debuggerconstants.h Change-Id: Id092c8d0bedad987e963b36b0e9b46e7182209a2 Reviewed-by: Jarek Kobus --- src/plugins/axivion/axivionperspective.cpp | 2 +- src/plugins/clangtools/clangtool.cpp | 1 - .../cmakeprojectmanager.cpp | 2 +- src/plugins/coco/cocoplugin.cpp | 16 +++++++------- src/plugins/cppcheck/cppcheckplugin.cpp | 2 +- .../ctfvisualizer/ctfvisualizertool.cpp | 2 +- src/plugins/debugger/CMakeLists.txt | 1 - .../debugger/analyzer/analyzerconstants.h | 22 ------------------- src/plugins/debugger/debugger.qbs | 1 - src/plugins/debugger/debuggerconstants.h | 12 +++++++++- src/plugins/debugger/debuggerplugin.cpp | 1 - src/plugins/perfprofiler/perfprofilertool.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +- src/plugins/valgrind/callgrindtool.cpp | 1 - src/plugins/valgrind/memchecktool.cpp | 2 +- 15 files changed, 26 insertions(+), 43 deletions(-) delete mode 100644 src/plugins/debugger/analyzer/analyzerconstants.h diff --git a/src/plugins/axivion/axivionperspective.cpp b/src/plugins/axivion/axivionperspective.cpp index 20b51518816..4d1fd6dd407 100644 --- a/src/plugins/axivion/axivionperspective.cpp +++ b/src/plugins/axivion/axivionperspective.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 99a053f8096..2a25de2930a 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -24,7 +24,6 @@ #include -#include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index 3dc42a9a316..0fd8c6edc24 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -26,8 +26,8 @@ #include #include -#include #include +#include #include #include diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index e499efba2db..558919a5389 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -11,13 +11,15 @@ #include #include #include + +#include + +#include + #include #include #include -#include - -#include #include #include #include @@ -29,12 +31,10 @@ #include using namespace Core; +using namespace ProjectExplorer; using namespace Utils; -namespace Coco { - -using namespace ProjectExplorer; -using namespace Internal; +namespace Coco::Internal { class CocoPlugin final : public ExtensionSystem::IPlugin { @@ -124,6 +124,6 @@ void CocoPlugin::initialize() initLanguageServer(); } -} // namespace Coco +} // namespace Coco::Internal #include "cocoplugin.moc" diff --git a/src/plugins/cppcheck/cppcheckplugin.cpp b/src/plugins/cppcheck/cppcheckplugin.cpp index 248223eecd8..87a7380b796 100644 --- a/src/plugins/cppcheck/cppcheckplugin.cpp +++ b/src/plugins/cppcheck/cppcheckplugin.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/ctfvisualizer/ctfvisualizertool.cpp b/src/plugins/ctfvisualizer/ctfvisualizertool.cpp index 51290be1ec3..b1422dca93f 100644 --- a/src/plugins/ctfvisualizer/ctfvisualizertool.cpp +++ b/src/plugins/ctfvisualizer/ctfvisualizertool.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/debugger/CMakeLists.txt b/src/plugins/debugger/CMakeLists.txt index 3bcc96bf536..4dc258ac67f 100644 --- a/src/plugins/debugger/CMakeLists.txt +++ b/src/plugins/debugger/CMakeLists.txt @@ -7,7 +7,6 @@ add_qtc_plugin(Debugger CLANG_BINDIR="${LLVM_TOOLS_BINARY_DIR}" SOURCES analyzer/analyzerbase.qrc - analyzer/analyzerconstants.h analyzer/analyzericons.h analyzer/analyzerrunconfigwidget.cpp analyzer/analyzerrunconfigwidget.h analyzer/analyzerutils.cpp analyzer/analyzerutils.h diff --git a/src/plugins/debugger/analyzer/analyzerconstants.h b/src/plugins/debugger/analyzer/analyzerconstants.h deleted file mode 100644 index 8e5f4662249..00000000000 --- a/src/plugins/debugger/analyzer/analyzerconstants.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Debugger { -namespace Constants { - -// Menu. -const char M_DEBUG_ANALYZER[] = "Analyzer.Menu.StartAnalyzer"; - -const char G_ANALYZER_CONTROL[] = "Menu.Group.Analyzer.Control"; -const char G_ANALYZER_TOOLS[] = "Menu.Group.Analyzer.Tools"; -const char G_ANALYZER_REMOTE_TOOLS[] = "Menu.Group.Analyzer.RemoteTools"; -const char G_ANALYZER_OPTIONS[] = "Menu.Group.Analyzer.Options"; - -const char ANALYZERTASK_ID[] = "Analyzer.TaskId"; - -} // namespace Constants -} // namespace Debugger diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index b42bb313741..9f9401801c2 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -230,7 +230,6 @@ QtcPlugin { prefix: "analyzer/" files: [ "analyzerbase.qrc", - "analyzerconstants.h", "analyzericons.h", "analyzerrunconfigwidget.cpp", "analyzerrunconfigwidget.h", diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index 186e2120378..48dfeb5b67f 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -14,7 +14,17 @@ const char MODE_DEBUG[] = "Mode.Debug"; // Debug mode context const char C_DEBUGMODE[] = "Debugger.DebugMode"; -const char DEBUGGER_RUN_FACTORY[] = "RunWorkerFactory.DebuggerRunWorkerFactory"; +const char DEBUGGER_RUN_FACTORY[] = "RunWorkerFactory.DebuggerRunWorkerFactory"; + +// Analyze menu +const char M_DEBUG_ANALYZER[] = "Analyzer.Menu.StartAnalyzer"; + +const char G_ANALYZER_CONTROL[] = "Menu.Group.Analyzer.Control"; +const char G_ANALYZER_TOOLS[] = "Menu.Group.Analyzer.Tools"; +const char G_ANALYZER_REMOTE_TOOLS[] = "Menu.Group.Analyzer.RemoteTools"; +const char G_ANALYZER_OPTIONS[] = "Menu.Group.Analyzer.Options"; + +const char ANALYZERTASK_ID[] = "Analyzer.TaskId"; } // namespace Constants diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index f77ac759669..d1c081cf5ec 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -26,7 +26,6 @@ #include "shared/hostutils.h" #include "console/console.h" -#include "analyzer/analyzerconstants.h" #include "analyzer/analyzerutils.h" #include diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index 4241d535925..c5656855527 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -16,8 +16,8 @@ #include #include -#include #include +#include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 945df939bb8..32fcbbad893 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -28,8 +28,8 @@ #include #include -#include #include +#include #include #include diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index f6fbacac2de..7327f7e8372 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -33,7 +33,6 @@ #include #include -#include #include #include diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 5989b54093a..d858d0a07a5 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -24,10 +24,10 @@ #include #include +#include #include #include #include -#include #include #include From cc13fc6c80f8e46161ba2c8b74f52c37238b073c Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 14:32:06 +0100 Subject: [PATCH 473/989] Debugger: Clean up some dialogs Remove two unused ones and use dialogParent() more consistently. Change-Id: I7c517d04fcd8fc8fb1e03fd81b7fbf176d0889b9 Reviewed-by: Jarek Kobus --- src/plugins/debugger/debuggerdialogs.cpp | 219 +---------------------- src/plugins/debugger/debuggerdialogs.h | 45 +---- src/plugins/debugger/debuggerplugin.cpp | 4 +- 3 files changed, 14 insertions(+), 254 deletions(-) diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index c6842c6b2c3..0b1727cb461 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -13,14 +13,12 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -33,9 +31,7 @@ #include #include #include -#include #include -#include #include using namespace Core; @@ -501,8 +497,8 @@ public: KitChooser *kitChooser; }; -AttachToQmlPortDialog::AttachToQmlPortDialog(QWidget *parent) - : QDialog(parent), +AttachToQmlPortDialog::AttachToQmlPortDialog() + : QDialog(ICore::dialogParent()), d(new AttachToQmlPortDialogPrivate) { setWindowTitle(Tr::tr("Start Debugger")); @@ -587,8 +583,8 @@ static QString cdbRemoteHelp() QString(cdbConnectionSyntax)); } -StartRemoteCdbDialog::StartRemoteCdbDialog(QWidget *parent) : - QDialog(parent), m_lineEdit(new QLineEdit) +StartRemoteCdbDialog::StartRemoteCdbDialog() + : QDialog(ICore::dialogParent()), m_lineEdit(new QLineEdit) { setWindowTitle(Tr::tr("Start a CDB Remote Session")); @@ -653,10 +649,10 @@ void StartRemoteCdbDialog::setConnection(const QString &c) m_okButton->setEnabled(!c.isEmpty()); } -AddressDialog::AddressDialog(QWidget *parent) : - QDialog(parent), - m_lineEdit(new QLineEdit), - m_box(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel)) +AddressDialog::AddressDialog() + : QDialog(ICore::dialogParent()), + m_lineEdit(new QLineEdit), + m_box(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel)) { setWindowTitle(Tr::tr("Select Start Address")); @@ -716,205 +712,6 @@ bool AddressDialog::isValid() const return ok; } -/////////////////////////////////////////////////////////////////////// -// -// StartRemoteEngineDialog -// -/////////////////////////////////////////////////////////////////////// - -class StartRemoteEngineDialogPrivate -{ -public: - FancyLineEdit *host; - FancyLineEdit *username; - QLineEdit *password; - FancyLineEdit *enginePath; - FancyLineEdit *inferiorPath; - QDialogButtonBox *buttonBox; -}; - -StartRemoteEngineDialog::StartRemoteEngineDialog(QWidget *parent) - : QDialog(parent), d(new StartRemoteEngineDialogPrivate) -{ - setWindowTitle(Tr::tr("Start Remote Engine")); - - d->host = new FancyLineEdit(this); - d->host->setHistoryCompleter("HostName"); - - d->username = new FancyLineEdit(this); - d->username->setHistoryCompleter("UserName"); - - d->password = new QLineEdit(this); - d->password->setEchoMode(QLineEdit::Password); - - d->enginePath = new FancyLineEdit(this); - d->enginePath->setHistoryCompleter("EnginePath"); - - d->inferiorPath = new FancyLineEdit(this); - d->inferiorPath->setHistoryCompleter("InferiorPath"); - - d->buttonBox = new QDialogButtonBox(this); - d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - - auto formLayout = new QFormLayout(); - formLayout->addRow(Tr::tr("&Host:"), d->host); - formLayout->addRow(Tr::tr("&Username:"), d->username); - formLayout->addRow(Tr::tr("&Password:"), d->password); - formLayout->addRow(Tr::tr("&Engine path:"), d->enginePath); - formLayout->addRow(Tr::tr("&Inferior path:"), d->inferiorPath); - - auto verticalLayout = new QVBoxLayout(this); - verticalLayout->addLayout(formLayout); - verticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); - verticalLayout->addWidget(d->buttonBox); - - connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -} - -StartRemoteEngineDialog::~StartRemoteEngineDialog() -{ - delete d; -} - -QString StartRemoteEngineDialog::host() const -{ - return d->host->text(); -} - -QString StartRemoteEngineDialog::username() const -{ - return d->username->text(); -} - -QString StartRemoteEngineDialog::password() const -{ - return d->password->text(); -} - -QString StartRemoteEngineDialog::inferiorPath() const -{ - return d->inferiorPath->text(); -} - -QString StartRemoteEngineDialog::enginePath() const -{ - return d->enginePath->text(); -} - -/////////////////////////////////////////////////////////////////////// -// -// TypeFormatsDialogUi -// -/////////////////////////////////////////////////////////////////////// - -class TypeFormatsDialogPage : public QWidget -{ -public: - TypeFormatsDialogPage() - { - m_layout = new QGridLayout; - m_layout->setColumnStretch(0, 2); - auto vboxLayout = new QVBoxLayout; - vboxLayout->addLayout(m_layout); - vboxLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Ignored, - QSizePolicy::MinimumExpanding)); - setLayout(vboxLayout); - } - - void addTypeFormats(const QString &type, - const DisplayFormats &typeFormats, int current) - { - const int row = m_layout->rowCount(); - int column = 0; - auto group = new QButtonGroup(this); - m_layout->addWidget(new QLabel(type), row, column++); - for (int i = -1; i != typeFormats.size(); ++i) { - auto choice = new QRadioButton(this); - choice->setText(i == -1 ? Tr::tr("Reset") - : WatchHandler::nameForFormat(typeFormats.at(i))); - m_layout->addWidget(choice, row, column++); - if (i == current) - choice->setChecked(true); - group->addButton(choice, i); - } - } -private: - QGridLayout *m_layout; -}; - -class TypeFormatsDialogUi -{ -public: - TypeFormatsDialogUi(TypeFormatsDialog *q) - { - tabs = new QTabWidget(q); - - buttonBox = new QDialogButtonBox(q); - buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - - auto layout = new QVBoxLayout(q); - layout->addWidget(tabs); - layout->addWidget(buttonBox); - q->setLayout(layout); - } - - void addPage(const QString &name) - { - auto page = new TypeFormatsDialogPage; - pages.append(page); - auto scroller = new QScrollArea; - scroller->setWidgetResizable(true); - scroller->setWidget(page); - scroller->setFrameStyle(QFrame::NoFrame); - tabs->addTab(scroller, name); - } - -public: - QList pages; - QDialogButtonBox *buttonBox; - -private: - QTabWidget *tabs; -}; - - -/////////////////////////////////////////////////////////////////////// -// -// TypeFormatsDialog -// -/////////////////////////////////////////////////////////////////////// - -TypeFormatsDialog::TypeFormatsDialog(QWidget *parent) - : QDialog(parent), m_ui(new TypeFormatsDialogUi(this)) -{ - setWindowTitle(Tr::tr("Type Formats")); - m_ui->addPage(Tr::tr("Qt Types")); - m_ui->addPage(Tr::tr("Standard Types")); - m_ui->addPage(Tr::tr("Misc Types")); - - connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -} - -TypeFormatsDialog::~TypeFormatsDialog() -{ - delete m_ui; -} - -void TypeFormatsDialog::addTypeFormats(const QString &type0, - const DisplayFormats &typeFormats, int current) -{ - QString type = type0; - type.replace("__", "::"); - int pos = 2; - if (type.startsWith('Q')) - pos = 0; - else if (type.startsWith("std::")) - pos = 1; - m_ui->pages[pos]->addTypeFormats(type, typeFormats, current); -} - } // Debugger::Internal Q_DECLARE_METATYPE(Debugger::Internal::StartApplicationParameters) diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h index 7d01d3c836b..04c7668e036 100644 --- a/src/plugins/debugger/debuggerdialogs.h +++ b/src/plugins/debugger/debuggerdialogs.h @@ -3,8 +3,6 @@ #pragma once -#include "watchhandler.h" - #include #include @@ -18,18 +16,13 @@ QT_END_NAMESPACE namespace Debugger::Internal { -class AttachToQmlPortDialogPrivate; -class DebuggerRunParameters; -class StartApplicationParameters; -class StartRemoteEngineDialogPrivate; - void runAttachToRemoteServerDialog(); void runStartAndDebugApplicationDialog(); class AttachToQmlPortDialog : public QDialog { public: - explicit AttachToQmlPortDialog(QWidget *parent); + AttachToQmlPortDialog(); ~AttachToQmlPortDialog() override; int port() const; @@ -39,13 +32,13 @@ public: void setKitId(Utils::Id id); private: - AttachToQmlPortDialogPrivate *d; + class AttachToQmlPortDialogPrivate *d; }; class StartRemoteCdbDialog : public QDialog { public: - explicit StartRemoteCdbDialog(QWidget *parent); + StartRemoteCdbDialog(); ~StartRemoteCdbDialog() override; QString connection() const; @@ -62,7 +55,7 @@ private: class AddressDialog : public QDialog { public: - explicit AddressDialog(QWidget *parent = nullptr); + AddressDialog(); void setAddress(quint64 a); quint64 address() const; @@ -80,34 +73,4 @@ private: QDialogButtonBox *m_box; }; -class StartRemoteEngineDialog : public QDialog -{ -public: - explicit StartRemoteEngineDialog(QWidget *parent); - ~StartRemoteEngineDialog() override; - QString username() const; - QString host() const; - QString password() const; - QString enginePath() const; - QString inferiorPath() const; - -private: - StartRemoteEngineDialogPrivate *d; -}; - -class TypeFormatsDialogUi; - -class TypeFormatsDialog : public QDialog -{ -public: - explicit TypeFormatsDialog(QWidget *parent); - ~TypeFormatsDialog() override; - - void addTypeFormats(const QString &type, const DisplayFormats &formats, - int currentFormat); - -private: - TypeFormatsDialogUi *m_ui; -}; - } // Debugger::Internal diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index d1c081cf5ec..d5fca135da7 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1690,7 +1690,7 @@ void DebuggerPluginPrivate::startRemoteCdbSession() Kit *kit = findUniversalCdbKit(); QTC_ASSERT(kit, return); - StartRemoteCdbDialog dlg(ICore::dialogParent()); + StartRemoteCdbDialog dlg; QString previousConnection = configValue(connectionKey).toString(); if (previousConnection.isEmpty()) previousConnection = "localhost:1234"; @@ -1819,7 +1819,7 @@ RunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, void DebuggerPluginPrivate::attachToQmlPort() { - AttachToQmlPortDialog dlg(ICore::dialogParent()); + AttachToQmlPortDialog dlg; const QVariant qmlServerPort = configValue("LastQmlServerPort"); if (qmlServerPort.isValid()) From ed276213651655734fc751cd72dd4353fe159987 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 14:50:19 +0100 Subject: [PATCH 474/989] Debugger: Move most of RemoteCdbSessionDialog handling ... to debuggerdialogs.cpp. Change-Id: I47e4eee43a79192c30a5a2c7360b1ec651131eb5 Reviewed-by: David Schulz --- src/plugins/debugger/debuggerdialogs.cpp | 47 ++++++++++++++++++++++-- src/plugins/debugger/debuggerdialogs.h | 20 ++-------- src/plugins/debugger/debuggerplugin.cpp | 27 +------------- 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 0b1727cb461..75f8cdb04c3 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -552,7 +552,8 @@ void AttachToQmlPortDialog::setKitId(Id id) d->kitChooser->setCurrentKitId(id); } -// --------- StartRemoteCdbDialog +// StartRemoteCdbDialog + static QString cdbRemoteHelp() { const char cdbConnectionSyntax[] = @@ -583,6 +584,22 @@ static QString cdbRemoteHelp() QString(cdbConnectionSyntax)); } +class StartRemoteCdbDialog final : public QDialog +{ +public: + StartRemoteCdbDialog(); + + QString connection() const; + void setConnection(const QString &); + +private: + void textChanged(const QString &); + void accept() override; + + QPushButton *m_okButton = nullptr; + QLineEdit *m_lineEdit; +}; + StartRemoteCdbDialog::StartRemoteCdbDialog() : QDialog(ICore::dialogParent()), m_lineEdit(new QLineEdit) { @@ -624,8 +641,6 @@ void StartRemoteCdbDialog::accept() QDialog::accept(); } -StartRemoteCdbDialog::~StartRemoteCdbDialog() = default; - void StartRemoteCdbDialog::textChanged(const QString &t) { m_okButton->setEnabled(!t.isEmpty()); @@ -649,6 +664,32 @@ void StartRemoteCdbDialog::setConnection(const QString &c) m_okButton->setEnabled(!c.isEmpty()); } +void runStartRemoteCdbSessionDialog(Kit *kit) +{ + QTC_ASSERT(kit, return); + const Key connectionKey = "DebugMode/CdbRemoteConnection"; + + StartRemoteCdbDialog dlg; + QString previousConnection = ICore::settings()->value(connectionKey).toString(); + if (previousConnection.isEmpty()) + previousConnection = "localhost:1234"; + dlg.setConnection(previousConnection); + if (dlg.exec() != QDialog::Accepted) + return; + + ICore::settings()->setValue(connectionKey, dlg.connection()); + + auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); + runControl->setKit(kit); + auto debugger = new DebuggerRunTool(runControl); + debugger->setStartMode(AttachToRemoteServer); + debugger->setCloseMode(KillAtClose); + debugger->setRemoteChannel(dlg.connection()); + debugger->startRunControl(); +} + +// AddressDialog + AddressDialog::AddressDialog() : QDialog(ICore::dialogParent()), m_lineEdit(new QLineEdit), diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h index 04c7668e036..e1b862db634 100644 --- a/src/plugins/debugger/debuggerdialogs.h +++ b/src/plugins/debugger/debuggerdialogs.h @@ -14,10 +14,13 @@ class QLineEdit; class QDialogButtonBox; QT_END_NAMESPACE +namespace ProjectExplorer { class Kit; } + namespace Debugger::Internal { void runAttachToRemoteServerDialog(); void runStartAndDebugApplicationDialog(); +void runStartRemoteCdbSessionDialog(ProjectExplorer::Kit *kit); class AttachToQmlPortDialog : public QDialog { @@ -35,23 +38,6 @@ private: class AttachToQmlPortDialogPrivate *d; }; -class StartRemoteCdbDialog : public QDialog -{ -public: - StartRemoteCdbDialog(); - ~StartRemoteCdbDialog() override; - - QString connection() const; - void setConnection(const QString &); - -private: - void textChanged(const QString &); - void accept() override; - - QPushButton *m_okButton = nullptr; - QLineEdit *m_lineEdit; -}; - class AddressDialog : public QDialog { public: diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index d5fca135da7..079359e9abc 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -631,7 +631,6 @@ public: void enableOrDisableBreakpoint(); void updateDebugWithoutDeployMenu(); - void startRemoteCdbSession(); void attachToRunningApplication(); void attachToUnstartedApplicationDialog(); void attachToQmlPort(); @@ -895,7 +894,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) this, &DebuggerPluginPrivate::attachToQmlPort); connect(&m_startRemoteCdbAction, &QAction::triggered, - this, &DebuggerPluginPrivate::startRemoteCdbSession); + this, [] { runStartRemoteCdbSessionDialog(findUniversalCdbKit()); }); // "Start Debugging" sub-menu // groups: @@ -1684,30 +1683,6 @@ void DebuggerPluginPrivate::reloadDebuggingHelpers() Tr::tr("Reload debugging helpers skipped as no engine is running."), 5000); } -void DebuggerPluginPrivate::startRemoteCdbSession() -{ - const Key connectionKey = "CdbRemoteConnection"; - Kit *kit = findUniversalCdbKit(); - QTC_ASSERT(kit, return); - - StartRemoteCdbDialog dlg; - QString previousConnection = configValue(connectionKey).toString(); - if (previousConnection.isEmpty()) - previousConnection = "localhost:1234"; - dlg.setConnection(previousConnection); - if (dlg.exec() != QDialog::Accepted) - return; - setConfigValue(connectionKey, dlg.connection()); - - auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); - runControl->setKit(kit); - auto debugger = new DebuggerRunTool(runControl); - debugger->setStartMode(AttachToRemoteServer); - debugger->setCloseMode(KillAtClose); - debugger->setRemoteChannel(dlg.connection()); - debugger->startRunControl(); -} - void DebuggerPluginPrivate::attachToRunningApplication() { auto kitChooser = new KitChooser; From 1d01c58b5d1aa7861ea97efabdc40b5e926c9431 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 15:13:47 +0100 Subject: [PATCH 475/989] Debugger: Move most of AttachToQmlPortDialog handling ... to debuggerdialogs. Also, de-pimpl and make final. Change-Id: I600a3a4ba7d9177a389513c5f6a0668ed9452a48 Reviewed-by: Jarek Kobus --- src/plugins/debugger/debuggerdialogs.cpp | 91 +++++++++++++++--------- src/plugins/debugger/debuggerdialogs.h | 18 +---- src/plugins/debugger/debuggerplugin.cpp | 42 +---------- 3 files changed, 61 insertions(+), 90 deletions(-) diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 75f8cdb04c3..945256be2c7 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -490,34 +490,42 @@ void StartApplicationDialog::setParameters(const StartApplicationParameters &p) // /////////////////////////////////////////////////////////////////////// -class AttachToQmlPortDialogPrivate +class AttachToQmlPortDialog final : public QDialog { public: - QSpinBox *portSpinBox; - KitChooser *kitChooser; + AttachToQmlPortDialog(); + + int port() const { return m_portSpinBox->value(); } + void setPort(const int port) { m_portSpinBox->setValue(port); } + + Kit *kit() const { return m_kitChooser->currentKit(); } + void setKitId(Utils::Id id) { m_kitChooser->setCurrentKitId(id); } + +private: + QSpinBox *m_portSpinBox; + KitChooser *m_kitChooser; }; AttachToQmlPortDialog::AttachToQmlPortDialog() - : QDialog(ICore::dialogParent()), - d(new AttachToQmlPortDialogPrivate) + : QDialog(ICore::dialogParent()) { - setWindowTitle(Tr::tr("Start Debugger")); + setWindowTitle(Tr::tr("Attach to QML Port")); - d->kitChooser = new KitChooser(this); - d->kitChooser->setShowIcons(true); - d->kitChooser->populate(); + m_kitChooser = new KitChooser(this); + m_kitChooser->setShowIcons(true); + m_kitChooser->populate(); - d->portSpinBox = new QSpinBox(this); - d->portSpinBox->setMaximum(65535); - d->portSpinBox->setValue(3768); + m_portSpinBox = new QSpinBox(this); + m_portSpinBox->setMaximum(65535); + m_portSpinBox->setValue(3768); auto buttonBox = new QDialogButtonBox(this); buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); auto formLayout = new QFormLayout(); - formLayout->addRow(Tr::tr("Kit:"), d->kitChooser); - formLayout->addRow(Tr::tr("&Port:"), d->portSpinBox); + formLayout->addRow(Tr::tr("Kit:"), m_kitChooser); + formLayout->addRow(Tr::tr("&Port:"), m_portSpinBox); auto verticalLayout = new QVBoxLayout(this); verticalLayout->addLayout(formLayout); @@ -527,29 +535,48 @@ AttachToQmlPortDialog::AttachToQmlPortDialog() connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } -AttachToQmlPortDialog::~AttachToQmlPortDialog() +void runAttachToQmlPortDialog() { - delete d; -} + AttachToQmlPortDialog dlg; + QtcSettings *settings = ICore::settings(); -void AttachToQmlPortDialog::setPort(const int port) -{ - d->portSpinBox->setValue(port); -} + const Key lastQmlServerPortKey = "DebugMode/LastQmlServerPort"; + const QVariant qmlServerPort = settings->value(lastQmlServerPortKey); -int AttachToQmlPortDialog::port() const -{ - return d->portSpinBox->value(); -} + if (qmlServerPort.isValid()) + dlg.setPort(qmlServerPort.toInt()); + else + dlg.setPort(-1); -Kit *AttachToQmlPortDialog::kit() const -{ - return d->kitChooser->currentKit(); -} + const Key lastProfileKey = "DebugMode/LastProfile"; + const Id kitId = Id::fromSetting(settings->value(lastProfileKey)); + if (kitId.isValid()) + dlg.setKitId(kitId); -void AttachToQmlPortDialog::setKitId(Id id) -{ - d->kitChooser->setCurrentKitId(id); + if (dlg.exec() != QDialog::Accepted) + return; + + Kit *kit = dlg.kit(); + QTC_ASSERT(kit, return); + settings->setValue(lastQmlServerPortKey, dlg.port()); + settings->setValue(lastProfileKey, kit->id().toSetting()); + + IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); + QTC_ASSERT(device, return); + + auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); + runControl->setKit(kit); + auto debugger = new DebuggerRunTool(runControl); + + QUrl qmlServer = device->toolControlChannel(IDevice::QmlControlChannel); + qmlServer.setPort(dlg.port()); + debugger->setQmlServer(qmlServer); + + SshParameters sshParameters = device->sshParameters(); + debugger->setRemoteChannel(sshParameters.host(), sshParameters.port()); + debugger->setStartMode(AttachToQmlServer); + + debugger->startRunControl(); } // StartRemoteCdbDialog diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h index e1b862db634..c156c4098b5 100644 --- a/src/plugins/debugger/debuggerdialogs.h +++ b/src/plugins/debugger/debuggerdialogs.h @@ -9,7 +9,6 @@ #include QT_BEGIN_NAMESPACE -class QPushButton; class QLineEdit; class QDialogButtonBox; QT_END_NAMESPACE @@ -21,22 +20,7 @@ namespace Debugger::Internal { void runAttachToRemoteServerDialog(); void runStartAndDebugApplicationDialog(); void runStartRemoteCdbSessionDialog(ProjectExplorer::Kit *kit); - -class AttachToQmlPortDialog : public QDialog -{ -public: - AttachToQmlPortDialog(); - ~AttachToQmlPortDialog() override; - - int port() const; - void setPort(const int port); - - ProjectExplorer::Kit *kit() const; - void setKitId(Utils::Id id); - -private: - class AttachToQmlPortDialogPrivate *d; -}; +void runAttachToQmlPortDialog(); class AddressDialog : public QDialog { diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 079359e9abc..f26f6be4639 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -891,7 +891,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) this, &DebuggerPluginPrivate::attachToUnstartedApplicationDialog); connect(&m_attachToQmlPortAction, &QAction::triggered, - this, &DebuggerPluginPrivate::attachToQmlPort); + this, [] { runAttachToQmlPortDialog(); }); connect(&m_startRemoteCdbAction, &QAction::triggered, this, [] { runStartRemoteCdbSessionDialog(findUniversalCdbKit()); }); @@ -1792,46 +1792,6 @@ RunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, return debugger->runControl(); } -void DebuggerPluginPrivate::attachToQmlPort() -{ - AttachToQmlPortDialog dlg; - - const QVariant qmlServerPort = configValue("LastQmlServerPort"); - if (qmlServerPort.isValid()) - dlg.setPort(qmlServerPort.toInt()); - else - dlg.setPort(-1); - - const Id kitId = Id::fromSetting(configValue("LastProfile")); - if (kitId.isValid()) - dlg.setKitId(kitId); - - if (dlg.exec() != QDialog::Accepted) - return; - - Kit *kit = dlg.kit(); - QTC_ASSERT(kit, return); - setConfigValue("LastQmlServerPort", dlg.port()); - setConfigValue("LastProfile", kit->id().toSetting()); - - IDevice::ConstPtr device = RunDeviceKitAspect::device(kit); - QTC_ASSERT(device, return); - - auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); - runControl->setKit(kit); - auto debugger = new DebuggerRunTool(runControl); - - QUrl qmlServer = device->toolControlChannel(IDevice::QmlControlChannel); - qmlServer.setPort(dlg.port()); - debugger->setQmlServer(qmlServer); - - SshParameters sshParameters = device->sshParameters(); - debugger->setRemoteChannel(sshParameters.host(), sshParameters.port()); - debugger->setStartMode(AttachToQmlServer); - - debugger->startRunControl(); -} - void DebuggerPluginPrivate::runScheduled() { for (DebuggerRunTool *debugger : std::as_const(m_scheduledStarts)) From b5d1d7641a356f60b2b4a7dd4893c3293d3e98c6 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 17:47:37 +0100 Subject: [PATCH 476/989] Debugger/ProjectExplorer: Promote run configuration aspect widgets These are the widgets at the bottom of the run config settings that share the ability to switch between a global and per-target setting. There is nothing inherently debugger specific here, except for the common history. Change-Id: I4c57c138bb05c2a505f1bac13161352417bd8fe4 Reviewed-by: Christian Kandeler --- src/plugins/debugger/CMakeLists.txt | 1 - .../analyzer/analyzerrunconfigwidget.cpp | 65 ------------------- .../analyzer/analyzerrunconfigwidget.h | 18 ----- src/plugins/debugger/debugger.qbs | 2 - .../perfrunconfigurationaspect.cpp | 8 ++- .../projectexplorer/runconfiguration.cpp | 59 ++++++++++++++++- .../projectexplorer/runconfiguration.h | 2 + .../qmlprofilerrunconfigurationaspect.cpp | 8 ++- src/plugins/valgrind/valgrindplugin.cpp | 4 +- 9 files changed, 72 insertions(+), 95 deletions(-) delete mode 100644 src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp delete mode 100644 src/plugins/debugger/analyzer/analyzerrunconfigwidget.h diff --git a/src/plugins/debugger/CMakeLists.txt b/src/plugins/debugger/CMakeLists.txt index 4dc258ac67f..7ce22ed3821 100644 --- a/src/plugins/debugger/CMakeLists.txt +++ b/src/plugins/debugger/CMakeLists.txt @@ -8,7 +8,6 @@ add_qtc_plugin(Debugger SOURCES analyzer/analyzerbase.qrc analyzer/analyzericons.h - analyzer/analyzerrunconfigwidget.cpp analyzer/analyzerrunconfigwidget.h analyzer/analyzerutils.cpp analyzer/analyzerutils.h analyzer/detailederrorview.cpp analyzer/detailederrorview.h analyzer/diagnosticlocation.cpp analyzer/diagnosticlocation.h diff --git a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp deleted file mode 100644 index 61f81f46ce3..00000000000 --- a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "analyzerrunconfigwidget.h" - -#include "../debuggertr.h" - -#include -#include - -#include -#include -#include - -using namespace Utils; - -namespace Debugger { - -AnalyzerRunConfigWidget::AnalyzerRunConfigWidget(ProjectExplorer::GlobalOrProjectAspect *aspect) -{ - using namespace Layouting; - - auto settingsCombo = new QComboBox; - settingsCombo->addItem(Tr::tr("Global")); - settingsCombo->addItem(Tr::tr("Custom")); - - auto restoreButton = new QPushButton(Tr::tr("Restore Global")); - - auto innerPane = new QWidget; - auto configWidget = aspect->projectSettings()->layouter()().emerge(); - - auto details = new DetailsWidget; - details->setWidget(innerPane); - - Column { - Row { settingsCombo, restoreButton, st }, - configWidget - }.attachTo(innerPane); - - Column { details }.attachTo(this); - - details->layout()->setContentsMargins(0, 0, 0, 0); - innerPane->layout()->setContentsMargins(0, 0, 0, 0); - layout()->setContentsMargins(0, 0, 0, 0); - - auto chooseSettings = [=](int setting) { - const bool isCustom = (setting == 1); - - settingsCombo->setCurrentIndex(setting); - aspect->setUsingGlobalSettings(!isCustom); - configWidget->setEnabled(isCustom); - restoreButton->setEnabled(isCustom); - details->setSummaryText(isCustom - ? Tr::tr("Use Customized Settings") - : Tr::tr("Use Global Settings")); - }; - - chooseSettings(aspect->isUsingGlobalSettings() ? 0 : 1); - - connect(settingsCombo, &QComboBox::activated, this, chooseSettings); - connect(restoreButton, &QPushButton::clicked, - aspect, &ProjectExplorer::GlobalOrProjectAspect::resetProjectToGlobalSettings); -} - -} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h deleted file mode 100644 index e6167f49880..00000000000 --- a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -#include - -namespace Debugger { - -class DEBUGGER_EXPORT AnalyzerRunConfigWidget : public QWidget -{ -public: - AnalyzerRunConfigWidget(ProjectExplorer::GlobalOrProjectAspect *aspect); -}; - -} // namespace Debugger diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index 9f9401801c2..34192c5dcc0 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -231,8 +231,6 @@ QtcPlugin { files: [ "analyzerbase.qrc", "analyzericons.h", - "analyzerrunconfigwidget.cpp", - "analyzerrunconfigwidget.h", "analyzerutils.cpp", "analyzerutils.h", "detailederrorview.cpp", diff --git a/src/plugins/perfprofiler/perfrunconfigurationaspect.cpp b/src/plugins/perfprofiler/perfrunconfigurationaspect.cpp index d1062ed732e..0b9781c867a 100644 --- a/src/plugins/perfprofiler/perfrunconfigurationaspect.cpp +++ b/src/plugins/perfprofiler/perfrunconfigurationaspect.cpp @@ -6,11 +6,13 @@ #include "perfrunconfigurationaspect.h" #include "perfsettings.h" -#include +#include + +using namespace ProjectExplorer; namespace PerfProfiler::Internal { -PerfRunConfigurationAspect::PerfRunConfigurationAspect(ProjectExplorer::Target *target) +PerfRunConfigurationAspect::PerfRunConfigurationAspect(Target *target) { setProjectSettings(new PerfSettings(target)); setGlobalSettings(&PerfProfiler::globalSettings()); @@ -18,7 +20,7 @@ PerfRunConfigurationAspect::PerfRunConfigurationAspect(ProjectExplorer::Target * setDisplayName(Tr::tr("Performance Analyzer Settings")); setUsingGlobalSettings(true); resetProjectToGlobalSettings(); - setConfigWidgetCreator([this] { return new Debugger::AnalyzerRunConfigWidget(this); }); + setConfigWidgetCreator([this] { return createRunConfigAspectWidget(this); }); } } // PerfProfiler::Internal diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 22c6282c698..2aed8850d20 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -32,9 +32,10 @@ #include #include +#include #include +#include #include -#include #include using namespace Utils; @@ -119,6 +120,62 @@ void GlobalOrProjectAspect::resetProjectToGlobalSettings() } +class RunConfigAspectWidget : public QWidget +{ +public: + explicit RunConfigAspectWidget(GlobalOrProjectAspect *aspect) + { + using namespace Layouting; + + auto settingsCombo = new QComboBox; + settingsCombo->addItem(Tr::tr("Global")); + settingsCombo->addItem(Tr::tr("Custom")); + + auto restoreButton = new QPushButton(Tr::tr("Restore Global")); + + auto innerPane = new QWidget; + auto configWidget = aspect->projectSettings()->layouter()().emerge(); + + auto details = new DetailsWidget; + details->setWidget(innerPane); + + Column { + Row { settingsCombo, restoreButton, st }, + configWidget + }.attachTo(innerPane); + + Column { details }.attachTo(this); + + details->layout()->setContentsMargins(0, 0, 0, 0); + innerPane->layout()->setContentsMargins(0, 0, 0, 0); + layout()->setContentsMargins(0, 0, 0, 0); + + auto chooseSettings = [=](int setting) { + const bool isCustom = (setting == 1); + + settingsCombo->setCurrentIndex(setting); + aspect->setUsingGlobalSettings(!isCustom); + configWidget->setEnabled(isCustom); + restoreButton->setEnabled(isCustom); + details->setSummaryText(isCustom + ? Tr::tr("Use Customized Settings") + : Tr::tr("Use Global Settings")); + }; + + chooseSettings(aspect->isUsingGlobalSettings() ? 0 : 1); + + connect(settingsCombo, &QComboBox::activated, this, chooseSettings); + connect(restoreButton, &QPushButton::clicked, + aspect, &ProjectExplorer::GlobalOrProjectAspect::resetProjectToGlobalSettings); + } +}; + +QWidget *createRunConfigAspectWidget(GlobalOrProjectAspect *aspect) +{ + return new RunConfigAspectWidget(aspect); +} + + /*! \class ProjectExplorer::RunConfiguration \inmodule QtCreator diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index ca78c0ee056..31489706c17 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -115,6 +115,8 @@ private: Utils::AspectContainer *m_globalSettings = nullptr; // Not owned. }; +PROJECTEXPLORER_EXPORT QWidget *createRunConfigAspectWidget(GlobalOrProjectAspect *); + // Documentation inside. class PROJECTEXPLORER_EXPORT RunConfiguration : public ProjectConfiguration { diff --git a/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp b/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp index e513e3fe6fd..89fa5817ae4 100644 --- a/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp @@ -7,11 +7,13 @@ #include "qmlprofilersettings.h" #include "qmlprofilertr.h" -#include +#include + +using namespace ProjectExplorer; namespace QmlProfiler::Internal { -QmlProfilerRunConfigurationAspect::QmlProfilerRunConfigurationAspect(ProjectExplorer::Target *) +QmlProfilerRunConfigurationAspect::QmlProfilerRunConfigurationAspect(Target *) { setProjectSettings(new QmlProfilerSettings); setGlobalSettings(&Internal::globalSettings()); @@ -19,7 +21,7 @@ QmlProfilerRunConfigurationAspect::QmlProfilerRunConfigurationAspect(ProjectExpl setDisplayName(Tr::tr("QML Profiler Settings")); setUsingGlobalSettings(true); resetProjectToGlobalSettings(); - setConfigWidgetCreator([this] { return new Debugger::AnalyzerRunConfigWidget(this); }); + setConfigWidgetCreator([this] { return createRunConfigAspectWidget(this); }); } } // QmlProfiler::Internal diff --git a/src/plugins/valgrind/valgrindplugin.cpp b/src/plugins/valgrind/valgrindplugin.cpp index 59b495f6adb..99e8209f82c 100644 --- a/src/plugins/valgrind/valgrindplugin.cpp +++ b/src/plugins/valgrind/valgrindplugin.cpp @@ -9,12 +9,12 @@ #include #include -#include #include #include #include +#include #ifdef WITH_TESTS # include "valgrindmemcheckparsertest.h" @@ -37,7 +37,7 @@ public: setDisplayName(Tr::tr("Valgrind Settings")); setUsingGlobalSettings(true); resetProjectToGlobalSettings(); - setConfigWidgetCreator([this] { return new Debugger::AnalyzerRunConfigWidget(this); }); + setConfigWidgetCreator([this] { return createRunConfigAspectWidget(this); }); } }; From e12a9242dfd3a0bad22d89edfcdb17a9284eb6af Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 20 Dec 2024 10:42:01 +0100 Subject: [PATCH 477/989] ProjectExplorer: Move output pane raising to RunControl Easier to discover there. Change-Id: Iba549379254aeb253a0b029eb1b5c02cc647c742 Reviewed-by: Christian Kandeler --- src/plugins/clangtools/clangtool.cpp | 2 +- src/plugins/projectexplorer/projectexplorer.cpp | 5 ----- src/plugins/projectexplorer/projectexplorer.h | 1 - src/plugins/projectexplorer/runcontrol.cpp | 5 +++++ src/plugins/projectexplorer/runcontrol.h | 2 ++ 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 2a25de2930a..b719ab6fd00 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -1013,7 +1013,7 @@ DiagnosticItem *ClangTool::diagnosticItem(const QModelIndex &index) const void ClangTool::showOutputPane() { - ProjectExplorerPlugin::showOutputPaneForRunControl(m_runControl); + m_runControl->showOutputPane(); } void ClangTool::reset() diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 3914c805952..e9bd1b51205 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2501,11 +2501,6 @@ void ProjectExplorerPlugin::startRunControl(RunControl *runControl) dd->startRunControl(runControl); } -void ProjectExplorerPlugin::showOutputPaneForRunControl(RunControl *runControl) -{ - appOutputPane().showOutputPaneForRunControl(runControl); -} - static HandleIncludeGuards canTryToRenameIncludeGuards(const Node *node) { return node->asFileNode() && node->asFileNode()->fileType() == FileType::Header diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index aebb14f8d25..e35dd4442b4 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -117,7 +117,6 @@ public: static const QList customParsers(); static void startRunControl(RunControl *runControl); - static void showOutputPaneForRunControl(RunControl *runControl); static Utils::FilePairs renameFiles( const QList> &nodesAndNewFilePaths); diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 9a0893737c8..faffb2e0811 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -701,6 +701,11 @@ QUrl RunControl::workerChannel() const return d->workerChannel; } +void RunControl::showOutputPane() +{ + appOutputPane().showOutputPaneForRunControl(this); +} + void RunControlPrivate::continueStart() { checkState(RunControlState::Starting); diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 3c3cd34ae8d..da5a3716634 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -257,6 +257,8 @@ public: void requestWorkerChannel(); QUrl workerChannel() const; + void showOutputPane(); + signals: void appendMessage(const QString &msg, Utils::OutputFormat format); void aboutToStart(); From f4060887172ba7ea03433b078dc5841525123962 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 19 Dec 2024 18:22:25 +0100 Subject: [PATCH 478/989] ProjectExplorer: More FilePath usage in ProjectWizardPage Otherwise, remote Linux paths are displayed with backslashes on Windows. Change-Id: I2c918364200a3420836328ee3d81a4bbd32bbc90 Reviewed-by: Alessandro Portale --- .../projectexplorer/projectwizardpage.cpp | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp index 4c3093e9530..40154bbf385 100644 --- a/src/plugins/projectexplorer/projectwizardpage.cpp +++ b/src/plugins/projectexplorer/projectwizardpage.cpp @@ -546,37 +546,35 @@ IVersionControl *ProjectWizardPage::currentVersionControl() void ProjectWizardPage::setFiles(const FilePaths &files) { m_commonDirectory = FileUtils::commonPath(files); - const bool hasNoCommonDirectory = m_commonDirectory.isEmpty() || files.size() < 2; + const bool hasCommonDirectory = !m_commonDirectory.isEmpty() && files.size() > 1; QString fileMessage; { QTextStream str(&fileMessage); str << "" - << (hasNoCommonDirectory ? Tr::tr("Files to be added:") : Tr::tr("Files to be added in")) + << (hasCommonDirectory ? Tr::tr("Files to be added in") : Tr::tr("Files to be added:")) << "

    ";
     
    -        QStringList formattedFiles;
    -        if (hasNoCommonDirectory) {
    -            formattedFiles = Utils::transform(files, &FilePath::toString);
    -        } else {
    +        FilePaths formattedFiles = files;
    +        if (hasCommonDirectory) {
                 str << m_commonDirectory.toUserOutput() << ":\n\n";
    -            int prefixSize = m_commonDirectory.toUserOutput().size();
    -            formattedFiles = Utils::transform(files, [prefixSize] (const FilePath &f) {
    -                return f.toString().mid(prefixSize + 1); // +1 skips the initial dir separator
    +            const QDir commonDir(m_commonDirectory.path());
    +            formattedFiles = transform(files, [&](const FilePath &f) {
    +                return FilePath::fromString(commonDir.relativeFilePath(f.path()));
                 });
             }
             // Alphabetically, and files in sub-directories first
    -        Utils::sort(formattedFiles, [](const QString &filePath1, const QString &filePath2) -> bool {
    -            const bool filePath1HasDir = filePath1.contains(QLatin1Char('/'));
    -            const bool filePath2HasDir = filePath2.contains(QLatin1Char('/'));
    +        Utils::sort(formattedFiles, [](const FilePath &filePath1, const FilePath &filePath2) -> bool {
    +            const bool filePath1HasDir = filePath1.path().contains('/');
    +            const bool filePath2HasDir = filePath2.path().contains('/');
     
                 if (filePath1HasDir == filePath2HasDir)
    -                return FilePath::fromString(filePath1) < FilePath::fromString(filePath2);
    +                return filePath1 < filePath2;
                 return filePath1HasDir;
             });
     
    -        for (const QString &f : std::as_const(formattedFiles))
    -            str << QDir::toNativeSeparators(f) << '\n';
    +        for (const FilePath &f : std::as_const(formattedFiles))
    +            str << f.toUserOutput() << '\n';
     
             str << "
    "; } From 2e99d3a909a519a8149b50ce5d72cdc3fc69950e Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 16:08:42 +0100 Subject: [PATCH 479/989] Debugger: Move AddressDialog handling to debuggerdialogs.cpp Change-Id: Icb1658d9bcf997a1d5ceb85670070f1981c8083f Reviewed-by: Jarek Kobus --- src/plugins/debugger/debuggerdialogs.cpp | 65 +++++++++++++----------- src/plugins/debugger/debuggerdialogs.h | 31 ++--------- src/plugins/debugger/debuggerengine.cpp | 11 ++-- src/plugins/debugger/debuggerplugin.cpp | 1 + src/plugins/debugger/registerhandler.cpp | 7 +-- src/plugins/debugger/stackhandler.cpp | 7 +-- src/plugins/debugger/watchhandler.cpp | 7 +-- 7 files changed, 50 insertions(+), 79 deletions(-) diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 945256be2c7..f88d439fa6b 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -715,7 +716,27 @@ void runStartRemoteCdbSessionDialog(Kit *kit) debugger->startRunControl(); } +// // AddressDialog +// + +class AddressDialog final : public QDialog +{ +public: + AddressDialog(); + + void setAddress(quint64 a) { m_lineEdit->setText("0x" + QString::number(a, 16)); } + quint64 address() const { return m_lineEdit->text().toULongLong(nullptr, 16); } + + void setOkButtonEnabled(bool v) { m_box->button(QDialogButtonBox::Ok)->setEnabled(v); } + bool isOkButtonEnabled() const { return m_box->button(QDialogButtonBox::Ok)->isEnabled(); } + +private: + void accept() override; + + QLineEdit *m_lineEdit; + QDialogButtonBox *m_box; +}; AddressDialog::AddressDialog() : QDialog(ICore::dialogParent()), @@ -736,48 +757,32 @@ AddressDialog::AddressDialog() connect(m_box, &QDialogButtonBox::accepted, this, &AddressDialog::accept); connect(m_box, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(m_lineEdit, &QLineEdit::returnPressed, this, &AddressDialog::accept); - connect(m_lineEdit, &QLineEdit::textChanged, this, &AddressDialog::textChanged); + + connect(m_lineEdit, &QLineEdit::textChanged, this, [this] { + const QString text = m_lineEdit->text(); + bool ok = false; + text.toULongLong(&ok, 16); + setOkButtonEnabled(ok); + }); setOkButtonEnabled(false); } -void AddressDialog::setOkButtonEnabled(bool v) -{ - m_box->button(QDialogButtonBox::Ok)->setEnabled(v); -} - -bool AddressDialog::isOkButtonEnabled() const -{ - return m_box->button(QDialogButtonBox::Ok)->isEnabled(); -} - -void AddressDialog::setAddress(quint64 a) -{ - m_lineEdit->setText("0x" + QString::number(a, 16)); -} - -quint64 AddressDialog::address() const -{ - return m_lineEdit->text().toULongLong(nullptr, 16); -} - void AddressDialog::accept() { if (isOkButtonEnabled()) QDialog::accept(); } -void AddressDialog::textChanged() +std::optional runAddressDialog(quint64 initialAddress) { - setOkButtonEnabled(isValid()); -} + AddressDialog dialog; + dialog.setAddress(initialAddress); -bool AddressDialog::isValid() const -{ - const QString text = m_lineEdit->text(); - bool ok = false; - text.toULongLong(&ok, 16); - return ok; + if (dialog.exec() != QDialog::Accepted) + return {}; + + return dialog.address(); } } // Debugger::Internal diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h index c156c4098b5..b9a3f06fd8b 100644 --- a/src/plugins/debugger/debuggerdialogs.h +++ b/src/plugins/debugger/debuggerdialogs.h @@ -3,15 +3,9 @@ #pragma once -#include -#include +#include -#include - -QT_BEGIN_NAMESPACE -class QLineEdit; -class QDialogButtonBox; -QT_END_NAMESPACE +#include namespace ProjectExplorer { class Kit; } @@ -22,25 +16,6 @@ void runStartAndDebugApplicationDialog(); void runStartRemoteCdbSessionDialog(ProjectExplorer::Kit *kit); void runAttachToQmlPortDialog(); -class AddressDialog : public QDialog -{ -public: - AddressDialog(); - - void setAddress(quint64 a); - quint64 address() const; - -private: - void textChanged(); - void accept() override; - - void setOkButtonEnabled(bool v); - bool isOkButtonEnabled() const; - - bool isValid() const; - - QLineEdit *m_lineEdit; - QDialogButtonBox *m_box; -}; +std::optional runAddressDialog(quint64 initialAddress); } // Debugger::Internal diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index a00ca94af64..b096c82fd7d 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -2376,12 +2376,11 @@ void DebuggerEngine::raiseWatchersWindow() void DebuggerEngine::openMemoryEditor() { - AddressDialog dialog; - if (dialog.exec() != QDialog::Accepted) - return; - MemoryViewSetupData data; - data.startAddress = dialog.address(); - openMemoryView(data); + if (std::optional result = runAddressDialog(0)) { + MemoryViewSetupData data; + data.startAddress = *result; + openMemoryView(data); + } } void DebuggerEngine::updateLocalsView(const GdbMi &all) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index f26f6be4639..bebae40aeaf 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 79d82d8501c..dd347465799 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -784,11 +784,8 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) addAction(this, menu, Tr::tr("Open Disassembler..."), m_engine->hasCapability(DisassemblerCapability), [this, address] { - AddressDialog dialog; - if (address) - dialog.setAddress(address); - if (dialog.exec() == QDialog::Accepted) - m_engine->openDisassemblerView(Location(dialog.address())); + if (std::optional result = runAddressDialog(address)) + m_engine->openDisassemblerView(Location(*result)); }); menu->addSeparator(); diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index fa39d3c62fc..95ad7868f2d 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -464,11 +464,8 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) addAction(this, menu, Tr::tr("Open Disassembler at Address..."), true, [this, address] { - AddressDialog dialog; - if (address) - dialog.setAddress(address); - if (dialog.exec() == QDialog::Accepted) - m_engine->openDisassemblerView(Location(dialog.address())); + if (std::optional result = runAddressDialog(address)) + m_engine->openDisassemblerView(Location(*result)); }); addAction(this, menu, Tr::tr("Disassemble Function..."), true, diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index a0fd11af6a7..69cd063f60d 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -1926,12 +1926,9 @@ QMenu *WatchModel::createMemoryMenu(WatchItem *item, QWidget *parent) addAction(this, menu, Tr::tr("Open Memory Editor..."), true, [this, item] { - AddressDialog dialog; - if (item->address) - dialog.setAddress(item->address); - if (dialog.exec() == QDialog::Accepted) { + if (std::optional result = runAddressDialog(item->address)) { MemoryViewSetupData data; - data.startAddress = dialog.address(); + data.startAddress = *result; m_engine->openMemoryView(data); } }); From 0f0ceeabe7c8e3c78fb1e7ffd3870d64505480c1 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 19 Dec 2024 16:34:48 +0100 Subject: [PATCH 480/989] Debugger: Move all core dialog handling to loadcoredialog.cpp Change-Id: Ide3d3ce73e756799bc3c1105935a8c2040a41835 Reviewed-by: Jarek Kobus --- src/plugins/debugger/debuggerplugin.cpp | 49 +------------- src/plugins/debugger/loadcoredialog.cpp | 86 +++++++++++++++++++++++-- src/plugins/debugger/loadcoredialog.h | 40 +----------- 3 files changed, 83 insertions(+), 92 deletions(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index bebae40aeaf..c56f7faebd9 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -877,7 +877,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) this, [] { runStartAndDebugApplicationDialog(); }); connect(&m_attachToCoreAction, &QAction::triggered, - this, &DebuggerPluginPrivate::attachCore); + this, [] { runAttachToCoreDialog(); }); connect(&m_attachToLastCoreAction, &QAction::triggered, this, &DebuggerPluginPrivate::attachToLastCore); @@ -1479,16 +1479,6 @@ void DebuggerPluginPrivate::parseCommandLineArguments() QTimer::singleShot(0, this, &DebuggerPluginPrivate::runScheduled); } -static void setConfigValue(const Key &name, const QVariant &value) -{ - ICore::settings()->setValue("DebugMode/" + name, value); -} - -static QVariant configValue(const Key &name) -{ - return ICore::settings()->value("DebugMode/" + name); -} - void DebuggerPluginPrivate::updatePresetState() { if (PluginManager::isShuttingDown()) @@ -1614,43 +1604,6 @@ void DebuggerPluginPrivate::onStartupProjectChanged(Project *project) updatePresetState(); } -void DebuggerPluginPrivate::attachCore() -{ - AttachCoreDialog dlg(ICore::dialogParent()); - - const QString lastExternalKit = configValue("LastExternalKit").toString(); - if (!lastExternalKit.isEmpty()) - dlg.setKitId(Id::fromString(lastExternalKit)); - dlg.setSymbolFile(FilePath::fromSettings(configValue("LastExternalExecutableFile"))); - dlg.setCoreFile(FilePath::fromSettings(configValue("LastLocalCoreFile"))); - dlg.setOverrideStartScript(FilePath::fromSettings(configValue("LastExternalStartScript"))); - dlg.setSysRoot(FilePath::fromSettings(configValue("LastSysRoot"))); - - if (dlg.exec() != QDialog::Accepted) - return; - - setConfigValue("LastExternalExecutableFile", dlg.symbolFile().toSettings()); - setConfigValue("LastLocalCoreFile", dlg.coreFile().toSettings()); - setConfigValue("LastExternalKit", dlg.kit()->id().toSetting()); - setConfigValue("LastExternalStartScript", dlg.overrideStartScript().toSettings()); - setConfigValue("LastSysRoot", dlg.sysRoot().toSettings()); - - auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); - runControl->setKit(dlg.kit()); - runControl->setDisplayName(Tr::tr("Core file \"%1\"").arg(dlg.coreFile().toUserOutput())); - auto debugger = new DebuggerRunTool(runControl); - - debugger->setInferiorExecutable(dlg.symbolFileCopy()); - debugger->setCoreFilePath(dlg.coreFileCopy()); - debugger->setStartMode(AttachToCore); - debugger->setCloseMode(DetachAtClose); - debugger->setOverrideStartScript(dlg.overrideStartScript()); - const FilePath sysRoot = dlg.sysRoot(); - if (!sysRoot.isEmpty()) - debugger->setSysRoot(sysRoot); - debugger->startRunControl(); -} - void DebuggerPluginPrivate::attachToLastCore() { QGuiApplication::setOverrideCursor(Qt::WaitCursor); diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index cc1b5ce3ebc..3362b4d3fdd 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -4,9 +4,12 @@ #include "loadcoredialog.h" #include "debuggerkitaspect.h" +#include "debuggerruncontrol.h" #include "debuggertr.h" #include "gdb/gdbengine.h" +#include + #include #include #include @@ -22,14 +25,9 @@ #include #include #include -#include #include -#include #include #include -#include -#include -#include using namespace Core; using namespace ProjectExplorer; @@ -86,6 +84,39 @@ public: } }; +class AttachCoreDialog : public QDialog +{ +public: + explicit AttachCoreDialog(QWidget *parent); + ~AttachCoreDialog() override; + + int exec() override; + + FilePath symbolFile() const; + FilePath coreFile() const; + FilePath overrideStartScript() const; + FilePath sysRoot() const; + + // For persistance. + ProjectExplorer::Kit *kit() const; + void setSymbolFile(const FilePath &symbolFilePath); + void setCoreFile(const FilePath &coreFilePath); + void setOverrideStartScript(const FilePath &scriptName); + void setSysRoot(const FilePath &sysRoot); + void setKitId(Id id); + + FilePath coreFileCopy() const; + FilePath symbolFileCopy() const; + + void accepted(); + +private: + void changed(); + void coreFileChanged(const FilePath &core); + + class AttachCoreDialogPrivate *d; +}; + AttachCoreDialog::AttachCoreDialog(QWidget *parent) : QDialog(parent), d(new AttachCoreDialogPrivate) { @@ -353,4 +384,49 @@ void AttachCoreDialog::setSysRoot(const FilePath &sysRoot) d->sysRootDirectory->setFilePath(sysRoot); } +void runAttachToCoreDialog() +{ + AttachCoreDialog dlg(ICore::dialogParent()); + + QtcSettings *settings = ICore::settings(); + + const Key executableKey("DebugMode/LastExternalExecutableFile"); + const Key localCoreKey("DebugMode/LastLocalCoreFile"); + const Key kitKey("DebugMode/LastExternalKit"); + const Key startScriptKey("DebugMode/LastExternalStartScript"); + const Key sysrootKey("DebugMode/LastSysRoot"); + + const QString lastExternalKit = settings->value(kitKey).toString(); + if (!lastExternalKit.isEmpty()) + dlg.setKitId(Id::fromString(lastExternalKit)); + dlg.setSymbolFile(FilePath::fromSettings(settings->value(executableKey))); + dlg.setCoreFile(FilePath::fromSettings(settings->value(localCoreKey))); + dlg.setOverrideStartScript(FilePath::fromSettings(settings->value(startScriptKey))); + dlg.setSysRoot(FilePath::fromSettings(settings->value(sysrootKey))); + + if (dlg.exec() != QDialog::Accepted) + return; + + settings->setValue(executableKey, dlg.symbolFile().toSettings()); + settings->setValue(localCoreKey, dlg.coreFile().toSettings()); + settings->setValue(kitKey, dlg.kit()->id().toSetting()); + settings->setValue(startScriptKey, dlg.overrideStartScript().toSettings()); + settings->setValue(sysrootKey, dlg.sysRoot().toSettings()); + + auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); + runControl->setKit(dlg.kit()); + runControl->setDisplayName(Tr::tr("Core file \"%1\"").arg(dlg.coreFile().toUserOutput())); + auto debugger = new DebuggerRunTool(runControl); + + debugger->setInferiorExecutable(dlg.symbolFileCopy()); + debugger->setCoreFilePath(dlg.coreFileCopy()); + debugger->setStartMode(AttachToCore); + debugger->setCloseMode(DetachAtClose); + debugger->setOverrideStartScript(dlg.overrideStartScript()); + const FilePath sysRoot = dlg.sysRoot(); + if (!sysRoot.isEmpty()) + debugger->setSysRoot(sysRoot); + debugger->startRunControl(); +} + } // Debugger::Internal diff --git a/src/plugins/debugger/loadcoredialog.h b/src/plugins/debugger/loadcoredialog.h index ee1d065f92d..ab0aa5daef2 100644 --- a/src/plugins/debugger/loadcoredialog.h +++ b/src/plugins/debugger/loadcoredialog.h @@ -3,46 +3,8 @@ #pragma once -#include - -#include - -namespace ProjectExplorer { class Kit; } -namespace Utils { class FilePath; } - namespace Debugger::Internal { -class AttachCoreDialog : public QDialog -{ -public: - explicit AttachCoreDialog(QWidget *parent); - ~AttachCoreDialog() override; - - int exec() override; - - Utils::FilePath symbolFile() const; - Utils::FilePath coreFile() const; - Utils::FilePath overrideStartScript() const; - Utils::FilePath sysRoot() const; - - // For persistance. - ProjectExplorer::Kit *kit() const; - void setSymbolFile(const Utils::FilePath &symbolFilePath); - void setCoreFile(const Utils::FilePath &coreFilePath); - void setOverrideStartScript(const Utils::FilePath &scriptName); - void setSysRoot(const Utils::FilePath &sysRoot); - void setKitId(Utils::Id id); - - Utils::FilePath coreFileCopy() const; - Utils::FilePath symbolFileCopy() const; - - void accepted(); - -private: - void changed(); - void coreFileChanged(const Utils::FilePath &core); - - class AttachCoreDialogPrivate *d; -}; +void runAttachToCoreDialog(); } // Debugger::Internal From 5ec8021ffe12f76bb9e425aeeb7e159e338220c8 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 20 Dec 2024 16:34:03 +0100 Subject: [PATCH 481/989] Debugger: De-pimpl AttachCoreDialog Change-Id: Ic2835ead1c707a8264549c361415b410218051f5 Reviewed-by: Jarek Kobus --- src/plugins/debugger/loadcoredialog.cpp | 308 +++++++++--------------- 1 file changed, 120 insertions(+), 188 deletions(-) diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index 3362b4d3fdd..4b4d4090731 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -36,31 +36,51 @@ using namespace Utils; namespace Debugger::Internal { -/////////////////////////////////////////////////////////////////////// -// -// AttachCoreDialog -// -/////////////////////////////////////////////////////////////////////// - -class AttachCoreDialogPrivate +class AttachCoreDialog final : public QDialog { public: - KitChooser *kitChooser; + AttachCoreDialog(); - PathChooser *symbolFileName; - PathChooser *coreFileName; - PathChooser *overrideStartScriptFileName; - PathChooser *sysRootDirectory; + int exec() final; - FilePath debuggerPath; + FilePath symbolFile() const { return m_symbolFileName->filePath(); } + FilePath coreFile() const { return m_coreFileName->filePath(); } + FilePath overrideStartScript() const { return m_overrideStartScript->filePath(); } + FilePath sysRoot() const { return m_sysRootDirectory->filePath(); } - QDialogButtonBox *buttonBox; - ProgressIndicator *progressIndicator; - QLabel *progressLabel; + // For persistance. + ProjectExplorer::Kit *kit() const { return m_kitChooser->currentKit(); } - TaskTree taskTree; - expected_str coreFileResult; - expected_str symbolFileResult; + void setSymbolFile(const FilePath &filePath) { m_symbolFileName->setFilePath(filePath); } + void setCoreFile(const FilePath &filePath) { m_coreFileName->setFilePath(filePath); } + void setOverrideStartScript(const FilePath &filePath) { m_overrideStartScript->setFilePath(filePath); } + void setSysRoot(const FilePath &sysRoot) { m_sysRootDirectory->setFilePath(sysRoot); } + void setKitId(Id id) { m_kitChooser->setCurrentKitId(id); } + + FilePath coreFileCopy() const; + FilePath symbolFileCopy() const; + +private: + void accepted(); + void changed(); + void coreFileChanged(const FilePath &core); + + KitChooser *m_kitChooser; + + PathChooser *m_symbolFileName; + PathChooser *m_coreFileName; + PathChooser *m_overrideStartScript; + PathChooser *m_sysRootDirectory; + + FilePath m_debuggerPath; + + QDialogButtonBox *m_buttonBox; + ProgressIndicator *m_progressIndicator; + QLabel *m_progressLabel; + + TaskTree m_taskTree; + expected_str m_coreFileResult; + expected_str m_symbolFileResult; struct State { @@ -77,170 +97,132 @@ public: State getDialogState() const { State st; - st.validKit = (kitChooser->currentKit() != nullptr); - st.validSymbolFilename = symbolFileName->isValid(); - st.validCoreFilename = coreFileName->isValid(); + st.validKit = (m_kitChooser->currentKit() != nullptr); + st.validSymbolFilename = m_symbolFileName->isValid(); + st.validCoreFilename = m_coreFileName->isValid(); return st; } }; -class AttachCoreDialog : public QDialog -{ -public: - explicit AttachCoreDialog(QWidget *parent); - ~AttachCoreDialog() override; - - int exec() override; - - FilePath symbolFile() const; - FilePath coreFile() const; - FilePath overrideStartScript() const; - FilePath sysRoot() const; - - // For persistance. - ProjectExplorer::Kit *kit() const; - void setSymbolFile(const FilePath &symbolFilePath); - void setCoreFile(const FilePath &coreFilePath); - void setOverrideStartScript(const FilePath &scriptName); - void setSysRoot(const FilePath &sysRoot); - void setKitId(Id id); - - FilePath coreFileCopy() const; - FilePath symbolFileCopy() const; - - void accepted(); - -private: - void changed(); - void coreFileChanged(const FilePath &core); - - class AttachCoreDialogPrivate *d; -}; - -AttachCoreDialog::AttachCoreDialog(QWidget *parent) - : QDialog(parent), d(new AttachCoreDialogPrivate) +AttachCoreDialog::AttachCoreDialog() + : QDialog(ICore::dialogParent()) { setWindowTitle(Tr::tr("Load Core File")); - d->buttonBox = new QDialogButtonBox(this); - d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - d->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); - d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + m_buttonBox = new QDialogButtonBox(this); + m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); + m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - d->kitChooser = new KitChooser(this); - d->kitChooser->setShowIcons(true); - d->kitChooser->populate(); + m_kitChooser = new KitChooser(this); + m_kitChooser->setShowIcons(true); + m_kitChooser->populate(); - d->coreFileName = new PathChooser(this); - d->coreFileName->setHistoryCompleter("Debugger.CoreFile.History"); - d->coreFileName->setExpectedKind(PathChooser::File); - d->coreFileName->setPromptDialogTitle(Tr::tr("Select Core File")); - d->coreFileName->setAllowPathFromDevice(true); + m_coreFileName = new PathChooser(this); + m_coreFileName->setHistoryCompleter("Debugger.CoreFile.History"); + m_coreFileName->setExpectedKind(PathChooser::File); + m_coreFileName->setPromptDialogTitle(Tr::tr("Select Core File")); + m_coreFileName->setAllowPathFromDevice(true); - d->symbolFileName = new PathChooser(this); - d->symbolFileName->setHistoryCompleter("Executable"); - d->symbolFileName->setExpectedKind(PathChooser::File); - d->symbolFileName->setPromptDialogTitle(Tr::tr("Select Executable or Symbol File")); - d->symbolFileName->setAllowPathFromDevice(true); - d->symbolFileName->setToolTip( + m_symbolFileName = new PathChooser(this); + m_symbolFileName->setHistoryCompleter("Executable"); + m_symbolFileName->setExpectedKind(PathChooser::File); + m_symbolFileName->setPromptDialogTitle(Tr::tr("Select Executable or Symbol File")); + m_symbolFileName->setAllowPathFromDevice(true); + m_symbolFileName->setToolTip( Tr::tr("Select a file containing debug information corresponding to the core file. " "Typically, this is the executable or a *.debug file if the debug " "information is stored separately from the executable.")); - d->overrideStartScriptFileName = new PathChooser(this); - d->overrideStartScriptFileName->setHistoryCompleter("Debugger.StartupScript.History"); - d->overrideStartScriptFileName->setExpectedKind(PathChooser::File); - d->overrideStartScriptFileName->setPromptDialogTitle(Tr::tr("Select Startup Script")); + m_overrideStartScript = new PathChooser(this); + m_overrideStartScript->setHistoryCompleter("Debugger.StartupScript.History"); + m_overrideStartScript->setExpectedKind(PathChooser::File); + m_overrideStartScript->setPromptDialogTitle(Tr::tr("Select Startup Script")); - d->sysRootDirectory = new PathChooser(this); - d->sysRootDirectory->setHistoryCompleter("Debugger.SysRoot.History"); - d->sysRootDirectory->setExpectedKind(PathChooser::Directory); - d->sysRootDirectory->setPromptDialogTitle(Tr::tr("Select SysRoot Directory")); - d->sysRootDirectory->setToolTip(Tr::tr( - "This option can be used to override the kit's SysRoot setting")); + m_sysRootDirectory = new PathChooser(this); + m_sysRootDirectory->setHistoryCompleter("Debugger.SysRoot.History"); + m_sysRootDirectory->setExpectedKind(PathChooser::Directory); + m_sysRootDirectory->setPromptDialogTitle(Tr::tr("Select SysRoot Directory")); + m_sysRootDirectory->setToolTip(Tr::tr( + "This option can be used to override the kit's SysRoot setting")); - d->progressIndicator = new ProgressIndicator(ProgressIndicatorSize::Small, this); - d->progressIndicator->setVisible(false); + m_progressIndicator = new ProgressIndicator(ProgressIndicatorSize::Small, this); + m_progressIndicator->setVisible(false); - d->progressLabel = new QLabel(); - d->progressLabel->setVisible(false); + m_progressLabel = new QLabel(); + m_progressLabel->setVisible(false); // clang-format off using namespace Layouting; Column { Form { - Tr::tr("Kit:"), d->kitChooser, br, - Tr::tr("Core file:"), d->coreFileName, br, - Tr::tr("&Executable or symbol file:"), d->symbolFileName, br, - Tr::tr("Override &start script:"), d->overrideStartScriptFileName, br, - Tr::tr("Override S&ysRoot:"), d->sysRootDirectory, br, + Tr::tr("Kit:"), m_kitChooser, br, + Tr::tr("Core file:"), m_coreFileName, br, + Tr::tr("&Executable or symbol file:"), m_symbolFileName, br, + Tr::tr("Override &start script:"), m_overrideStartScript, br, + Tr::tr("Override S&ysRoot:"), m_sysRootDirectory, br, }, st, hr, Row { - d->progressIndicator, d->progressLabel, d->buttonBox + m_progressIndicator, m_progressLabel, m_buttonBox } }.attachTo(this); // clang-format on } -AttachCoreDialog::~AttachCoreDialog() -{ - delete d; -} - int AttachCoreDialog::exec() { - connect(d->symbolFileName, &PathChooser::validChanged, this, &AttachCoreDialog::changed); - connect(d->coreFileName, &PathChooser::validChanged, this, [this] { - coreFileChanged(d->coreFileName->unexpandedFilePath()); + connect(m_symbolFileName, &PathChooser::validChanged, this, &AttachCoreDialog::changed); + connect(m_coreFileName, &PathChooser::validChanged, this, [this] { + coreFileChanged(m_coreFileName->unexpandedFilePath()); }); - connect(d->coreFileName, &PathChooser::textChanged, this, [this] { - coreFileChanged(d->coreFileName->unexpandedFilePath()); + connect(m_coreFileName, &PathChooser::textChanged, this, [this] { + coreFileChanged(m_coreFileName->unexpandedFilePath()); }); - connect(d->kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed); - connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(d->buttonBox, &QDialogButtonBox::accepted, this, &AttachCoreDialog::accepted); + connect(m_kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &AttachCoreDialog::accepted); changed(); - connect(&d->taskTree, &TaskTree::done, this, [this] { + connect(&m_taskTree, &TaskTree::done, this, [this] { setEnabled(true); - d->progressIndicator->setVisible(false); - d->progressLabel->setVisible(false); + m_progressIndicator->setVisible(false); + m_progressLabel->setVisible(false); - if (!d->coreFileResult) { + if (!m_coreFileResult) { QMessageBox::critical(this, Tr::tr("Error"), Tr::tr("Failed to copy core file to device: %1") - .arg(d->coreFileResult.error())); + .arg(m_coreFileResult.error())); return; } - if (!d->symbolFileResult) { + if (!m_symbolFileResult) { QMessageBox::critical(this, Tr::tr("Error"), Tr::tr("Failed to copy symbol file to device: %1") - .arg(d->coreFileResult.error())); + .arg(m_coreFileResult.error())); return; } accept(); }); - connect(&d->taskTree, &TaskTree::progressValueChanged, this, [this](int value) { + connect(&m_taskTree, &TaskTree::progressValueChanged, this, [this](int value) { const QString text = Tr::tr("Copying files to device... %1/%2") .arg(value) - .arg(d->taskTree.progressMaximum()); - d->progressLabel->setText(text); + .arg(m_taskTree.progressMaximum()); + m_progressLabel->setText(text); }); - AttachCoreDialogPrivate::State st = d->getDialogState(); + State st = getDialogState(); if (!st.validKit) { - d->kitChooser->setFocus(); + m_kitChooser->setFocus(); } else if (!st.validCoreFilename) { - d->coreFileName->setFocus(); + m_coreFileName->setFocus(); } else if (!st.validSymbolFilename) { - d->symbolFileName->setFocus(); + m_symbolFileName->setFocus(); } return QDialog::exec(); @@ -284,109 +266,59 @@ void AttachCoreDialog::accepted() AsyncTask{[this, copyFileAsync](auto &task) { task.setConcurrentCallData(copyFileAsync, coreFile()); }, - [this](const Async &task) { d->coreFileResult = task.result(); }, + [this](const Async &task) { m_coreFileResult = task.result(); }, CallDoneIf::Success}, AsyncTask{[this, copyFileAsync](auto &task) { task.setConcurrentCallData(copyFileAsync, symbolFile()); }, - [this](const Async &task) { d->symbolFileResult = task.result(); }, + [this](const Async &task) { m_symbolFileResult = task.result(); }, CallDoneIf::Success} }; - d->taskTree.setRecipe(root); - d->taskTree.start(); + m_taskTree.setRecipe(root); + m_taskTree.start(); - d->progressLabel->setText(Tr::tr("Copying files to device...")); + m_progressLabel->setText(Tr::tr("Copying files to device...")); setEnabled(false); - d->progressIndicator->setVisible(true); - d->progressLabel->setVisible(true); + m_progressIndicator->setVisible(true); + m_progressLabel->setVisible(true); } void AttachCoreDialog::coreFileChanged(const FilePath &coreFile) { if (coreFile.osType() != OsType::OsTypeWindows && coreFile.exists()) { - Kit *k = d->kitChooser->currentKit(); + Kit *k = m_kitChooser->currentKit(); QTC_ASSERT(k, return); ProcessRunData debugger = DebuggerKitAspect::runnable(k); CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(debugger, coreFile); if (!cinfo.foundExecutableName.isEmpty()) - d->symbolFileName->setFilePath(cinfo.foundExecutableName); - else if (!d->symbolFileName->isValid() && !cinfo.rawStringFromCore.isEmpty()) - d->symbolFileName->setFilePath(FilePath::fromString(cinfo.rawStringFromCore)); + m_symbolFileName->setFilePath(cinfo.foundExecutableName); + else if (!m_symbolFileName->isValid() && !cinfo.rawStringFromCore.isEmpty()) + m_symbolFileName->setFilePath(FilePath::fromString(cinfo.rawStringFromCore)); } changed(); } void AttachCoreDialog::changed() { - AttachCoreDialogPrivate::State st = d->getDialogState(); - d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(st.isValid()); -} - -FilePath AttachCoreDialog::coreFile() const -{ - return d->coreFileName->filePath(); -} - -FilePath AttachCoreDialog::symbolFile() const -{ - return d->symbolFileName->filePath(); + State st = getDialogState(); + m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(st.isValid()); } FilePath AttachCoreDialog::coreFileCopy() const { - return d->coreFileResult.value_or(d->symbolFileName->filePath()); + return m_coreFileResult.value_or(m_symbolFileName->filePath()); } FilePath AttachCoreDialog::symbolFileCopy() const { - return d->symbolFileResult.value_or(d->symbolFileName->filePath()); -} - -void AttachCoreDialog::setSymbolFile(const FilePath &symbolFilePath) -{ - d->symbolFileName->setFilePath(symbolFilePath); -} - -void AttachCoreDialog::setCoreFile(const FilePath &coreFilePath) -{ - d->coreFileName->setFilePath(coreFilePath); -} - -void AttachCoreDialog::setKitId(Id id) -{ - d->kitChooser->setCurrentKitId(id); -} - -Kit *AttachCoreDialog::kit() const -{ - return d->kitChooser->currentKit(); -} - -FilePath AttachCoreDialog::overrideStartScript() const -{ - return d->overrideStartScriptFileName->filePath(); -} - -void AttachCoreDialog::setOverrideStartScript(const FilePath &scriptName) -{ - d->overrideStartScriptFileName->setFilePath(scriptName); -} - -FilePath AttachCoreDialog::sysRoot() const -{ - return d->sysRootDirectory->filePath(); -} - -void AttachCoreDialog::setSysRoot(const FilePath &sysRoot) -{ - d->sysRootDirectory->setFilePath(sysRoot); + return m_symbolFileResult.value_or(m_symbolFileName->filePath()); } void runAttachToCoreDialog() { - AttachCoreDialog dlg(ICore::dialogParent()); + AttachCoreDialog dlg; QtcSettings *settings = ICore::settings(); From eb4648004faa8121844e2f1b252e63e2e1bfc57f Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 9 Dec 2024 13:09:25 +0100 Subject: [PATCH 482/989] Utils: Use Qt::ColorScheme-based API The OS specific handling of light/dark system theming in Qt Creator was implemented by passing around bool values. Qt 6.5 comes with a new enum Qt::ColorScheme and respecive themeing API. This change replaces some of the legacy code with the new Qt API. "System Information" displays the color schemes of the current theme and the one of the system. Change-Id: Id39af399dd54ea239bd750c45ea74a48be5efbd2 Reviewed-by: Cristian Adam --- src/libs/utils/theme/theme.cpp | 51 +++++++---------------- src/libs/utils/theme/theme.h | 3 +- src/libs/utils/theme/theme_mac.h | 1 - src/libs/utils/theme/theme_mac.mm | 13 ------ src/plugins/coreplugin/coreconstants.h | 2 - src/plugins/coreplugin/icore.cpp | 4 ++ src/plugins/coreplugin/manhattanstyle.cpp | 2 +- src/plugins/coreplugin/themechooser.cpp | 10 ++++- 8 files changed, 29 insertions(+), 57 deletions(-) diff --git a/src/libs/utils/theme/theme.cpp b/src/libs/utils/theme/theme.cpp index 322e6a26a6c..9dd8798e8ae 100644 --- a/src/libs/utils/theme/theme.cpp +++ b/src/libs/utils/theme/theme.cpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace Utils { @@ -41,17 +42,12 @@ QColor creatorColor(Theme::Color role) return m_creatorTheme->color(role); } -static bool paletteIsDark(const QPalette &pal) -{ - return pal.color(QPalette::Window).lightnessF() < pal.color(QPalette::WindowText).lightnessF(); -} - static bool isOverridingPalette(const Theme *theme) { if (theme->flag(Theme::DerivePaletteFromTheme)) return true; if (theme->flag(Theme::DerivePaletteFromThemeIfNeeded) - && paletteIsDark(Theme::initialPalette()) != theme->flag(Theme::DarkUserInterface)) { + && qGuiApp->styleHints()->colorScheme() != theme->colorScheme()) { return true; } return false; @@ -70,22 +66,12 @@ static void setMacAppearance(Theme *theme) // theme by forcing light aqua for light creator themes // and dark aqua for dark themes. if (theme) - Internal::forceMacAppearance(theme->flag(Theme::DarkUserInterface)); + Internal::forceMacAppearance(theme->colorScheme() == Qt::ColorScheme::Dark); #else Q_UNUSED(theme) #endif } -static bool macOSSystemIsDark() -{ -#ifdef Q_OS_MACOS - static bool systemIsDark = Internal::currentAppearanceIsDark(); - return systemIsDark; -#else - return false; -#endif -} - void setCreatorTheme(Theme *theme) { if (m_creatorTheme == theme) @@ -122,7 +108,8 @@ QStringList Theme::preferredStyles() const { // Force Fusion style if we have a dark theme on Windows or Linux, // because the default QStyle might not be up for it - if (!HostOsInfo::isMacHost() && d->preferredStyles.isEmpty() && flag(DarkUserInterface)) + if (!HostOsInfo::isMacHost() && d->preferredStyles.isEmpty() + && colorScheme() == Qt::ColorScheme::Dark) return {"Fusion"}; return d->preferredStyles; } @@ -326,26 +313,16 @@ void Theme::readSettings(QSettings &settings) } } -bool Theme::systemUsesDarkMode() +Qt::ColorScheme Theme::colorScheme() const { - if (HostOsInfo::isWindowsHost()) { - constexpr char regkey[] - = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; - bool ok; - const int setting = QSettings(regkey, QSettings::NativeFormat).value("AppsUseLightTheme").toInt(&ok); - return ok && setting == 0; - } + return flag(Theme::DarkUserInterface) ? Qt::ColorScheme::Dark + : Qt::ColorScheme::Light; +} - if (HostOsInfo::isMacHost()) - return macOSSystemIsDark(); - - // Avoid enforcing the initial palette. - // The initial palette must be set after setting the macOS appearance in setInitialPalette, - // but systemUsesDarkMode is used to determine the default theme, which is in turn required - // for the setInitialPalette call - if (m_initialPalette) - return paletteIsDark(*m_initialPalette); - return paletteIsDark(QApplication::palette()); +Qt::ColorScheme Theme::systemColorScheme() +{ + static const Qt::ColorScheme initialColorScheme = qGuiApp->styleHints()->colorScheme(); + return initialColorScheme; } // If you copy QPalette, default values stay at default, even if that default is different @@ -365,7 +342,7 @@ static QPalette copyPalette(const QPalette &p) void Theme::setInitialPalette(Theme *initTheme) { - macOSSystemIsDark(); // initialize value for system mode + systemColorScheme(); // initialize value for system mode setMacAppearance(initTheme); initialPalette(); } diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 4f3f167b065..d0f78c2e83f 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -554,7 +554,8 @@ public: void readSettings(QSettings &settings); - static bool systemUsesDarkMode(); + Qt::ColorScheme colorScheme() const; + static Qt::ColorScheme systemColorScheme(); static QPalette initialPalette(); static void setInitialPalette(Theme *initTheme); diff --git a/src/libs/utils/theme/theme_mac.h b/src/libs/utils/theme/theme_mac.h index 903773be888..7f8c83febbf 100644 --- a/src/libs/utils/theme/theme_mac.h +++ b/src/libs/utils/theme/theme_mac.h @@ -13,7 +13,6 @@ namespace Utils { namespace Internal { void forceMacAppearance(bool dark); -bool currentAppearanceIsDark(); void setMacOSHelpMenu(QMenu *menu); } // Internal diff --git a/src/libs/utils/theme/theme_mac.mm b/src/libs/utils/theme/theme_mac.mm index e01ace28f94..a033efa4558 100644 --- a/src/libs/utils/theme/theme_mac.mm +++ b/src/libs/utils/theme/theme_mac.mm @@ -10,25 +10,12 @@ namespace Utils { namespace Internal { -bool currentAppearanceMatches(bool dark) -{ - auto appearance = [NSApp.effectiveAppearance - bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]]; - return - [appearance isEqualToString:(dark ? NSAppearanceNameDarkAqua : NSAppearanceNameAqua)]; -} - void forceMacAppearance(bool dark) { NSApp.appearance = [NSAppearance appearanceNamed:(dark ? NSAppearanceNameDarkAqua : NSAppearanceNameAqua)]; } -bool currentAppearanceIsDark() -{ - return currentAppearanceMatches(true); -} - void setMacOSHelpMenu(QMenu *menu) { NSApp.helpMenu = menu->toNSMenu(); diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index d381b3ce1f2..07162dafe95 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -219,8 +219,6 @@ const char SETTINGS_DEFAULTTEXTENCODING[] = "General/DefaultFileEncoding"; const char SETTINGS_DEFAULT_LINE_TERMINATOR[] = "General/DefaultLineTerminator"; const char SETTINGS_THEME[] = "Core/CreatorTheme"; -const char DEFAULT_THEME[] = "flat"; -const char DEFAULT_DARK_THEME[] = "flat-dark"; const char TR_CLEAR_MENU[] = QT_TRANSLATE_NOOP("QtC::Core", "Clear Menu"); diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 55e99c92e1d..4720d548b81 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -1009,6 +1009,10 @@ QString uiConfigInformation() info.append(QString("Color: %1\n").arg(StyleHelper::requestedBaseColor().name())); info.append(QString("Theme: %1 \"%2\"\n").arg(creatorTheme()->id()) .arg(creatorTheme()->displayName())); + info.append(QString("Theme color scheme: Qt::ColorScheme::%1\n") + .arg(QVariant::fromValue(creatorTheme()->colorScheme()).toString())); + info.append(QString("System color scheme: Qt::ColorScheme::%1\n") + .arg(QVariant::fromValue(Theme::systemColorScheme()).toString())); const QString toolbarStyle = StyleHelper::toolbarStyle() == StyleHelper::ToolbarStyle::Compact ? "Compact" : "Relaxed"; info.append(QString("Toolbar style: Utils::StyleHelper::ToolbarStyle%1\n").arg(toolbarStyle)); diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 22969b68525..ad971eb3730 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -115,7 +115,7 @@ bool lightColored(const QWidget *widget) static bool isDarkFusionStyle(const QStyle *style) { - return creatorTheme()->flag(Theme::DarkUserInterface) + return creatorTheme()->colorScheme() == Qt::ColorScheme::Dark && strcmp(style->metaObject()->className(), "QFusionStyle") == 0; } diff --git a/src/plugins/coreplugin/themechooser.cpp b/src/plugins/coreplugin/themechooser.cpp index 2605c30b047..e1c76ca7cb5 100644 --- a/src/plugins/coreplugin/themechooser.cpp +++ b/src/plugins/coreplugin/themechooser.cpp @@ -125,8 +125,14 @@ ThemeChooser::~ThemeChooser() static QString defaultThemeId() { - return Theme::systemUsesDarkMode() ? QString(Constants::DEFAULT_DARK_THEME) - : QString(Constants::DEFAULT_THEME); + switch (Theme::systemColorScheme()) { + case Qt::ColorScheme::Light: + return QString("flat"); + case Qt::ColorScheme::Dark: + return QString("flat-dark"); + default: + return QString("flat"); + } } void ThemeChooser::apply() From 9d78bf899efd34315bfe82e65ff7c3b595fefe7b Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 20 Dec 2024 17:02:54 +0100 Subject: [PATCH 483/989] ProjectExplorer: Introduce a RunControl::start() And use it in various places. Change-Id: I525d6fe89652ceba9f675b0b8c9e7ea6a8bcf4be Reviewed-by: Jarek Kobus --- src/plugins/autotest/testrunner.cpp | 2 +- src/plugins/clangtools/clangtool.cpp | 2 +- src/plugins/debugger/debuggerdialogs.cpp | 22 +++++++++------ src/plugins/debugger/debuggerplugin.cpp | 28 +++++++++++-------- src/plugins/debugger/debuggerruncontrol.cpp | 7 +---- src/plugins/debugger/debuggerruncontrol.h | 2 -- src/plugins/debugger/debuggertest.cpp | 2 +- src/plugins/debugger/loadcoredialog.cpp | 5 ++-- src/plugins/lua/bindings/project.cpp | 2 +- src/plugins/projectexplorer/runcontrol.cpp | 5 ++++ src/plugins/projectexplorer/runcontrol.h | 2 ++ .../qmlpreview/qmlpreviewruncontrol.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +- src/plugins/qnx/qnxdebugsupport.cpp | 3 +- src/plugins/valgrind/callgrindtool.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 2 +- 16 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 698903c1ed6..be2454531cf 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -588,7 +588,7 @@ void TestRunner::debugTests() runControl, &RunControl::initiateStop); connect(runControl, &RunControl::stopped, this, &TestRunner::onFinished); - ProjectExplorerPlugin::startRunControl(runControl); + runControl->start(); if (useOutputProcessor && testSettings().popupOnStart()) popupResultsPane(); } diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index b719ab6fd00..a5ecf187176 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -897,7 +897,7 @@ void ClangTool::startTool(FileSelection fileSelection, const RunSettings &runSet m_infoBarWidget->setInfoText("Waiting for build to finish..."); setState(State::PreparationStarted); - ProjectExplorerPlugin::startRunControl(m_runControl); + m_runControl->start(); } FileInfos ClangTool::collectFileInfos(Project *project, FileSelection fileSelection) diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index f88d439fa6b..abfa5670f3b 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -380,10 +380,6 @@ void StartApplicationDialog::run(bool attachRemote) Kit *k = dialog.kitChooser->currentKit(); - auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); - runControl->setKit(k); - auto debugger = new DebuggerRunTool(runControl); - const StartApplicationParameters newParameters = dialog.parameters(); if (newParameters != history.back()) { history.append(newParameters); @@ -405,7 +401,12 @@ void StartApplicationDialog::run(bool attachRemote) &dialog, Tr::tr("Cannot debug"), Tr::tr("Cannot debug application: Kit has no device")); return; } - ProcessRunData inferior = newParameters.runnable; + + auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); + runControl->setKit(k); + + auto debugger = new DebuggerRunTool(runControl); + const QString inputAddress = dialog.channelOverrideEdit->text(); if (!inputAddress.isEmpty()) debugger->setRemoteChannel(inputAddress); @@ -414,7 +415,7 @@ void StartApplicationDialog::run(bool attachRemote) debugger->setRunControlName(newParameters.displayName()); debugger->setBreakOnMain(newParameters.breakAtMain); debugger->setDebugInfoLocation(newParameters.debugInfoLocation); - debugger->setInferior(inferior); + debugger->setInferior(newParameters.runnable); debugger->setCommandsAfterConnect(newParameters.serverInitCommands); debugger->setCommandsForReset(newParameters.serverResetCommands); debugger->setUseTerminal(newParameters.runInTerminal); @@ -435,7 +436,8 @@ void StartApplicationDialog::run(bool attachRemote) debugger->setUseContinueInsteadOfRun(true); debugger->setRunControlName(Tr::tr("Attach to %1").arg(debugger->remoteChannel())); } - debugger->startRunControl(); + + runControl->start(); } void runAttachToRemoteServerDialog() @@ -577,7 +579,7 @@ void runAttachToQmlPortDialog() debugger->setRemoteChannel(sshParameters.host(), sshParameters.port()); debugger->setStartMode(AttachToQmlServer); - debugger->startRunControl(); + runControl->start(); } // StartRemoteCdbDialog @@ -709,11 +711,13 @@ void runStartRemoteCdbSessionDialog(Kit *kit) auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); runControl->setKit(kit); + auto debugger = new DebuggerRunTool(runControl); debugger->setStartMode(AttachToRemoteServer); debugger->setCloseMode(KillAtClose); debugger->setRemoteChannel(dlg.connection()); - debugger->startRunControl(); + + runControl->start(); } // diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index c56f7faebd9..feaa221ab16 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -660,7 +660,7 @@ public: ActionContainer *m_menu = nullptr; - QList m_scheduledStarts; + QList m_scheduledStarts; ProxyAction m_visibleStartAction; // The fat debug button ProxyAction m_hiddenStopAction; @@ -1420,7 +1420,7 @@ bool DebuggerPluginPrivate::parseArgument(QStringList::const_iterator &it, } debugger->setUseTerminal(useTerminal); - m_scheduledStarts.append(debugger); + m_scheduledStarts.append(runControl); return true; } // -wincrashevent :. A handle used for @@ -1448,7 +1448,7 @@ bool DebuggerPluginPrivate::parseArgument(QStringList::const_iterator &it, "does not match the pattern :.").arg(*it, option); return false; } - m_scheduledStarts.append(debugger); + m_scheduledStarts.append(runControl); return true; } @@ -1619,13 +1619,14 @@ void DebuggerPluginPrivate::attachToLastCore() auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); runControl->setKit(KitManager::defaultKit()); runControl->setDisplayName(Tr::tr("Last Core file \"%1\"").arg(lastCore.coreFile.toString())); - auto debugger = new DebuggerRunTool(runControl); + auto debugger = new DebuggerRunTool(runControl); debugger->setInferiorExecutable(lastCore.binary); debugger->setCoreFilePath(lastCore.coreFile); debugger->setStartMode(AttachToCore); debugger->setCloseMode(DetachAtClose); - debugger->startRunControl(); + + runControl->start(); } void DebuggerPluginPrivate::reloadDebuggingHelpers() @@ -1674,7 +1675,8 @@ void DebuggerPluginPrivate::attachToRunningApplication() debugger->setCloseMode(DetachAtClose); debugger->setUseContinueInsteadOfRun(true); debugger->setContinueAfterAttach(false); - debugger->startRunControl(); + + runControl->start(); } } @@ -1734,6 +1736,7 @@ RunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, runControl->setKit(kit); //: %1: PID runControl->setDisplayName(Tr::tr("Process %1").arg(processInfo.processId)); + auto debugger = new DebuggerRunTool(runControl); debugger->setAttachPid(ProcessHandle(processInfo.processId)); debugger->setInferiorExecutable(device->filePath(processInfo.executable)); @@ -1741,15 +1744,15 @@ RunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, debugger->setCloseMode(DetachAtClose); debugger->setContinueAfterAttach(contAfterAttach); - debugger->startRunControl(); + runControl->start(); - return debugger->runControl(); + return runControl; } void DebuggerPluginPrivate::runScheduled() { - for (DebuggerRunTool *debugger : std::as_const(m_scheduledStarts)) - debugger->startRunControl(); + for (RunControl *runControl : std::as_const(m_scheduledStarts)) + runControl->start(); } void DebuggerPluginPrivate::editorOpened(IEditor *editor) @@ -2283,15 +2286,18 @@ void DebuggerPlugin::attachToProcess(const qint64 processId, const Utils::FilePa void DebuggerPlugin::attachExternalApplication(RunControl *rc) { ProcessHandle pid = rc->applicationProcessHandle(); + auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); runControl->setTarget(rc->target()); runControl->setDisplayName(Tr::tr("Process %1").arg(pid.pid())); + auto debugger = new DebuggerRunTool(runControl); debugger->setInferiorExecutable(rc->targetFilePath()); debugger->setAttachPid(pid); debugger->setStartMode(AttachToLocalProcess); debugger->setCloseMode(DetachAtClose); - debugger->startRunControl(); + + runControl->start(); } void DebuggerPlugin::getEnginesState(QByteArray *json) const diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 18a4e1030cb..3b7120c35b5 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -613,7 +613,7 @@ void DebuggerRunTool::continueAfterDebugServerStart() debugger->setCloseMode(DetachAtClose); debugger->setRunControlName(name); debugger->setCoreFilePath(FilePath::fromString(coreFile), true); - debugger->startRunControl(); + rc->start(); }); first = false; @@ -961,11 +961,6 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm } } -void DebuggerRunTool::startRunControl() -{ - ProjectExplorerPlugin::startRunControl(runControl()); -} - void DebuggerRunTool::addSolibSearchDir(const QString &str) { QString path = str; diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index 2f056666ee7..623bd2af1db 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -27,8 +27,6 @@ public: AllowTerminal allowTerminal = DoAllowTerminal); ~DebuggerRunTool() override; - void startRunControl(); - void start() override; void stop() override; diff --git a/src/plugins/debugger/debuggertest.cpp b/src/plugins/debugger/debuggertest.cpp index 66a92590d2b..ca74a8a8a83 100644 --- a/src/plugins/debugger/debuggertest.cpp +++ b/src/plugins/debugger/debuggertest.cpp @@ -114,7 +114,7 @@ void DebuggerUnitTests::testStateMachine() connect(debugger, &DebuggerRunTool::stopped, &QTestEventLoop::instance(), &QTestEventLoop::exitLoop); - debugger->startRunControl(); + runControl->start(); QTestEventLoop::instance().enterLoop(5); } diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index 4b4d4090731..78dfe4d9ef0 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -348,8 +348,8 @@ void runAttachToCoreDialog() auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); runControl->setKit(dlg.kit()); runControl->setDisplayName(Tr::tr("Core file \"%1\"").arg(dlg.coreFile().toUserOutput())); - auto debugger = new DebuggerRunTool(runControl); + auto debugger = new DebuggerRunTool(runControl); debugger->setInferiorExecutable(dlg.symbolFileCopy()); debugger->setCoreFilePath(dlg.coreFileCopy()); debugger->setStartMode(AttachToCore); @@ -358,7 +358,8 @@ void runAttachToCoreDialog() const FilePath sysRoot = dlg.sysRoot(); if (!sysRoot.isEmpty()) debugger->setSysRoot(sysRoot); - debugger->startRunControl(); + + runControl->start(); } } // Debugger::Internal diff --git a/src/plugins/lua/bindings/project.cpp b/src/plugins/lua/bindings/project.cpp index 6f83bcd3642..b61980c7c2d 100644 --- a/src/plugins/lua/bindings/project.cpp +++ b/src/plugins/lua/bindings/project.cpp @@ -95,7 +95,7 @@ void setupProjectModule() auto startRun = [rc = std::move(rc)]() mutable { if (!rc->createMainWorker()) return; - ProjectExplorerPlugin::startRunControl(rc.release()); + rc.release()->start(); }; if (status == BuildForRunConfigStatus::Building) { diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index faffb2e0811..0cfd0b23269 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -380,6 +380,11 @@ void RunControl::copyDataFromRunControl(RunControl *runControl) d->copyData(runControl->d.get()); } +void RunControl::start() +{ + ProjectExplorerPlugin::startRunControl(this); +} + void RunControl::resetDataForAttachToCore() { d->m_workers.clear(); diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index da5a3716634..e7ca277ea06 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -151,6 +151,8 @@ public: explicit RunControl(Utils::Id mode); ~RunControl() final; + void start(); + void setTarget(Target *target); void setKit(Kit *kit); diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp index bef05103e36..322b4b2df20 100644 --- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp +++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp @@ -124,7 +124,7 @@ QmlPreviewRunner::QmlPreviewRunner(RunControl *runControl, const QmlPreviewRunne [runControl] { auto rc = new RunControl(ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE); rc->copyDataFromRunControl(runControl); - ProjectExplorerPlugin::startRunControl(rc); + rc->start(); }); runControl->initiateStop(); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 32fcbbad893..9a0c38a1e7d 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -609,7 +609,7 @@ ProjectExplorer::RunControl *QmlProfilerTool::attachToWaitingApplication() connect(d->m_profilerConnections, &QmlProfilerClientManager::connectionClosed, runControl, &RunControl::initiateStop); - ProjectExplorerPlugin::startRunControl(runControl); + runControl->start(); return runControl; } diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index c9fc71ef42d..1bdabaea923 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -158,7 +157,7 @@ void showAttachToProcessDialog() debugger->setSysRoot(qtVersion->qnxTarget()); debugger->setUseContinueInsteadOfRun(true); - ProjectExplorerPlugin::startRunControl(runControl); + runControl->start(); } // QnxDebugWorkerFactory diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 7327f7e8372..1e6b6a06838 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -262,7 +262,7 @@ CallgrindTool::CallgrindTool(QObject *parent) runControl->createMainWorker(); runControl->setCommandLine(dlg.commandLine()); runControl->setWorkingDirectory(dlg.workingDirectory()); - ProjectExplorerPlugin::startRunControl(runControl); + runControl->start(); }); // If there is a CppEditor context menu add our own context menu actions. diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index d858d0a07a5..ff93b090f2d 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -654,7 +654,7 @@ MemcheckTool::MemcheckTool(QObject *parent) rc->createMainWorker(); rc->setCommandLine(dlg.commandLine()); rc->setWorkingDirectory(dlg.workingDirectory()); - ProjectExplorerPlugin::startRunControl(rc); + rc->start(); }); m_perspective.addToolBarAction(m_startAction); From 27ef562958817fed801658da97ab604b44bc5ea7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 13 Dec 2024 14:24:51 +0100 Subject: [PATCH 484/989] QbsProjectManager: Adapt to upstream API change Task-number: QBS-1818 Change-Id: Ie367e14f91531311569079a3b1cc6225366f79ee Reviewed-by: Ivan Komissarov --- src/plugins/qbsprojectmanager/qbssession.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index 309c1777895..7e484b2eefe 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -501,7 +501,10 @@ void QbsSession::handlePacket(const QJsonObject &packet) } else if (type == "log-data") { Core::MessageManager::writeSilently("[qbs] " + packet.value("message").toString()); } else if (type == "warning") { - ErrorInfo(packet.value("warning").toObject()).generateTasks(Task::Warning); + if (const auto it = packet.find("error"); it != packet.end()) + ErrorInfo(it->toObject()).generateTasks(Task::Error); + else + ErrorInfo(packet.value("warning").toObject()).generateTasks(Task::Warning); } else if (type == "task-started") { emit taskStarted(packet.value("description").toString(), packet.value("max-progress").toInt()); From 7b48d08df9a8cc59e8954bd02e64681ab96d3a03 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 23 Dec 2024 09:55:25 +0200 Subject: [PATCH 485/989] Valgrind: Fix Windows build Amends 9d78bf899efd34315bfe82e65ff7c3b595fefe7b. Change-Id: Ie69bd56e7b60ea717f15c3977f192127072273fd Reviewed-by: Christian Stenger --- src/plugins/valgrind/memchecktool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index ff93b090f2d..881cd29a6ee 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -1612,7 +1612,7 @@ void HeobData::processFinished() connect(m_runControl, &RunControl::started, this, &HeobData::debugStarted); connect(m_runControl, &RunControl::stopped, this, &HeobData::debugStopped); - debugger->startRunControl(); + m_runControl->start(); return; } From 617aec1fce5704c1eb2db5bb0052d458b2b88fd3 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Fri, 13 Dec 2024 15:21:21 +0100 Subject: [PATCH 486/989] LSP: add BaseSettings::isValidOnProject() virtual method Add a method to BaseSettings that allow language clients to tell whether they can be used on a certain project. This allows BaseSettings to be disabled on certain projects, for example qmlls can't be enabled on a project that has an invalid Qt version. Task-number: QTCREATORBUG-31897 Change-Id: Id8d6c05bc31c8596f685852ff20179d7f728feda Reviewed-by: David Schulz --- src/plugins/languageclient/languageclientmanager.cpp | 9 ++++++++- src/plugins/languageclient/languageclientsettings.cpp | 7 ++++++- src/plugins/languageclient/languageclientsettings.h | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 84070bc4638..287fda803e0 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -358,6 +358,8 @@ void LanguageClientManager::applySettings(BaseSettings *setting) const Utils::FilePath filePath = textDocument->filePath(); for (ProjectExplorer::Project *project : ProjectExplorer::ProjectManager::projects()) { + if (!setting->isValidOnProject(project)) + continue; const bool settingIsEnabled = ProjectSettings(project).enabledSettings().contains(setting->m_id) || (setting->m_enabled @@ -636,8 +638,13 @@ void LanguageClientManager::documentOpened(Core::IDocument *document) // check whether we already have a client running for this project Client *clientForProject = Utils::findOrDefault(clients, Utils::equal(&Client::project, project)); - if (!clientForProject) + + // create a client only when valid on the current project + if (!clientForProject) { + if (!setting->isValidOnProject(project)) + continue; clientForProject = startClient(setting, project); + } QTC_ASSERT(clientForProject, continue); openDocumentWithClient(textDocument, clientForProject); diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index d00974c1be2..011bee64963 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -588,6 +588,11 @@ bool BaseSettings::isValid() const return !m_name.isEmpty(); } +bool BaseSettings::isValidOnProject(ProjectExplorer::Project *) const +{ + return isValid(); +} + Client *BaseSettings::createClient() const { return createClient(static_cast(nullptr)); @@ -608,7 +613,7 @@ bool BaseSettings::isEnabledOnProject(ProjectExplorer::Project *project) const Client *BaseSettings::createClient(ProjectExplorer::Project *project) const { - if (!isValid() || !isEnabledOnProject(project)) + if (!isValidOnProject(project) || !isEnabledOnProject(project)) return nullptr; BaseClientInterface *interface = createInterface(project); QTC_ASSERT(interface, return nullptr); diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index 3530b2c5242..ce0bd97b893 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -80,6 +80,7 @@ public: virtual QWidget *createSettingsWidget(QWidget *parent = nullptr) const; virtual BaseSettings *copy() const = 0; virtual bool isValid() const; + virtual bool isValidOnProject(ProjectExplorer::Project *project) const; Client *createClient() const; Client *createClient(ProjectExplorer::Project *project) const; bool isEnabledOnProject(ProjectExplorer::Project *project) const; From c783ac4f8192248289d0e74159ede54862b020b4 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Wed, 4 Dec 2024 11:59:04 +0100 Subject: [PATCH 487/989] qmlls: disable and warn on broken Qt kits Warn the user that qmlls can't start when using an invalid Qt kit, instead of trying to start an empty CommandLine. Task-number: QTCREATORBUG-31897 Change-Id: I7bb7a473b1ffad34dd6c77a23fd700d829ea2216 Reviewed-by: David Schulz --- .../qmljseditor/qmllsclientsettings.cpp | 22 +++++++++++++++++-- src/plugins/qmljseditor/qmllsclientsettings.h | 2 ++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index 3379111953d..b5451b824e8 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include #include @@ -115,8 +117,7 @@ static std::pair evaluateLatestQmlls() static CommandLine commandLineForQmlls(const Project *project) { const auto *qtVersion = qtVersionFromProject(project); - if (!qtVersion) - return {}; + QTC_ASSERT(qtVersion, return {}); auto [executable, version] = qmllsSettings()->m_useLatestQmlls @@ -139,6 +140,23 @@ static CommandLine commandLineForQmlls(const Project *project) return result; } +bool QmllsClientSettings::isValidOnProject(ProjectExplorer::Project *project) const +{ + if (!BaseSettings::isValidOnProject(project)) + return false; + + if (!project || !QtVersionManager::isLoaded()) + return false; + + if (!qtVersionFromProject(project)) { + Core::MessageManager::writeSilently( + "Current kit does not have a valid Qt version, disabling QML Language Server..."); + return false; + } + + return true; +} + BaseClientInterface *QmllsClientSettings::createInterface(Project *project) const { auto interface = new StdIOClientInterface; diff --git a/src/plugins/qmljseditor/qmllsclientsettings.h b/src/plugins/qmljseditor/qmllsclientsettings.h index d27f0ad350b..7f240897f8f 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.h +++ b/src/plugins/qmljseditor/qmllsclientsettings.h @@ -24,6 +24,8 @@ public: void toMap(Utils::Store &map) const override; void fromMap(const Utils::Store &map) override; + bool isValidOnProject(ProjectExplorer::Project *project) const override; + // helpers: bool isEnabledOnProjectFile(const Utils::FilePath &file) const; bool useQmllsWithBuiltinCodemodelOnProject(const Utils::FilePath &file) const; From 6ecfb9da363ab6f3b103c3ca814f203fb7c03ee2 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Tue, 3 Dec 2024 11:43:31 +0100 Subject: [PATCH 488/989] qmlls: use import paths also used in old codemodel Add the import paths used by the old codemodel to qmlls via "-I" commandline parameter. This includes import paths passed from the QML_IMPORT_PATH CMake variable. The downside of passing the import paths as commandline parameters to qmlls is that all QML module end up using the same import path. In general, this is not the case, QML Modules with "DEPENDENCIES TARGET" or "IMPORT_PATH" in their qt_add_qml_module()-call might have extra import paths that other modules don't have. An example for this is a QML Module linking to another static QML module. It builds fine but qmlls can't find the static QML module if its outside the Qml import path. This scenario works fine when using QT_QML_GENERATE_QMLLS_INI. Add a manual test project with such a QML_IMPORT_PATH CMake variable, where qmlls should not warn about importing MyModule in Main.qml. Task-number: QTCREATORBUG-31897 Change-Id: Ic4c048dfdacfc2de11db8973dcbdca83989af320 Reviewed-by: David Schulz Reviewed-by: Fabian Kosmale --- .../qmljseditor/qmllsclientsettings.cpp | 10 +++- .../projectWithQML_IMPORT_PATH/CMakeLists.txt | 47 +++++++++++++++++++ .../qmlls/projectWithQML_IMPORT_PATH/Main.qml | 14 ++++++ .../qmlls/projectWithQML_IMPORT_PATH/main.cpp | 19 ++++++++ .../somesubfolder/CMakeLists.txt | 1 + .../somesubfolder/subsub/CMakeLists.txt | 1 + .../subsub/MyModule/CMakeLists.txt | 6 +++ .../somesubfolder/subsub/MyModule/Main.qml | 5 ++ 8 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/CMakeLists.txt create mode 100644 tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/Main.qml create mode 100644 tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/main.cpp create mode 100644 tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/CMakeLists.txt create mode 100644 tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/CMakeLists.txt create mode 100644 tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/MyModule/CMakeLists.txt create mode 100644 tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/MyModule/Main.qml diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index b5451b824e8..ce629ba5d1d 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -114,7 +114,7 @@ static std::pair evaluateLatestQmlls() return std::make_pair(latestQmlls, latestVersion); } -static CommandLine commandLineForQmlls(const Project *project) +static CommandLine commandLineForQmlls(Project *project) { const auto *qtVersion = qtVersionFromProject(project); QTC_ASSERT(qtVersion, return {}); @@ -133,6 +133,14 @@ static CommandLine commandLineForQmlls(const Project *project) if (version >= QVersionNumber(6, 8, 0)) result.addArgs({"-I", qtVersion->qmlPath().path()}); + // add custom import paths that the embedded codemodel uses too + const QmlJS::ModelManagerInterface::ProjectInfo projectInfo + = QmlJS::ModelManagerInterface::instance()->projectInfo(project); + for (QmlJS::PathAndLanguage path : projectInfo.importPaths) { + if (path.language() == QmlJS::Dialect::Qml) + result.addArgs({"-I", path.path().path()}); + } + // qmlls 6.8.1 and later require the documentation path if (version >= QVersionNumber(6, 8, 1)) result.addArgs({"-d", qtVersion->docsPath().path()}); diff --git a/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/CMakeLists.txt b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/CMakeLists.txt new file mode 100644 index 00000000000..a0351728ca7 --- /dev/null +++ b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.16) + +project(untitled3 VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Quick) + +qt_standard_project_setup(REQUIRES 6.7) + +qt_add_executable(appuntitled3 + main.cpp +) + +set(QML_IMPORT_PATH ${CMAKE_CURRENT_BINARY_DIR}/somesubfolder/subsub CACHE PATH "Path to the QML modules in build directory") + +add_subdirectory(somesubfolder) + +qt_add_qml_module(appuntitled3 + URI untitled3 + VERSION 1.0 + QML_FILES + Main.qml + IMPORT_PATH ${CMAKE_CURRENT_BINARY_DIR}/somesubfolder/subsub +) + +# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. +# If you are developing for iOS or macOS you should consider setting an +# explicit, fixed bundle identifier manually though. +set_target_properties(appuntitled3 PROPERTIES +# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appuntitled3 + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +target_link_libraries(appuntitled3 + PRIVATE Qt6::Quick +) + +include(GNUInstallDirs) +install(TARGETS appuntitled3 + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/Main.qml b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/Main.qml new file mode 100644 index 00000000000..30b6121e93c --- /dev/null +++ b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/Main.qml @@ -0,0 +1,14 @@ +import QtQuick +// this qmlls warning should not be there: Warnings occurred while importing "MyModule" +import MyModule + +Window { + id: window + width: 640 + height: 480 + visible: true + title: qsTr("Hello World") + + // this qmlls warning should be there (to prove that qmlls is indeed running): Property "invalid" does not exist + invalid: 123 +} diff --git a/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/main.cpp b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/main.cpp new file mode 100644 index 00000000000..57282606d04 --- /dev/null +++ b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/main.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include +#include + + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, + &app, []() { QCoreApplication::exit(-1); }, + Qt::QueuedConnection); + engine.loadFromModule("untitled3", "Main"); + + return app.exec(); +} diff --git a/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/CMakeLists.txt b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/CMakeLists.txt new file mode 100644 index 00000000000..5406e2812c3 --- /dev/null +++ b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(subsub) diff --git a/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/CMakeLists.txt b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/CMakeLists.txt new file mode 100644 index 00000000000..24448dc5379 --- /dev/null +++ b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(MyModule) diff --git a/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/MyModule/CMakeLists.txt b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/MyModule/CMakeLists.txt new file mode 100644 index 00000000000..847d4661014 --- /dev/null +++ b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/MyModule/CMakeLists.txt @@ -0,0 +1,6 @@ + +qt_add_qml_module(MyModule + URI MyModule + QML_FILES + Main.qml +) diff --git a/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/MyModule/Main.qml b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/MyModule/Main.qml new file mode 100644 index 00000000000..5560aee7276 --- /dev/null +++ b/tests/manual/qml/qmlls/projectWithQML_IMPORT_PATH/somesubfolder/subsub/MyModule/Main.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + +} From bd481fa3005ccba51f3a60cdcaa73d2d69ffda4d Mon Sep 17 00:00:00 2001 From: Alexis Jeandet Date: Sat, 28 Dec 2024 15:29:53 +0100 Subject: [PATCH 489/989] MesonProjectManager: Tidy sources list Some source were not used anymore and others were not listed in CMakelists.txt. Change-Id: Icfb6ef4302fb0cd712ab6db46e982e0fb2596310 Reviewed-by: Eike Ziller --- .../mesonprojectmanager/CMakeLists.txt | 1 + .../buildsystemfilesparser.h | 19 -- .../mesonactionsmanager.cpp | 1 - src/plugins/mesonprojectmanager/projecttree.h | 22 -- .../mesonprojectmanager/toolwrapper.cpp | 226 ------------------ src/plugins/mesonprojectmanager/toolwrapper.h | 87 ------- 6 files changed, 1 insertion(+), 355 deletions(-) delete mode 100644 src/plugins/mesonprojectmanager/buildsystemfilesparser.h delete mode 100644 src/plugins/mesonprojectmanager/projecttree.h delete mode 100644 src/plugins/mesonprojectmanager/toolwrapper.cpp delete mode 100644 src/plugins/mesonprojectmanager/toolwrapper.h diff --git a/src/plugins/mesonprojectmanager/CMakeLists.txt b/src/plugins/mesonprojectmanager/CMakeLists.txt index 6c84b808eb5..b549fb3bc9f 100644 --- a/src/plugins/mesonprojectmanager/CMakeLists.txt +++ b/src/plugins/mesonprojectmanager/CMakeLists.txt @@ -18,6 +18,7 @@ add_qtc_plugin(MesonProjectManager mesoninfoparser.h mesonoutputparser.cpp mesonoutputparser.h + mesonpluginconstants.h mesonproject.cpp mesonproject.h mesonprojectimporter.cpp diff --git a/src/plugins/mesonprojectmanager/buildsystemfilesparser.h b/src/plugins/mesonprojectmanager/buildsystemfilesparser.h deleted file mode 100644 index d88068bf626..00000000000 --- a/src/plugins/mesonprojectmanager/buildsystemfilesparser.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) 2020 Alexis Jeandet. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "common.h" -#include "mesonpluginconstants.h" - -#include -#include -#include -#include -#include - -namespace MesonProjectManager { -namespace Internal { - -} // namespace Internal -} // namespace MesonProjectManager diff --git a/src/plugins/mesonprojectmanager/mesonactionsmanager.cpp b/src/plugins/mesonprojectmanager/mesonactionsmanager.cpp index 2510d071124..e69b3490522 100644 --- a/src/plugins/mesonprojectmanager/mesonactionsmanager.cpp +++ b/src/plugins/mesonprojectmanager/mesonactionsmanager.cpp @@ -6,7 +6,6 @@ #include "mesonbuildsystem.h" #include "mesonpluginconstants.h" #include "mesonprojectmanagertr.h" -#include "mesonprojectnodes.h" #include #include diff --git a/src/plugins/mesonprojectmanager/projecttree.h b/src/plugins/mesonprojectmanager/projecttree.h deleted file mode 100644 index d7ab32ecec1..00000000000 --- a/src/plugins/mesonprojectmanager/projecttree.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (C) 2020 Alexis Jeandet. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "mesoninfoparser.h" -#include "mesonprojectnodes.h" - -#include - -namespace MesonProjectManager::Internal { - -class ProjectTree -{ -public: - ProjectTree(); - static std::unique_ptr buildTree(const Utils::FilePath &srcDir, - const TargetsList &targets, - const Utils::FilePaths &bsFiles); -}; - -} // MesonProjectManager::Internal diff --git a/src/plugins/mesonprojectmanager/toolwrapper.cpp b/src/plugins/mesonprojectmanager/toolwrapper.cpp deleted file mode 100644 index 99238663158..00000000000 --- a/src/plugins/mesonprojectmanager/toolwrapper.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (C) 2020 Alexis Jeandet. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "toolwrapper.h" - -#include "mesonpluginconstants.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -using namespace Utils; - -namespace MesonProjectManager { -namespace Internal { - -static ToolType typeFromId(const QString &id) -{ - if (id == Constants::ToolsSettings::TOOL_TYPE_NINJA) - return ToolType::Ninja; - if (id == Constants::ToolsSettings::TOOL_TYPE_MESON) - return ToolType::Meson; - QTC_CHECK(false); - return ToolType::Meson; -} - -ToolWrapper::ToolWrapper(const Store &data) -{ - m_toolType = typeFromId(data.value(Constants::ToolsSettings::TOOL_TYPE_KEY).toString()); - m_name = data[Constants::ToolsSettings::NAME_KEY].toString(); - m_exe = FilePath::fromSettings(data[Constants::ToolsSettings::EXE_KEY]); - m_id = Id::fromSetting(data[Constants::ToolsSettings::ID_KEY]); - m_autoDetected = data[Constants::ToolsSettings::AUTO_DETECTED_KEY].toBool(); -} - -ToolWrapper::ToolWrapper(ToolType toolType, - const QString &name, - const FilePath &path, - bool autoDetected) - : m_toolType(toolType) - , m_version(read_version(path)) - , m_isValid{path.exists() && m_version.isValid} - , m_autoDetected{autoDetected} - , m_id{Utils::Id::generate()} - , m_exe{path} - , m_name{name} -{} - -ToolWrapper::ToolWrapper(ToolType toolType, - const QString &name, - const FilePath &path, - const Id &id, - bool autoDetected) - : m_toolType(toolType) - , m_version(read_version(path)) - , m_isValid{path.exists() && m_version.isValid} - , m_autoDetected{autoDetected} - , m_id{id} - , m_exe{path} - , m_name{name} -{ - QTC_ASSERT(m_id.isValid(), m_id = Utils::Id::generate()); -} - -ToolWrapper::~ToolWrapper() = default; - -void ToolWrapper::setExe(const Utils::FilePath &newExe) -{ - m_exe = newExe; - m_version = read_version(m_exe); -} - -Version ToolWrapper::read_version(const Utils::FilePath &toolPath) -{ - if (toolPath.toFileInfo().isExecutable()) { - Utils::Process process; - process.setCommand({ toolPath, { "--version" } }); - process.start(); - if (process.waitForFinished()) - return Version::fromString(process.cleanedStdOut()); - } - return {}; -} - -Store ToolWrapper::toVariantMap() const -{ - Utils::Store data; - data.insert(Constants::ToolsSettings::NAME_KEY, m_name); - data.insert(Constants::ToolsSettings::EXE_KEY, m_exe.toSettings()); - data.insert(Constants::ToolsSettings::AUTO_DETECTED_KEY, m_autoDetected); - data.insert(Constants::ToolsSettings::ID_KEY, m_id.toSetting()); - if (m_toolType == ToolType::Meson) - data.insert(Constants::ToolsSettings::TOOL_TYPE_KEY, Constants::ToolsSettings::TOOL_TYPE_MESON); - else - data.insert(Constants::ToolsSettings::TOOL_TYPE_KEY, Constants::ToolsSettings::TOOL_TYPE_NINJA); - return data; -} - -template -void impl_option_cat(QStringList &list, const First &first) -{ - list.append(first); -} - -template -void impl_option_cat(QStringList &list, const First &first, const T &...args) -{ - impl_option_cat(list, first); - impl_option_cat(list, args...); -} - -template -QStringList options_cat(const T &...args) -{ - QStringList result; - impl_option_cat(result, args...); - return result; -} - -Command ToolWrapper::setup(const FilePath &sourceDirectory, - const FilePath &buildDirectory, - const QStringList &options) const -{ - return {{m_exe, options_cat("setup", options, sourceDirectory.path(), buildDirectory.path())}, - sourceDirectory}; -} - -Command ToolWrapper::configure(const FilePath &sourceDirectory, - const FilePath &buildDirectory, - const QStringList &options) const -{ - if (!isSetup(buildDirectory)) - return setup(sourceDirectory, buildDirectory, options); - return {{m_exe, options_cat("configure", options, buildDirectory.path())}, - buildDirectory}; -} - -Command ToolWrapper::regenerate(const FilePath &sourceDirectory, - const FilePath &buildDirectory) const -{ - return {{m_exe, - options_cat("--internal", - "regenerate", - sourceDirectory.path(), - buildDirectory.path(), - "--backend", - "ninja")}, - buildDirectory}; -} - -Command ToolWrapper::introspect(const Utils::FilePath &sourceDirectory) const -{ - return {{m_exe, - {"introspect", "--all", QString("%1/meson.build").arg(sourceDirectory.path())}}, - sourceDirectory}; -} - -template -bool containsFiles(const QString &path, const File_t &file) -{ - return QFileInfo::exists(QString("%1/%2").arg(path).arg(file)); -} - -template -bool containsFiles(const QString &path, const File_t &file, const T &...files) -{ - return containsFiles(path, file) && containsFiles(path, files...); -} - -bool run_meson(const Command &command, QIODevice *output) -{ - Utils::Process process; - process.setWorkingDirectory(command.workDir); - process.setCommand(command.cmdLine); - process.start(); - if (!process.waitForFinished()) - return false; - if (output) { - output->write(process.rawStdOut()); - } - return process.exitCode() == 0; -} - -bool isSetup(const Utils::FilePath &buildPath) -{ - using namespace Utils; - return containsFiles(buildPath.pathAppended(Constants::MESON_INFO_DIR).toString(), - Constants::MESON_INTRO_TESTS, - Constants::MESON_INTRO_TARGETS, - Constants::MESON_INTRO_INSTALLED, - Constants::MESON_INTRO_BENCHMARKS, - Constants::MESON_INTRO_BUIDOPTIONS, - Constants::MESON_INTRO_PROJECTINFO, - Constants::MESON_INTRO_DEPENDENCIES, - Constants::MESON_INTRO_BUILDSYSTEM_FILES); -} - -static std::optional findToolHelper(const QStringList &exeNames) -{ - Environment systemEnvironment = Environment::systemEnvironment(); - for (const auto &exe : exeNames) { - const FilePath exe_path = systemEnvironment.searchInPath(exe); - if (exe_path.exists()) - return exe_path; - } - return std::nullopt; -} - -std::optional findTool(ToolType toolType) -{ - if (toolType == ToolType::Meson) - return findToolHelper({"meson.py", "meson"}); - if (toolType == ToolType::Ninja) - return findToolHelper({"ninja", "ninja-build"}); - QTC_CHECK(false); - return {}; -} - -} // namespace Internal -} // namespace MesonProjectManager diff --git a/src/plugins/mesonprojectmanager/toolwrapper.h b/src/plugins/mesonprojectmanager/toolwrapper.h deleted file mode 100644 index 85589d1a199..00000000000 --- a/src/plugins/mesonprojectmanager/toolwrapper.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (C) 2020 Alexis Jeandet. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "versionhelper.h" - -#include -#include -#include - -#include - -namespace MesonProjectManager { -namespace Internal { - -enum class ToolType { Meson, Ninja }; - -class Command -{ -public: - Utils::CommandLine cmdLine; - Utils::FilePath workDir; -}; - -class ToolWrapper final -{ -public: - ToolWrapper() = delete; - explicit ToolWrapper(const Utils::Store &data); - ToolWrapper(ToolType toolType, - const QString &name, - const Utils::FilePath &path, - bool autoDetected = false); - ToolWrapper(ToolType toolType, - const QString &name, - const Utils::FilePath &path, - const Utils::Id &id, - bool autoDetected = false); - - ~ToolWrapper(); - - const Version &version() const noexcept { return m_version; } - bool isValid() const noexcept { return m_isValid; } - bool autoDetected() const noexcept { return m_autoDetected; } - Utils::Id id() const noexcept { return m_id; } - Utils::FilePath exe() const noexcept { return m_exe; } - QString name() const noexcept { return m_name; } - - void setName(const QString &newName) { m_name = newName; } - void setExe(const Utils::FilePath &newExe); - - static Version read_version(const Utils::FilePath &toolPath); - - Utils::Store toVariantMap() const; - - ToolType toolType() const { return m_toolType; } - void setToolType(ToolType newToolType) { m_toolType = newToolType; } - - Command setup(const Utils::FilePath &sourceDirectory, - const Utils::FilePath &buildDirectory, - const QStringList &options = {}) const; - Command configure(const Utils::FilePath &sourceDirectory, - const Utils::FilePath &buildDirectory, - const QStringList &options = {}) const; - Command regenerate(const Utils::FilePath &sourceDirectory, - const Utils::FilePath &buildDirectory) const; - Command introspect(const Utils::FilePath &sourceDirectory) const; - -private: - ToolType m_toolType; - Version m_version; - bool m_isValid; - bool m_autoDetected; - Utils::Id m_id; - Utils::FilePath m_exe; - QString m_name; -}; - -bool run_meson(const Command &command, QIODevice *output = nullptr); - -bool isSetup(const Utils::FilePath &buildPath); - -std::optional findTool(ToolType toolType); - -} // namespace Internal -} // namespace MesonProjectManager From da6f5f24ba648c0b20b77bea0ef473035d73b413 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Fri, 13 Dec 2024 16:46:31 +0100 Subject: [PATCH 490/989] LSP: avoid duplicates in sortedSettingsForDocument() Avoid returning the same BaseSettings* multiple times in the list returned by sortedSettingsForDocument(). This leads to duplicate work later on. Amends 2e96194681092c8c04f746f7f06424676cca7cf4. Change-Id: I27e530a8cdd1cd13153236a651636511b2f0603d Reviewed-by: Eike Ziller --- src/plugins/languageclient/languageclientmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 925de96fe9a..86fd28fa93d 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -615,7 +615,7 @@ static QList sortedSettingsForDocument(Core::IDocument *document }); return true; // continue }); - return result; + return Utils::filteredUnique(result); } return Utils::filtered(prefilteredSettings, [document](BaseSettings *setting) { From c8041374f2daa3cc52d8515af9ebac6595d9069c Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 2 Jan 2025 15:55:52 +0100 Subject: [PATCH 491/989] Core: Implement disabled state for Figma designed components The components partially looked enabled while being disabled. Fixes: QTCREATORBUG-32281 Change-Id: Ifa267e8bc9bc77c4a38a214acf71530f2122425a Reviewed-by: Cristian Adam --- src/plugins/coreplugin/welcomepagehelper.cpp | 44 ++++++++++++++------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 478bb0249e3..e569e8ca6e6 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -40,6 +40,8 @@ namespace Core { using namespace WelcomePageHelpers; using namespace StyleHelper::SpacingTokens; +const qreal disabledIconOpacity = 0.3; + static QColor themeColor(Theme::Color role) { return creatorColor(role); @@ -215,16 +217,21 @@ void Button::paintEvent(QPaintEvent *event) switch (m_role) { case MediumPrimary: case SmallPrimary: { - const QBrush fill(creatorColor(isDown() - ? Theme::Token_Accent_Subtle - : hovered ? Theme::Token_Accent_Muted - : Theme::Token_Accent_Default)); + const Theme::Color color = isEnabled() ? (isDown() + ? Theme::Token_Accent_Subtle + : (hovered ? Theme::Token_Accent_Muted + : Theme::Token_Accent_Default)) + : Theme::Token_Foreground_Subtle; + const QBrush fill(creatorColor(color)); drawCardBackground(&p, bgR, fill, QPen(Qt::NoPen), brRectRounding); break; } case MediumSecondary: case SmallSecondary: { - const QPen outline(creatorColor(Theme::Token_Text_Default), hovered ? 2 : 1); + const Theme::Color color = isEnabled() ? Theme::Token_Stroke_Strong + : Theme::Token_Stroke_Subtle; + const qreal width = hovered ? 2.0 : 1.0; + const QPen outline(creatorColor(color), width); drawCardBackground(&p, bgR, QBrush(Qt::NoBrush), outline, brRectRounding); break; } @@ -259,7 +266,8 @@ void Button::paintEvent(QPaintEvent *event) const QString elidedLabelText = fm.elidedText(text(), Qt::ElideRight, availableLabelWidth); const QRect labelR(margins.left(), margins.top(), availableLabelWidth, tf.lineHeight()); p.setFont(font); - p.setPen(tf.color()); + const QColor textColor = isEnabled() ? tf.color() : creatorColor(Theme::Token_Text_Subtle); + p.setPen(textColor); p.drawText(labelR, tf.drawTextFlags, elidedLabelText); } @@ -301,7 +309,8 @@ Label::Label(const QString &text, Role role, QWidget *parent) setFixedHeight(vPadding + tF.lineHeight() + vPadding); setFont(tF.font()); QPalette pal = palette(); - pal.setColor(QPalette::WindowText, tF.color()); + pal.setColor(QPalette::Active, QPalette::WindowText, tF.color()); + pal.setColor(QPalette::Disabled, QPalette::WindowText, creatorColor(Theme::Token_Text_Subtle)); setPalette(pal); } @@ -328,7 +337,9 @@ SearchBox::SearchBox(QWidget *parent) QPalette pal = palette(); pal.setColor(QPalette::Base, Qt::transparent); - pal.setColor(QPalette::PlaceholderText, searchBoxPlaceholderTF.color()); + pal.setColor(QPalette::Active, QPalette::PlaceholderText, searchBoxPlaceholderTF.color()); + pal.setColor(QPalette::Disabled, QPalette::PlaceholderText, + creatorColor(Theme::Token_Text_Subtle)); pal.setColor(QPalette::Text, searchBoxTextTF.color()); setPalette(pal); @@ -358,12 +369,14 @@ void SearchBox::leaveEvent(QEvent *event) update(); } -static void paintCommonBackground(QPainter *p, const QRectF &rect, const QWidget *widget) +static void paintCommonBackground(QPainter *p, const QRectF &rect, const QWidget *w) { const QBrush fill(creatorColor(Theme::Token_Background_Muted)); - const Theme::Color c = widget->hasFocus() ? Theme::Token_Stroke_Strong : - widget->underMouse() ? Theme::Token_Stroke_Muted - : Theme::Token_Stroke_Subtle; + const Theme::Color c = + w->isEnabled() ? (w->hasFocus() ? Theme::Token_Stroke_Strong + : (w->underMouse() ? Theme::Token_Stroke_Muted + : Theme::Token_Stroke_Subtle)) + : Theme::Token_Foreground_Subtle; const QPen pen(creatorColor(c)); drawCardBackground(p, rect, fill, pen); } @@ -385,6 +398,8 @@ void SearchBox::paintEvent(QPaintEvent *event) const QPixmap icon = searchBoxIcon(); const QSize iconS = icon.deviceIndependentSize().toSize(); const QPoint iconPos(width() - HPaddingXs - iconS.width(), (height() - iconS.height()) / 2); + if (!isEnabled()) + p.setOpacity(disabledIconOpacity); p.drawPixmap(iconPos, icon); } @@ -450,12 +465,15 @@ void ComboBox::paintEvent(QPaintEvent *) const QRect textR(margins.left(), margins.top(), width() - margins.right(), ComboBoxTf.lineHeight()); p.setFont(ComboBoxTf.font()); - p.setPen(ComboBoxTf.color()); + const QColor color = isEnabled() ? ComboBoxTf.color() : creatorColor(Theme::Token_Text_Subtle); + p.setPen(color); p.drawText(textR, ComboBoxTf.drawTextFlags, currentText()); const QPixmap icon = comboBoxIcon(); const QSize iconS = icon.deviceIndependentSize().toSize(); const QPoint iconPos(width() - HPaddingXs - iconS.width(), (height() - iconS.height()) / 2); + if (!isEnabled()) + p.setOpacity(disabledIconOpacity); p.drawPixmap(iconPos, icon); } From 946dadfdb2a1b5273c6dcb276d3096dbd29538ed Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 2 Jan 2025 17:46:07 +0100 Subject: [PATCH 492/989] Core: Rename Button::Role::Medium* to Button::Role::Large* The variations were renamed in Figma. Follow suit here in order to stay aligned. Change-Id: I797e00a3dfcdee4302e8b0b06d13392a1c0979bd Reviewed-by: Cristian Adam --- src/plugins/coreplugin/welcomepagehelper.cpp | 24 +++++++++---------- src/plugins/coreplugin/welcomepagehelper.h | 6 ++--- .../extensionmanagerwidget.cpp | 2 +- .../projectexplorer/projectwelcomepage.cpp | 2 +- src/plugins/welcome/welcomeplugin.cpp | 4 ++-- .../tst_manual_widgets_components.cpp | 4 ++-- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index e569e8ca6e6..ead05cb3018 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -114,16 +114,16 @@ enum WidgetState { static const TextFormat &buttonTF(Button::Role role, WidgetState state) { using namespace WelcomePageHelpers; - static const TextFormat mediumPrimaryTF + static const TextFormat largePrimaryTF {Theme::Token_Basic_White, StyleHelper::UiElement::UiElementButtonMedium, Qt::AlignCenter | Qt::TextDontClip | Qt::TextShowMnemonic}; - static const TextFormat mediumSecondaryTF - {Theme::Token_Text_Default, mediumPrimaryTF.uiElement, mediumPrimaryTF.drawTextFlags}; + static const TextFormat largeSecondaryTF + {Theme::Token_Text_Default, largePrimaryTF.uiElement, largePrimaryTF.drawTextFlags}; static const TextFormat smallPrimaryTF - {mediumPrimaryTF.themeColor, StyleHelper::UiElement::UiElementButtonSmall, - mediumPrimaryTF.drawTextFlags}; + {largePrimaryTF.themeColor, StyleHelper::UiElement::UiElementButtonSmall, + largePrimaryTF.drawTextFlags}; static const TextFormat smallSecondaryTF - {mediumSecondaryTF.themeColor, smallPrimaryTF.uiElement, smallPrimaryTF.drawTextFlags}; + {largeSecondaryTF.themeColor, smallPrimaryTF.uiElement, smallPrimaryTF.drawTextFlags}; static const TextFormat smallListDefaultTF {Theme::Token_Text_Default, StyleHelper::UiElement::UiElementIconStandard, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip | Qt::TextShowMnemonic}; @@ -140,8 +140,8 @@ static const TextFormat &buttonTF(Button::Role role, WidgetState state) {Theme::Token_Text_Default, tagDefaultTF.uiElement}; switch (role) { - case Button::MediumPrimary: return mediumPrimaryTF; - case Button::MediumSecondary: return mediumSecondaryTF; + case Button::LargePrimary: return largePrimaryTF; + case Button::LargeSecondary: return largeSecondaryTF; case Button::SmallPrimary: return smallPrimaryTF; case Button::SmallSecondary: return smallSecondaryTF; case Button::SmallList: return (state == WidgetStateDefault) ? smallListDefaultTF @@ -151,7 +151,7 @@ static const TextFormat &buttonTF(Button::Role role, WidgetState state) case Button::Tag: return (state == WidgetStateDefault) ? tagDefaultTF : tagHoverTF; } - return mediumPrimaryTF; + return largePrimaryTF; } Button::Button(const QString &text, Role role, QWidget *parent) @@ -215,7 +215,7 @@ void Button::paintEvent(QPaintEvent *event) const qreal brRectRounding = 3.75; switch (m_role) { - case MediumPrimary: + case LargePrimary: case SmallPrimary: { const Theme::Color color = isEnabled() ? (isDown() ? Theme::Token_Accent_Subtle @@ -226,7 +226,7 @@ void Button::paintEvent(QPaintEvent *event) drawCardBackground(&p, bgR, fill, QPen(Qt::NoPen), brRectRounding); break; } - case MediumSecondary: + case LargeSecondary: case SmallSecondary: { const Theme::Color color = isEnabled() ? Theme::Token_Stroke_Strong : Theme::Token_Stroke_Subtle; @@ -283,7 +283,7 @@ void Button::updateMargins() setContentsMargins(HPaddingXs, VPaddingXxs, HPaddingXs, VPaddingXxs); return; } - const bool tokenSizeS = m_role == MediumPrimary || m_role == MediumSecondary + const bool tokenSizeS = m_role == LargePrimary || m_role == LargeSecondary || m_role == SmallList || m_role == SmallLink; const int gap = tokenSizeS ? HGapS : HGapXs; const int hPaddingR = tokenSizeS ? HPaddingS : HPaddingXs; diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index 8ee3f50b371..60fad31910e 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -75,8 +75,8 @@ class CORE_EXPORT Button : public QAbstractButton { public: enum Role { - MediumPrimary, - MediumSecondary, + LargePrimary, + LargeSecondary, SmallPrimary, SmallSecondary, SmallList, @@ -96,7 +96,7 @@ protected: private: void updateMargins(); - const Role m_role = MediumPrimary; + const Role m_role = LargePrimary; QPixmap m_pixmap; }; diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index bd751148ee4..280cedacb63 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -150,7 +150,7 @@ public: m_dlCount->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); m_details = new ElidingLabel; applyTf(m_details, detailsTF); - installButton = new Button(Tr::tr("Install..."), Button::MediumPrimary); + installButton = new Button(Tr::tr("Install..."), Button::LargePrimary); installButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); installButton->hide(); diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 5a82d076e24..41c41b3f78e 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -827,7 +827,7 @@ public: auto sessions = new QWidget; { auto sessionsLabel = new Core::Label(Tr::tr("Sessions"), Core::Label::Primary); - auto manageSessionsButton = new Button(Tr::tr("Manage..."), Button::MediumSecondary); + auto manageSessionsButton = new Button(Tr::tr("Manage..."), Button::LargeSecondary); auto sessionsList = new TreeView(this, "Sessions"); sessionsList->setModel(projectWelcomePage->m_sessionModel); sessionsList->header()->setSectionHidden(1, true); // The "last modified" column. diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index d364519bd3a..1b2ef235f57 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -123,8 +123,8 @@ public: }; { - auto newButton = new Button(Tr::tr("Create Project..."), Button::MediumPrimary); - auto openButton = new Button(Tr::tr("Open Project..."), Button::MediumSecondary); + auto newButton = new Button(Tr::tr("Create Project..."), Button::LargePrimary); + auto openButton = new Button(Tr::tr("Open Project..."), Button::LargeSecondary); Column projectButtons { newButton, diff --git a/tests/manual/widgets/components/tst_manual_widgets_components.cpp b/tests/manual/widgets/components/tst_manual_widgets_components.cpp index 7e8ea63d34b..654d5c127a4 100644 --- a/tests/manual/widgets/components/tst_manual_widgets_components.cpp +++ b/tests/manual/widgets/components/tst_manual_widgets_components.cpp @@ -27,8 +27,8 @@ QWidget *widgets() Group { title("Core::Button"), Column { - new Core::Button("MediumPrimary", Core::Button::MediumPrimary), - new Core::Button("MediumSecondary", Core::Button::MediumSecondary), + new Core::Button("LargePrimary", Core::Button::LargePrimary), + new Core::Button("LargeSecondary", Core::Button::LargeSecondary), new Core::Button("SmallPrimary", Core::Button::SmallPrimary), new Core::Button("SmallSecondary", Core::Button::SmallSecondary), new Core::Button("SmallList", Core::Button::SmallList), From f29bbc1cade6ba49259c156680e8aa148218753d Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Thu, 2 Jan 2025 09:54:33 +0100 Subject: [PATCH 493/989] qmlls: make a warning translatable Add a missing Tr::tr() to make the warning translatable. Amends c783ac4f8192248289d0e74159ede54862b020b4. Task-number: QTCREATORBUG-31897 Change-Id: Iaf86dbae222fc355ba78b5c7637c3f319634a810 Reviewed-by: David Schulz --- src/plugins/qmljseditor/qmllsclientsettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index ce629ba5d1d..dd8f62e07dc 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -158,7 +158,7 @@ bool QmllsClientSettings::isValidOnProject(ProjectExplorer::Project *project) co if (!qtVersionFromProject(project)) { Core::MessageManager::writeSilently( - "Current kit does not have a valid Qt version, disabling QML Language Server..."); + Tr::tr("Current kit does not have a valid Qt version, disabling QML Language Server...")); return false; } From a28d4b010e60423629e7012bdf30cad3ccdcd293 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 13 Nov 2024 16:49:59 +0100 Subject: [PATCH 494/989] Doc: Describe how to install Windows App SDK Create a how-to category for SDKs and also add the Android SDK and NDK topics there. Task-number: QTCREATORBUG-32016 Change-Id: I2731662e58a7b34c871ad1e0825e8868058ebe82 Reviewed-by: Morteza Jamshidi Reviewed-by: Oliver Wolff --- ...qtcreator-preferences-windows-app-sdk.webp | Bin 0 -> 5556 bytes .../src/creator-how-to-set-up-winappsdk.qdoc | 35 ++++++++++++++++++ .../external-resources.qdoc | 8 ++++ .../howto/creator-only/creator-how-tos.qdoc | 6 +++ doc/qtcreator/src/qtcreator-toc.qdoc | 2 + 5 files changed, 51 insertions(+) create mode 100644 doc/qtcreator/images/qtcreator-preferences-windows-app-sdk.webp create mode 100644 doc/qtcreator/src/creator-how-to-set-up-winappsdk.qdoc diff --git a/doc/qtcreator/images/qtcreator-preferences-windows-app-sdk.webp b/doc/qtcreator/images/qtcreator-preferences-windows-app-sdk.webp new file mode 100644 index 0000000000000000000000000000000000000000..605f45eb2f00c3b03d9d6cb87297c60ba9ce1051 GIT binary patch literal 5556 zcmWIYbaPuH%D@or>J$(bVBxbslz~A%_>d>V*9X(K{V$ZZEZ-Lr&Q*pV z_gh{mT=^vDKBM=N{)#sRXAW}eH@ke)oAZnB%m3DY252}+2#l^ShjuJ zPTA{c-p02%Clv0kt3I6b@_K&y0i9Icd~g35dbOI&&*prcQ+=r9<@0y9yIR7Wk2)?l zc8D*2dvWJm zbCN699X`HLeui1aEY%drw)pCpt4zw3f^EvBkJ_!)&aeBhb?5X84y#oQJ^SaZnkAO= zUn?=!z>eW)_FAi;c>!Jh&mKRxljUMZ*lm@&9*TUr{ZuY&N9PZcHN{gK<{M<5nC*4#{I4LB$$?i7b_GUpZ~AJ$obWGV-udUc z%NG8Os!8QHG*7MAAyH?|_b*wz!8EDWWWr(X?D*NUugtmoYPr1QyS1#!EM7kil2%QW zanxOYC81J4ZOW^KU)J1>@|0Q_(%&I^o^fHC0bkK6b=!r1@_$a5dUGDfBbVcEn~OIz z8hwyx40^QN#H8P9ny_6A&wHn=E6-b5LR+u6B=vl-n74WRXQxMHa_N8nh@45|RWK^m zeYyHyOUtDA+0~iXoEL=h&z367UVD|>{gun&v(EloS1YWX$zp%z*I6s`6^ANr`R^}X zq+Bv_-XQ^_h_4n=tHje7I!u#Tt=Ow$7Td+oS)KOW^v>a1aD~IsjDoEV%w<~Vq-7CuKz`Sp@eX;T`b?>99i|;?e0}dne$#J zPGS>0^6qL48^axI`|e5WB^E6ddagXrYy0Yuo`uq4icA}8#pm2Lb$Z)6v44s9HK9kp ze-xxM7^?rjUv+86`qJ?D7ac5NwkBJ(F7j<-G1xw7-V4pRxv_U`ZWR3$c|IjW>TBiU z8C#@Y_(=YID|F-Qn}rYWyj>+2mZpF3P34B8hx87_Mn+6$kbmD_&!RAS6~Co-l@QN7 zwh344?(xH}5=eVfXAJ*{uHUAVWi_xO#R$4|TY%a`%ISed{u zCy#UKD@E@cAtjT&e+ra2yq@i~@Z-AImm3WlLsp4Tns?$rWc%L1KQG zywIk8?HesAOLv{7?tPxV+Y;_3E#u z%Txqx*Q)T!nB-2B@o(B1rhi4>{HUXd>B1{YkqM4PdsuIrj^6cjSwzR8sgYBAVmd{Z zKRQsf;J4Mm*}LlM=U=H|+s7g2zgxAP%XZ$fv_H@9z52uUM{vi(Z#oZSH*8N{yiI(m zQP)K2Jl9X6f2C@q@@_7R<&5jy!}zUEbXpx#&Xs9$cR#b;_$g9zKJ4wGKKBEn)rCj3 z9~@#o820v%?dc7!YxgPW`@YS(CsF%Ftu%b)$!+hvI~Um?|J zQOpQ-iW~-(+c*(dP7SEJ%o#;75y>Rlp zT29?t%U5e?Re4e$0~% zcU5-jt4i(jXt%y2pX-zL?d)Rda@9{;jBZ{_T_d`5>w@U6OExE_Em{|S;Pk;wrD?)v z53+6jRpEN#oMiZx{@|9Q&CV7~QYSJ#E&L*SJ9o~%KbN+o`ELCnk&=*DK7(^wzsgd(L6Ln8)?&_%EGm$f5 zj#72IE26enuRpwKe^6J$)u52Z&l?~7&{%QtjkEuwC+n29_&CXwCeN7fXjvsD61M%6 zlgLZXb9~Hwp`tG9nx{3z?7bs(mTO~N%Dbzn6K}qiKQ{NGRp0IDnd^>&EwmE7erSUB zt>apcyd*xFpV^}ItJzvh)ufl{g-g!#p8DTT%1?F$6h2=nU7Pv-i=EZ|?g#hsIG?{w zbErC`-ZA5{(?4(ix65no_>9z@mqg5*BW-T7aOEz>#RAXPY+DmH-)2k3e4S0JPabkjKmV!mtT`;clFi_o=8u~~|9vnpDwi*&N?%aC8)aX{Zil=nj3qZB!_wkOvz5}2+Ugo>3hzI%0O zS7ApXzmvht@MMqZOP8Ve_&gF;&)(p<)^3ex_WMHD z-xjV$3w8>w>s~merC0Igg{6AaRxEm)edoTLu_E*d5!gI(@2JxOx)&o3*N zJCB_b>iw`(x>l2CjzatBv`sP<#Y)mf{3Y?_r;&fcTx^GZgz^Zjj^^;)4ypZg?2)wXi$uQ!jir$#b#_uO#PN?$W^iQcBZs6ayrzon}WE>k^u$}2{*@OfhE@n2@g z`$Ge_u?D)%k$?0%uq9&EJk2xfxH>8-x)dsp+|sJ+d&utS9xak6sNuBe;7qZAv##;~ z82(NRP`KBBE@7s|s}d_0mybfCf;yW!E^b<(r~7zjw}V;fNM`t@y@^MdUFNNm4)l{|>~7## z*>)v`v2=O%+{}o}M(-ad@GZOcYV+jvAvVuE9H->WnbtnjY~tMzu^Ojv%|r)2;fJ7# zBfWh7*|1NsGYZU@B}=wmT(11EepTPrhAg≥2(~OPRNFM%3!_Zu^2NJ9rgS+;TpKRKqXG)3B{#b92hi4)Jf{@q7Tzsfojuy4M@k%__#e$whw zbk-a@x4j{Y;dR}`vc)sg&7h7FOH!UX!|UkbnX__s%S$pHHJJDGM4r~Y(43}q9VJt> z7FvApGCP#Ffxoe~T%3KyBaZHVGe>1(so=sVjt{n6%s9TeT1HW9$}F7)?`r0EIyl*_ zIJ&5F(czZhuvMBD{a6DclqEF;WX^er#=8W`F$flWt(>T{{=o!orJX*X3T6h?ER8as zIyL`AeEi|X%NBB+tx&kIXV$GZRZ<7<=`KwO+I(U6x;Zz0o()Q=ynRP2y)MV5=~;lf ziLrdkl`O`o$p_!*mfqQs#l6D%dCvKrQyM|JS!Y%WC^v&LevcY&rEl#u)o2G(v9mlv zphDsMtXF}RzMvv&=cItHFpIovKc#MX^eFBswfxXt+jzf@HEPD{b1x>Y*fF>8(USgI z?UxT9ah|U(sm}LnMP-ETOntv!D=ItW_KB1`{o68SmA6ahqEm0o3a_}IUA%bt%gNF+ zH3CCs%J%(QQ7K`&L%`Tk>(re2FCQN1pQRpsymba|!=h7f3a+@HJ^V8Br;JhHq7_EF zv)7&j8@WuxJWgLwbywN6kMaB6PkL2v+IR84^g(Z?+9EeOVeQQq&eyV4gIxZb=|SZ8 zC!$xs=>=crb`^gLWxYG8z3Ol5vSs2ilfy&Uclh|~FNs{gLbFFZv#sRyL8H>G+}~Xe z2X6hf=JTqo{&MlD6*?+mAs5XLgvlM8uMyO`^`%9atJDUeHO5yfU29u+{gScr77m)f z^VMswsd?*Trd`~$?8?E3q6J?fJ`1Kz4&x~GpVhfI>+41jH?@APVB#E)t27mIVaMm>Wk_^_xEQ4 zYCIOX?-6?LbIfz=FP$T5@Aa}6mDj9zHPhoYU-^zew^be6yf~GdK6SKtb#6X0{n4I9 zO6R98&J}VhXXBVWEmd;mrnMHcM33%ReEZh&B3Zp(rw(PJ6T>s`grC=+<9% zU9U1n2c|CR&^To!aJ?@=?pnk5!oi%von7=8nmG&)o9ZbIqrZe z*~n>s&2<+fT@v1;c4`+l@4weq9GYHQtPGpq8W*~@t~{`GL0HJiFWmkdo*Qgp%^rt5 z7v1{V>ub@a*)dMu3q`&N%ygM{CArZ(M8b#t#dg1^EgF|5cSMHXd=a`e*~)L#)%1no zp{wu5hQxM=yPx3h9ZB43v9 zbcz>mIFiM)zv}Uqx~|V%S-#IsEbEOqH=}oP*4N1Ap;v#Ei;Mn``57_w2iMV={()qk9>+kOFThsd@Cy0g$TnP1A8Nntf zx-lr`kkpB~i1e(_U0im7%Udkx1gunwgNz6DS`7PEhb#UU@`b}O{MvpkYyweHV79Qfh zjo;vc)c2{a;+G~HPG6b%?EbpTYs0Txxq5D?EpaR=o}`ntz+|0W$fXPK0=#;Cqt^U!_VK%4Qq&`7>oR58 zrWL|nuNmbl93BOj=jq;6Cb_CKBna&}3p7k6}C{BvW;(=P@eCp_=m880PQRFQM(Qa}v$!DjTNuWtdyyXsqV7T3pCwqeI1i8;Q9$RbQf24brd)1-l zTK?us{w#_`GcGnST3Nf|jGvaN;lJvjm2+IC_=Kb`O(>YVAXvNM0+U>P;T8>%?MLQT z&bPc^S*0T`_2tK-Z^u9Me|YZjZS$P_xpzM1?*H_gzkcDFkJ6Xp#jmTm&24p+d37?T zTJYSFKi_t>iEGu&_$}T#EmLClmbYK;Dap<{A|>H3t$u&Uw}i^ZFD>jwyfuB3Ul?A# zxcP>%xly1|;MR@H2|GfPs_|vIe=h+1ruSKG^ z6A$J)@_0{p?R50WiqDVV*RHUxEOwmp{$lDzyLS1_oBXSkGXE{oS7^T3|M1WJi_DAH zo)T19^kh*~h}U6d-w2JJ51k5q@5ChVnUw4NeC+-07rTRX=|*5(P!Hp%?mSTpJhGm%a2d>=WeBJH?FTOsBN=-f9-=o^))V?KThi}#I=_SUpV~x zad52>^EZWq9{x@C;Y@!+I*!agQvBwZ^mPkc^=cVVa4hVU>3)CFaZeb7sL7OLYgx;g zZ9kl8Ja&B2qUzj-8aF;hX)lr9b?)e;xGN2Liyn$!P}Pa>Uzf)@(bh^}->ND1)odp= z8ngdyj4@K(U)cM~u{dL0?6KFXi(CR97VmpG?SFp7h0cIyyJnnk`Lr \uicontrol SDKs > \uicontrol {Windows App SDK}. + \image qtcreator-preferences-windows-app-sdk.webp {Win App SDK Preferences} + \li In \uicontrol {Download location}, specify the path to a folder where + NuGet and the SDK will be downloaded. + \li In \uicontrol {NuGet location}, specify the path to NuGet, or + select \uicontrol {Download NuGet} to automatically download and + install NuGet. + \li In \uicontrol {Windows App SDK location} specify the directory where + the SDK is installed, or select \uicontrol {Download WindowsAppSDK} + to automatically download and install the SDK with NuGet. + \endlist +*/ diff --git a/doc/qtcreator/src/external-resources/external-resources.qdoc b/doc/qtcreator/src/external-resources/external-resources.qdoc index c4e4ec852b2..2260a760b7d 100644 --- a/doc/qtcreator/src/external-resources/external-resources.qdoc +++ b/doc/qtcreator/src/external-resources/external-resources.qdoc @@ -129,6 +129,14 @@ \externalpage http://developer.android.com/guide/components/fundamentals.html \title Android Application Fundamentals */ +/*! + \externalpage https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/downloads + \title Latest Windows App SDK downloads +*/ +/*! + \externalpage https://www.nuget.org/downloads + \title Available NuGet Distribution Versions +*/ /*! \externalpage https://doc.qt.io/qt/qtquicktest-index.html#executing-c-before-qml-tests \title Executing C++ Before QML Tests diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc index a3ff886b09a..b9d30dac9c0 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc @@ -141,6 +141,12 @@ \generatelist creator-how-to-remote-linux + \section2 SDKs + + Manage SDKs for application development for different platforms. + + \generatelist creator-how-to-sdks + \section2 VxWorks Build \l {Qt for VxWorks}, and create VxWorks build and run kits. diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index be259080797..abb0fbb189c 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -62,6 +62,8 @@ \generatelist creator-how-to-qnx \li Remote Linux \generatelist creator-how-to-remote-linux + \li SDKs + \generatelist creator-how-to-sdks \li WebAssembly \generatelist creator-how-to-webassembly \li VxWorks From 881b6f8c7bd23b024f22909096d0ba961ed8169c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20K=C3=B6hne?= Date: Fri, 3 Jan 2025 12:47:57 +0100 Subject: [PATCH 495/989] Fix typo in QmlDesignerBasePlugin function name Change-Id: Ia98224e254d8b131bbb4ad37916773c808f5e6de Reviewed-by: Marco Bubke --- src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp | 4 ++-- src/plugins/qmldesignerbase/qmldesignerbaseplugin.h | 2 +- src/plugins/qmldesignerlite/qmldesignerliteplugin.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp index 888b3fa0397..ceb19e7b7fd 100644 --- a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp +++ b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp @@ -77,7 +77,7 @@ QByteArray QmlDesignerBasePlugin::experimentalFeaturesSettingsKey() return QByteArray(experimentalFeatures) + version.toLatin1(); } -void QmlDesignerBasePlugin::enbableLiteMode() +void QmlDesignerBasePlugin::enableLiteMode() { global->m_enableLiteMode = true; } @@ -90,7 +90,7 @@ bool QmlDesignerBasePlugin::isLiteModeEnabled() bool QmlDesignerBasePlugin::initialize(const QStringList &arguments, QString *) { if (arguments.contains("-qml-lite-designer")) - enbableLiteMode(); + enableLiteMode(); WindowManager::registerDeclarativeType(); StudioQuickUtils::registerDeclarativeType(); diff --git a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h index a8dc5a7f423..5787ac5e6b3 100644 --- a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h +++ b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h @@ -33,7 +33,7 @@ public: static bool experimentalFeaturesEnabled(); static QByteArray experimentalFeaturesSettingsKey(); - static void enbableLiteMode(); + static void enableLiteMode(); static bool isLiteModeEnabled(); private: diff --git a/src/plugins/qmldesignerlite/qmldesignerliteplugin.cpp b/src/plugins/qmldesignerlite/qmldesignerliteplugin.cpp index 4414b92f7ca..2903ff1206b 100644 --- a/src/plugins/qmldesignerlite/qmldesignerliteplugin.cpp +++ b/src/plugins/qmldesignerlite/qmldesignerliteplugin.cpp @@ -9,7 +9,7 @@ namespace QmlDesigner { QmlDesignerLitePlugin::QmlDesignerLitePlugin() { - QmlDesignerBasePlugin::enbableLiteMode(); + QmlDesignerBasePlugin::enableLiteMode(); } QmlDesignerLitePlugin::~QmlDesignerLitePlugin() = default; From dcbfc31b4193a32b497af819840b29b0863ee184 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 3 Jan 2025 17:27:21 +0100 Subject: [PATCH 496/989] Core: Implement "Tertiary" Figma-designed button variant Fixes: QTCREATORBUG-32285 Change-Id: Ic3214b7d88eb568a59488211161a6d544602bb3e Reviewed-by: Cristian Adam --- src/plugins/coreplugin/welcomepagehelper.cpp | 19 +++++++++++++++++-- src/plugins/coreplugin/welcomepagehelper.h | 2 ++ .../tst_manual_widgets_components.cpp | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index ead05cb3018..7dc4fb89beb 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -141,9 +141,13 @@ static const TextFormat &buttonTF(Button::Role role, WidgetState state) switch (role) { case Button::LargePrimary: return largePrimaryTF; - case Button::LargeSecondary: return largeSecondaryTF; + case Button::LargeSecondary: + case Button::LargeTertiary: + return largeSecondaryTF; case Button::SmallPrimary: return smallPrimaryTF; - case Button::SmallSecondary: return smallSecondaryTF; + case Button::SmallSecondary: + case Button::SmallTertiary: + return smallSecondaryTF; case Button::SmallList: return (state == WidgetStateDefault) ? smallListDefaultTF : smallListCheckedTF; case Button::SmallLink: return (state == WidgetStateDefault) ? smallLinkDefaultTF @@ -235,6 +239,17 @@ void Button::paintEvent(QPaintEvent *event) drawCardBackground(&p, bgR, QBrush(Qt::NoBrush), outline, brRectRounding); break; } + case LargeTertiary: + case SmallTertiary: { + const Theme::Color border = isDown() ? Theme::Token_Stroke_Muted + : Theme::Token_Stroke_Subtle; + const Theme::Color bg = isEnabled() ? (isDown() ? Theme::Token_Foreground_Default + : (hovered ? Theme::Token_Foreground_Muted + : Theme::Token_Foreground_Subtle)) + : Theme::Token_Foreground_Subtle; + drawCardBackground(&p, bgR, creatorColor(bg), creatorColor(border), brRectRounding); + break; + } case SmallList: { if (isChecked() || hovered) { const QBrush fill(creatorColor(isChecked() ? Theme::Token_Foreground_Muted diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index 60fad31910e..a95c2cef9ea 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -77,8 +77,10 @@ public: enum Role { LargePrimary, LargeSecondary, + LargeTertiary, SmallPrimary, SmallSecondary, + SmallTertiary, SmallList, SmallLink, Tag, diff --git a/tests/manual/widgets/components/tst_manual_widgets_components.cpp b/tests/manual/widgets/components/tst_manual_widgets_components.cpp index 654d5c127a4..8cf6b4d742b 100644 --- a/tests/manual/widgets/components/tst_manual_widgets_components.cpp +++ b/tests/manual/widgets/components/tst_manual_widgets_components.cpp @@ -29,8 +29,10 @@ QWidget *widgets() Column { new Core::Button("LargePrimary", Core::Button::LargePrimary), new Core::Button("LargeSecondary", Core::Button::LargeSecondary), + new Core::Button("LargeTertiary", Core::Button::LargeTertiary), new Core::Button("SmallPrimary", Core::Button::SmallPrimary), new Core::Button("SmallSecondary", Core::Button::SmallSecondary), + new Core::Button("SmallTertiary", Core::Button::SmallTertiary), new Core::Button("SmallList", Core::Button::SmallList), new Core::Button("SmallLink", Core::Button::SmallLink), new Core::Button("Tag", Core::Button::Tag), From 7a8dfd2ce3a692d578c220abd363149f954fe04a Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Fri, 3 Jan 2025 12:51:05 +0100 Subject: [PATCH 497/989] qmlls: don't pass import paths for qmlls < 6.8 Add a missing braces to avoid passing import path to qmlls versions that don't support it. Task-number: QTCREATORBUG-31897 Change-Id: Ia247ebe34790a2b5cf93ffd6080e0784ee317ee7 Reviewed-by: David Schulz --- src/plugins/qmljseditor/qmllsclientsettings.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index dd8f62e07dc..acccea6e07c 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -130,15 +130,16 @@ static CommandLine commandLineForQmlls(Project *project) result.addArgs({"-b", configuration->buildDirectory().path()}); // qmlls 6.8 and later require the import path - if (version >= QVersionNumber(6, 8, 0)) + if (version >= QVersionNumber(6, 8, 0)) { result.addArgs({"-I", qtVersion->qmlPath().path()}); - // add custom import paths that the embedded codemodel uses too - const QmlJS::ModelManagerInterface::ProjectInfo projectInfo - = QmlJS::ModelManagerInterface::instance()->projectInfo(project); - for (QmlJS::PathAndLanguage path : projectInfo.importPaths) { - if (path.language() == QmlJS::Dialect::Qml) - result.addArgs({"-I", path.path().path()}); + // add custom import paths that the embedded codemodel uses too + const QmlJS::ModelManagerInterface::ProjectInfo projectInfo + = QmlJS::ModelManagerInterface::instance()->projectInfo(project); + for (QmlJS::PathAndLanguage path : projectInfo.importPaths) { + if (path.language() == QmlJS::Dialect::Qml) + result.addArgs({"-I", path.path().path()}); + } } // qmlls 6.8.1 and later require the documentation path From 70a0cf16011da2ff1139da9dd151b07b5410aad0 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Fri, 3 Jan 2025 12:51:05 +0100 Subject: [PATCH 498/989] qmlls: be invalid if no qmlls was found Make the qmlls client invalid if it can't find the latest qmlls version (if there is no qmlls version installed for example). Task-number: QTCREATORBUG-31897 Change-Id: I74fa72bd2a95126a2a091f88c64dfa60155e4508 Reviewed-by: David Schulz --- src/plugins/qmljseditor/qmllsclientsettings.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index acccea6e07c..13033617891 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -163,6 +163,9 @@ bool QmllsClientSettings::isValidOnProject(ProjectExplorer::Project *project) co return false; } + if (m_useLatestQmlls && evaluateLatestQmlls().first.isEmpty()) + return false; + return true; } From cb8097793716a458335c253c54072aea39ac7c39 Mon Sep 17 00:00:00 2001 From: Sami Shalayel Date: Fri, 3 Jan 2025 12:53:46 +0100 Subject: [PATCH 499/989] qmlls: display executable path after name Add the executable path of qmlls after its name, so that it is actually displayed to the user which version of qmlls it is currently using. This should help us when/if users will report more bugs with qmlls in the future. Task-number: QTCREATORBUG-31897 Change-Id: I5fded78cd5c0c2a3a2f4b40128d3668c5720709e Reviewed-by: David Schulz --- .../languageclient/languageclientsettings.cpp | 5 ++++- src/plugins/qmljseditor/qmllsclientsettings.cpp | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 011bee64963..26a7a860a76 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -618,7 +618,10 @@ Client *BaseSettings::createClient(ProjectExplorer::Project *project) const BaseClientInterface *interface = createInterface(project); QTC_ASSERT(interface, return nullptr); auto *client = createClient(interface); - client->setName(Utils::globalMacroExpander()->expand(m_name)); + + if (client->name().isEmpty()) + client->setName(Utils::globalMacroExpander()->expand(m_name)); + client->setSupportedLanguage(m_languageFilter); client->setInitializationOptions(initializationOptions()); client->setActivateDocumentAutomatically(true); diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index 13033617891..4a7a72b2b93 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -169,16 +169,27 @@ bool QmllsClientSettings::isValidOnProject(ProjectExplorer::Project *project) co return true; } +class QmllsClientInterface : public StdIOClientInterface +{ +public: + FilePath qmllsFilePath() const { return m_cmd.executable(); } +}; + BaseClientInterface *QmllsClientSettings::createInterface(Project *project) const { - auto interface = new StdIOClientInterface; + auto interface = new QmllsClientInterface; interface->setCommandLine(commandLineForQmlls(project)); return interface; } Client *QmllsClientSettings::createClient(BaseClientInterface *interface) const { - return new QmllsClient(static_cast(interface)); + auto qmllsInterface = static_cast(interface); + auto client = new QmllsClient(qmllsInterface); + const QString name = QString("%1 (%2)").arg( + Utils::globalMacroExpander()->expand(m_name), qmllsInterface->qmllsFilePath().toString()); + client->setName(name); + return client; } class QmllsClientSettingsWidget : public QWidget From 0c5c42a6d68a3a77b5761204298926a18407cc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20De=20Canni=C3=A8re?= Date: Fri, 3 Jan 2025 16:50:16 +0100 Subject: [PATCH 500/989] About: Fix typo Amends 810a855b427cabb098afa3f6171ed7648476778d Change-Id: Ie20b77f06768ddea42ead137bd6bffc29c73618f Reviewed-by: Alessandro Portale Reviewed-by: Eike Ziller --- src/plugins/coreplugin/icore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 4720d548b81..266eae04cf2 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -1313,7 +1313,7 @@ QString ICore::aboutInformationHtml() wrapBr(appInfo.copyright)) + br + Tr::tr("The Qt logo, axivion stopping software erosion logo, Qt Group logo, as well as " - "Qt®, Axivion®, avixion stopping software erosion®, Boot to Qt®, Built with " + "Qt®, Axivion®, axivion stopping software erosion®, Boot to Qt®, Built with " "Qt®, Coco®, froglogic®, Qt Cloud Services®, Qt Developer Days®, Qt Embedded®, " "Qt Enterprise®, Qt Group®, Qt Mobile®, Qt Quick®, Qt Quick Compiler®, Squish® " "are registered trademarks of The Qt Company Ltd. or its subsidiaries."); From bcdf7d71b6e23c17f3a9963264c6025b8747fa93 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 11 Dec 2024 11:46:34 +0100 Subject: [PATCH 501/989] Utils: Remove parent argument from FileUtils dialogs Some were using ICore::dialogParent() directly and the 'nullptr' users were using that implicitly, but quite a few actually effectively changed now from some local widget to (implicit) ICore::dialogParent(). Change-Id: Ibb2767b1289221dd26757361235ee88df4a1695e Reviewed-by: Eike Ziller --- src/libs/utils/checkablemessagebox.cpp | 24 ++++-------- src/libs/utils/checkablemessagebox.h | 4 -- src/libs/utils/fileutils.cpp | 37 +++++++------------ src/libs/utils/fileutils.h | 8 +--- src/libs/utils/guiutils.cpp | 4 +- src/libs/utils/guiutils.h | 2 +- src/libs/utils/pathchooser.cpp | 15 +++----- src/libs/utils/pathlisteditor.cpp | 2 +- src/plugins/android/androiddeployqtstep.cpp | 3 +- src/plugins/android/androidmanifesteditor.cpp | 1 - .../android/keystorecertificatedialog.cpp | 2 +- src/plugins/android/manifestwizard.cpp | 2 +- .../android/splashscreencontainerwidget.cpp | 8 ++-- src/plugins/autotest/testresultspane.cpp | 2 +- src/plugins/axivion/axivionperspective.cpp | 3 +- .../clangformatglobalconfigwidget.cpp | 2 - src/plugins/clangtools/clangtool.cpp | 6 +-- src/plugins/clangtools/clangtoolsutils.cpp | 3 +- .../cmakebuildconfiguration.cpp | 1 - .../cmakeprojectmanager.cpp | 2 - .../coreplugin/dialogs/shortcutsettings.cpp | 3 +- src/plugins/coreplugin/documentmanager.cpp | 4 +- .../editormanager/editormanager.cpp | 2 +- src/plugins/coreplugin/icore.cpp | 1 - .../coreplugin/locator/directoryfilter.cpp | 4 +- .../coreplugin/locator/filesystemfilter.cpp | 3 +- src/plugins/coreplugin/loggingviewer.cpp | 16 +++----- src/plugins/coreplugin/outputwindow.cpp | 2 +- .../coreplugin/plugininstallwizard.cpp | 2 +- src/plugins/cppeditor/cppfilesettingspage.cpp | 2 +- src/plugins/debugger/breakhandler.cpp | 3 +- src/plugins/debugger/cdb/cdbengine.cpp | 4 +- src/plugins/debugger/debuggerengine.cpp | 1 - src/plugins/debugger/debuggerplugin.cpp | 5 +-- src/plugins/debugger/debuggerruncontrol.cpp | 1 - .../debuggersourcepathmappingwidget.cpp | 2 +- src/plugins/debugger/logwindow.cpp | 8 ++-- src/plugins/debugger/watchhandler.cpp | 1 - src/plugins/diffeditor/diffeditorplugin.cpp | 4 +- src/plugins/fossil/fossilplugin.cpp | 2 +- src/plugins/git/gerrit/gerritplugin.cpp | 2 +- src/plugins/git/gitclient.cpp | 2 - src/plugins/help/docsettingspage.cpp | 3 +- src/plugins/help/generalsettingspage.cpp | 6 +-- src/plugins/languageclient/lspinspector.cpp | 2 +- src/plugins/modeleditor/modeleditor.cpp | 1 - src/plugins/perforce/perforceplugin.cpp | 4 +- src/plugins/perfprofiler/perfloaddialog.cpp | 5 +-- src/plugins/perfprofiler/perfprofilertool.cpp | 4 +- .../projectexplorer/environmentwidget.cpp | 4 +- .../kitmanagerconfigwidget.cpp | 2 +- .../projectexplorer/parseissuesdialog.cpp | 2 +- src/plugins/projectexplorer/project.cpp | 3 +- .../projectexplorer/projectexplorer.cpp | 10 ++--- src/plugins/projectexplorer/projectwindow.cpp | 2 +- src/plugins/projectexplorer/runcontrol.cpp | 3 +- .../propertyeditor/aligndistribute.cpp | 1 - .../libs/qmldesignerutils/fileextractor.cpp | 3 +- src/plugins/qmlprofiler/qmlprofilertool.cpp | 4 +- src/plugins/qnx/qnxsettingspage.cpp | 2 +- src/plugins/qtsupport/qtoptionspage.cpp | 6 +-- .../remotelinux/publickeydeploymentdialog.cpp | 2 +- .../remotelinux/sshkeycreationdialog.cpp | 2 +- src/plugins/screenrecorder/cropandtrim.cpp | 2 +- src/plugins/screenrecorder/export.cpp | 2 +- src/plugins/screenrecorder/record.cpp | 3 +- src/plugins/scxmleditor/common/mainwidget.cpp | 6 +-- .../scxmleditor/outputpane/errorwidget.cpp | 2 +- src/plugins/squish/squishfilehandler.cpp | 2 +- src/plugins/squish/squishnavigationwidget.cpp | 5 +-- src/plugins/squish/squishsettings.cpp | 6 +-- src/plugins/studiowelcome/qdsnewdialog.cpp | 3 +- src/plugins/terminal/terminalsettings.cpp | 1 - src/plugins/texteditor/bookmarkmanager.cpp | 3 +- .../texteditor/codestyleselectorwidget.cpp | 3 +- src/plugins/texteditor/fontsettingspage.cpp | 6 +-- src/plugins/valgrind/callgrindtool.cpp | 1 - src/plugins/valgrind/memchecktool.cpp | 2 - src/plugins/valgrind/valgrindsettings.cpp | 2 +- src/plugins/vcsbase/vcsbaseplugin.cpp | 2 +- .../crashhandlerdialog.cpp | 3 +- 81 files changed, 118 insertions(+), 212 deletions(-) diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp index 1d721e04c86..67c929952f1 100644 --- a/src/libs/utils/checkablemessagebox.cpp +++ b/src/libs/utils/checkablemessagebox.cpp @@ -80,7 +80,6 @@ static void prepare(QMessageBox::Icon icon, } static QMessageBox::StandardButton exec( - QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &text, @@ -96,7 +95,7 @@ static QMessageBox::StandardButton exec( return acceptButton; } - QMessageBox msgBox(dialogParent(parent)); + QMessageBox msgBox(dialogParent()); prepare(icon, title, text, decider, buttons, defaultButton, buttonTextOverrides, msg, msgBox); msgBox.exec(); @@ -108,8 +107,7 @@ static QMessageBox::StandardButton exec( return clickedBtn; } -static void show(QWidget *parent, - QMessageBox::Icon icon, +static void show(QMessageBox::Icon icon, const QString &title, const QString &text, CheckableDecider decider, @@ -132,7 +130,7 @@ static void show(QWidget *parent, return; } - QMessageBox *msgBox = new QMessageBox(dialogParent(parent)); + QMessageBox *msgBox = new QMessageBox(dialogParent()); prepare(icon, title, text, decider, buttons, defaultButton, buttonTextOverrides, msg, *msgBox); std::optional> guardPtr; @@ -183,7 +181,6 @@ CheckableDecider::CheckableDecider(bool *storage) } QMessageBox::StandardButton CheckableMessageBox::question( - QWidget *parent, const QString &title, const QString &question, const CheckableDecider &decider, @@ -193,8 +190,7 @@ QMessageBox::StandardButton CheckableMessageBox::question( QMap buttonTextOverrides, const QString &msg) { - return exec(parent, - QMessageBox::Question, + return exec(QMessageBox::Question, title, question, decider, @@ -206,7 +202,6 @@ QMessageBox::StandardButton CheckableMessageBox::question( } void CheckableMessageBox::question_async( - QWidget *parent, const QString &title, const QString &question, const CheckableDecider &decider, @@ -218,8 +213,7 @@ void CheckableMessageBox::question_async( QMap buttonTextOverrides, const QString &msg) { - show(parent, - QMessageBox::Question, + show(QMessageBox::Question, title, question, decider, @@ -233,7 +227,6 @@ void CheckableMessageBox::question_async( } QMessageBox::StandardButton CheckableMessageBox::information( - QWidget *parent, const QString &title, const QString &text, const CheckableDecider &decider, @@ -242,8 +235,7 @@ QMessageBox::StandardButton CheckableMessageBox::information( QMap buttonTextOverrides, const QString &msg) { - return exec(parent, - QMessageBox::Information, + return exec(QMessageBox::Information, title, text, decider, @@ -255,7 +247,6 @@ QMessageBox::StandardButton CheckableMessageBox::information( } void CheckableMessageBox::information_async( - QWidget *parent, const QString &title, const QString &text, const CheckableDecider &decider, @@ -266,8 +257,7 @@ void CheckableMessageBox::information_async( QMap buttonTextOverrides, const QString &msg) { - show(parent, - QMessageBox::Information, + show(QMessageBox::Information, title, text, decider, diff --git a/src/libs/utils/checkablemessagebox.h b/src/libs/utils/checkablemessagebox.h index 364860e39f1..42b53dabeb0 100644 --- a/src/libs/utils/checkablemessagebox.h +++ b/src/libs/utils/checkablemessagebox.h @@ -31,7 +31,6 @@ class QTCREATOR_UTILS_EXPORT CheckableMessageBox { public: static QMessageBox::StandardButton question( - QWidget *parent, const QString &title, const QString &question, const CheckableDecider &decider, @@ -42,7 +41,6 @@ public: const QString &msg = {}); static void question_async( - QWidget *parent, const QString &title, const QString &question, const CheckableDecider &decider, @@ -55,7 +53,6 @@ public: const QString &msg = {}); static QMessageBox::StandardButton information( - QWidget *parent, const QString &title, const QString &text, const CheckableDecider &decider, @@ -65,7 +62,6 @@ public: const QString &msg = {}); static void information_async( - QWidget *parent, const QString &title, const QString &text, const CheckableDecider &decider, diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 626b0e08fe8..e0f48d7234f 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -311,10 +311,8 @@ TempFileSaver::~TempFileSaver() namespace FileUtils { #ifdef QT_GUI_LIB -CopyAskingForOverwrite::CopyAskingForOverwrite(QWidget *dialogParent, - const std::function &postOperation) - : m_parent(dialogParent) - , m_postOperation(postOperation) +CopyAskingForOverwrite::CopyAskingForOverwrite(const std::function &postOperation) + : m_postOperation(postOperation) {} CopyHelper CopyAskingForOverwrite::operator()() @@ -326,7 +324,7 @@ CopyHelper CopyAskingForOverwrite::operator()() copyFile = false; else if (!m_overwriteAll) { const int res = QMessageBox::question( - m_parent, + dialogParent(), Tr::tr("Overwrite File?"), Tr::tr("Overwrite existing file \"%1\"?").arg(dest.toUserOutput()), QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No @@ -454,8 +452,7 @@ static void prepareNonNativeDialog(QFileDialog &dialog) } } -FilePaths getFilePaths(QWidget *parent, - const QString &caption, +FilePaths getFilePaths(const QString &caption, const FilePath &dir, const QString &filter, QString *selectedFilter, @@ -465,7 +462,7 @@ FilePaths getFilePaths(QWidget *parent, QFileDialog::FileMode fileMode, QFileDialog::AcceptMode acceptMode) { - QFileDialog dialog(parent, caption, dir.toFSPathString(), filter); + QFileDialog dialog(dialogParent(), caption, dir.toFSPathString(), filter); dialog.setFileMode(fileMode); if (forceNonNativeDialog) @@ -505,8 +502,7 @@ bool hasNativeFileDialog() return *hasNative; } -FilePath getOpenFilePath(QWidget *parent, - const QString &caption, +FilePath getOpenFilePath(const QString &caption, const FilePath &dir, const QString &filter, QString *selectedFilter, @@ -522,8 +518,7 @@ FilePath getOpenFilePath(QWidget *parent, #endif const QStringList schemes = QStringList(QStringLiteral("file")); - return firstOrEmpty(getFilePaths(dialogParent(parent), - caption, + return firstOrEmpty(getFilePaths(caption, dir, filter, selectedFilter, @@ -534,8 +529,7 @@ FilePath getOpenFilePath(QWidget *parent, QFileDialog::AcceptOpen)); } -FilePath getSaveFilePath(QWidget *parent, - const QString &caption, +FilePath getSaveFilePath(const QString &caption, const FilePath &dir, const QString &filter, QString *selectedFilter, @@ -545,8 +539,7 @@ FilePath getSaveFilePath(QWidget *parent, forceNonNativeDialog = forceNonNativeDialog || !dir.isLocal(); const QStringList schemes = QStringList(QStringLiteral("file")); - return firstOrEmpty(getFilePaths(dialogParent(parent), - caption, + return firstOrEmpty(getFilePaths(caption, dir, filter, selectedFilter, @@ -557,8 +550,7 @@ FilePath getSaveFilePath(QWidget *parent, QFileDialog::AcceptSave)); } -FilePath getExistingDirectory(QWidget *parent, - const QString &caption, +FilePath getExistingDirectory(const QString &caption, const FilePath &dir, QFileDialog::Options options, bool fromDeviceIfShiftIsPressed, @@ -573,8 +565,7 @@ FilePath getExistingDirectory(QWidget *parent, #endif const QStringList schemes = QStringList(QStringLiteral("file")); - return firstOrEmpty(getFilePaths(dialogParent(parent), - caption, + return firstOrEmpty(getFilePaths(caption, dir, {}, nullptr, @@ -585,8 +576,7 @@ FilePath getExistingDirectory(QWidget *parent, QFileDialog::AcceptOpen)); } -FilePaths getOpenFilePaths(QWidget *parent, - const QString &caption, +FilePaths getOpenFilePaths(const QString &caption, const FilePath &dir, const QString &filter, QString *selectedFilter, @@ -595,8 +585,7 @@ FilePaths getOpenFilePaths(QWidget *parent, bool forceNonNativeDialog = !dir.isLocal(); const QStringList schemes = QStringList(QStringLiteral("file")); - return getFilePaths(dialogParent(parent), - caption, + return getFilePaths(caption, dir, filter, selectedFilter, diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 274535c2d3e..33340492b38 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -37,13 +37,11 @@ using CopyHelper = std::function &postOperation = {}); + explicit CopyAskingForOverwrite(const std::function &postOperation = {}); CopyHelper operator()(); FilePaths files() const; private: - QWidget *m_parent; FilePaths m_files; std::function m_postOperation; bool m_overwriteAll = false; @@ -83,7 +81,6 @@ QTCREATOR_UTILS_EXPORT FilePaths usefulExtraSearchPaths(); QTCREATOR_UTILS_EXPORT bool hasNativeFileDialog(); QTCREATOR_UTILS_EXPORT FilePath getOpenFilePath( - QWidget *parent, const QString &caption, const FilePath &dir = {}, const QString &filter = {}, @@ -93,7 +90,6 @@ QTCREATOR_UTILS_EXPORT FilePath getOpenFilePath( bool forceNonNativeDialog = false); QTCREATOR_UTILS_EXPORT FilePath getSaveFilePath( - QWidget *parent, const QString &caption, const FilePath &dir = {}, const QString &filter = {}, @@ -102,7 +98,6 @@ QTCREATOR_UTILS_EXPORT FilePath getSaveFilePath( bool forceNonNativeDialog = false); QTCREATOR_UTILS_EXPORT FilePath getExistingDirectory( - QWidget *parent, const QString &caption, const FilePath &dir = {}, QFileDialog::Options options = QFileDialog::ShowDirsOnly, @@ -110,7 +105,6 @@ QTCREATOR_UTILS_EXPORT FilePath getExistingDirectory( bool forceNonNativeDialog = false); QTCREATOR_UTILS_EXPORT FilePaths getOpenFilePaths( - QWidget *parent, const QString &caption, const FilePath &dir = {}, const QString &filter = {}, diff --git a/src/libs/utils/guiutils.cpp b/src/libs/utils/guiutils.cpp index d7d9cb5f84f..03ec8bfd889 100644 --- a/src/libs/utils/guiutils.cpp +++ b/src/libs/utils/guiutils.cpp @@ -53,9 +53,9 @@ void setDialogParentGetter(QWidget *(*getter)()) s_dialogParentGetter = getter; } -QWidget *dialogParent(QWidget *parent) +QWidget *dialogParent() { - return parent ? parent : s_dialogParentGetter ? s_dialogParentGetter() : nullptr; + return s_dialogParentGetter ? s_dialogParentGetter() : nullptr; } } // namespace Utils diff --git a/src/libs/utils/guiutils.h b/src/libs/utils/guiutils.h index fea37f98f3c..4d1d9037381 100644 --- a/src/libs/utils/guiutils.h +++ b/src/libs/utils/guiutils.h @@ -11,7 +11,7 @@ namespace Utils { QTCREATOR_UTILS_EXPORT void setWheelScrollingWithoutFocusBlocked(QWidget *widget); -QTCREATOR_UTILS_EXPORT QWidget *dialogParent(QWidget *parent); +QTCREATOR_UTILS_EXPORT QWidget *dialogParent(); QTCREATOR_UTILS_EXPORT void setDialogParentGetter(QWidget *(*getter)()); } // namespace Utils diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 73558995979..7c735debed0 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -408,8 +408,7 @@ void PathChooser::slotBrowse(bool remote) switch (d->m_acceptingKind) { case PathChooser::Directory: case PathChooser::ExistingDirectory: - newPath = FileUtils::getExistingDirectory(this, - makeDialogTitle(Tr::tr("Choose Directory")), + newPath = FileUtils::getExistingDirectory(makeDialogTitle(Tr::tr("Choose Directory")), predefined, {}, d->m_allowPathFromDevice, @@ -417,8 +416,7 @@ void PathChooser::slotBrowse(bool remote) break; case PathChooser::ExistingCommand: case PathChooser::Command: - newPath = FileUtils::getOpenFilePath(this, - makeDialogTitle(Tr::tr("Choose Executable")), + newPath = FileUtils::getOpenFilePath(makeDialogTitle(Tr::tr("Choose Executable")), predefined, d->m_dialogFilter, nullptr, @@ -428,8 +426,7 @@ void PathChooser::slotBrowse(bool remote) newPath = appBundleExpandedPath(newPath); break; case PathChooser::File: // fall through - newPath = FileUtils::getOpenFilePath(this, - makeDialogTitle(Tr::tr("Choose File")), + newPath = FileUtils::getOpenFilePath(makeDialogTitle(Tr::tr("Choose File")), predefined, d->m_dialogFilter, nullptr, @@ -439,8 +436,7 @@ void PathChooser::slotBrowse(bool remote) newPath = appBundleExpandedPath(newPath); break; case PathChooser::SaveFile: - newPath = FileUtils::getSaveFilePath(this, - makeDialogTitle(Tr::tr("Choose File")), + newPath = FileUtils::getSaveFilePath(makeDialogTitle(Tr::tr("Choose File")), predefined, d->m_dialogFilter, nullptr, @@ -448,8 +444,7 @@ void PathChooser::slotBrowse(bool remote) remote); break; case PathChooser::Any: { - newPath = FileUtils::getOpenFilePath(this, - makeDialogTitle(Tr::tr("Choose File")), + newPath = FileUtils::getOpenFilePath(makeDialogTitle(Tr::tr("Choose File")), predefined, d->m_dialogFilter, nullptr, diff --git a/src/libs/utils/pathlisteditor.cpp b/src/libs/utils/pathlisteditor.cpp index 5964027dc6c..2b2ddae591d 100644 --- a/src/libs/utils/pathlisteditor.cpp +++ b/src/libs/utils/pathlisteditor.cpp @@ -99,7 +99,7 @@ PathListEditor::PathListEditor(QWidget *parent) : { setLayout(d->layout); addButton(Tr::tr("Insert..."), this, [this] { - const FilePath dir = FileUtils::getExistingDirectory(this, d->fileDialogTitle); + const FilePath dir = FileUtils::getExistingDirectory(d->fileDialogTitle); if (!dir.isEmpty()) insertPathAtCursor(dir.toUserOutput()); }); diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index a5a1c22241a..3fa191ee0a2 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -531,8 +531,7 @@ QWidget *AndroidDeployQtStep::createConfigWidget() connect(installCustomApkButton, &QAbstractButton::clicked, this, [this, widget] { const FilePath packagePath - = FileUtils::getOpenFilePath(widget, - Tr::tr("Qt Android Installer"), + = FileUtils::getOpenFilePath(Tr::tr("Qt Android Installer"), FileUtils::homePath(), Tr::tr("Android package (*.apk)")); if (packagePath.isEmpty()) diff --git a/src/plugins/android/androidmanifesteditor.cpp b/src/plugins/android/androidmanifesteditor.cpp index b344b4a3a0a..cbb3047ad45 100644 --- a/src/plugins/android/androidmanifesteditor.cpp +++ b/src/plugins/android/androidmanifesteditor.cpp @@ -231,7 +231,6 @@ void IconWidget::setIconFromPath(const FilePath &iconPath) void IconWidget::selectIcon() { FilePath file = FileUtils::getOpenFilePath( - this, m_iconSelectionText, FileUtils::homePath(), //: %1 expands to wildcard list for file dialog, do not change order diff --git a/src/plugins/android/keystorecertificatedialog.cpp b/src/plugins/android/keystorecertificatedialog.cpp index df746b8e84a..710e32fa719 100644 --- a/src/plugins/android/keystorecertificatedialog.cpp +++ b/src/plugins/android/keystorecertificatedialog.cpp @@ -279,7 +279,7 @@ void AndroidCreateKeystoreCertificate::buttonBoxAccepted() if (!validateUserInput()) return; - m_keystoreFilePath = FileUtils::getSaveFilePath(this, Tr::tr("Keystore Filename"), + m_keystoreFilePath = FileUtils::getSaveFilePath(Tr::tr("Keystore Filename"), FileUtils::homePath() / "android_release.keystore", Tr::tr("Keystore files (*.keystore *.jks)")); if (m_keystoreFilePath.isEmpty()) diff --git a/src/plugins/android/manifestwizard.cpp b/src/plugins/android/manifestwizard.cpp index 3627c118173..d7bc20b87e1 100644 --- a/src/plugins/android/manifestwizard.cpp +++ b/src/plugins/android/manifestwizard.cpp @@ -255,7 +255,7 @@ void CreateAndroidManifestWizard::createAndroidTemplateFiles() if (m_directory.isEmpty()) return; - FileUtils::CopyAskingForOverwrite copy(this); + FileUtils::CopyAskingForOverwrite copy; Target *target = m_buildSystem->target(); QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(target->kit()); if (!version) diff --git a/src/plugins/android/splashscreencontainerwidget.cpp b/src/plugins/android/splashscreencontainerwidget.cpp index 22ea3a1738d..5bc42829b72 100644 --- a/src/plugins/android/splashscreencontainerwidget.cpp +++ b/src/plugins/android/splashscreencontainerwidget.cpp @@ -254,7 +254,7 @@ void SplashScreenWidget::setImageFromPath(const FilePath &imagePath, bool resize void SplashScreenWidget::selectImage() { - const FilePath file = FileUtils::getOpenFilePath(this, m_imageSelectionText, + const FilePath file = FileUtils::getOpenFilePath(m_imageSelectionText, FileUtils::homePath(), QStringLiteral("%1 (*.png *.jpg *.jpeg)") .arg(Tr::tr("Images"))); @@ -589,7 +589,7 @@ SplashScreenContainerWidget::SplashScreenContainerWidget( } }); connect(m_masterImage, &QToolButton::clicked, this, [this] { - const FilePath file = FileUtils::getOpenFilePath(this, Tr::tr("Select master image"), + const FilePath file = FileUtils::getOpenFilePath(Tr::tr("Select master image"), FileUtils::homePath(), fileDialogImageFiles); if (!file.isEmpty()) { for (auto &&imageWidget : m_imageWidgets) @@ -599,7 +599,7 @@ SplashScreenContainerWidget::SplashScreenContainerWidget( } }); connect(m_portraitMasterImage, &QToolButton::clicked, this, [this] { - const FilePath file = FileUtils::getOpenFilePath(this, Tr::tr("Select portrait master image"), + const FilePath file = FileUtils::getOpenFilePath(Tr::tr("Select portrait master image"), FileUtils::homePath(), fileDialogImageFiles); if (!file.isEmpty()) { for (auto &&imageWidget : m_portraitImageWidgets) @@ -609,7 +609,7 @@ SplashScreenContainerWidget::SplashScreenContainerWidget( } }); connect(m_landscapeMasterImage, &QToolButton::clicked, this, [this] { - const FilePath file = FileUtils::getOpenFilePath(this, Tr::tr("Select landscape master image"), + const FilePath file = FileUtils::getOpenFilePath(Tr::tr("Select landscape master image"), FileUtils::homePath(), fileDialogImageFiles); if (!file.isEmpty()) { for (auto &&imageWidget : m_landscapeImageWidgets) diff --git a/src/plugins/autotest/testresultspane.cpp b/src/plugins/autotest/testresultspane.cpp index d30c42e14b6..18b1edc3bca 100644 --- a/src/plugins/autotest/testresultspane.cpp +++ b/src/plugins/autotest/testresultspane.cpp @@ -656,7 +656,7 @@ void TestResultsPane::onCopyWholeTriggered() void TestResultsPane::onSaveWholeTriggered() { - const FilePath filePath = FileUtils::getSaveFilePath(nullptr, Tr::tr("Save Output To")); + const FilePath filePath = FileUtils::getSaveFilePath(Tr::tr("Save Output To")); if (filePath.isEmpty()) return; diff --git a/src/plugins/axivion/axivionperspective.cpp b/src/plugins/axivion/axivionperspective.cpp index 4d1fd6dd407..dfe44e5dc03 100644 --- a/src/plugins/axivion/axivionperspective.cpp +++ b/src/plugins/axivion/axivionperspective.cpp @@ -1119,8 +1119,7 @@ void AxivionPerspective::handleAnchorClicked(const QUrl &url) "Do you want to open \"%1\" with its default application?") .arg(url.toString()); const QMessageBox::StandardButton pressed - = CheckableMessageBox::question(Core::ICore::dialogParent(), - Tr::tr("Open External Links"), + = CheckableMessageBox::question(Tr::tr("Open External Links"), detail, Key("AxivionOpenExternalLinks")); if (pressed == QMessageBox::Yes) diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index 86bca4e40d4..13a739f501b 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -376,7 +376,6 @@ private: void slotImportClicked() final { const FilePath filePath = FileUtils::getOpenFilePath( - this, Tr::tr("Import Code Format"), {}, Tr::tr("ClangFormat (*clang-format*);;All files (*)")); @@ -406,7 +405,6 @@ private: { ICodeStylePreferences *currentPreferences = m_codeStyle->currentPreferences(); const FilePath filePath = FileUtils::getSaveFilePath( - this, Tr::tr("Export Code Format"), FileUtils::homePath(), Tr::tr("ClangFormat (*clang-format*);;All files (*)")); diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index a5ecf187176..9c23b4cf63b 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -638,8 +638,7 @@ static bool continueDespiteReleaseBuild(const QString &toolName) "

    %2

    " "") .arg(problem, question); - return CheckableMessageBox::question(ICore::dialogParent(), - title, + return CheckableMessageBox::question(title, message, Key("ClangToolsCorrectModeWarning")) == QMessageBox::Yes; @@ -968,8 +967,7 @@ void ClangTool::loadDiagnosticsFromFiles() { // Ask user for files const FilePaths filePaths - = FileUtils::getOpenFilePaths(nullptr, - Tr::tr("Select YAML Files with Diagnostics"), + = FileUtils::getOpenFilePaths(Tr::tr("Select YAML Files with Diagnostics"), FileUtils::homePath(), Tr::tr("YAML Files (*.yml *.yaml);;All Files (*)")); if (filePaths.isEmpty()) diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index e7b42a21b4a..5f144c97e92 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -138,8 +138,7 @@ QString hintAboutBuildBeforeAnalysis() void showHintAboutBuildBeforeAnalysis() { - Utils::CheckableMessageBox::information(Core::ICore::dialogParent(), - Tr::tr("Info About Build the Project Before Analysis"), + Utils::CheckableMessageBox::information(Tr::tr("Info About Build the Project Before Analysis"), hintAboutBuildBeforeAnalysis(), Key("ClangToolsDisablingBuildBeforeAnalysisHint")); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 2fc3451e279..765ed17137e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -610,7 +610,6 @@ void CMakeBuildSettingsWidget::batchEditConfiguration() void CMakeBuildSettingsWidget::reconfigureWithInitialParameters() { QMessageBox::StandardButton reply = CheckableMessageBox::question( - Core::ICore::dialogParent(), Tr::tr("Re-configure with Initial Parameters"), Tr::tr("Clear CMake configuration and configure with initial parameters?"), settings(m_buildConfig->project()).askBeforeReConfigureInitialParams.askAgainCheckableDecider(), diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index 0fd8c6edc24..0f137a4cdc7 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -450,7 +449,6 @@ void CMakeManager::reloadCMakePresets() return; QMessageBox::StandardButton clickedButton = CheckableMessageBox::question( - Core::ICore::dialogParent(), Tr::tr("Reload CMake Presets"), Tr::tr("Re-generates the kits that were created for CMake presets. All manual " "modifications to the CMake project settings will be lost."), diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp index 5e12b1ba0e9..b17468894b6 100644 --- a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp +++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp @@ -743,8 +743,7 @@ void ShortcutSettingsWidget::resetToDefault() void ShortcutSettingsWidget::importAction() { - FilePath fileName = FileUtils::getOpenFilePath(nullptr, - Tr::tr("Import Keyboard Mapping Scheme"), + FilePath fileName = FileUtils::getOpenFilePath(Tr::tr("Import Keyboard Mapping Scheme"), schemesPath(), Tr::tr("Keyboard Mapping Scheme (*.kms)")); if (!fileName.isEmpty()) { diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index e2529372be6..697e68f186a 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -795,7 +795,7 @@ FilePath DocumentManager::getSaveFileName(const QString &title, const FilePath & bool repeat; do { repeat = false; - filePath = FileUtils::getSaveFilePath(nullptr, title, path, filter, selectedFilter); + filePath = FileUtils::getSaveFilePath(title, path, filter, selectedFilter); if (!filePath.isEmpty()) { // If the selected filter is All Files (*) we leave the name exactly as the user // specified. Otherwise the suffix must be one available in the selected filter. If @@ -1040,7 +1040,7 @@ FilePaths DocumentManager::getOpenFileNames(const QString &filters, QFileDialog::Options options) { const FilePath path = pathIn.isEmpty() ? fileDialogInitialDirectory() : pathIn; - const FilePaths files = FileUtils::getOpenFilePaths(nullptr, Tr::tr("Open File"), path, filters, + const FilePaths files = FileUtils::getOpenFilePaths(Tr::tr("Open File"), path, filters, selectedFilter, options); if (!files.isEmpty()) setFileDialogLastVisitedDirectory(files.front().absolutePath()); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index abab9654be8..c2fe46ff5f0 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -822,7 +822,7 @@ bool EditorManagerPrivate::skipOpeningBigTextFile(const FilePath &filePath) CheckableDecider decider(&askAgain); QMessageBox::StandardButton clickedButton - = CheckableMessageBox::question(ICore::dialogParent(), title, text, decider); + = CheckableMessageBox::question(title, text, decider); systemSettings().warnBeforeOpeningBigFiles.setValue(askAgain); return clickedButton != QMessageBox::Yes; } diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 266eae04cf2..2ebb4fbbefd 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -2040,7 +2040,6 @@ void ICorePrivate::registerDefaultActions() "Locator.Actions from the menu"); CheckableMessageBox::information( - Core::ICore::dialogParent(), Tr::tr("Hide Menu Bar"), Tr::tr("This will hide the menu bar completely. " "You can show it again by typing %1." diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 23b853682d3..0b3407e33f3 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -316,7 +316,7 @@ bool DirectoryFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) void DirectoryFilter::handleAddDirectory() { - FilePath dir = FileUtils::getExistingDirectory(m_dialog, Tr::tr("Select Directory")); + FilePath dir = FileUtils::getExistingDirectory(Tr::tr("Select Directory")); if (!dir.isEmpty()) m_dialog->directoryList->addItem(dir.toUserOutput()); } @@ -326,7 +326,7 @@ void DirectoryFilter::handleEditDirectory() if (m_dialog->directoryList->selectedItems().count() < 1) return; QListWidgetItem *currentItem = m_dialog->directoryList->selectedItems().at(0); - FilePath dir = FileUtils::getExistingDirectory(m_dialog, Tr::tr("Select Directory"), + FilePath dir = FileUtils::getExistingDirectory(Tr::tr("Select Directory"), FilePath::fromUserInput(currentItem->text())); if (!dir.isEmpty()) currentItem->setText(dir.toUserOutput()); diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 3213d32504b..cc7b423a78c 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -59,8 +59,7 @@ static ILocatorFilter::MatchLevel matchLevelFor(const QRegularExpressionMatch &m static bool askForCreating(const QString &title, const FilePath &filePath) { QMessageBox::StandardButton selected - = CheckableMessageBox::question(ICore::dialogParent(), - title, + = CheckableMessageBox::question(title, Tr::tr("Create \"%1\"?").arg(filePath.shortNativePath()), Key(kAlwaysCreate), QMessageBox::Yes | QMessageBox::Cancel, diff --git a/src/plugins/coreplugin/loggingviewer.cpp b/src/plugins/coreplugin/loggingviewer.cpp index 060e8b0ffff..8b3847b9ddf 100644 --- a/src/plugins/coreplugin/loggingviewer.cpp +++ b/src/plugins/coreplugin/loggingviewer.cpp @@ -33,6 +33,9 @@ #include #include #include + +using namespace Utils; + namespace Core::Internal { static QColor colorForCategory(const QString &category); @@ -947,10 +950,7 @@ void LoggingViewManagerWidget::showLogCategoryContextMenu(const QPoint &pos) con void LoggingViewManagerWidget::saveLoggingsToFile() const { - const Utils::FilePath fp = Utils::FileUtils::getSaveFilePath(ICore::dialogParent(), - Tr::tr("Save Logs As"), - {}, - "*.log"); + const FilePath fp = FileUtils::getSaveFilePath(Tr::tr("Save Logs As"), {}, "*.log"); if (fp.isEmpty()) return; @@ -980,10 +980,7 @@ void LoggingViewManagerWidget::saveLoggingsToFile() const void LoggingCategoryModel::saveEnabledCategoryPreset() const { - Utils::FilePath fp = Utils::FileUtils::getSaveFilePath(ICore::dialogParent(), - Tr::tr("Save Enabled Categories As..."), - {}, - "*.json"); + FilePath fp = FileUtils::getSaveFilePath(Tr::tr("Save Enabled Categories As..."), {}, "*.json"); if (fp.isEmpty()) return; @@ -1023,8 +1020,7 @@ void LoggingCategoryModel::saveEnabledCategoryPreset() const void LoggingCategoryModel::loadAndUpdateFromPreset() { - Utils::FilePath fp = Utils::FileUtils::getOpenFilePath(ICore::dialogParent(), - Tr::tr("Load Enabled Categories From")); + FilePath fp = FileUtils::getOpenFilePath(Tr::tr("Load Enabled Categories From")); if (fp.isEmpty()) return; // read file, update categories diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index 95e148225c4..d3c0a850ae7 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -305,7 +305,7 @@ void OutputWindow::contextMenuEvent(QContextMenuEvent *event) QAction *saveAction = menu->addAction(Tr::tr("Save Contents...")); connect(saveAction, &QAction::triggered, this, [this] { const FilePath file = FileUtils::getSaveFilePath( - ICore::dialogParent(), {}, FileUtils::homePath() / d->outputFileNameHint); + {}, FileUtils::homePath() / d->outputFileNameHint); if (!file.isEmpty()) { QString error; Utils::TextFileFormat format; diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp index 8f06015aec7..a227a549ff3 100644 --- a/src/plugins/coreplugin/plugininstallwizard.cpp +++ b/src/plugins/coreplugin/plugininstallwizard.cpp @@ -528,7 +528,7 @@ bool executePluginInstallWizard(const FilePath &archive) return copyPluginFile(data.sourcePath, installPath); } else { QString error; - FileUtils::CopyAskingForOverwrite copy(ICore::dialogParent(), postCopyOperation()); + FileUtils::CopyAskingForOverwrite copy(postCopyOperation()); if (!FileUtils::copyRecursively(data.extractedPath, installPath, &error, copy())) { QMessageBox::warning( ICore::dialogParent(), Tr::tr("Failed to Copy Plugin Files"), error); diff --git a/src/plugins/cppeditor/cppfilesettingspage.cpp b/src/plugins/cppeditor/cppfilesettingspage.cpp index b9c64965a68..d34e62e4d28 100644 --- a/src/plugins/cppeditor/cppfilesettingspage.cpp +++ b/src/plugins/cppeditor/cppfilesettingspage.cpp @@ -487,7 +487,7 @@ void CppFileSettingsWidget::slotEdit() FilePath path = licenseTemplatePath(); if (path.isEmpty()) { // Pick a file name and write new template, edit with C++ - path = FileUtils::getSaveFilePath(this, Tr::tr("Choose Location for New License Template File")); + path = FileUtils::getSaveFilePath(Tr::tr("Choose Location for New License Template File")); if (path.isEmpty()) return; FileSaver saver(path, QIODevice::Text); diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 924026af056..e4472309f2c 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -2792,8 +2792,7 @@ void BreakpointManager::gotoLocation(const GlobalBreakpoint &gbp) const void BreakpointManager::executeDeleteAllBreakpointsDialog() { QMessageBox::StandardButton pressed - = CheckableMessageBox::question(ICore::dialogParent(), - Tr::tr("Remove All Breakpoints"), + = CheckableMessageBox::question(Tr::tr("Remove All Breakpoints"), Tr::tr("Are you sure you want to remove all breakpoints " "from all files in the current session?"), Key("RemoveAllBreakpoints")); diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 0dc2d321613..009be94f88f 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2239,8 +2239,7 @@ void CdbEngine::checkQtSdkPdbFiles(const QString &module) "symbols for the debugger.") .arg(qtName); - CheckableMessageBox::information_async(Core::ICore::dialogParent(), - Tr::tr("Missing Qt Debug Information"), + CheckableMessageBox::information_async(Tr::tr("Missing Qt Debug Information"), message, Key("CdbQtSdkPdbHint")); @@ -2264,7 +2263,6 @@ void CdbEngine::parseOutputLine(QString line) if (!m_initialSessionIdleHandled && line.startsWith("SECURE: File not allowed to be loaded") && line.endsWith("qtcreatorcdbext.dll")) { CheckableMessageBox::information( - Core::ICore::dialogParent(), Tr::tr("Debugger Start Failed"), Tr::tr("The system prevents loading of \"%1\", which is required for debugging. " "Make sure that your antivirus solution is up to date and if that does not work " diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index b096c82fd7d..a2a144db7d7 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -2939,7 +2939,6 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) } if (warnOnInappropriateDebugger) { CheckableMessageBox::information( - Core::ICore::dialogParent(), Tr::tr("Warning"), Tr::tr("The selected debugger may be inappropriate for the inferior.\n" "Examining symbols and setting breakpoints by file name and line number " diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index feaa221ab16..d05df3ad870 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1928,7 +1928,7 @@ void DebuggerPluginPrivate::dumpLog() LogWindow *logWindow = engine->logWindow(); QTC_ASSERT(logWindow, return); - const FilePath filePath = FileUtils::getSaveFilePath(nullptr, Tr::tr("Save Debugger Log"), + const FilePath filePath = FileUtils::getSaveFilePath(Tr::tr("Save Debugger Log"), TemporaryDirectory::masterDirectoryFilePath()); if (filePath.isEmpty()) return; @@ -2207,8 +2207,7 @@ bool wantRunTool(ToolMode toolMode, const QString &toolName) "or otherwise insufficient output.

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

    ") .arg(toolName).arg(currentMode).arg(toolModeString); - if (Utils::CheckableMessageBox::question(ICore::dialogParent(), - title, + if (Utils::CheckableMessageBox::question(title, message, Key("AnalyzerCorrectModeWarning")) != QMessageBox::Yes) diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 3b7120c35b5..36341ce2882 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -652,7 +652,6 @@ void DebuggerRunTool::continueAfterDebugServerStart() bool doNotAskAgain = false; CheckableDecider decider(&doNotAskAgain); CheckableMessageBox::information( - Core::ICore::dialogParent(), Tr::tr("Debugger"), warningMessage, decider, diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index 1b3916db281..8f5d6a92aea 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -381,7 +381,7 @@ void DebuggerSourcePathMappingWidget::slotAdd() void DebuggerSourcePathMappingWidget::slotAddQt() { // Add a mapping for various Qt build locations in case of unpatched builds. - const FilePath qtSourcesPath = FileUtils::getExistingDirectory(this, Tr::tr("Qt Sources")); + const FilePath qtSourcesPath = FileUtils::getExistingDirectory(Tr::tr("Qt Sources")); if (qtSourcesPath.isEmpty()) return; for (const QString &buildPath : qtBuildPaths()) diff --git a/src/plugins/debugger/logwindow.cpp b/src/plugins/debugger/logwindow.cpp index 8e534ce9722..7816afab508 100644 --- a/src/plugins/debugger/logwindow.cpp +++ b/src/plugins/debugger/logwindow.cpp @@ -68,16 +68,16 @@ QChar static charForChannel(int channel) } } -static bool writeLogContents(const QPlainTextEdit *editor, QWidget *parent) +static bool writeLogContents(const QPlainTextEdit *editor) { bool success = false; while (!success) { - const FilePath filePath = FileUtils::getSaveFilePath(parent, Tr::tr("Log File")); + const FilePath filePath = FileUtils::getSaveFilePath(Tr::tr("Log File")); if (filePath.isEmpty()) break; FileSaver saver(filePath, QIODevice::Text); saver.write(editor->toPlainText().toUtf8()); - if (saver.finalize(parent)) + if (saver.finalize()) success = true; } return success; @@ -228,7 +228,7 @@ public: QAction *clearContentsAction() const { return m_clearContentsAction; } private: - void saveContents() { writeLogContents(this, this); } + void saveContents() { writeLogContents(this); } QAction *m_clearContentsAction; QAction *m_saveContentsAction; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 69cd063f60d..90efd2b7c93 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -2570,7 +2570,6 @@ void WatchModel::clearWatches() return; const QMessageBox::StandardButton ret = CheckableMessageBox::question( - ICore::dialogParent(), Tr::tr("Remove All Expression Evaluators"), Tr::tr("Are you sure you want to remove all expression evaluators?"), Key("RemoveAllWatchers")); diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 26e614accd6..1a62c6d3d27 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -518,12 +518,12 @@ void DiffEditorPlugin::diffOpenFiles() void DiffEditorPlugin::diffExternalFiles() { - const FilePath filePath1 = FileUtils::getOpenFilePath(nullptr, Tr::tr("Select First File for Diff")); + const FilePath filePath1 = FileUtils::getOpenFilePath(Tr::tr("Select First File for Diff")); if (filePath1.isEmpty()) return; if (EditorManager::skipOpeningBigTextFile(filePath1)) return; - const FilePath filePath2 = FileUtils::getOpenFilePath(nullptr, Tr::tr("Select Second File for Diff")); + const FilePath filePath2 = FileUtils::getOpenFilePath(Tr::tr("Select Second File for Diff")); if (filePath2.isEmpty()) return; if (EditorManager::skipOpeningBigTextFile(filePath2)) diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index ea049c95d93..6ec17bbd086 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -687,7 +687,7 @@ void FossilPluginPrivate::createRepository() // Prompt for a directory that is not under version control yet QWidget *mw = ICore::dialogParent(); do { - directory = FileUtils::getExistingDirectory(nullptr, Tr::tr("Choose Checkout Directory"), directory); + directory = FileUtils::getExistingDirectory(Tr::tr("Choose Checkout Directory"), directory); if (directory.isEmpty()) return; const IVersionControl *managingControl = VcsManager::findVersionControlForDirectory(directory); diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 9db9c4d7a79..0222f2b91ce 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -335,7 +335,7 @@ void GerritPlugin::fetch(const std::shared_ptr &change, int mode) const QString title = Git::Tr::tr("Enter Local Repository for \"%1\" (%2)").arg(change->project, change->branch); const FilePath suggestedRespository = findLocalRepository(change->project, change->branch); - repository = FileUtils::getExistingDirectory(m_dialog.data(), title, suggestedRespository); + repository = FileUtils::getExistingDirectory(title, suggestedRespository); } if (repository.isEmpty()) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 85f8dbfd7a4..811a754cc7d 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -1267,7 +1267,6 @@ void GitClient::archive(const FilePath &workingDirectory, QString commit) commit = output.trimmed(); FilePath archiveName = FileUtils::getSaveFilePath( - nullptr, Tr::tr("Generate %1 archive").arg(repoName), repoDirectory.pathAppended(QString("../%1-%2").arg(repoName, commit.left(8))), filters.keys().join(";;"), @@ -1357,7 +1356,6 @@ QStringList GitClient::setupCheckoutArguments(const FilePath &workingDirectory, return arguments; if (Utils::CheckableMessageBox::question( - ICore::dialogParent() /*parent*/, Tr::tr("Create Local Branch") /*title*/, Tr::tr("Would you like to create a local branch?") /*message*/, Key("Git.CreateLocalBranchOnCheckout"), /* decider */ diff --git a/src/plugins/help/docsettingspage.cpp b/src/plugins/help/docsettingspage.cpp index 8663e6e93cd..e06815ed930 100644 --- a/src/plugins/help/docsettingspage.cpp +++ b/src/plugins/help/docsettingspage.cpp @@ -213,8 +213,7 @@ DocSettingsPageWidget::DocSettingsPageWidget() void DocSettingsPageWidget::addDocumentation() { - const FilePaths files = FileUtils::getOpenFilePaths(Core::ICore::dialogParent(), - Tr::tr("Add Documentation"), + const FilePaths files = FileUtils::getOpenFilePaths(Tr::tr("Add Documentation"), m_recentDialogPath, Tr::tr("Qt Help Files (*.qch)")); diff --git a/src/plugins/help/generalsettingspage.cpp b/src/plugins/help/generalsettingspage.cpp index 384752d4c19..ae0a0eed3a8 100644 --- a/src/plugins/help/generalsettingspage.cpp +++ b/src/plugins/help/generalsettingspage.cpp @@ -351,8 +351,7 @@ void GeneralSettingsPageWidget::importBookmarks() { errorLabel->setVisible(false); - FilePath filePath = FileUtils::getOpenFilePath(nullptr, - Tr::tr("Import Bookmarks"), + FilePath filePath = FileUtils::getOpenFilePath(Tr::tr("Import Bookmarks"), FilePath::fromString(QDir::currentPath()), Tr::tr("Files (*.xbel)")); @@ -375,8 +374,7 @@ void GeneralSettingsPageWidget::exportBookmarks() { errorLabel->setVisible(false); - FilePath filePath = FileUtils::getSaveFilePath(nullptr, - Tr::tr("Save File"), + FilePath filePath = FileUtils::getSaveFilePath(Tr::tr("Save File"), "untitled.xbel", Tr::tr("Files (*.xbel)")); diff --git a/src/plugins/languageclient/lspinspector.cpp b/src/plugins/languageclient/lspinspector.cpp index 1f9dddfe7e3..685d5abce86 100644 --- a/src/plugins/languageclient/lspinspector.cpp +++ b/src/plugins/languageclient/lspinspector.cpp @@ -317,7 +317,7 @@ void LspLogWidget::saveLog() stream << "\n\n"; }); - const FilePath filePath = FileUtils::getSaveFilePath(this, Tr::tr("Log File")); + const FilePath filePath = FileUtils::getSaveFilePath(Tr::tr("Log File")); if (filePath.isEmpty()) return; FileSaver saver(filePath, QIODevice::Text); diff --git a/src/plugins/modeleditor/modeleditor.cpp b/src/plugins/modeleditor/modeleditor.cpp index dcf2c5b5185..4d5fdc180f6 100644 --- a/src/plugins/modeleditor/modeleditor.cpp +++ b/src/plugins/modeleditor/modeleditor.cpp @@ -613,7 +613,6 @@ void ModelEditor::exportToImage(bool selectedElements) filter += Tr::tr(";;SVG (*.svg)"); #endif // QT_NO_SVG QString fileName = FileUtils::getSaveFilePath( - nullptr, selectedElements ? Tr::tr("Export Selected Elements") : Tr::tr("Export Diagram"), FilePath::fromString(d->lastExportDirPath), filter).toFSPathString(); if (!fileName.isEmpty()) { diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 1cabd56984d..6ee2c1dc234 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -786,7 +786,7 @@ void PerforcePluginPrivate::annotateCurrentFile() void PerforcePluginPrivate::annotateFile() { - const FilePath filePath = FileUtils::getOpenFilePath(nullptr, Tr::tr("p4 annotate")); + const FilePath filePath = FileUtils::getOpenFilePath(Tr::tr("p4 annotate")); if (!filePath.isEmpty()) annotate(filePath.parentDir(), filePath.fileName()); } @@ -828,7 +828,7 @@ void PerforcePluginPrivate::filelogCurrentFile() void PerforcePluginPrivate::filelogFile() { - const FilePath file = FileUtils::getOpenFilePath(nullptr, Tr::tr("p4 filelog")); + const FilePath file = FileUtils::getOpenFilePath(Tr::tr("p4 filelog")); if (!file.isEmpty()) filelog(file.parentDir(), file.fileName()); } diff --git a/src/plugins/perfprofiler/perfloaddialog.cpp b/src/plugins/perfprofiler/perfloaddialog.cpp index eaec6c3c129..e1722b3a48e 100644 --- a/src/plugins/perfprofiler/perfloaddialog.cpp +++ b/src/plugins/perfprofiler/perfloaddialog.cpp @@ -89,7 +89,7 @@ ProjectExplorer::Kit *PerfLoadDialog::kit() const void PerfLoadDialog::on_browseTraceFileButton_pressed() { FilePath filePath = FileUtils::getOpenFilePath( - this, Tr::tr("Choose Perf Trace"), {}, + Tr::tr("Choose Perf Trace"), {}, Tr::tr("Perf traces (*%1)").arg(Constants::TraceFileExtension)); if (filePath.isEmpty()) return; @@ -99,8 +99,7 @@ void PerfLoadDialog::on_browseTraceFileButton_pressed() void PerfLoadDialog::on_browseExecutableDirButton_pressed() { - FilePath filePath = FileUtils::getExistingDirectory( - this, Tr::tr("Choose Directory of Executable")); + FilePath filePath = FileUtils::getExistingDirectory(Tr::tr("Choose Directory of Executable")); if (filePath.isEmpty()) return; diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index c5656855527..793a5a9ef77 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -589,7 +589,7 @@ void PerfProfilerTool::showLoadTraceDialog() { m_perspective.select(); - FilePath filePath = FileUtils::getOpenFilePath(nullptr, Tr::tr("Load Trace File"), + FilePath filePath = FileUtils::getOpenFilePath(Tr::tr("Load Trace File"), {}, Tr::tr("Trace File (*.ptq)")); if (filePath.isEmpty()) return; @@ -608,7 +608,7 @@ void PerfProfilerTool::showSaveTraceDialog() { m_perspective.select(); - FilePath filePath = FileUtils::getSaveFilePath(nullptr, Tr::tr("Save Trace File"), + FilePath filePath = FileUtils::getSaveFilePath(Tr::tr("Save Trace File"), {}, Tr::tr("Trace File (*.ptq)")); if (filePath.isEmpty()) return; diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 2b11622c346..e14bbabfe87 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -83,7 +83,7 @@ public: connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(addButton, &QPushButton::clicked, this, [this] { - const FilePath dir = FileUtils::getExistingDirectory(this, Tr::tr("Choose Directory")); + const FilePath dir = FileUtils::getExistingDirectory(Tr::tr("Choose Directory")); if (!dir.isEmpty()) addPath(dir.toUserOutput()); }); @@ -495,7 +495,7 @@ void EnvironmentWidget::unsetEnvironmentButtonClicked() void EnvironmentWidget::amendPathList(Utils::EnvironmentItem::Operation op) { const QString varName = d->m_model->indexToVariable(d->m_environmentView->currentIndex()); - const FilePath dir = FileUtils::getExistingDirectory(this, Tr::tr("Choose Directory")); + const FilePath dir = FileUtils::getExistingDirectory(Tr::tr("Choose Directory")); if (dir.isEmpty()) return; Utils::EnvironmentItems changes = d->m_model->userChanges(); diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index 5cdca7c87be..156345a1ec5 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -296,7 +296,7 @@ void KitManagerConfigWidget::setIcon() } iconMenu.addSeparator(); iconMenu.addAction(PathChooser::browseButtonLabel(), [this] { - const FilePath path = FileUtils::getOpenFilePath(this, Tr::tr("Select Icon"), + const FilePath path = FileUtils::getOpenFilePath(Tr::tr("Select Icon"), m_modifiedKit->iconPath(), Tr::tr("Images (*.png *.xpm *.jpg)")); if (path.isEmpty()) diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp index 290833045a6..74c985245a0 100644 --- a/src/plugins/projectexplorer/parseissuesdialog.cpp +++ b/src/plugins/projectexplorer/parseissuesdialog.cpp @@ -50,7 +50,7 @@ ParseIssuesDialog::ParseIssuesDialog(QWidget *parent) : QDialog(parent), d(new P const auto loadFileButton = new QPushButton(Tr::tr("Load from File...")); connect(loadFileButton, &QPushButton::clicked, this, [this] { - const FilePath filePath = FileUtils::getOpenFilePath(this, Tr::tr("Choose File")); + const FilePath filePath = FileUtils::getOpenFilePath(Tr::tr("Choose File")); if (filePath.isEmpty()) return; QFile file(filePath.toString()); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 2385a7d4c13..32c0127f055 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -798,8 +798,7 @@ FilePath Project::projectDirectory() const void Project::changeRootProjectDirectory() { - FilePath rootPath = FileUtils::getExistingDirectory(nullptr, - ::PE::Tr::tr("Select the Root Directory"), + FilePath rootPath = FileUtils::getExistingDirectory(::PE::Tr::tr("Select the Root Directory"), rootProjectDirectory(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index e9bd1b51205..95076a45862 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1979,8 +1979,7 @@ void ProjectExplorerPluginPrivate::loadAction() dir = isProject ? fn : fn.absolutePath(); } - FilePath filePath = Utils::FileUtils::getOpenFilePath(ICore::dialogParent(), - Tr::tr("Load Project"), + FilePath filePath = Utils::FileUtils::getOpenFilePath(Tr::tr("Load Project"), dir, dd->projectFilterString()); if (filePath.isEmpty()) @@ -2005,8 +2004,7 @@ void ProjectExplorerPluginPrivate::openWorkspaceAction() dir = isProject ? fn : fn.absolutePath(); } - FilePath filePath = Utils::FileUtils::getExistingDirectory( - ICore::dialogParent(), Tr::tr("Open Workspace"), dir); + FilePath filePath = Utils::FileUtils::getExistingDirectory(Tr::tr("Open Workspace"), dir); if (filePath.isEmpty()) return; @@ -3664,7 +3662,7 @@ void ProjectExplorerPluginPrivate::addExistingProjects() QTC_ASSERT(projectNode, return); const FilePath dir = currentNode->directory(); FilePaths subProjectFilePaths = Utils::FileUtils::getOpenFilePaths( - nullptr, Tr::tr("Choose Project File"), dir, + Tr::tr("Choose Project File"), dir, projectNode->subProjectFileNamePatterns().join(";;")); if (!ProjectTree::hasNode(projectNode)) return; @@ -3702,7 +3700,7 @@ void ProjectExplorerPluginPrivate::handleAddExistingFiles() QTC_ASSERT(folderNode, return); const FilePaths filePaths = - Utils::FileUtils::getOpenFilePaths(nullptr, Tr::tr("Add Existing Files"), node->directory()); + Utils::FileUtils::getOpenFilePaths(Tr::tr("Add Existing Files"), node->directory()); if (filePaths.isEmpty()) return; diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index 8dcf19bcf4b..248d797648c 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -927,7 +927,7 @@ public: QTC_ASSERT(projectImporter, return); FilePath importDir = - FileUtils::getExistingDirectory(nullptr, Tr::tr("Import Directory"), + FileUtils::getExistingDirectory(Tr::tr("Import Directory"), project->projectDirectory()); Target *lastTarget = nullptr; diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 0cfd0b23269..1860cdc0c0a 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1294,8 +1294,7 @@ bool RunControl::showPromptToStopDialog(const QString &title, if (prompt) decider = CheckableDecider(prompt); - auto selected = CheckableMessageBox::question(Core::ICore::dialogParent(), - title, + auto selected = CheckableMessageBox::question(title, text, decider, QMessageBox::Yes | QMessageBox::Cancel, diff --git a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp index b74190bb911..4f993d7380b 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp @@ -668,7 +668,6 @@ bool AlignDistribute::executePixelPerfectDialog() const Utils::CheckableDecider decider(Key("WarnAboutPixelPerfectDistribution")); QMessageBox::StandardButton pressed = Utils::CheckableMessageBox::question( - Core::ICore::dialogParent(), tr("Cannot Distribute Perfectly"), tr("These objects cannot be distributed to equal pixel values. " "Do you want to distribute to the nearest possible values?"), diff --git a/src/plugins/qmldesigner/libs/qmldesignerutils/fileextractor.cpp b/src/plugins/qmldesigner/libs/qmldesignerutils/fileextractor.cpp index efc72b79944..e11a46fe7cf 100644 --- a/src/plugins/qmldesigner/libs/qmldesignerutils/fileextractor.cpp +++ b/src/plugins/qmldesigner/libs/qmldesignerutils/fileextractor.cpp @@ -104,8 +104,7 @@ void FileExtractor::setTargetPath(const QString &path) void FileExtractor::browse() { - const FilePath path = FileUtils::getExistingDirectory(nullptr, tr("Choose Directory"), - m_targetPath); + const FilePath path = FileUtils::getExistingDirectory(tr("Choose Directory"), m_targetPath); if (!path.isEmpty()) { removeTempTargetPath(); m_targetPath = path; diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 9a0c38a1e7d..efc3fcd0641 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -644,7 +644,7 @@ void QmlProfilerTool::showSaveDialog() QLatin1String tFile(QtdFileExtension); QLatin1String zFile(QztFileExtension); FilePath filePath = FileUtils::getSaveFilePath( - nullptr, Tr::tr("Save QML Trace"), + Tr::tr("Save QML Trace"), globalSettings().lastTraceFile(), Tr::tr("QML traces (*%1 *%2)").arg(zFile).arg(tFile)); if (!filePath.isEmpty()) { @@ -668,7 +668,7 @@ void QmlProfilerTool::showLoadDialog() QLatin1String tFile(QtdFileExtension); QLatin1String zFile(QztFileExtension); FilePath filePath = FileUtils::getOpenFilePath( - nullptr, Tr::tr("Load QML Trace"), + Tr::tr("Load QML Trace"), globalSettings().lastTraceFile(), Tr::tr("QML traces (*%1 *%2)").arg(zFile).arg(tFile)); diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 03b2166f902..3d228c0d2bb 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -597,7 +597,7 @@ void QnxSettingsWidget::addConfiguration() else filter = "*.sh file"; - const FilePath envFile = FileUtils::getOpenFilePath(this, Tr::tr("Select QNX Environment File"), + const FilePath envFile = FileUtils::getOpenFilePath(Tr::tr("Select QNX Environment File"), {}, filter); if (envFile.isEmpty()) return; diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index ec6b3b720ef..e382b2f984d 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -682,8 +682,7 @@ QtSettingsPageWidget::~QtSettingsPageWidget() void QtSettingsPageWidget::addQtDir() { FilePath qtVersion - = FileUtils::getOpenFilePath(this, - Tr::tr("Select a qmake Executable"), + = FileUtils::getOpenFilePath(Tr::tr("Select a qmake Executable"), {}, BuildableHelperLibrary::filterForQmakeFileDialog(), nullptr, @@ -754,8 +753,7 @@ void QtSettingsPageWidget::editPath() { QtVersion *current = currentVersion(); FilePath qtVersion = - FileUtils::getOpenFilePath(this, - Tr::tr("Select a qmake Executable"), + FileUtils::getOpenFilePath(Tr::tr("Select a qmake Executable"), current->qmakeFilePath().absolutePath(), BuildableHelperLibrary::filterForQmakeFileDialog(), nullptr, diff --git a/src/plugins/remotelinux/publickeydeploymentdialog.cpp b/src/plugins/remotelinux/publickeydeploymentdialog.cpp index c7fdaaf50f9..f7801b3b964 100644 --- a/src/plugins/remotelinux/publickeydeploymentdialog.cpp +++ b/src/plugins/remotelinux/publickeydeploymentdialog.cpp @@ -31,7 +31,7 @@ PublicKeyDeploymentDialog *PublicKeyDeploymentDialog::createDialog( const DeviceConstRef &device, QWidget *parent) { const FilePath dir = device.sshParameters().privateKeyFile.parentDir(); - const FilePath publicKeyFileName = FileUtils::getOpenFilePath(nullptr, + const FilePath publicKeyFileName = FileUtils::getOpenFilePath( Tr::tr("Choose Public Key File"), dir, Tr::tr("Public Key Files (*.pub);;All Files (*)")); if (publicKeyFileName.isEmpty()) diff --git a/src/plugins/remotelinux/sshkeycreationdialog.cpp b/src/plugins/remotelinux/sshkeycreationdialog.cpp index a94a56cf61e..aed27946b3a 100644 --- a/src/plugins/remotelinux/sshkeycreationdialog.cpp +++ b/src/plugins/remotelinux/sshkeycreationdialog.cpp @@ -129,7 +129,7 @@ void SshKeyCreationDialog::generateKeys() void SshKeyCreationDialog::handleBrowseButtonClicked() { - const FilePath filePath = FileUtils::getSaveFilePath(this, Tr::tr("Choose Private Key File Name")); + const FilePath filePath = FileUtils::getSaveFilePath(Tr::tr("Choose Private Key File Name")); if (!filePath.isEmpty()) setPrivateKeyFile(filePath); } diff --git a/src/plugins/screenrecorder/cropandtrim.cpp b/src/plugins/screenrecorder/cropandtrim.cpp index 14f4c7fb4ad..07e6da99e2d 100644 --- a/src/plugins/screenrecorder/cropandtrim.cpp +++ b/src/plugins/screenrecorder/cropandtrim.cpp @@ -338,7 +338,7 @@ CropWidget::CropWidget(QWidget *parent) connect(saveImageButton, &QToolButton::clicked, this, [this] { FilePathAspect &lastDir = Internal::settings().lastSaveImageDirectory; const QString ext(".png"); - FilePath file = FileUtils::getSaveFilePath(nullptr, Tr::tr("Save Current Frame As"), + FilePath file = FileUtils::getSaveFilePath(Tr::tr("Save Current Frame As"), lastDir(), "*" + ext); if (!file.isEmpty()) { if (!file.endsWith(ext)) diff --git a/src/plugins/screenrecorder/export.cpp b/src/plugins/screenrecorder/export.cpp index 00daed94a88..de845fd1cdc 100644 --- a/src/plugins/screenrecorder/export.cpp +++ b/src/plugins/screenrecorder/export.cpp @@ -155,7 +155,7 @@ ExportWidget::ExportWidget(QWidget *parent) [&lastFormat] (const Format &f) { return f.displayName == lastFormat(); }).fileDialogFilter(); - FilePath file = FileUtils::getSaveFilePath(nullptr, Tr::tr("Save As"), lastDir(), + FilePath file = FileUtils::getSaveFilePath(Tr::tr("Save As"), lastDir(), fileDialogFilters(), &selectedFilter); if (!file.isEmpty()) { m_currentFormat = findOr(formats(), defaultFormat, diff --git a/src/plugins/screenrecorder/record.cpp b/src/plugins/screenrecorder/record.cpp index 70e1d5e2758..cc0cbd00fd5 100644 --- a/src/plugins/screenrecorder/record.cpp +++ b/src/plugins/screenrecorder/record.cpp @@ -278,8 +278,7 @@ RecordWidget::RecordWidget(const FilePath &recordFile, QWidget *parent) }); connect(m_openClipAction, &QAction::triggered, this, [this, progressLabel] { const FilePath lastDir = Internal::settings().lastOpenDirectory(); - const FilePath file = FileUtils::getOpenFilePath(Core::ICore::dialogParent(), - m_openClipAction->text(), lastDir, + const FilePath file = FileUtils::getOpenFilePath(m_openClipAction->text(), lastDir, "Mov/qtrle rgb24 (*.mov)"); if (!file.isEmpty()) { Internal::settings().lastOpenDirectory.setValue(file.parentDir()); diff --git a/src/plugins/scxmleditor/common/mainwidget.cpp b/src/plugins/scxmleditor/common/mainwidget.cpp index b180caa5850..35909cc2bd6 100644 --- a/src/plugins/scxmleditor/common/mainwidget.cpp +++ b/src/plugins/scxmleditor/common/mainwidget.cpp @@ -421,8 +421,7 @@ void MainWidget::exportToImage() .arg(lastFolder) .arg(suggestedFileName) .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmss")); - const FilePath filePath = FileUtils::getSaveFilePath(this, - Tr::tr("Export Canvas to Image"), + const FilePath filePath = FileUtils::getSaveFilePath(Tr::tr("Export Canvas to Image"), FilePath::fromString(suggestedFileName), saveImageFileFilter()); if (!filePath.isEmpty()) { @@ -451,8 +450,7 @@ void MainWidget::saveScreenShot() const QString documentsLocation = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); const FilePath lastFolder = FilePath::fromSettings( s->value(Constants::C_SETTINGS_LASTSAVESCREENSHOTFOLDER, documentsLocation)); - const FilePath filePath = FileUtils::getSaveFilePath(this, - Tr::tr("Save Screenshot"), + const FilePath filePath = FileUtils::getSaveFilePath(Tr::tr("Save Screenshot"), lastFolder / "scxml_screenshot.png", saveImageFileFilter()); if (!filePath.isEmpty()) { diff --git a/src/plugins/scxmleditor/outputpane/errorwidget.cpp b/src/plugins/scxmleditor/outputpane/errorwidget.cpp index 6120ea573be..2bbd158a97a 100644 --- a/src/plugins/scxmleditor/outputpane/errorwidget.cpp +++ b/src/plugins/scxmleditor/outputpane/errorwidget.cpp @@ -186,7 +186,7 @@ QString ErrorWidget::modifyExportedValue(const QString &val) void ErrorWidget::exportWarnings() { - FilePath fileName = FileUtils::getSaveFilePath(this, Tr::tr("Export to File"), {}, Tr::tr("CSV files (*.csv)")); + FilePath fileName = FileUtils::getSaveFilePath(Tr::tr("Export to File"), {}, Tr::tr("CSV files (*.csv)")); if (fileName.isEmpty()) return; diff --git a/src/plugins/squish/squishfilehandler.cpp b/src/plugins/squish/squishfilehandler.cpp index d47a492708d..975f3646f6a 100644 --- a/src/plugins/squish/squishfilehandler.cpp +++ b/src/plugins/squish/squishfilehandler.cpp @@ -467,7 +467,7 @@ void addAllEntriesRecursively(SquishTestTreeItem *item) void SquishFileHandler::addSharedFolder() { const Utils::FilePath chosen = Utils::FileUtils::getExistingDirectory( - Core::ICore::dialogParent(), Tr::tr("Select Global Script Folder")); + Tr::tr("Select Global Script Folder")); if (chosen.isEmpty()) return; diff --git a/src/plugins/squish/squishnavigationwidget.cpp b/src/plugins/squish/squishnavigationwidget.cpp index d3fb523196e..46f81aae31c 100644 --- a/src/plugins/squish/squishnavigationwidget.cpp +++ b/src/plugins/squish/squishnavigationwidget.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -337,8 +336,7 @@ void SquishNavigationWidget::onRemoveSharedFileTriggered(const QModelIndex &idx) const QString detail = Tr::tr("Do you really want to delete \"%1\" permanently?") .arg(scriptFile.toUserOutput()); const QMessageBox::StandardButton pressed - = CheckableMessageBox::question(Core::ICore::dialogParent(), - Tr::tr("Remove Shared File"), + = CheckableMessageBox::question(Tr::tr("Remove Shared File"), detail, Key("RemoveSharedSquishScript"), QMessageBox::Yes | QMessageBox::No, @@ -388,7 +386,6 @@ void SquishNavigationWidget::onRemoveAllSharedFolderTriggered() void SquishNavigationWidget::onRecordTestCase(const QString &suiteName, const QString &testCase) { QMessageBox::StandardButton pressed = CheckableMessageBox::question( - Core::ICore::dialogParent(), Tr::tr("Record Test Case"), Tr::tr("Do you want to record over the test case \"%1\"? The existing content will " "be overwritten by the recorded script.") diff --git a/src/plugins/squish/squishsettings.cpp b/src/plugins/squish/squishsettings.cpp index de4bf4744b2..7aac82bde54 100644 --- a/src/plugins/squish/squishsettings.cpp +++ b/src/plugins/squish/squishsettings.cpp @@ -477,8 +477,7 @@ void SquishServerSettingsWidget::addMappedAut(TreeItem *categoryItem, SquishServ { FilePath entry = original ? FilePath::fromString(original->data(1, Qt::DisplayRole).toString()) : FilePath(); - const FilePath aut = FileUtils::getOpenFilePath(nullptr, Tr::tr("Select Application to test"), - entry); + const FilePath aut = FileUtils::getOpenFilePath(Tr::tr("Select Application to test"), entry); if (aut.isEmpty()) return; const QString fileName = aut.completeBaseName(); @@ -504,8 +503,7 @@ void SquishServerSettingsWidget::addAutPath(TreeItem *categoryItem, SquishServer const QString originalPathStr = original ? original->data(0, Qt::DisplayRole).toString() : QString(); FilePath entry = FilePath::fromString(originalPathStr); - const FilePath path = FileUtils::getExistingDirectory(nullptr, - Tr::tr("Select Application Path"), entry); + const FilePath path = FileUtils::getExistingDirectory(Tr::tr("Select Application Path"), entry); if (path.isEmpty() || path == entry) return; const QString pathStr = path.toString(); diff --git a/src/plugins/studiowelcome/qdsnewdialog.cpp b/src/plugins/studiowelcome/qdsnewdialog.cpp index e483effd8ae..107125ac802 100644 --- a/src/plugins/studiowelcome/qdsnewdialog.cpp +++ b/src/plugins/studiowelcome/qdsnewdialog.cpp @@ -449,8 +449,7 @@ void QdsNewDialog::reject() QString QdsNewDialog::chooseProjectLocation() { - Utils::FilePath newPath = Utils::FileUtils::getExistingDirectory(m_dialog.get(), - tr("Choose Directory"), + Utils::FilePath newPath = Utils::FileUtils::getExistingDirectory(tr("Choose Directory"), m_qmlProjectLocation); return QDir::toNativeSeparators(newPath.toString()); diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index 4ac13061798..de8d7dac1b3 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -575,7 +575,6 @@ TerminalSettings::TerminalSettings() connect(loadThemeButton, &QPushButton::clicked, this, [] { const FilePath path = FileUtils::getOpenFilePath( - Core::ICore::dialogParent(), "Open Theme", {}, "All Scheme formats (*.itermcolors *.json *.colorscheme *.theme *.theme.txt);;" diff --git a/src/plugins/texteditor/bookmarkmanager.cpp b/src/plugins/texteditor/bookmarkmanager.cpp index eac800cfc33..930503a927f 100644 --- a/src/plugins/texteditor/bookmarkmanager.cpp +++ b/src/plugins/texteditor/bookmarkmanager.cpp @@ -298,8 +298,7 @@ void BookmarkView::keyPressEvent(QKeyEvent *event) void BookmarkView::removeAll() { - if (CheckableMessageBox::question(this, - Tr::tr("Remove All Bookmarks"), + if (CheckableMessageBox::question(Tr::tr("Remove All Bookmarks"), Tr::tr("Are you sure you want to remove all bookmarks from " "all files in the current session?"), Key("RemoveAllBookmarks")) diff --git a/src/plugins/texteditor/codestyleselectorwidget.cpp b/src/plugins/texteditor/codestyleselectorwidget.cpp index 5eb373f00f1..b1efbb6fc14 100644 --- a/src/plugins/texteditor/codestyleselectorwidget.cpp +++ b/src/plugins/texteditor/codestyleselectorwidget.cpp @@ -198,7 +198,7 @@ void CodeStyleSelectorWidget::slotRemoveClicked() void CodeStyleSelectorWidget::slotImportClicked() { const FilePath fileName = - FileUtils::getOpenFilePath(this, Tr::tr("Import Code Style"), {}, + FileUtils::getOpenFilePath(Tr::tr("Import Code Style"), {}, Tr::tr("Code styles (*.xml);;All files (*)")); if (!fileName.isEmpty()) { CodeStylePool *codeStylePool = m_codeStyle->delegatingPool(); @@ -217,7 +217,6 @@ void CodeStyleSelectorWidget::slotExportClicked() { ICodeStylePreferences *currentPreferences = m_codeStyle->currentPreferences(); const FilePath filePath = FileUtils::getSaveFilePath( - this, Tr::tr("Export Code Style"), FileUtils::homePath().pathAppended(QString::fromUtf8(currentPreferences->id() + ".xml")), Tr::tr("Code styles (*.xml);;All files (*)")); diff --git a/src/plugins/texteditor/fontsettingspage.cpp b/src/plugins/texteditor/fontsettingspage.cpp index 67fe67b6973..dac8152a1e4 100644 --- a/src/plugins/texteditor/fontsettingspage.cpp +++ b/src/plugins/texteditor/fontsettingspage.cpp @@ -601,8 +601,7 @@ void FontSettingsPageWidget::deleteColorScheme() void FontSettingsPageWidget::importScheme() { const FilePath importedFile - = Utils::FileUtils::getOpenFilePath(this, - Tr::tr("Import Color Scheme"), + = Utils::FileUtils::getOpenFilePath(Tr::tr("Import Color Scheme"), {}, Tr::tr("Color scheme (*.xml);;All files (*)")); @@ -650,8 +649,7 @@ void FontSettingsPageWidget::exportScheme() const ColorSchemeEntry &entry = m_schemeListModel.colorSchemeAt(index); const FilePath filePath - = Utils::FileUtils::getSaveFilePath(this, - Tr::tr("Export Color Scheme"), + = Utils::FileUtils::getSaveFilePath(Tr::tr("Export Color Scheme"), entry.filePath, Tr::tr("Color scheme (*.xml);;All files (*)")); diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 11f6ee5a35f..39b73ab491b 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -853,7 +853,6 @@ void CallgrindTool::slotRequestDump() void CallgrindTool::loadExternalLogFile() { const FilePath filePath = FileUtils::getOpenFilePath( - nullptr, Tr::tr("Open Callgrind Log File"), {}, Tr::tr("Callgrind Output (callgrind.out*);;All Files (*)")); diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 881cd29a6ee..24a277da57f 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -764,7 +764,6 @@ void MemcheckTool::heobAction() const QString dwarfstackPath = dialog.path() + '/' + dwarfstack; if (!QFileInfo::exists(dwarfstackPath) && CheckableMessageBox::information( - Core::ICore::dialogParent(), Tr::tr("Heob"), Tr::tr("Heob used with MinGW projects needs the %1 DLLs for proper " "stacktrace resolution.") @@ -987,7 +986,6 @@ void MemcheckTool::loadShowXmlLogFile(const QString &filePath, const QString &ex void MemcheckTool::loadExternalXmlLogFile() { const FilePath filePath = FileUtils::getOpenFilePath( - nullptr, Tr::tr("Open Memcheck XML Log File"), {}, Tr::tr("XML Files (*.xml);;All Files (*)")); diff --git a/src/plugins/valgrind/valgrindsettings.cpp b/src/plugins/valgrind/valgrindsettings.cpp index 386020c7a80..d1d521c158d 100644 --- a/src/plugins/valgrind/valgrindsettings.cpp +++ b/src/plugins/valgrind/valgrindsettings.cpp @@ -57,7 +57,7 @@ void SuppressionAspect::addSuppressionFile(const FilePath &suppression) void SuppressionAspectPrivate::slotAddSuppression() { const FilePaths files = - FileUtils::getOpenFilePaths(nullptr, + FileUtils::getOpenFilePaths( Tr::tr("Valgrind Suppression Files"), globalSettings().lastSuppressionDirectory(), Tr::tr("Valgrind Suppression File (*.supp);;All Files (*)")); diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index 1a8f33258e0..8bd270daf3a 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -655,7 +655,7 @@ void VersionControlBase::createRepository() // Prompt for a directory that is not under version control yet QWidget *mw = ICore::dialogParent(); do { - directory = FileUtils::getExistingDirectory(nullptr, Tr::tr("Choose Repository Directory"), directory); + directory = FileUtils::getExistingDirectory(Tr::tr("Choose Repository Directory"), directory); if (directory.isEmpty()) return; const IVersionControl *managingControl = VcsManager::findVersionControlForDirectory(directory); diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp index 77084cab5ce..07015b6445f 100644 --- a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp +++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp @@ -222,8 +222,7 @@ bool CrashHandlerDialog::runDebuggerWhileBacktraceNotFinished() ""); const QMessageBox::StandardButton button - = Utils::CheckableMessageBox::question(this, - title, + = Utils::CheckableMessageBox::question(title, message, Utils::Key(SettingsKeySkipWarningAbortingBacktrace), QMessageBox::Yes | QMessageBox::No, From 4c5c33eb800fb3936e8f679604e89ae47860ee78 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 11 Dec 2024 12:46:35 +0100 Subject: [PATCH 502/989] Core: Remove one functional indirection in copyPostOperation And replace a FilePath::toString() by .path() Change-Id: I5e4c36f8fd9cc0494cf76f274f259d97231b2dc0 Reviewed-by: Marcus Tillmanns --- .../coreplugin/plugininstallwizard.cpp | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp index a227a549ff3..a02bee4d4e9 100644 --- a/src/plugins/coreplugin/plugininstallwizard.cpp +++ b/src/plugins/coreplugin/plugininstallwizard.cpp @@ -452,18 +452,16 @@ private: QTextEdit *m_terms = nullptr; }; -static std::function postCopyOperation() +static void postCopyOperation(FilePath filePath) { - return [](const FilePath &filePath) { - if (!HostOsInfo::isMacHost()) - return; - // On macOS, downloaded files get a quarantine flag, remove it, otherwise it is a hassle - // to get it loaded as a plugin in Qt Creator. - Process xattr; - xattr.setCommand({"/usr/bin/xattr", {"-d", "com.apple.quarantine", filePath.absoluteFilePath().toString()}}); - using namespace std::chrono_literals; - xattr.runBlocking(1s); - }; + if (!HostOsInfo::isMacHost()) + return; + // On macOS, downloaded files get a quarantine flag, remove it, otherwise it is a hassle + // to get it loaded as a plugin in Qt Creator. + Process xattr; + xattr.setCommand({"/usr/bin/xattr", {"-d", "com.apple.quarantine", filePath.absoluteFilePath().path()}}); + using namespace std::chrono_literals; + xattr.runBlocking(1s); } static bool copyPluginFile(const FilePath &src, const FilePath &dest) @@ -490,7 +488,7 @@ static bool copyPluginFile(const FilePath &src, const FilePath &dest) Tr::tr("Failed to write file \"%1\".").arg(destFile.toUserOutput())); return false; } - postCopyOperation()(destFile); + postCopyOperation(destFile); return true; } @@ -528,7 +526,7 @@ bool executePluginInstallWizard(const FilePath &archive) return copyPluginFile(data.sourcePath, installPath); } else { QString error; - FileUtils::CopyAskingForOverwrite copy(postCopyOperation()); + FileUtils::CopyAskingForOverwrite copy(&postCopyOperation); if (!FileUtils::copyRecursively(data.extractedPath, installPath, &error, copy())) { QMessageBox::warning( ICore::dialogParent(), Tr::tr("Failed to Copy Plugin Files"), error); From 42e25dcd4d884f7610200d9afddf76e2eb88994e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Jan 2025 14:41:41 +0100 Subject: [PATCH 503/989] ProcessRunner: Simplify handleDone() Change-Id: I026511906542eea126bb6d6c3c3cbc96e46934a8 Reviewed-by: hjk --- src/plugins/projectexplorer/runcontrol.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 1860cdc0c0a..83a2eecb608 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1505,8 +1505,7 @@ qint64 SimpleTargetRunnerPrivate::privateApplicationPID() const void SimpleTargetRunnerPrivate::handleDone() { m_resultData = m_process.resultData(); - QTC_ASSERT(m_state == Run, forwardDone(); return); - + QTC_CHECK(m_state == Run); forwardDone(); } From 27103de07ef35f2ed3b69035353bb664fb625053 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 6 Jan 2025 09:04:45 +0100 Subject: [PATCH 504/989] Translations: Fix spelling of "axivion" Change-Id: I203dbd2982d6df3f2a43f63edbc8aa22efbfd9e3 Reviewed-by: Eike Ziller --- share/qtcreator/translations/qtcreator_de.ts | 4 ++-- share/qtcreator/translations/qtcreator_fr.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index efff9d28f66..5b248654b4b 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -19451,8 +19451,8 @@ Wenn die Systemzeiger für das Verändern der Größe von Ansichten nicht korrek Die ausführbare Datei %1 konnte in %2 nicht gefunden werden - The Qt logo, axivion stopping software erosion logo, Qt Group logo, as well as Qt®, Axivion®, avixion stopping software erosion®, Boot to Qt®, Built with Qt®, Coco®, froglogic®, Qt Cloud Services®, Qt Developer Days®, Qt Embedded®, Qt Enterprise®, Qt Group®, Qt Mobile®, Qt Quick®, Qt Quick Compiler®, Squish® are registered trademarks of The Qt Company Ltd. or its subsidiaries. - The Qt logo, axivion stopping software erosion logo, Qt Group logo, as well as Qt®, Axivion®, avixion stopping software erosion®, Boot to Qt®, Built with Qt®, Coco®, froglogic®, Qt Cloud Services®, Qt Developer Days®, Qt Embedded®, Qt Enterprise®, Qt Group®, Qt Mobile®, Qt Quick®, Qt Quick Compiler®, Squish® are registered trademarks of The Qt Company Ltd. or its subsidiaries. + The Qt logo, axivion stopping software erosion logo, Qt Group logo, as well as Qt®, Axivion®, axivion stopping software erosion®, Boot to Qt®, Built with Qt®, Coco®, froglogic®, Qt Cloud Services®, Qt Developer Days®, Qt Embedded®, Qt Enterprise®, Qt Group®, Qt Mobile®, Qt Quick®, Qt Quick Compiler®, Squish® are registered trademarks of The Qt Company Ltd. or its subsidiaries. + The Qt logo, axivion stopping software erosion logo, Qt Group logo, as well as Qt®, Axivion®, axivion stopping software erosion®, Boot to Qt®, Built with Qt®, Coco®, froglogic®, Qt Cloud Services®, Qt Developer Days®, Qt Embedded®, Qt Enterprise®, Qt Group®, Qt Mobile®, Qt Quick®, Qt Quick Compiler®, Squish® are registered trademarks of The Qt Company Ltd. or its subsidiaries. %1 is free software, and you are welcome to redistribute it under <a href="%2">certain conditions</a>. For some components, different conditions might apply though. diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index 56ad2edae26..2892664098f 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -20038,8 +20038,8 @@ provided they were unmodified before the refactoring. Impossible de trouver l'exécutable %1 dans %2 - The Qt logo, axivion stopping software erosion logo, Qt Group logo, as well as Qt®, Axivion®, avixion stopping software erosion®, Boot to Qt®, Built with Qt®, Coco®, froglogic®, Qt Cloud Services®, Qt Developer Days®, Qt Embedded®, Qt Enterprise®, Qt Group®, Qt Mobile®, Qt Quick®, Qt Quick Compiler®, Squish® are registered trademarks of The Qt Company Ltd. or its subsidiaries. - Le logo Qt, le logo axivion stopper stopping software erosion, le logo du groupe Qt, ainsi que Qt®, Axivion®, avixion stopping software erosion®, Boot to Qt®, Built with Qt®, Coco®, froglogic®, Qt Cloud Services®, Qt Developer Days®, Qt Embedded®, Qt Enterprise®, Qt Group®, Qt Mobile®, Qt Quick®, Qt Quick Compiler®, Squish® sont des marques déposées de The Qt Company Ltd. ou de ses filiales. + The Qt logo, axivion stopping software erosion logo, Qt Group logo, as well as Qt®, Axivion®, axivion stopping software erosion®, Boot to Qt®, Built with Qt®, Coco®, froglogic®, Qt Cloud Services®, Qt Developer Days®, Qt Embedded®, Qt Enterprise®, Qt Group®, Qt Mobile®, Qt Quick®, Qt Quick Compiler®, Squish® are registered trademarks of The Qt Company Ltd. or its subsidiaries. + Le logo Qt, le logo axivion stopper stopping software erosion, le logo du groupe Qt, ainsi que Qt®, Axivion®, axivion stopping software erosion®, Boot to Qt®, Built with Qt®, Coco®, froglogic®, Qt Cloud Services®, Qt Developer Days®, Qt Embedded®, Qt Enterprise®, Qt Group®, Qt Mobile®, Qt Quick®, Qt Quick Compiler®, Squish® sont des marques déposées de The Qt Company Ltd. ou de ses filiales. %1 is free software, and you are welcome to redistribute it under <a href="%2">certain conditions</a>. For some components, different conditions might apply though. From 754bb5847faaebbc129f55df667e2bd5cd7a720d Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Fri, 20 Dec 2024 11:45:13 +0100 Subject: [PATCH 505/989] Debugger: Fix enabling breakpoints on click Calling `BreakpointItem::setEnabled` from `BreakpointMarker::clicked` is wrong and dangerous. It never actually enables a global breakpoint, just updates the marker. While doing so, it calls `BreakpointItem::adjustMarker`, which in turn calls `BreakpointItem::destroyMarker`, which destroys the original marker, hence the dangerous part. What we actually want is simply enable the corresponding global breakpoint instead. Amends 8f3a0ebabbb03d6d95a354ad648d3a55b5ff0214. Change-Id: I423752be4e4f51198e9e2968a978b57bce43a3ec Reviewed-by: hjk --- src/plugins/debugger/breakhandler.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index e4472309f2c..8a24e7e8269 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -120,10 +120,14 @@ public: void clicked() final { QTC_ASSERT(m_bp, return); - if (!m_bp->isEnabled()) - m_bp->setEnabled(true); - else + + if (m_bp->isEnabled()) { m_bp->deleteGlobalOrThisBreakpoint(); + return; + } + + if (const GlobalBreakpoint gbp = m_bp->globalBreakpoint()) + gbp->setEnabled(true); } public: From fe2fe1a60de1200c25ad6babc2736630adeef938 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 22 Nov 2024 19:12:01 +0100 Subject: [PATCH 506/989] Axivion: Reuse resolveDashboardInfoUrl() Change-Id: Ic8627be0353e7a789cd569030da91bb46751c885 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionperspective.cpp | 17 +++++++---------- src/plugins/axivion/axivionplugin.cpp | 11 ++++++----- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/plugins/axivion/axivionperspective.cpp b/src/plugins/axivion/axivionperspective.cpp index dfe44e5dc03..e99f906488d 100644 --- a/src/plugins/axivion/axivionperspective.cpp +++ b/src/plugins/axivion/axivionperspective.cpp @@ -1074,18 +1074,17 @@ void AxivionPerspective::resetDashboard() bool AxivionPerspective::handleContextMenu(const QString &issue, const ItemViewEvent &e) { - std::optional tableInfoOpt = m_issuesWidget->currentTableInfo(); + if (!currentDashboardInfo()) + return false; + const std::optional tableInfoOpt = m_issuesWidget->currentTableInfo(); if (!tableInfoOpt) return false; const QString baseUri = tableInfoOpt->issueBaseViewUri.value_or(QString()); if (baseUri.isEmpty()) return false; - auto info = currentDashboardInfo(); - if (!info) - return false; - QUrl issueBaseUrl = info->source.resolved(baseUri).resolved(issue); - QUrl dashboardUrl = info->source.resolved(baseUri); + QUrl dashboardUrl = resolveDashboardInfoUrl(baseUri); + QUrl issueBaseUrl = dashboardUrl.resolved(issue); const IssueListSearch search = m_issuesWidget->searchFromUi(); issueBaseUrl.setQuery(search.toUrlQuery(QueryMode::SimpleQuery)); dashboardUrl.setQuery(search.toUrlQuery(QueryMode::FilterQuery)); @@ -1147,11 +1146,9 @@ void AxivionPerspective::updateToolbarButtons() void AxivionPerspective::openFilterHelp() { - std::optional dashboardInfo = currentDashboardInfo(); - QTC_ASSERT(dashboardInfo, return); - std::optional projInfo = projectInfo(); + const std::optional projInfo = projectInfo(); if (projInfo && projInfo->issueFilterHelp) - QDesktopServices::openUrl(dashboardInfo->source.resolved(*projInfo->issueFilterHelp)); + QDesktopServices::openUrl(resolveDashboardInfoUrl(*projInfo->issueFilterHelp)); } static QPointer theAxivionPerspective; diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 5fe3f8cf81a..0dcc71d33f3 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -364,7 +364,7 @@ static QUrl constructUrl(const QString &projectName, const QString &subPath, con return {}; const QByteArray encodedProjectName = QUrl::toPercentEncoding(projectName); const QUrl path(QString{"api/projects/" + QString::fromUtf8(encodedProjectName) + '/'}); - QUrl url = dd->m_dashboardInfo->source.resolved(path); + QUrl url = resolveDashboardInfoUrl(path); if (!subPath.isEmpty() && QTC_GUARD(!subPath.startsWith('/'))) url = url.resolved(subPath); if (!query.isEmpty()) @@ -396,6 +396,8 @@ static QByteArray contentTypeData(ContentType contentType) QUrl resolveDashboardInfoUrl(const QUrl &resource) { + QTC_ASSERT(dd, return {}); + QTC_ASSERT(dd->m_dashboardInfo, return {}); return dd->m_dashboardInfo->source.resolved(resource); } @@ -649,8 +651,7 @@ static Group authorizationRecipe() return SetupResult::StopWithError; apiTokenStorage->credential = dashboardStorage->credential; - apiTokenStorage->url - = dd->m_dashboardInfo->source.resolved(*dashboardDto.userApiTokenUrl); + apiTokenStorage->url = resolveDashboardInfoUrl(*dashboardDto.userApiTokenUrl); apiTokenStorage->csrfToken = dashboardDto.csrfToken.toUtf8(); const Dto::ApiTokenCreationRequestDto requestDto{*passwordStorage, "IdePlugin", apiTokenDescription(), 0}; @@ -832,8 +833,8 @@ Group projectInfoRecipe(const QString &projectName) auto it = dd->m_dashboardInfo->projectUrls.constFind(targetProjectName); if (it == dd->m_dashboardInfo->projectUrls.constEnd()) it = dd->m_dashboardInfo->projectUrls.constBegin(); - taskTree.setRecipe( - fetchDataRecipe(dd->m_dashboardInfo->source.resolved(*it), handler)); + taskTree.setRecipe(fetchDataRecipe(resolveDashboardInfoUrl(*it), + handler)); return SetupResult::Continue; }; From 9a8f5b687e57c0baed1c6edc8a0ef4382df3f9c8 Mon Sep 17 00:00:00 2001 From: Alexis Jeandet Date: Sat, 28 Dec 2024 15:28:47 +0100 Subject: [PATCH 507/989] MesonProjectManager: Replace recursive templates by fold expressions Change-Id: I07000adac1294abdf9b4b2d033ce01e552d40f3b Reviewed-by: hjk --- .../mesonprojectmanager/mesontools.cpp | 29 +++---------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/src/plugins/mesonprojectmanager/mesontools.cpp b/src/plugins/mesonprojectmanager/mesontools.cpp index 5ab0d1f3923..646c132c55d 100644 --- a/src/plugins/mesonprojectmanager/mesontools.cpp +++ b/src/plugins/mesonprojectmanager/mesontools.cpp @@ -87,24 +87,10 @@ Store ToolWrapper::toVariantMap() const return data; } -template -void impl_option_cat(QStringList &list, const First &first) -{ - list.append(first); -} - -template -void impl_option_cat(QStringList &list, const First &first, const T &...args) -{ - impl_option_cat(list, first); - impl_option_cat(list, args...); -} - -template -QStringList options_cat(const T &...args) +QStringList options_cat(const auto &...args) { QStringList result; - impl_option_cat(result, args...); + (result.append(args), ...); return result; } @@ -146,16 +132,9 @@ ProcessRunData ToolWrapper::introspect(const FilePath &sourceDirectory) const sourceDirectory}; } -template -bool containsFiles(const QString &path, const File_t &file) +bool containsFiles(const QString &path, const auto &...files) { - return QFileInfo::exists(QString("%1/%2").arg(path).arg(file)); -} - -template -bool containsFiles(const QString &path, const File_t &file, const T &...files) -{ - return containsFiles(path, file) && containsFiles(path, files...); + return (QFileInfo::exists(QString("%1/%2").arg(path).arg(files)) && ...); } bool run_meson(const ProcessRunData &runData, QIODevice *output) From b727460ff5838cb10c41ded41a948bffc1882f5a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Jan 2025 11:21:39 +0100 Subject: [PATCH 508/989] CMakeParser: Get rid of the std::optional holding a container There is no need to enclose a container inside the std::optional, as if the container is empty, it indicates that no values are in. Holding optional for a container class may lead to the confusing behavior, that the optional itself isn't empty, but holding an empty container. Instead, introduce a m_callStackDetected flag. Task-number: QTCREATORBUG-29965 Change-Id: If8d43e0633286c076e3da436eb61114aa68f4c35 Reviewed-by: Cristian Adam --- .../cmakeprojectmanager/cmakeoutputparser.cpp | 41 ++++++++++--------- .../cmakeprojectmanager/cmakeoutputparser.h | 3 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp b/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp index 387a4dfbce6..b62cc3ce0d9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeoutputparser.cpp @@ -129,20 +129,20 @@ OutputLineParser::Result CMakeOutputParser::handleLine(const QString &line, Outp m_errorOrWarningLine.function = match.captured(4); return {Status::InProgress, linkSpecs}; - } - else if (trimmedLine.startsWith(QLatin1String(" ")) && !m_lastTask.isNull() && !m_callStack) { - if (m_skippedFirstEmptyLine) - m_lastTask.details.append(QString()); - m_lastTask.details.append(trimmedLine.mid(2)); - return Status::InProgress; } else if (trimmedLine.startsWith(QLatin1String(" ")) && !m_lastTask.isNull()) { - match = m_sourceLineAndFunction.match(trimmedLine); - if (match.hasMatch()) { - CallStackLine stackLine; - stackLine.file = absoluteFilePath(resolvePath(match.captured(1))); - stackLine.line = match.captured(2).toInt(); - stackLine.function = match.captured(3); - m_callStack.value() << stackLine; + if (m_callStackDetected) { + match = m_sourceLineAndFunction.match(trimmedLine); + if (match.hasMatch()) { + CallStackLine stackLine; + stackLine.file = absoluteFilePath(resolvePath(match.captured(1))); + stackLine.line = match.captured(2).toInt(); + stackLine.function = match.captured(3); + m_callStack << stackLine; + } + } else { + if (m_skippedFirstEmptyLine) + m_lastTask.details.append(QString()); + m_lastTask.details.append(trimmedLine.mid(2)); } return {Status::InProgress}; } else if (trimmedLine.endsWith(QLatin1String("in cmake code at"))) { @@ -160,7 +160,7 @@ OutputLineParser::Result CMakeOutputParser::handleLine(const QString &line, Outp // Do not pass on lines starting with "-- " or "* ". Those are typical CMake output return Status::InProgress; } else if (trimmedLine.startsWith("Call Stack (most recent call first):")) { - m_callStack = QList(); + m_callStackDetected = true; return {Status::InProgress}; } return Status::NotHandled; @@ -214,19 +214,19 @@ void CMakeOutputParser::flush() t.summary = t.details.takeFirst(); m_lines += t.details.count(); - if (m_callStack.has_value() && !m_callStack.value().isEmpty()) { - t.file = m_callStack.value().last().file; - t.line = m_callStack.value().last().line; + if (!m_callStack.isEmpty()) { + t.file = m_callStack.last().file; + t.line = m_callStack.last().line; LinkSpecs specs; t.details << QString(); t.details << Tr::tr("Call stack:"); m_lines += 2; - m_callStack->push_front(m_errorOrWarningLine); + m_callStack.push_front(m_errorOrWarningLine); int offset = t.details.join('\n').size(); - Utils::reverseForeach(m_callStack.value(), [&](const auto &line) { + Utils::reverseForeach(m_callStack, [&](const auto &line) { const QString fileAndLine = QString("%1:%2").arg(line.file.path()).arg(line.line); const QString completeLine = QString(" %1%2").arg(fileAndLine).arg(line.function); @@ -247,7 +247,8 @@ void CMakeOutputParser::flush() scheduleTask(t, m_lines, 1); m_lines = 0; - m_callStack.reset(); + m_callStack.clear(); + m_callStackDetected = false; } } // CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakeoutputparser.h b/src/plugins/cmakeprojectmanager/cmakeoutputparser.h index bdbddb58bf3..84a7878661e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeoutputparser.h +++ b/src/plugins/cmakeprojectmanager/cmakeoutputparser.h @@ -49,7 +49,8 @@ private: int line = -1; QString function; }; - std::optional> m_callStack; + QList m_callStack; + bool m_callStackDetected = false; CallStackLine m_errorOrWarningLine; }; From f119f3fbda8b7ab8b8f25acac228d3e9445e590e Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 6 Jan 2025 11:29:58 +0100 Subject: [PATCH 509/989] CompilerExplorer: remove unused function Change-Id: I5f32f7b9f9f56a10c8c3e02ef2d4495a20d82e33 Reviewed-by: Marcus Tillmanns --- src/plugins/compilerexplorer/compilerexplorereditor.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/plugins/compilerexplorer/compilerexplorereditor.cpp b/src/plugins/compilerexplorer/compilerexplorereditor.cpp index 43086b9061b..c623f527d27 100644 --- a/src/plugins/compilerexplorer/compilerexplorereditor.cpp +++ b/src/plugins/compilerexplorer/compilerexplorereditor.cpp @@ -185,7 +185,6 @@ class SourceEditorWidget : public QWidget public: SourceEditorWidget(const std::shared_ptr &settings, QUndoStack *undoStack); - QString sourceCode(); SourceSettings *sourceSettings() { return m_sourceSettings.get(); } void focusInEvent(QFocusEvent *) override { emit gotFocus(); } @@ -522,13 +521,6 @@ SourceEditorWidget::SourceEditorWidget(const std::shared_ptr &se setFocusProxy(m_codeEditor); } -QString SourceEditorWidget::sourceCode() -{ - if (m_codeEditor && m_codeEditor->textDocument()) - return QString::fromUtf8(m_codeEditor->textDocument()->contents()); - return {}; -} - void SourceEditorWidget::markSourceLocation( const std::optional &assemblyLine) { From b626da4e2c13f698e9930471edaa75a1cb5dbc48 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 2 Jan 2025 08:56:19 +0100 Subject: [PATCH 510/989] Editor: fix typo Change-Id: I9abb2e3abb44753a86445d2aea37c97b5beeeb56 Reviewed-by: Christian Stenger --- src/plugins/texteditor/texteditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 97b67e45248..51e9f52374e 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -5108,7 +5108,7 @@ void TextEditorWidgetPrivate::highlightSearchResults(const QTextBlock &block, co if (!m_find->inScope(start, end)) continue; - // check if the result is inside the visibale area for long blocks + // check if the result is inside the visible area for long blocks const QTextLine &startLine = block.layout()->lineForTextPosition(idx); const QTextLine &endLine = block.layout()->lineForTextPosition(idx + l); From 705dcb17b8adad1b6fd78a02ccb1d0b1d0ca3ddd Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 13 Dec 2024 11:14:28 +0100 Subject: [PATCH 511/989] Disambiguate translations for "None" Translations can be different depending on context. Give each usage a disambiguation text. Task-number: QTCREATORBUG-31978 Change-Id: I44ac524d7448787360e825fad1d430ded3f07659 Reviewed-by: Christian Stenger --- src/libs/extensionsystem/plugindetailsview.cpp | 3 ++- src/plugins/android/androiddevice.cpp | 2 +- src/plugins/baremetal/debugserverproviderchooser.cpp | 2 +- src/plugins/cmakeprojectmanager/cmakesettingspage.cpp | 2 +- src/plugins/coreplugin/find/ifindfilter.cpp | 2 +- .../cppeditor/quickfixes/insertfunctiondefinition.cpp | 5 ++++- src/plugins/debugger/debuggerkitaspect.cpp | 2 +- src/plugins/debugger/moduleshandler.cpp | 3 ++- src/plugins/ios/iosbuildconfiguration.cpp | 2 +- src/plugins/nim/project/nimcompilerbuildstep.cpp | 2 +- src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp | 7 ++++++- src/plugins/projectexplorer/projectexplorersettings.cpp | 3 ++- src/plugins/projectexplorer/toolchainkitaspect.cpp | 6 +++--- src/plugins/projectexplorer/toolchainmanager.cpp | 6 +++--- src/plugins/projectexplorer/toolchainoptionspage.cpp | 2 +- src/plugins/python/pythonsettings.cpp | 2 +- src/plugins/qmlprofiler/quick3dframemodel.cpp | 2 +- src/plugins/qmlprofiler/quick3dframeview.cpp | 4 ++-- src/plugins/qtsupport/qtkitaspect.cpp | 3 ++- src/plugins/qtsupport/qtoptionspage.cpp | 6 +++--- src/plugins/texteditor/behaviorsettingswidget.cpp | 2 +- src/plugins/texteditor/completionsettingspage.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 2 +- 23 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/libs/extensionsystem/plugindetailsview.cpp b/src/libs/extensionsystem/plugindetailsview.cpp index eba1058dcbe..903e7410ac1 100644 --- a/src/libs/extensionsystem/plugindetailsview.cpp +++ b/src/libs/extensionsystem/plugindetailsview.cpp @@ -155,7 +155,8 @@ void PluginDetailsView::update(PluginSpec *spec) d->compatVersion->setText(spec->compatVersion()); d->vendor->setText(spec->vendor()); d->vendorId->setText(spec->vendorId()); - d->component->setText(spec->category().isEmpty() ? Tr::tr("None") : spec->category()); + d->component->setText( + spec->category().isEmpty() ? Tr::tr("None", "No category") : spec->category()); const auto toHtmlLink = [](const QString &url) { return QString::fromLatin1("
    %1").arg(url); }; diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index d29f149f5b7..e0d731420c3 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -574,7 +574,7 @@ QString AndroidDevice::deviceTypeName() const QString AndroidDevice::skinName() const { const QString skin = avdSettings()->value("skin.name").toString(); - return skin.isEmpty() ? Tr::tr("None") : skin; + return skin.isEmpty() ? Tr::tr("None", "No skin") : skin; } QString AndroidDevice::androidTargetName() const diff --git a/src/plugins/baremetal/debugserverproviderchooser.cpp b/src/plugins/baremetal/debugserverproviderchooser.cpp index ac05c88e0d4..dcf148cbbd4 100644 --- a/src/plugins/baremetal/debugserverproviderchooser.cpp +++ b/src/plugins/baremetal/debugserverproviderchooser.cpp @@ -82,7 +82,7 @@ void DebugServerProviderChooser::populate() { const QSignalBlocker blocker(m_chooser); m_chooser->clear(); - m_chooser->addItem(Tr::tr("None")); + m_chooser->addItem(Tr::tr("None", "No debug server provider")); for (const IDebugServerProvider *p : DebugServerProviderManager::providers()) { if (!providerMatches(p)) diff --git a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp index 5dc29c3df8a..36ee8406c00 100644 --- a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp @@ -139,7 +139,7 @@ QVariant CMakeToolTreeItem::data(int column, int role) const if (!m_id.isValid()) { if (role == Qt::DisplayRole && column == 0) - return Tr::tr("None"); + return Tr::tr("None", "No CMake tool"); if (role == ProjectExplorer::KitAspect::IsNoneRole) return true; return {}; diff --git a/src/plugins/coreplugin/find/ifindfilter.cpp b/src/plugins/coreplugin/find/ifindfilter.cpp index eca6c4f2a91..d7c251f71bb 100644 --- a/src/plugins/coreplugin/find/ifindfilter.cpp +++ b/src/plugins/coreplugin/find/ifindfilter.cpp @@ -371,7 +371,7 @@ QString IFindFilter::descriptionForFindFlags(FindFlags flags) flagStrings.append(Tr::tr("Preserve case")); QString description = Tr::tr("Flags: %1"); if (flagStrings.isEmpty()) - description = description.arg(Tr::tr("None")); + description = description.arg(Tr::tr("None", "No find flags")); else description = description.arg(flagStrings.join(Tr::tr(", "))); return description; diff --git a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp index 3d95fc21f8e..204014dfebf 100644 --- a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp +++ b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp @@ -238,7 +238,10 @@ public: setWindowTitle(Tr::tr("Member Function Implementations")); const auto defaultImplTargetComboBox = new QComboBox; - QStringList implTargetStrings{Tr::tr("None"), Tr::tr("Inline"), Tr::tr("Outside Class")}; + QStringList implTargetStrings{ + Tr::tr("None", "No default implementation location"), + Tr::tr("Inline"), + Tr::tr("Outside Class")}; if (!implFile.isEmpty()) implTargetStrings.append(implFile.fileName()); defaultImplTargetComboBox->insertItems(0, implTargetStrings); diff --git a/src/plugins/debugger/debuggerkitaspect.cpp b/src/plugins/debugger/debuggerkitaspect.cpp index 6f578828434..895dc5b6fd5 100644 --- a/src/plugins/debugger/debuggerkitaspect.cpp +++ b/src/plugins/debugger/debuggerkitaspect.cpp @@ -60,7 +60,7 @@ public: rootItem()->appendChild(new DebuggerTreeItem(item, false)); } DebuggerItem noneItem; - noneItem.setUnexpandedDisplayName(Tr::tr("None")); + noneItem.setUnexpandedDisplayName(Tr::tr("None", "No debugger")); rootItem()->appendChild(new DebuggerTreeItem(noneItem, false)); } diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index a6b10b59ffe..bf56c71da38 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -70,7 +70,8 @@ QVariant ModuleItem::data(int column, int role) const if (role == Qt::DisplayRole) switch (module.elfData.symbolsType) { case UnknownSymbols: return Tr::tr("Unknown"); - case NoSymbols: return Tr::tr("None"); + case NoSymbols: + return Tr::tr("None", "Symbols Type (No debug information found)"); case PlainSymbols: return Tr::tr("Plain"); case FastSymbols: return Tr::tr("Fast"); case LinkedSymbols: return Tr::tr("debuglnk"); diff --git a/src/plugins/ios/iosbuildconfiguration.cpp b/src/plugins/ios/iosbuildconfiguration.cpp index bbca70a263e..eb3350b3510 100644 --- a/src/plugins/ios/iosbuildconfiguration.cpp +++ b/src/plugins/ios/iosbuildconfiguration.cpp @@ -271,7 +271,7 @@ void IosSigningSettingsWidget::populateProvisioningProfiles() m_signEntityCombo->setItemData(index, profile->details(), Qt::ToolTipRole); } } else { - m_signEntityCombo->addItem(Tr::tr("None")); + m_signEntityCombo->addItem(Tr::tr("None", "No signing identity")); } } // Maintain previous selection. diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp index 8c2dfa67c40..ce820926bed 100644 --- a/src/plugins/nim/project/nimcompilerbuildstep.cpp +++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp @@ -64,7 +64,7 @@ QWidget *NimCompilerBuildStep::createConfigWidget() commandTextEdit->setMinimumSize(QSize(0, 0)); auto defaultArgumentsComboBox = new QComboBox(widget); - defaultArgumentsComboBox->addItem(Tr::tr("None")); + defaultArgumentsComboBox->addItem(Tr::tr("None", "No default arguments")); defaultArgumentsComboBox->addItem(Tr::tr("Debug")); defaultArgumentsComboBox->addItem(Tr::tr("Release")); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp index 22768efca2f..18d90bca77c 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonprojectpage.cpp @@ -139,7 +139,12 @@ void JsonProjectPage::initUiForSubProject() const QList currentProjects = ProjectManager::projects(); QList projectInfos; - projectInfos.append({Tr::tr("None"), Core::DocumentManager::projectsDirectory(), {}, {}, {}}); + projectInfos.append( + {Tr::tr("None", "Add to project: None"), + Core::DocumentManager::projectsDirectory(), + {}, + {}, + {}}); int index = -1; int counter = 1; // we've added None already for (const Project *proj : currentProjects) { diff --git a/src/plugins/projectexplorer/projectexplorersettings.cpp b/src/plugins/projectexplorer/projectexplorersettings.cpp index f940b8d1a5f..de18ec30002 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.cpp +++ b/src/plugins/projectexplorer/projectexplorersettings.cpp @@ -346,7 +346,8 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget() const QSizePolicy cbSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); m_buildBeforeDeployComboBox->setSizePolicy(cbSizePolicy); m_stopBeforeBuildComboBox = new QComboBox; - m_stopBeforeBuildComboBox->addItem(Tr::tr("None"), int(StopBeforeBuild::None)); + m_stopBeforeBuildComboBox->addItem( + Tr::tr("None", "Stop applications before building: None"), int(StopBeforeBuild::None)); m_stopBeforeBuildComboBox->addItem(Tr::tr("All"), int(StopBeforeBuild::All)); m_stopBeforeBuildComboBox->addItem(Tr::tr("Same Project"), int(StopBeforeBuild::SameProject)); m_stopBeforeBuildComboBox->addItem(Tr::tr("Same Build Directory"), diff --git a/src/plugins/projectexplorer/toolchainkitaspect.cpp b/src/plugins/projectexplorer/toolchainkitaspect.cpp index d68d3b24ae8..05ce6d9b56e 100644 --- a/src/plugins/projectexplorer/toolchainkitaspect.cpp +++ b/src/plugins/projectexplorer/toolchainkitaspect.cpp @@ -338,7 +338,7 @@ QString ToolchainKitAspectFactory::displayNamePostfix(const Kit *k) const KitAspectFactory::ItemList ToolchainKitAspectFactory::toUserOutput(const Kit *k) const { Toolchain *tc = ToolchainKitAspect::cxxToolchain(k); - return {{Tr::tr("Compiler"), tc ? tc->displayName() : Tr::tr("None")}}; + return {{Tr::tr("Compiler"), tc ? tc->displayName() : Tr::tr("None", "No compiler")}}; } void ToolchainKitAspectFactory::addToBuildEnvironment(const Kit *k, Environment &env) const @@ -356,7 +356,7 @@ void ToolchainKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expa expander->registerVariable("Compiler:Name", Tr::tr("Compiler"), [kit] { const Toolchain *tc = ToolchainKitAspect::cxxToolchain(kit); - return tc ? tc->displayName() : Tr::tr("None"); + return tc ? tc->displayName() : Tr::tr("None", "No compiler"); }); expander->registerVariable("Compiler:Executable", Tr::tr("Path to the compiler executable"), @@ -369,7 +369,7 @@ void ToolchainKitAspectFactory::addToMacroExpander(Kit *kit, MacroExpander *expa expander->registerPrefix("Compiler:Name", Tr::tr("Compiler for different languages"), [kit](const QString &ls) { const Toolchain *tc = ToolchainKitAspect::toolchain(kit, findLanguage(ls)); - return tc ? tc->displayName() : Tr::tr("None"); + return tc ? tc->displayName() : Tr::tr("None", "No compiler"); }); expander->registerPrefix("Compiler:Executable", Tr::tr("Compiler executable for different languages"), [kit](const QString &ls) { diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp index c7d7ce786cf..e958049d86b 100644 --- a/src/plugins/projectexplorer/toolchainmanager.cpp +++ b/src/plugins/projectexplorer/toolchainmanager.cpp @@ -265,9 +265,9 @@ void ToolchainManager::registerLanguageCategory(const LanguageCategory &language QString ToolchainManager::displayNameOfLanguageId(const Utils::Id &id) { - QTC_ASSERT(id.isValid(), return Tr::tr("None")); + QTC_ASSERT(id.isValid(), return Tr::tr("None", "No compiler language")); QString display = d->m_displayNameForLanguage.value(id); - QTC_ASSERT(!display.isEmpty(), return Tr::tr("None")); + QTC_ASSERT(!display.isEmpty(), return Tr::tr("None", "No compiler language")); return display; } @@ -276,7 +276,7 @@ QString ToolchainManager::displayNameOfLanguageCategory(const LanguageCategory & if (int(category.size()) == 1) return displayNameOfLanguageId(*category.begin()); QString name = d->m_displayNameForCategory.value(category); - QTC_ASSERT(!name.isEmpty(), return Tr::tr("None")); + QTC_ASSERT(!name.isEmpty(), return Tr::tr("None", "No compiler category")); return name; } diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp index c3f09d1fecd..da6ee179327 100644 --- a/src/plugins/projectexplorer/toolchainoptionspage.cpp +++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp @@ -52,7 +52,7 @@ QVariant ToolchainTreeItem::data(int column, int role) const switch (role) { case Qt::DisplayRole: if (column == 0) - return bundle ? bundle->displayName() : Tr::tr("None"); + return bundle ? bundle->displayName() : Tr::tr("None", "Toolchain bundle display name"); return bundle->typeDisplayName(); case Qt::ToolTipRole: { if (!bundle) diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 20eae05906b..e9fbff36b10 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -1172,7 +1172,7 @@ Utils::ListModel *createInterpreterModel(QObject * model->setDataAccessor([](const Interpreter &interpreter, int column, int role) -> QVariant { if (interpreter.id == "none") { if (role == Qt::DisplayRole) - return Tr::tr("None"); + return Tr::tr("None", "No Python interpreter"); if (role == KitAspect::IsNoneRole) return true; return {}; diff --git a/src/plugins/qmlprofiler/quick3dframemodel.cpp b/src/plugins/qmlprofiler/quick3dframemodel.cpp index ea8d09c2475..0774a9315c2 100644 --- a/src/plugins/qmlprofiler/quick3dframemodel.cpp +++ b/src/plugins/qmlprofiler/quick3dframemodel.cpp @@ -472,7 +472,7 @@ QStringList Quick3DFrameModel::frameNames(const QString &view3D) const void Quick3DFrameModel::setFilterFrame(const QString &frame) { - if (frame == Tr::tr("None")) { + if (frame == Tr::tr("None", "Compare Frame: None")) { m_filterFrame = -1; } else { QString title = Tr::tr("Frame"); diff --git a/src/plugins/qmlprofiler/quick3dframeview.cpp b/src/plugins/qmlprofiler/quick3dframeview.cpp index 64f51c9970f..d0b59afc703 100644 --- a/src/plugins/qmlprofiler/quick3dframeview.cpp +++ b/src/plugins/qmlprofiler/quick3dframeview.cpp @@ -85,7 +85,7 @@ Quick3DFrameView::Quick3DFrameView(QmlProfilerModelManager *profilerModelManager list << model->view3DNames(); view3DComboModel->setStringList(list); list.clear(); - list << Tr::tr("None"); + list << Tr::tr("None", "Compare Frame: None"); list << model->frameNames(Tr::tr("All")); frameComboModel->setStringList(list); }); @@ -93,7 +93,7 @@ Quick3DFrameView::Quick3DFrameView(QmlProfilerModelManager *profilerModelManager m_mainView->setFilterView3D(text); model->setFilterView3D(text); QStringList list; - list << Tr::tr("None"); + list << Tr::tr("None", "Compare Frame: None"); list << model->frameNames(text); frameComboModel->setStringList(list); }); diff --git a/src/plugins/qtsupport/qtkitaspect.cpp b/src/plugins/qtsupport/qtkitaspect.cpp index a69c7997864..45ce44b0f3a 100644 --- a/src/plugins/qtsupport/qtkitaspect.cpp +++ b/src/plugins/qtsupport/qtkitaspect.cpp @@ -286,7 +286,8 @@ QString QtKitAspectFactory::displayNamePostfix(const Kit *k) const KitAspectFactory::ItemList QtKitAspectFactory::toUserOutput(const Kit *k) const { QtVersion *version = QtKitAspect::qtVersion(k); - return {{Tr::tr("Qt version"), version ? version->displayName() : Tr::tr("None")}}; + return { + {Tr::tr("Qt version"), version ? version->displayName() : Tr::tr("None", "No Qt version")}}; } void QtKitAspectFactory::addToBuildEnvironment(const Kit *k, Environment &env) const diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index e382b2f984d..62aabe6e7e2 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -169,7 +169,7 @@ QVariant QtVersionItem::data(int column, int role) const if (role == KitAspect::IsNoneRole && column == 0) return true; if (role == Qt::DisplayRole && column == 0) - return Tr::tr("None"); + return Tr::tr("None", "No Qt version"); if (role == KitAspect::IdRole) return -1; return TreeItem::data(column, role); @@ -438,8 +438,8 @@ QtSettingsPageWidget::QtSettingsPageWidget() m_documentationSetting->addItem(Tr::tr("Highest Version Only"), int(QtVersionManager::DocumentationSetting::HighestOnly)); m_documentationSetting->addItem(Tr::tr("All"), int(QtVersionManager::DocumentationSetting::All)); - m_documentationSetting->addItem(Tr::tr("None"), - int(QtVersionManager::DocumentationSetting::None)); + m_documentationSetting->addItem( + Tr::tr("None", "No documentation"), int(QtVersionManager::DocumentationSetting::None)); const int selectedIndex = m_documentationSetting->findData( int(QtVersionManager::documentationSetting())); if (selectedIndex >= 0) diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp index 9bdc7ff444a..9fd1d49414a 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.cpp +++ b/src/plugins/texteditor/behaviorsettingswidget.cpp @@ -74,7 +74,7 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) d->tabKeyBehavior->addItem(Tr::tr("In Leading White Space")); d->smartBackspaceBehavior = new QComboBox; - d->smartBackspaceBehavior->addItem(Tr::tr("None")); + d->smartBackspaceBehavior->addItem(Tr::tr("None", "Backspace indentation: None")); d->smartBackspaceBehavior->addItem(Tr::tr("Follows Previous Indents")); d->smartBackspaceBehavior->addItem(Tr::tr("Unindents")); d->smartBackspaceBehavior->setToolTip(Tr::tr("\n" diff --git a/src/plugins/texteditor/completionsettingspage.cpp b/src/plugins/texteditor/completionsettingspage.cpp index 271eac8129b..5283cb5ce34 100644 --- a/src/plugins/texteditor/completionsettingspage.cpp +++ b/src/plugins/texteditor/completionsettingspage.cpp @@ -65,7 +65,7 @@ CompletionSettingsPageWidget::CompletionSettingsPageWidget(CompletionSettingsPag { m_caseSensitivity = new QComboBox; m_caseSensitivity->addItem(Tr::tr("Full")); - m_caseSensitivity->addItem(Tr::tr("None")); + m_caseSensitivity->addItem(Tr::tr("None", "Case-sensitivity: None")); m_caseSensitivity->addItem(Tr::tr("First Letter")); auto caseSensitivityLabel = new QLabel(Tr::tr("&Case-sensitivity:")); diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 24a277da57f..97ebcbba1e3 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -1224,7 +1224,7 @@ HeobDialog::HeobDialog(QWidget *parent) : auto leakDetailLabel = new QLabel(Tr::tr("Leak details:")); leakDetailLayout->addWidget(leakDetailLabel); m_leakDetailCombo = new QComboBox; - m_leakDetailCombo->addItem(Tr::tr("None")); + m_leakDetailCombo->addItem(Tr::tr("None", "Leak details: None")); m_leakDetailCombo->addItem(Tr::tr("Simple")); m_leakDetailCombo->addItem(Tr::tr("Detect Leak Types")); m_leakDetailCombo->addItem(Tr::tr("Detect Leak Types (Show Reachable)")); From 638874edfbea299d7c9eeb742a41b96788cf5aa4 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 13 Dec 2024 12:25:47 +0100 Subject: [PATCH 512/989] Disambiguate translations for "All" Translations can be different depending on context. Give each usage a disambiguation text. Task-number: QTCREATORBUG-31978 Change-Id: I5fe854f96ce285943ff47993cd6d56db603d1c27 Reviewed-by: Christian Stenger --- src/libs/extensionsystem/plugindetailsview.cpp | 2 +- src/plugins/android/androidsdkmanagerdialog.cpp | 2 +- src/plugins/autotest/projectsettingswidget.cpp | 2 +- src/plugins/autotest/testsettings.cpp | 2 +- src/plugins/cppeditor/symbolsfindfilter.cpp | 8 +++++--- src/plugins/extensionmanager/extensionsbrowser.cpp | 6 ++---- src/plugins/git/gitclient.cpp | 8 ++++---- src/plugins/projectexplorer/projectexplorersettings.cpp | 2 +- src/plugins/qmlprofiler/quick3dframemodel.cpp | 4 ++-- src/plugins/qmlprofiler/quick3dframeview.cpp | 6 +++--- src/plugins/qtsupport/qtoptionspage.cpp | 3 ++- 11 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/libs/extensionsystem/plugindetailsview.cpp b/src/libs/extensionsystem/plugindetailsview.cpp index 903e7410ac1..9dff8f58985 100644 --- a/src/libs/extensionsystem/plugindetailsview.cpp +++ b/src/libs/extensionsystem/plugindetailsview.cpp @@ -164,7 +164,7 @@ void PluginDetailsView::update(PluginSpec *spec) d->documentationUrl->setText(toHtmlLink(spec->documentationUrl())); d->location->setText(spec->filePath().toUserOutput()); const QString pattern = spec->platformSpecification().pattern(); - const QString platform = pattern.isEmpty() ? Tr::tr("All") : pattern; + const QString platform = pattern.isEmpty() ? Tr::tr("All", "Platforms: All") : pattern; const QString platformString = Tr::tr("%1 (current: \"%2\")") .arg(platform, PluginManager::platformName()); d->platforms->setText(platformString); diff --git a/src/plugins/android/androidsdkmanagerdialog.cpp b/src/plugins/android/androidsdkmanagerdialog.cpp index 4de5df631bf..679dc2376d0 100644 --- a/src/plugins/android/androidsdkmanagerdialog.cpp +++ b/src/plugins/android/androidsdkmanagerdialog.cpp @@ -439,7 +439,7 @@ AndroidSdkManagerDialog::AndroidSdkManagerDialog() auto showAvailableRadio = new QRadioButton(Tr::tr("Available")); auto showInstalledRadio = new QRadioButton(Tr::tr("Installed")); - auto showAllRadio = new QRadioButton(Tr::tr("All")); + auto showAllRadio = new QRadioButton(Tr::tr("All", "Show all packages")); showAllRadio->setChecked(true); auto optionsButton = new QPushButton(Tr::tr("Advanced Options...")); diff --git a/src/plugins/autotest/projectsettingswidget.cpp b/src/plugins/autotest/projectsettingswidget.cpp index 9a14b40345d..eb450dbbd3b 100644 --- a/src/plugins/autotest/projectsettingswidget.cpp +++ b/src/plugins/autotest/projectsettingswidget.cpp @@ -62,7 +62,7 @@ ProjectTestSettingsWidget::ProjectTestSettingsWidget(Project *project) m_activeFrameworks->setRootIsDecorated(false); m_runAfterBuild = new QComboBox; m_runAfterBuild->addItem(Tr::tr("No Tests")); - m_runAfterBuild->addItem(Tr::tr("All")); + m_runAfterBuild->addItem(Tr::tr("All", "Run tests after build")); m_runAfterBuild->addItem(Tr::tr("Selected")); m_runAfterBuild->setCurrentIndex(int(m_projectSettings->runAfterBuild())); m_applyFilter.setToolTip(Tr::tr("Apply path filters before scanning for tests.")); diff --git a/src/plugins/autotest/testsettings.cpp b/src/plugins/autotest/testsettings.cpp index af1767e4283..84edff3102d 100644 --- a/src/plugins/autotest/testsettings.cpp +++ b/src/plugins/autotest/testsettings.cpp @@ -107,7 +107,7 @@ TestSettings::TestSettings() runAfterBuild.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox); runAfterBuild.setToolTip(Tr::tr("Runs chosen tests automatically if a build succeeded.")); runAfterBuild.addOption(Tr::tr("No Tests")); - runAfterBuild.addOption(Tr::tr("All")); + runAfterBuild.addOption(Tr::tr("All", "Run tests after build")); runAfterBuild.addOption(Tr::tr("Selected")); fromSettings(); diff --git a/src/plugins/cppeditor/symbolsfindfilter.cpp b/src/plugins/cppeditor/symbolsfindfilter.cpp index 5d7c2e57aa3..68d68b50bb2 100644 --- a/src/plugins/cppeditor/symbolsfindfilter.cpp +++ b/src/plugins/cppeditor/symbolsfindfilter.cpp @@ -223,9 +223,11 @@ QString SymbolsFindFilter::toolTip(FindFlags findFlags) const if (m_symbolsToSearch & SymbolSearcher::Declarations) types.append(Tr::tr("Declarations")); return Tr::tr("Scope: %1\nTypes: %2\nFlags: %3") - .arg(searchScope() == SymbolSearcher::SearchGlobal ? Tr::tr("All") : Tr::tr("Projects"), - types.join(", "), - IFindFilter::descriptionForFindFlags(findFlags)); + .arg( + searchScope() == SymbolSearcher::SearchGlobal ? Tr::tr("All", "Symbol search scope") + : Tr::tr("Projects"), + types.join(", "), + IFindFilter::descriptionForFindFlags(findFlags)); } // #pragma mark -- SymbolsFindFilterConfigWidget diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index 420bb0344fb..ed04d938ed2 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -448,10 +448,8 @@ public: { static const QList options = { { - Tr::tr("All"), - []([[maybe_unused]] const QModelIndex &index) { - return true; - }, + Tr::tr("All", "Extensions filter"), + []([[maybe_unused]] const QModelIndex &index) { return true; }, }, { Tr::tr("Extension packs"), diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 811a754cc7d..ca1a65fb9ae 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -647,10 +647,10 @@ public: GitLogConfig(bool fileRelated, GitEditorWidget *editor) : GitBaseConfig(editor) { - QAction *allBranchesButton = - addToggleButton(QStringList{"--all"}, - Tr::tr("All"), - Tr::tr("Show log for all local branches.")); + QAction *allBranchesButton = addToggleButton( + QStringList{"--all"}, + Tr::tr("All", "All branches"), + Tr::tr("Show log for all local branches.")); mapSetting(allBranchesButton, &settings().allBranches); QAction *firstParentButton = addToggleButton({"-m", "--first-parent"}, diff --git a/src/plugins/projectexplorer/projectexplorersettings.cpp b/src/plugins/projectexplorer/projectexplorersettings.cpp index de18ec30002..1ffffec2b7a 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.cpp +++ b/src/plugins/projectexplorer/projectexplorersettings.cpp @@ -348,7 +348,7 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget() m_stopBeforeBuildComboBox = new QComboBox; m_stopBeforeBuildComboBox->addItem( Tr::tr("None", "Stop applications before building: None"), int(StopBeforeBuild::None)); - m_stopBeforeBuildComboBox->addItem(Tr::tr("All"), int(StopBeforeBuild::All)); + m_stopBeforeBuildComboBox->addItem(Tr::tr("All", "Stop all projects"), int(StopBeforeBuild::All)); m_stopBeforeBuildComboBox->addItem(Tr::tr("Same Project"), int(StopBeforeBuild::SameProject)); m_stopBeforeBuildComboBox->addItem(Tr::tr("Same Build Directory"), int(StopBeforeBuild::SameBuildDir)); diff --git a/src/plugins/qmlprofiler/quick3dframemodel.cpp b/src/plugins/qmlprofiler/quick3dframemodel.cpp index 0774a9315c2..1e99fde12e5 100644 --- a/src/plugins/qmlprofiler/quick3dframemodel.cpp +++ b/src/plugins/qmlprofiler/quick3dframemodel.cpp @@ -443,7 +443,7 @@ QList Quick3DFrameModel::frameIndices(const QString &view3DFilter) const { QList ret; int key = -1; - if (view3DFilter != Tr::tr("All")) { + if (view3DFilter != Tr::tr("All", "All frames")) { for (int v3d : m_frameTimes.keys()) { if (m_modelManager->eventType(m_eventData[v3d]).data() == view3DFilter) { key = v3d; @@ -484,7 +484,7 @@ void Quick3DFrameModel::setFilterFrame(const QString &frame) void Quick3DFrameModel::setFilterView3D(const QString &view3D) { int key = -1; - if (view3D != Tr::tr("All")) { + if (view3D != Tr::tr("All", "All View3D frames")) { for (int v3d : m_frameTimes.keys()) { if (m_modelManager->eventType(m_eventData[v3d]).data() == view3D) { key = v3d; diff --git a/src/plugins/qmlprofiler/quick3dframeview.cpp b/src/plugins/qmlprofiler/quick3dframeview.cpp index d0b59afc703..78bbc53d651 100644 --- a/src/plugins/qmlprofiler/quick3dframeview.cpp +++ b/src/plugins/qmlprofiler/quick3dframeview.cpp @@ -81,12 +81,12 @@ Quick3DFrameView::Quick3DFrameView(QmlProfilerModelManager *profilerModelManager groupLayout->addLayout(hMainLayout); connect(model, &Quick3DFrameModel::modelReset, [model, view3DComboModel, frameComboModel](){ QStringList list; - list << Tr::tr("All"); + list << Tr::tr("All", "All View3D frames"); list << model->view3DNames(); view3DComboModel->setStringList(list); list.clear(); list << Tr::tr("None", "Compare Frame: None"); - list << model->frameNames(Tr::tr("All")); + list << model->frameNames(Tr::tr("All", "Compare Frame: All")); frameComboModel->setStringList(list); }); connect(view3DComboBox, &QComboBox::currentTextChanged, [this, model, frameComboModel](const QString &text){ @@ -161,7 +161,7 @@ Quick3DMainView::Quick3DMainView(Quick3DFrameModel *model, bool compareView, QWi void Quick3DMainView::setFilterView3D(const QString &objectName) { - if (objectName == Tr::tr("All")) + if (objectName == Tr::tr("All", "All View3D frames")) m_sortModel->setFilterFixedString(""); else m_sortModel->setFilterFixedString(objectName); diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 62aabe6e7e2..df01eb76f17 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -437,7 +437,8 @@ QtSettingsPageWidget::QtSettingsPageWidget() m_documentationSetting->addItem(Tr::tr("Highest Version Only"), int(QtVersionManager::DocumentationSetting::HighestOnly)); - m_documentationSetting->addItem(Tr::tr("All"), int(QtVersionManager::DocumentationSetting::All)); + m_documentationSetting->addItem( + Tr::tr("All", "All documentation"), int(QtVersionManager::DocumentationSetting::All)); m_documentationSetting->addItem( Tr::tr("None", "No documentation"), int(QtVersionManager::DocumentationSetting::None)); const int selectedIndex = m_documentationSetting->findData( From ab27988186b345fdd06740c1c6bb048ee72156fa Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 2 Jan 2025 14:18:31 +0100 Subject: [PATCH 513/989] PE: Rename SimpleTargetRunner into ProcessRunner Change-Id: Ie666fe0811aa63c54edf12934c6db4e17b26c252 Reviewed-by: hjk --- .../debugservers/gdb/gdbserverprovider.cpp | 2 +- .../debugservers/uvsc/uvscserverprovider.cpp | 2 +- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 4 +- .../haskell/haskellrunconfiguration.cpp | 2 +- .../mcusupport/mcusupportrunconfiguration.cpp | 2 +- .../mesonrunconfiguration.cpp | 2 +- src/plugins/nim/nimplugin.cpp | 6 +- .../customexecutablerunconfiguration.cpp | 2 +- .../desktoprunconfiguration.cpp | 4 +- src/plugins/projectexplorer/runcontrol.cpp | 80 +++++++++---------- src/plugins/projectexplorer/runcontrol.h | 20 ++--- .../projectexplorer/workspaceproject.cpp | 2 +- src/plugins/python/pythonrunconfiguration.cpp | 2 +- .../qmlpreview/qmlpreviewruncontrol.cpp | 2 +- .../qmlprofiler/qmlprofilerruncontrol.cpp | 2 +- .../qmlprojectmanager/qmlprojectplugin.cpp | 2 +- src/plugins/qnx/qnxanalyzesupport.cpp | 2 +- src/plugins/qnx/qnxdebugsupport.cpp | 4 +- src/plugins/qnx/qnxrunconfiguration.cpp | 2 +- .../appmanagerruncontrol.cpp | 4 +- .../remotelinux/remotelinuxdebugsupport.cpp | 4 +- .../webassemblyrunconfiguration.cpp | 2 +- 22 files changed, 74 insertions(+), 80 deletions(-) diff --git a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp index f510428e97e..ea8d4312597 100644 --- a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp @@ -172,7 +172,7 @@ RunWorker *GdbServerProvider::targetRunner(RunControl *runControl) const // Command arguments are in host OS style as the bare metal's GDB servers are launched // on the host, not on that target. - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setId("BareMetalGdbServer"); // Baremetal's GDB servers are launched on the host, not on the target. worker->setStartModifier([worker, cmd = command()] { diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp index c71c0d894af..0ccf87661d1 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp @@ -204,7 +204,7 @@ bool UvscServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMess ProjectExplorer::RunWorker *UvscServerProvider::targetRunner(RunControl *runControl) const { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setId("BareMetalUvscServer"); worker->setCommandLine({DebuggerKitAspect::runnable(runControl->kit()).command.executable(), {"-j0", QStringLiteral("-s%1").arg(m_channel.port())}}); diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index 5018b45d2fb..f46c2c7e746 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -29,7 +29,7 @@ namespace Qdb::Internal { static RunWorker *createQdbDeviceInferiorWorker(RunControl *runControl, QmlDebugServicesPreset qmlServices) { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setId("QdbDeviceInferiorWorker"); worker->setStartModifier([worker, runControl, qmlServices] { @@ -90,7 +90,7 @@ public: QdbRunWorkerFactory() { setProducer([](RunControl *runControl) { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setStartModifier([worker] { const CommandLine remoteCommand = worker->commandLine(); const FilePath remoteExe = remoteCommand.executable(); diff --git a/src/plugins/haskell/haskellrunconfiguration.cpp b/src/plugins/haskell/haskellrunconfiguration.cpp index c2acef8cb49..749fe050e78 100644 --- a/src/plugins/haskell/haskellrunconfiguration.cpp +++ b/src/plugins/haskell/haskellrunconfiguration.cpp @@ -91,7 +91,7 @@ public: void setupHaskellRunSupport() { static HaskellRunConfigurationFactory runConfigFactory; - static SimpleTargetRunnerFactory runWorkerFactory{{Constants::C_HASKELL_RUNCONFIG_ID}}; + static ProcessRunnerFactory runWorkerFactory{{Constants::C_HASKELL_RUNCONFIG_ID}}; static SimpleDebugRunnerFactory debugWorkerFactory{{Constants::C_HASKELL_RUNCONFIG_ID}}; } diff --git a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp index 781b27e9740..87d8e20a8ae 100644 --- a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp +++ b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp @@ -84,7 +84,7 @@ McuSupportRunConfigurationFactory::McuSupportRunConfigurationFactory() FlashRunWorkerFactory::FlashRunWorkerFactory() { setProducer([](RunControl *runControl) { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setStartModifier([worker, runControl] { const Target *target = runControl->target(); worker->setCommandLine({cmakeFilePath(target), diff --git a/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp b/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp index 65c732f335c..caf0823e7cd 100644 --- a/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp +++ b/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp @@ -97,7 +97,7 @@ void setupMesonRunConfiguration() void setupMesonRunAndDebugWorkers() { using namespace Debugger; - static SimpleTargetRunnerFactory theMesonRunWorkerFactory({Constants::MESON_RUNCONFIG_ID}); + static ProcessRunnerFactory theMesonRunWorkerFactory({Constants::MESON_RUNCONFIG_ID}); static SimpleDebugRunnerFactory theMesonDebugRunWorkerFactory({Constants::MESON_RUNCONFIG_ID}); } diff --git a/src/plugins/nim/nimplugin.cpp b/src/plugins/nim/nimplugin.cpp index 577f464a958..6315b5e92cc 100644 --- a/src/plugins/nim/nimplugin.cpp +++ b/src/plugins/nim/nimplugin.cpp @@ -49,11 +49,11 @@ public: NimRunConfigurationFactory nimRunConfigFactory; NimbleRunConfigurationFactory nimbleRunConfigFactory; NimbleTestConfigurationFactory nimbleTestConfigFactory; - SimpleTargetRunnerFactory nimRunWorkerFactory{{nimRunConfigFactory.runConfigurationId()}}; - SimpleTargetRunnerFactory nimbleRunWorkerFactory{{nimbleRunConfigFactory.runConfigurationId()}}; + ProcessRunnerFactory nimRunWorkerFactory{{nimRunConfigFactory.runConfigurationId()}}; + ProcessRunnerFactory nimbleRunWorkerFactory{{nimbleRunConfigFactory.runConfigurationId()}}; SimpleDebugRunnerFactory nimDebugWorkerFactory{{nimRunConfigFactory.runConfigurationId()}}; SimpleDebugRunnerFactory nimbleDebugWorkerFactory{{nimbleRunConfigFactory.runConfigurationId()}}; - SimpleTargetRunnerFactory nimbleTestWorkerFactory{{nimbleTestConfigFactory.runConfigurationId()}}; + ProcessRunnerFactory nimbleTestWorkerFactory{{nimbleTestConfigFactory.runConfigurationId()}}; NimbleBuildStepFactory nimbleBuildStepFactory; NimbleTaskStepFactory nimbleTaskStepFactory; NimCompilerBuildStepFactory buildStepFactory; diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp index b9c746703c5..fe4b707bf64 100644 --- a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp +++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp @@ -75,7 +75,7 @@ CustomExecutableRunConfigurationFactory::CustomExecutableRunConfigurationFactory CustomExecutableRunWorkerFactory::CustomExecutableRunWorkerFactory() { - setProduct(); + setProduct(); addSupportedRunMode(Constants::NORMAL_RUN_MODE); addSupportedRunConfig(Constants::CUSTOM_EXECUTABLE_RUNCONFIG_ID); } diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.cpp b/src/plugins/projectexplorer/desktoprunconfiguration.cpp index 3582dad2bf8..b3545746d8e 100644 --- a/src/plugins/projectexplorer/desktoprunconfiguration.cpp +++ b/src/plugins/projectexplorer/desktoprunconfiguration.cpp @@ -3,7 +3,7 @@ #include "desktoprunconfiguration.h" -#include "buildsystem.h" +#include "deploymentdata.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" #include "runconfigurationaspects.h" @@ -237,7 +237,7 @@ void setupDesktopRunConfigurations() void setupDesktopRunWorker() { - static SimpleTargetRunnerFactory theDesktopRunWorkerFactory({ + static ProcessRunnerFactory theDesktopRunWorkerFactory({ Constants::CMAKE_RUNCONFIG_ID, Constants::QBS_RUNCONFIG_ID, Constants::QMAKE_RUNCONFIG_ID diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 83a2eecb608..22d0f538ce5 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1366,15 +1366,15 @@ void RunControlPrivate::debugMessage(const QString &msg) const } -// SimpleTargetRunnerPrivate +// ProcessRunnerPrivate namespace Internal { -class SimpleTargetRunnerPrivate : public QObject +class ProcessRunnerPrivate : public QObject { public: - explicit SimpleTargetRunnerPrivate(SimpleTargetRunner *parent); - ~SimpleTargetRunnerPrivate() override; + explicit ProcessRunnerPrivate(ProcessRunner *parent); + ~ProcessRunnerPrivate() override; void start(); void stop(); @@ -1391,7 +1391,7 @@ public: qint64 privateApplicationPID() const; bool isRunning() const; - SimpleTargetRunner *q = nullptr; + ProcessRunner *q = nullptr; bool m_runAsRoot = false; @@ -1425,16 +1425,16 @@ static QProcess::ProcessChannelMode defaultProcessChannelMode() ? QProcess::MergedChannels : QProcess::SeparateChannels; } -SimpleTargetRunnerPrivate::SimpleTargetRunnerPrivate(SimpleTargetRunner *parent) +ProcessRunnerPrivate::ProcessRunnerPrivate(ProcessRunner *parent) : q(parent) { m_process.setProcessChannelMode(defaultProcessChannelMode()); - connect(&m_process, &Process::started, this, &SimpleTargetRunnerPrivate::forwardStarted); - connect(&m_process, &Process::done, this, &SimpleTargetRunnerPrivate::handleDone); + connect(&m_process, &Process::started, this, &ProcessRunnerPrivate::forwardStarted); + connect(&m_process, &Process::done, this, &ProcessRunnerPrivate::handleDone); connect(&m_process, &Process::readyReadStandardError, - this, &SimpleTargetRunnerPrivate::handleStandardError); + this, &ProcessRunnerPrivate::handleStandardError); connect(&m_process, &Process::readyReadStandardOutput, - this, &SimpleTargetRunnerPrivate::handleStandardOutput); + this, &ProcessRunnerPrivate::handleStandardOutput); connect(&m_process, &Process::requestingStop, this, [this] { q->appendMessage(Tr::tr("Requesting process to stop ...."), NormalMessageFormat); }); @@ -1471,13 +1471,13 @@ SimpleTargetRunnerPrivate::SimpleTargetRunnerPrivate(SimpleTargetRunner *parent) } } -SimpleTargetRunnerPrivate::~SimpleTargetRunnerPrivate() +ProcessRunnerPrivate::~ProcessRunnerPrivate() { if (m_state == Run) forwardDone(); } -void SimpleTargetRunnerPrivate::stop() +void ProcessRunnerPrivate::stop() { if (m_stopRequested || m_state != Run) return; @@ -1489,12 +1489,12 @@ void SimpleTargetRunnerPrivate::stop() m_process.stop(); } -bool SimpleTargetRunnerPrivate::isRunning() const +bool ProcessRunnerPrivate::isRunning() const { return m_process.state() != QProcess::NotRunning; } -qint64 SimpleTargetRunnerPrivate::privateApplicationPID() const +qint64 ProcessRunnerPrivate::privateApplicationPID() const { if (!isRunning()) return 0; @@ -1502,14 +1502,14 @@ qint64 SimpleTargetRunnerPrivate::privateApplicationPID() const return m_process.processId(); } -void SimpleTargetRunnerPrivate::handleDone() +void ProcessRunnerPrivate::handleDone() { m_resultData = m_process.resultData(); QTC_CHECK(m_state == Run); forwardDone(); } -void SimpleTargetRunnerPrivate::handleStandardOutput() +void ProcessRunnerPrivate::handleStandardOutput() { if (m_suppressDefaultStdOutHandling) return; @@ -1518,7 +1518,7 @@ void SimpleTargetRunnerPrivate::handleStandardOutput() q->appendMessage(msg, StdOutFormat, false); } -void SimpleTargetRunnerPrivate::handleStandardError() +void ProcessRunnerPrivate::handleStandardError() { if (m_suppressDefaultStdOutHandling) return; @@ -1527,7 +1527,7 @@ void SimpleTargetRunnerPrivate::handleStandardError() q->appendMessage(msg, StdErrFormat, false); } -void SimpleTargetRunnerPrivate::start() +void ProcessRunnerPrivate::start() { CommandLine cmdLine = m_command; Environment env = m_environment; @@ -1576,9 +1576,9 @@ void SimpleTargetRunnerPrivate::start() } /*! - \class ProjectExplorer::SimpleTargetRunner + \class ProjectExplorer::ProcessRunner - \brief The SimpleTargetRunner class is the application launcher of the + \brief The ProcessRunner class is the application launcher of the ProjectExplorer plugin. Encapsulates processes running in a console or as GUI processes, @@ -1586,15 +1586,15 @@ void SimpleTargetRunnerPrivate::start() \sa Utils::Process */ -SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl) - : RunWorker(runControl), d(new Internal::SimpleTargetRunnerPrivate(this)) +ProcessRunner::ProcessRunner(RunControl *runControl) + : RunWorker(runControl), d(new Internal::ProcessRunnerPrivate(this)) { - setId("SimpleTargetRunner"); + setId("ProcessRunner"); } -SimpleTargetRunner::~SimpleTargetRunner() = default; +ProcessRunner::~ProcessRunner() = default; -void SimpleTargetRunnerPrivate::forwardDone() +void ProcessRunnerPrivate::forwardDone() { if (m_stopReported) return; @@ -1615,7 +1615,7 @@ void SimpleTargetRunnerPrivate::forwardDone() q->reportStopped(); } -void SimpleTargetRunnerPrivate::forwardStarted() +void ProcessRunnerPrivate::forwardStarted() { const bool isDesktop = m_command.executable().isLocal(); if (isDesktop) { @@ -1628,7 +1628,7 @@ void SimpleTargetRunnerPrivate::forwardStarted() q->reportStarted(); } -void SimpleTargetRunner::start() +void ProcessRunner::start() { d->m_command = runControl()->commandLine(); d->m_workingDirectory = runControl()->workingDirectory(); @@ -1673,53 +1673,53 @@ void SimpleTargetRunner::start() d->start(); } -void SimpleTargetRunner::stop() +void ProcessRunner::stop() { d->m_stopForced = true; d->stop(); } -void SimpleTargetRunner::setStartModifier(const std::function &startModifier) +void ProcessRunner::setStartModifier(const std::function &startModifier) { d->m_startModifier = startModifier; } -CommandLine SimpleTargetRunner::commandLine() const +CommandLine ProcessRunner::commandLine() const { return d->m_command; } -void SimpleTargetRunner::setCommandLine(const Utils::CommandLine &commandLine) +void ProcessRunner::setCommandLine(const Utils::CommandLine &commandLine) { d->m_command = commandLine; } -void SimpleTargetRunner::setEnvironment(const Environment &environment) +void ProcessRunner::setEnvironment(const Environment &environment) { d->m_environment = environment; } -void SimpleTargetRunner::setWorkingDirectory(const FilePath &workingDirectory) +void ProcessRunner::setWorkingDirectory(const FilePath &workingDirectory) { d->m_workingDirectory = workingDirectory; } -void SimpleTargetRunner::setProcessMode(Utils::ProcessMode processMode) +void ProcessRunner::setProcessMode(Utils::ProcessMode processMode) { d->m_process.setProcessMode(processMode); } -Process *SimpleTargetRunner::process() const +Process *ProcessRunner::process() const { return &d->m_process; } -void SimpleTargetRunner::suppressDefaultStdOutHandling() +void ProcessRunner::suppressDefaultStdOutHandling() { d->m_suppressDefaultStdOutHandling = true; } -void SimpleTargetRunner::forceRunOnHost() +void ProcessRunner::forceRunOnHost() { const FilePath executable = d->m_command.executable(); if (!executable.isLocal()) { @@ -2031,11 +2031,11 @@ void addOutputParserFactory(const std::function &runConfigs) +ProcessRunnerFactory::ProcessRunnerFactory(const QList &runConfigs) { - setProduct(); + setProduct(); addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); setSupportedRunConfigs(runConfigs); } diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index e7ca277ea06..4b273191636 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -38,7 +38,7 @@ class Target; namespace Internal { class RunControlPrivate; class RunWorkerPrivate; -class SimpleTargetRunnerPrivate; +class ProcessRunnerPrivate; } // Internal class PROJECTEXPLORER_EXPORT RunWorker : public QObject @@ -277,17 +277,11 @@ private: const std::unique_ptr d; }; - -/** - * A simple TargetRunner for cases where a plain ApplicationLauncher is - * sufficient for running purposes. - */ - -class PROJECTEXPLORER_EXPORT SimpleTargetRunner final : public RunWorker +class PROJECTEXPLORER_EXPORT ProcessRunner final : public RunWorker { public: - explicit SimpleTargetRunner(RunControl *runControl); - ~SimpleTargetRunner() override; + explicit ProcessRunner(RunControl *runControl); + ~ProcessRunner() override; void setStartModifier(const std::function &startModifier); @@ -309,13 +303,13 @@ private: const Utils::ProcessRunData &runnable() const = delete; void setRunnable(const Utils::ProcessRunData &) = delete; - const std::unique_ptr d; + const std::unique_ptr d; }; -class PROJECTEXPLORER_EXPORT SimpleTargetRunnerFactory : public RunWorkerFactory +class PROJECTEXPLORER_EXPORT ProcessRunnerFactory : public RunWorkerFactory { public: - explicit SimpleTargetRunnerFactory(const QList &runConfig); + explicit ProcessRunnerFactory(const QList &runConfig); }; diff --git a/src/plugins/projectexplorer/workspaceproject.cpp b/src/plugins/projectexplorer/workspaceproject.cpp index fbba5d3a556..56872416298 100644 --- a/src/plugins/projectexplorer/workspaceproject.cpp +++ b/src/plugins/projectexplorer/workspaceproject.cpp @@ -437,7 +437,7 @@ class WorkspaceProjectRunWorkerFactory : public RunWorkerFactory public: WorkspaceProjectRunWorkerFactory() { - setProduct(); + setProduct(); addSupportedRunMode(Constants::NORMAL_RUN_MODE); addSupportedRunConfig(WORKSPACE_PROJECT_RUNCONFIG_ID); } diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index e8f6719a0ab..7a53f0427ec 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -178,7 +178,7 @@ void setupPythonRunConfiguration() void setupPythonRunWorker() { - static SimpleTargetRunnerFactory thePythonRunWorkerFactory( + static ProcessRunnerFactory thePythonRunWorkerFactory( {Constants::C_PYTHONRUNCONFIGURATION_ID} ); } diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp index 322b4b2df20..f37ad564a01 100644 --- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp +++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp @@ -178,7 +178,7 @@ LocalQmlPreviewSupportFactory::LocalQmlPreviewSupportFactory() { setId(ProjectExplorer::Constants::QML_PREVIEW_RUN_FACTORY); setProducer([](RunControl *runControl) { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setId("LocalQmlPreviewSupport"); runControl->setQmlChannel(Utils::urlFromLocalSocket()); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index ec416eb38d1..e745af59d7d 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -144,7 +144,7 @@ void QmlProfilerRunner::profilerStateChanged() RunWorker *createLocalQmlProfilerWorker(RunControl *runControl) { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setId("LocalQmlProfilerSupport"); diff --git a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp index 42d6b5b62df..5eca23749db 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp @@ -272,7 +272,7 @@ private: void extensionsInitialized() final { // These rely on the base tool factories being present: - static SimpleTargetRunnerFactory runWorkerFactory{{Constants::QML_RUNCONFIG_ID}}; + static ProcessRunnerFactory runWorkerFactory{{Constants::QML_RUNCONFIG_ID}}; static SimpleQmlProfilerRunnerFactory qmlProfilerRunWorkerFactory{{Constants::QML_RUNCONFIG_ID}}; static SimpleDebugRunnerFactory debugRunWorkerFactory{{Constants::QML_RUNCONFIG_ID}}; static SimplePreviewRunnerFactory previewRunWorkerFactory{{Constants::QML_RUNCONFIG_ID}}; diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index 923c00af4de..bb1489579cd 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -21,7 +21,7 @@ public: QnxQmlProfilerWorkerFactory() { setProducer([](RunControl *runControl) { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setId("QnxQmlProfilerSupport"); worker->appendMessage(Tr::tr("Preparing remote side..."), LogMessageFormat); diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index 1bdabaea923..9470298dc63 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -136,7 +136,7 @@ void showAttachToProcessDialog() debugger->setupPortsGatherer(); debugger->setUseCtrlCStub(true); if (debugger->isCppDebugging()) { - auto pdebugRunner = new SimpleTargetRunner(runControl); + auto pdebugRunner = new ProcessRunner(runControl); pdebugRunner->setId("PDebugRunner"); pdebugRunner->setStartModifier([pdebugRunner, debugger] { const int pdebugPort = debugger->debugChannel().port(); @@ -175,7 +175,7 @@ public: debugger->setupPortsGatherer(); - auto debuggeeRunner = new SimpleTargetRunner(runControl); + auto debuggeeRunner = new ProcessRunner(runControl); debuggeeRunner->setId("QnxDebuggeeRunner"); debuggeeRunner->setStartModifier([debuggeeRunner] { diff --git a/src/plugins/qnx/qnxrunconfiguration.cpp b/src/plugins/qnx/qnxrunconfiguration.cpp index 37092106346..7c866c830a0 100644 --- a/src/plugins/qnx/qnxrunconfiguration.cpp +++ b/src/plugins/qnx/qnxrunconfiguration.cpp @@ -95,7 +95,7 @@ public: void setupQnxRunnning() { static QnxRunConfigurationFactory theQnxRunConfigurationFactory; - static SimpleTargetRunnerFactory theQnxRunWorkerFactory({Constants::QNX_RUNCONFIG_ID}); + static ProcessRunnerFactory theQnxRunWorkerFactory({Constants::QNX_RUNCONFIG_ID}); } } // Qnx::Internal diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 9066f77d52b..aa6ab14c3e4 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -43,7 +43,7 @@ namespace AppManager::Internal { static RunWorker *createInferiorRunner(RunControl *runControl, QmlDebugServicesPreset qmlServices) { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setId(AppManager::Constants::DEBUG_LAUNCHER_ID); worker->setEssential(true); @@ -193,7 +193,7 @@ public: AppManagerRunWorkerFactory() { setProducer([](RunControl *runControl) { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setId("ApplicationManagerPlugin.Run.TargetRunner"); QObject::connect(worker, &RunWorker::stopped, worker, [worker, runControl] { worker->appendMessage( diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp index 69dec931378..dd6c8912bd7 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp @@ -32,7 +32,7 @@ class RemoteLinuxRunWorkerFactory final : public RunWorkerFactory public: RemoteLinuxRunWorkerFactory() { - setProduct(); + setProduct(); addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); addSupportedDeviceType(Constants::GenericLinuxOsType); setSupportedRunConfigs(supportedRunConfigs()); @@ -76,7 +76,7 @@ public: setProducer([](RunControl *runControl) { runControl->requestQmlChannel(); - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); worker->setId("RemoteLinuxQmlToolingSupport"); auto runworker = runControl->createWorker(runnerIdForRunMode(runControl->runMode())); diff --git a/src/plugins/webassembly/webassemblyrunconfiguration.cpp b/src/plugins/webassembly/webassemblyrunconfiguration.cpp index 8783150a55d..89f239ac6a3 100644 --- a/src/plugins/webassembly/webassemblyrunconfiguration.cpp +++ b/src/plugins/webassembly/webassemblyrunconfiguration.cpp @@ -216,7 +216,7 @@ public: EmrunRunWorkerFactory() { setProducer([](RunControl *runControl) { - auto worker = new SimpleTargetRunner(runControl); + auto worker = new ProcessRunner(runControl); runControl->requestWorkerChannel(); worker->setStartModifier([worker, runControl] { From 1285aff18ab132ef040df2cc3cfba6eb82b8d008 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 19 Dec 2024 12:54:31 +0100 Subject: [PATCH 514/989] Callgrind: Remove superfluous action Operate directly on m_startAction. Change-Id: Ib86b2dfff664aeffa683f378d9e490a59f3f40a3 Reviewed-by: hjk --- src/plugins/valgrind/callgrindtool.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 39b73ab491b..68306fee210 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -227,20 +227,17 @@ CallgrindTool::CallgrindTool(QObject *parent) "Callgrind tool to record function calls when a program runs."); if (!Utils::HostOsInfo::isWindowsHost()) { - auto action = new QAction(Tr::tr("Valgrind Function Profiler"), this); - action->setToolTip(toolTip); - menu->addAction(ActionManager::registerAction(action, CallgrindLocalActionId), + m_startAction->setText(Tr::tr("Valgrind Function Profiler")); + m_startAction->setParent(this); + m_startAction->setToolTip(toolTip); + menu->addAction(ActionManager::registerAction(m_startAction, CallgrindLocalActionId), Debugger::Constants::G_ANALYZER_TOOLS); - QObject::connect(action, &QAction::triggered, this, [this, action] { - if (!Debugger::wantRunTool(OptimizedMode, action->text())) + QObject::connect(m_startAction, &QAction::triggered, this, [this] { + if (!Debugger::wantRunTool(OptimizedMode, m_startAction->text())) return; m_perspective.select(); ProjectExplorerPlugin::runStartupProject(CALLGRIND_RUN_MODE); }); - QObject::connect(m_startAction, &QAction::triggered, action, &QAction::triggered); - QObject::connect(m_startAction, &QAction::changed, action, [action, this] { - action->setEnabled(m_startAction->isEnabled()); - }); } auto action = new QAction(Tr::tr("Valgrind Function Profiler (External Application)"), this); From ce24a8d9f6249aa683419937c596f7bf05bd1c0c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 3 Dec 2024 15:54:35 +0100 Subject: [PATCH 515/989] Editor: improve expanding block selection Replace the main cursor with a block selection instead of a normal selection when using alt+shift+LMB. This is more in line with other IDEs and also feels more natural. Change-Id: Id4dba7cec65ddeb34ab525d90a41aebf78457d0d Reviewed-by: Andrii Semkiv Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/texteditor.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 51e9f52374e..ae49dffbf8c 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -7173,9 +7173,23 @@ void TextEditorWidget::mousePressEvent(QMouseEvent *e) const QTextCursor &cursor = cursorForPosition(e->pos()); if (e->modifiers() & Qt::AltModifier && !(e->modifiers() & Qt::ControlModifier)) { if (e->modifiers() & Qt::ShiftModifier) { - QTextCursor c = multiCursor.mainCursor(); - c.setPosition(cursor.position(), QTextCursor::KeepAnchor); - multiCursor.replaceMainCursor(c); + const QTextCursor anchor = multiCursor.takeMainCursor(); + + const TabSettings tabSettings = d->m_document->tabSettings(); + int eventColumn + = tabSettings.columnAt(cursor.block().text(), cursor.positionInBlock()); + if (cursor.positionInBlock() == cursor.block().length() - 1) { + eventColumn += int( + (e->pos().x() - cursorRect(cursor).center().x()) / d->charWidth()); + } + + const int anchorColumn + = tabSettings.columnAt(anchor.block().text(), anchor.positionInBlock()); + const TextEditorWidgetPrivate::BlockSelection blockSelection + = {cursor.blockNumber(), eventColumn, anchor.blockNumber(), anchorColumn}; + + multiCursor.addCursors(d->generateCursorsForBlockSelection(blockSelection)); + setMultiTextCursor(multiCursor); } else { multiCursor.addCursor(cursor); } From f84205dab7a4096c4d8a90194287c5cba69e7514 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 7 Jan 2025 09:53:24 +0100 Subject: [PATCH 516/989] Utils: Don't force an application palette on Qt::ColorScheme::Unknown When using a dark QtC theme on "light" environment and or when using a light QtC theme on a "dark" environment, the application palette is set accordingly. After switching to Qt::ColorScheme-based API, the palette got also set for environments reporting Qt::ColorScheme::Unknown. This change avoids it. Amends: eb4648004faa8121844e2f1b252e63e2e1bfc57f Change-Id: Ibb5dcd02aff6e665a59fd4f67407f00a9ff6e9b0 Reviewed-by: hjk --- src/libs/utils/theme/theme.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/theme/theme.cpp b/src/libs/utils/theme/theme.cpp index 9dd8798e8ae..292a317228c 100644 --- a/src/libs/utils/theme/theme.cpp +++ b/src/libs/utils/theme/theme.cpp @@ -46,9 +46,9 @@ static bool isOverridingPalette(const Theme *theme) { if (theme->flag(Theme::DerivePaletteFromTheme)) return true; - if (theme->flag(Theme::DerivePaletteFromThemeIfNeeded) - && qGuiApp->styleHints()->colorScheme() != theme->colorScheme()) { - return true; + if (theme->flag(Theme::DerivePaletteFromThemeIfNeeded)) { + const Qt::ColorScheme systemTheme = qGuiApp->styleHints()->colorScheme(); + return systemTheme != Qt::ColorScheme::Unknown && systemTheme != theme->colorScheme(); } return false; } From 79542bb6d16bda7d9c261e96f4df3076fac27997 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 2 Jan 2025 15:03:09 +0100 Subject: [PATCH 517/989] PerfProfiler: Replace LocalPerfRecordWorker::recorder with property Do it temporarily. In a followup patch the LocalPerfRecordWorker is going to be replaced by ProcessRunner. Change-Id: I88dc0624b19aa105efce6b0d36d530296214c132 Reviewed-by: Ulf Hermann Reviewed-by: hjk --- src/plugins/perfprofiler/perfprofilerruncontrol.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp index 78348d411c7..69949e5e670 100644 --- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp +++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp @@ -97,6 +97,7 @@ public: void start() final { m_process = new Process(this); + runControl()->setProperty("PerfProcess", QVariant::fromValue(m_process.get())); connect(m_process, &Process::started, this, &RunWorker::reportStarted); connect(m_process, &Process::done, this, [this] { @@ -136,8 +137,6 @@ public: m_process->terminate(); } - Process *recorder() { return m_process; } - private: QPointer m_process; }; @@ -185,13 +184,7 @@ public: &PerfProfilerTool::onRunControlFinished); PerfDataReader *reader = m_perfParserWorker->reader(); - Process *perfProcess = nullptr; - if (auto prw = qobject_cast(m_perfRecordWorker)) { - // That's the local case. - perfProcess = prw->recorder(); - } else { - perfProcess = runControl()->property("PerfProcess").value(); - } + Process *perfProcess = runControl()->property("PerfProcess").value(); if (perfProcess) { connect(perfProcess, &Process::readyReadStandardError, this, [this, perfProcess] { From 543acde1c843b732d216a90b61addf4eb5d9a0f3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 2 Jan 2025 15:34:22 +0100 Subject: [PATCH 518/989] PerfProfiler: Get rid of LocalPerfRecordWorker Use ProcessRunner instead. Task-number: QTCREATORBUG-29168 Change-Id: Id0ef0590fb807dfc3476742cd69f7cd98b11d2f8 Reviewed-by: Ulf Hermann Reviewed-by: hjk --- .../perfprofiler/perfprofilerruncontrol.cpp | 88 +++++-------------- src/plugins/projectexplorer/runcontrol.h | 2 + .../appmanagerruncontrol.cpp | 4 +- 3 files changed, 24 insertions(+), 70 deletions(-) diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp index 69949e5e670..a56fe7603c3 100644 --- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp +++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp @@ -83,64 +83,6 @@ private: PerfDataReader m_reader; }; -class LocalPerfRecordWorker final : public RunWorker -{ - Q_OBJECT - -public: - LocalPerfRecordWorker(RunControl *runControl) - : RunWorker(runControl) - { - setId("LocalPerfRecordWorker"); - } - - void start() final - { - m_process = new Process(this); - runControl()->setProperty("PerfProcess", QVariant::fromValue(m_process.get())); - - connect(m_process, &Process::started, this, &RunWorker::reportStarted); - connect(m_process, &Process::done, this, [this] { - // The terminate() below will frequently lead to QProcess::Crashed. We're not interested - // in that. FailedToStart is the only actual failure. - if (m_process->error() == QProcess::FailedToStart) { - const QString msg = Tr::tr("Perf Process Failed to Start"); - QMessageBox::warning(Core::ICore::dialogParent(), msg, - Tr::tr("Make sure that you are running a recent Linux kernel " - "and that the \"perf\" utility is available.")); - reportFailure(msg); - return; - } - if (!m_process->cleanedStdErr().isEmpty()) - appendMessage(m_process->cleanedStdErr(), StdErrFormat); - reportStopped(); - }); - - const Store perfArgs = runControl()->settingsData(PerfProfiler::Constants::PerfSettingsId); - const QString recordArgs = perfArgs[Constants::PerfRecordArgsId].toString(); - - CommandLine cmd({device()->filePath("perf"), {"record"}}); - cmd.addArgs(recordArgs, CommandLine::Raw); - cmd.addArgs({"-o", "-", "--"}); - cmd.addCommandLineAsArgs(runControl()->commandLine(), CommandLine::Raw); - - m_process->setCommand(cmd); - m_process->setWorkingDirectory(runControl()->workingDirectory()); - m_process->setEnvironment(runControl()->environment()); - appendMessage("Starting Perf: " + cmd.toUserOutput(), NormalMessageFormat); - m_process->start(); - } - - void stop() final - { - if (m_process) - m_process->terminate(); - } - -private: - QPointer m_process; -}; - class PerfProfilerRunner final : public RunWorker { public: @@ -155,20 +97,34 @@ public: // If the parser is gone, there is no point in going on. m_perfParserWorker->setEssential(true); - if ((m_perfRecordWorker = runControl->createWorker("PerfRecorder"))) { + if ((m_perfRecordWorker = qobject_cast(runControl->createWorker("PerfRecorder")))) { m_perfParserWorker->addStartDependency(m_perfRecordWorker); - addStartDependency(m_perfParserWorker); - } else { - m_perfRecordWorker = new LocalPerfRecordWorker(runControl); + m_perfRecordWorker = new ProcessRunner(runControl); + m_perfRecordWorker->suppressDefaultStdOutHandling(); + + m_perfRecordWorker->setStartModifier([this, runControl] { + const Store perfArgs = runControl->settingsData(PerfProfiler::Constants::PerfSettingsId); + const QString recordArgs = perfArgs[Constants::PerfRecordArgsId].toString(); + + CommandLine cmd({device()->filePath("perf"), {"record"}}); + cmd.addArgs(recordArgs, CommandLine::Raw); + cmd.addArgs({"-o", "-", "--"}); + cmd.addCommandLineAsArgs(runControl->commandLine(), CommandLine::Raw); + + m_perfRecordWorker->setCommandLine(cmd); + m_perfRecordWorker->setWorkingDirectory(runControl->workingDirectory()); + m_perfRecordWorker->setEnvironment(runControl->environment()); + appendMessage("Starting Perf: " + cmd.toUserOutput(), NormalMessageFormat); + }); m_perfRecordWorker->addStartDependency(m_perfParserWorker); - addStartDependency(m_perfRecordWorker); // In the local case, the parser won't automatically stop when the recorder does. So we need // to mark the recorder as essential, too. m_perfRecordWorker->setEssential(true); } + addStartDependency(m_perfRecordWorker); m_perfParserWorker->addStopDependency(m_perfRecordWorker); PerfProfilerTool::instance()->onWorkerCreation(runControl); @@ -184,7 +140,7 @@ public: &PerfProfilerTool::onRunControlFinished); PerfDataReader *reader = m_perfParserWorker->reader(); - Process *perfProcess = runControl()->property("PerfProcess").value(); + Process *perfProcess = m_perfRecordWorker->process(); if (perfProcess) { connect(perfProcess, &Process::readyReadStandardError, this, [this, perfProcess] { @@ -202,7 +158,7 @@ public: private: PerfParserWorker *m_perfParserWorker = nullptr; - RunWorker *m_perfRecordWorker = nullptr; + ProcessRunner *m_perfRecordWorker = nullptr; }; // PerfProfilerRunWorkerFactory @@ -223,5 +179,3 @@ void setupPerfProfilerRunWorker() } } // PerfProfiler::Internal - -#include "perfprofilerruncontrol.moc" diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 4b273191636..c2199f88303 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -279,6 +279,8 @@ private: class PROJECTEXPLORER_EXPORT ProcessRunner final : public RunWorker { + Q_OBJECT + public: explicit ProcessRunner(RunControl *runControl); ~ProcessRunner() override; diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index aa6ab14c3e4..1771bb96ef6 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -47,10 +47,8 @@ static RunWorker *createInferiorRunner(RunControl *runControl, QmlDebugServicesP worker->setId(AppManager::Constants::DEBUG_LAUNCHER_ID); worker->setEssential(true); - if (worker->usesPerfChannel()) { + if (worker->usesPerfChannel()) worker->suppressDefaultStdOutHandling(); - runControl->setProperty("PerfProcess", QVariant::fromValue(worker->process())); - } worker->setStartModifier([worker, runControl, qmlServices] { FilePath controller = runControl->aspectData()->filePath; From a822f6db982458b2387b8c82480d45159ce9a6b8 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 6 Jan 2025 11:58:25 +0100 Subject: [PATCH 519/989] LanguageClient: remove indirect QString::toUtf8/fromUtf8 roundtrip Change-Id: I80146250cf5be5d408c30337869dd5baed923d5a Reviewed-by: Christian Stenger --- src/plugins/languageclient/lspinspector.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/languageclient/lspinspector.cpp b/src/plugins/languageclient/lspinspector.cpp index 685d5abce86..dcec7d0d599 100644 --- a/src/plugins/languageclient/lspinspector.cpp +++ b/src/plugins/languageclient/lspinspector.cpp @@ -489,8 +489,7 @@ LspInspectorWidget::LspInspectorWidget(LspInspector *inspector) for (Client *client : clients) { errMsg += sendMessage( client, - Utils::globalMacroExpander()->expand( - QString::fromUtf8(messageEditor->document()->contents()))); + Utils::globalMacroExpander()->expand(messageEditor->textDocument()->plainText())); } errorLabel->setText(errMsg); }; From ac5ca391ddcd706d58edd84a365dbc7abfe0745f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 6 Jan 2025 12:00:34 +0100 Subject: [PATCH 520/989] QmlEditor: remove indirect QString::toUtf8/fromUtf8 roundtrip Change-Id: Ie83ba8ff03834f10ef1b4d23827141817deb1bf3 Reviewed-by: Christian Stenger --- src/plugins/qmljseditor/qmljseditorplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp index 0678d79b383..7bb446ab9f2 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.cpp +++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp @@ -226,7 +226,7 @@ void QmlJSEditorPluginPrivate::reformatFile() QmlJS::Document::MutablePtr latestDocument; const Utils::FilePath fileName = m_currentDocument->filePath(); - latestDocument = snapshot.documentFromSource(QString::fromUtf8(m_currentDocument->contents()), + latestDocument = snapshot.documentFromSource(m_currentDocument->plainText(), fileName, QmlJS::ModelManagerInterface::guessLanguageOfFile(fileName)); latestDocument->parseQml(); From 49a66abf1f6afcf59df9376f656d6037fb234865 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 2 Jan 2025 15:50:54 +0100 Subject: [PATCH 521/989] PE: Get rid of ProcessRunner::process() Provide stdOutData() signal instead. Change-Id: Ie89c64c67ea383a9f2265bad3b527d3337342656 Reviewed-by: hjk --- .../perfprofiler/perfprofilerruncontrol.cpp | 17 +++++------------ src/plugins/projectexplorer/runcontrol.cpp | 15 +++------------ src/plugins/projectexplorer/runcontrol.h | 4 +++- 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp index a56fe7603c3..e0f200eae8b 100644 --- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp +++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp @@ -140,18 +140,11 @@ public: &PerfProfilerTool::onRunControlFinished); PerfDataReader *reader = m_perfParserWorker->reader(); - Process *perfProcess = m_perfRecordWorker->process(); - - if (perfProcess) { - connect(perfProcess, &Process::readyReadStandardError, this, [this, perfProcess] { - appendMessage(QString::fromLocal8Bit(perfProcess->readAllRawStandardError()), - StdErrFormat); - }); - connect(perfProcess, &Process::readyReadStandardOutput, this, [this, reader, perfProcess] { - if (!reader->feedParser(perfProcess->readAllRawStandardOutput())) - reportFailure(Tr::tr("Failed to transfer Perf data to perfparser.")); - }); - } + connect(m_perfRecordWorker, &ProcessRunner::stdOutData, + this, [this, reader](const QByteArray &data) { + if (!reader->feedParser(data)) + reportFailure(Tr::tr("Failed to transfer Perf data to perfparser.")); + }); reportStarted(); } diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 22d0f538ce5..52819edb0a3 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1512,17 +1512,13 @@ void ProcessRunnerPrivate::handleDone() void ProcessRunnerPrivate::handleStandardOutput() { if (m_suppressDefaultStdOutHandling) - return; - - const QString msg = m_process.readAllStandardOutput(); - q->appendMessage(msg, StdOutFormat, false); + emit q->stdOutData(m_process.readAllRawStandardOutput()); + else + q->appendMessage(m_process.readAllStandardOutput(), StdOutFormat, false); } void ProcessRunnerPrivate::handleStandardError() { - if (m_suppressDefaultStdOutHandling) - return; - const QString msg = m_process.readAllStandardError(); q->appendMessage(msg, StdErrFormat, false); } @@ -1709,11 +1705,6 @@ void ProcessRunner::setProcessMode(Utils::ProcessMode processMode) d->m_process.setProcessMode(processMode); } -Process *ProcessRunner::process() const -{ - return &d->m_process; -} - void ProcessRunner::suppressDefaultStdOutHandling() { d->m_suppressDefaultStdOutHandling = true; diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index c2199f88303..60794cb80ff 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -293,11 +293,13 @@ public: void setEnvironment(const Utils::Environment &environment); void setWorkingDirectory(const Utils::FilePath &workingDirectory); void setProcessMode(Utils::ProcessMode processMode); - Utils::Process *process() const; void suppressDefaultStdOutHandling(); void forceRunOnHost(); +signals: + void stdOutData(const QByteArray &data); + private: void start() final; void stop() final; From da475f400dcf1cf309d0d1622f57b76a136db281 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Jan 2025 15:33:53 +0100 Subject: [PATCH 522/989] QmlProfiler: Simplify QmlProfilerRunner Remove registerProfilerStateManager() and connect to state manager's signal directly from the start() function. Remove Q_OBJECT macro. Change-Id: Id03486f077c81909fbe0889bb342ee7595631e9d Reviewed-by: Ulf Hermann Reviewed-by: hjk --- .../qmlprofiler/qmlprofilerruncontrol.cpp | 41 +++++-------------- .../qmlprofiler/qmlprofilerruncontrol.h | 7 ---- src/plugins/qmlprofiler/qmlprofilertool.cpp | 5 +-- 3 files changed, 13 insertions(+), 40 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index e745af59d7d..5b12e2e2f5d 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -3,6 +3,7 @@ #include "qmlprofilerruncontrol.h" +#include "qmlprofilerstatemanager.h" #include "qmlprofilertool.h" #include @@ -23,8 +24,6 @@ #include #include -#include - using namespace Core; using namespace ProjectExplorer; @@ -61,9 +60,17 @@ QmlProfilerRunner::~QmlProfilerRunner() void QmlProfilerRunner::start() { - if (!d->m_profilerState) - QmlProfilerTool::instance()->finalizeRunControl(this); + if (d->m_profilerState) + disconnect(d->m_profilerState, &QmlProfilerStateManager::stateChanged, this, nullptr); + + QmlProfilerTool::instance()->finalizeRunControl(this); + d->m_profilerState = QmlProfilerTool::instance()->stateManager(); QTC_ASSERT(d->m_profilerState, return); + + connect(d->m_profilerState, &QmlProfilerStateManager::stateChanged, this, [this] { + if (d->m_profilerState->currentState() == QmlProfilerStateManager::Idle) + reportStopped(); + }); reportStarted(); } @@ -116,32 +123,6 @@ void QmlProfilerRunner::cancelProcess() runControl()->initiateStop(); } -void QmlProfilerRunner::registerProfilerStateManager( QmlProfilerStateManager *profilerState ) -{ - // disconnect old - if (d->m_profilerState) - disconnect(d->m_profilerState, &QmlProfilerStateManager::stateChanged, - this, &QmlProfilerRunner::profilerStateChanged); - - d->m_profilerState = profilerState; - - // connect - if (d->m_profilerState) - connect(d->m_profilerState, &QmlProfilerStateManager::stateChanged, - this, &QmlProfilerRunner::profilerStateChanged); -} - -void QmlProfilerRunner::profilerStateChanged() -{ - switch (d->m_profilerState->currentState()) { - case QmlProfilerStateManager::Idle: - reportStopped(); - break; - default: - break; - } -} - RunWorker *createLocalQmlProfilerWorker(RunControl *runControl) { auto worker = new ProcessRunner(runControl); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h index dcc374c9892..f2a4ea1656f 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h @@ -3,8 +3,6 @@ #pragma once -#include "qmlprofilerstatemanager.h" - #include #include @@ -18,21 +16,16 @@ namespace Internal { class QmlProfilerRunner : public ProjectExplorer::RunWorker { - Q_OBJECT - public: QmlProfilerRunner(ProjectExplorer::RunControl *runControl); ~QmlProfilerRunner() override; - void registerProfilerStateManager( QmlProfilerStateManager *profilerState ); void cancelProcess(); private: void start() override; void stop() override; - void profilerStateChanged(); - class QmlProfilerRunnerPrivate; QmlProfilerRunnerPrivate *d; }; diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index efc3fcd0641..810d373887f 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -178,7 +178,7 @@ QmlProfilerTool::QmlProfilerTool() d->m_clearButton->setIcon(Utils::Icons::CLEAN_TOOLBAR.icon()); d->m_clearButton->setToolTip(Tr::tr("Discard data")); - connect(d->m_clearButton, &QAbstractButton::clicked, [this](){ + connect(d->m_clearButton, &QAbstractButton::clicked, [this] { if (checkForUnsavedNotes()) clearData(); }); @@ -382,7 +382,6 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunner *runWorker) connect(d->m_stopAction, &QAction::triggered, runControl, &RunControl::initiateStop); updateRunActions(); - runWorker->registerProfilerStateManager(d->m_profilerState); // // Initialize m_projectFinder @@ -391,7 +390,7 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunner *runWorker) d->m_profilerModelManager->populateFileFinder(runControl->target()); connect(d->m_profilerConnections, &QmlProfilerClientManager::connectionFailed, - runWorker, [this, runWorker]() { + runWorker, [this, runWorker] { auto infoBox = new QMessageBox(ICore::dialogParent()); infoBox->setIcon(QMessageBox::Critical); infoBox->setWindowTitle(QGuiApplication::applicationDisplayName()); From 2ddfd1f273a5951257017c4a194d1768f91f193d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 2 Jan 2025 16:28:53 +0100 Subject: [PATCH 523/989] ProfProfiler: Simplify setting dependency Change-Id: I75feca18c52454515c1004e3f82d10fb1aa87d9a Reviewed-by: hjk --- src/plugins/perfprofiler/perfprofilerruncontrol.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp index e0f200eae8b..de54818cf0b 100644 --- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp +++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp @@ -96,10 +96,9 @@ public: // If the parser is gone, there is no point in going on. m_perfParserWorker->setEssential(true); + m_perfRecordWorker = qobject_cast(runControl->createWorker("PerfRecorder")); - if ((m_perfRecordWorker = qobject_cast(runControl->createWorker("PerfRecorder")))) { - m_perfParserWorker->addStartDependency(m_perfRecordWorker); - } else { + if (!m_perfRecordWorker) { m_perfRecordWorker = new ProcessRunner(runControl); m_perfRecordWorker->suppressDefaultStdOutHandling(); @@ -118,14 +117,13 @@ public: appendMessage("Starting Perf: " + cmd.toUserOutput(), NormalMessageFormat); }); - m_perfRecordWorker->addStartDependency(m_perfParserWorker); - // In the local case, the parser won't automatically stop when the recorder does. So we need // to mark the recorder as essential, too. m_perfRecordWorker->setEssential(true); } addStartDependency(m_perfRecordWorker); + m_perfParserWorker->addStartDependency(m_perfRecordWorker); m_perfParserWorker->addStopDependency(m_perfRecordWorker); PerfProfilerTool::instance()->onWorkerCreation(runControl); } From 5fa27341fec78c98966b5b5cae97f93824309278 Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Mon, 6 Jan 2025 15:20:34 +0100 Subject: [PATCH 524/989] qmllsclient: fix initialization options When qmlls is started from the shared interface LanguageClientManager, initializationOptions are passed from the settings. Amends a737828d7d6b385ef09355e0c56b4ff9620b4f0a Change-Id: I9a92b185e9ebc1f5726a8c9f69a2cb2a55658a70 Reviewed-by: Sami Shalayel --- src/plugins/qmljseditor/qmllsclient.cpp | 4 ---- src/plugins/qmljseditor/qmllsclientsettings.cpp | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/qmljseditor/qmllsclient.cpp b/src/plugins/qmljseditor/qmllsclient.cpp index 9749ccd7d6d..f6407114170 100644 --- a/src/plugins/qmljseditor/qmllsclient.cpp +++ b/src/plugins/qmljseditor/qmllsclient.cpp @@ -141,10 +141,6 @@ QmllsClient::QmllsClient(StdIOClientInterface *interface) &ProjectExplorer::BuildManager::buildQueueFinished, this, [this]() { LanguageClientManager::restartClient(this); }); - QJsonObject initializationOptions { - {"qtCreatorHighlighting", true} - }; - setInitializationOptions(initializationOptions); semanticTokenSupport()->setTokenTypesMap(QmllsClient::semanticTokenTypesMap()); semanticTokenSupport()->setTextStyleForTokenType( [](int tokenType) -> std::optional { diff --git a/src/plugins/qmljseditor/qmllsclientsettings.cpp b/src/plugins/qmljseditor/qmllsclientsettings.cpp index 4a7a72b2b93..13f76093087 100644 --- a/src/plugins/qmljseditor/qmllsclientsettings.cpp +++ b/src/plugins/qmljseditor/qmllsclientsettings.cpp @@ -64,6 +64,7 @@ QmllsClientSettings::QmllsClientSettings() m_settingsTypeId = Constants::QMLLS_CLIENT_SETTINGS_ID; m_startBehavior = RequiresProject; + m_initializationOptions = "{\"qtCreatorHighlighting\": true}"; } static QtVersion *qtVersionFromProject(const Project *project) From 94c43600852a0d018cb82f46c6549960f182dca8 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 12 Dec 2024 11:50:31 +0100 Subject: [PATCH 525/989] Python: optimize the pip and venv checks Those checks can take an considerable amount of time. So instead of running them the first time we want to check this info run them in the background as soon as we have loaded the python settings. Change-Id: I287acd2a5fd7b053873257238f7dfbaa9cf00170 Reviewed-by: Christian Stenger --- src/plugins/python/pythonsettings.cpp | 17 +++++++++--- src/plugins/python/pythonutils.cpp | 39 ++++++++++++++++----------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index e9fbff36b10..bc6eebc7885 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -855,11 +855,18 @@ QString PythonSettings::pylsConfiguration() return settingsInstance->m_pylsConfiguration; } +static void cacheVenvAndPipUsability(const Interpreter &interpreter) +{ + Utils::asyncRun(&venvIsUsable, interpreter.command); + Utils::asyncRun(&pipIsUsable, interpreter.command); +} + void PythonSettings::addInterpreter(const Interpreter &interpreter, bool isDefault) { if (Utils::anyOf(settingsInstance->m_interpreters, Utils::equal(&Interpreter::id, interpreter.id))) return; settingsInstance->m_interpreters.append(interpreter); + cacheVenvAndPipUsability(interpreter); if (isDefault) settingsInstance->m_defaultInterpreterId = interpreter.id; saveSettings(); @@ -1026,8 +1033,12 @@ void PythonSettings::initFromSettings(QtcSettings *settings) const auto [valid, outdatedInterpreters] = Utils::partition(m_interpreters, keepInterpreter); m_interpreters = valid; - if (!settings->value(kitsGeneratedKey, false).toBool()) { - for (const Interpreter &interpreter : m_interpreters) { + const bool kitsGenerated = settings->value(kitsGeneratedKey, false).toBool(); + if (kitsGenerated) + fixupPythonKits(); + for (const Interpreter &interpreter : std::as_const(m_interpreters)) { + cacheVenvAndPipUsability(interpreter); + if (!kitsGenerated) { if (interpreter.autoDetected) { const FilePath &cmd = interpreter.command; if (!cmd.isLocal() || cmd.parentDir().pathAppended("activate").exists()) @@ -1035,8 +1046,6 @@ void PythonSettings::initFromSettings(QtcSettings *settings) } addKitsForInterpreter(interpreter, false); } - } else { - fixupPythonKits(); } for (const Interpreter &outdated : outdatedInterpreters) diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 04144a3e41b..efcfc4940a5 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -192,31 +193,37 @@ bool isVenvPython(const FilePath &python) return python.parentDir().parentDir().pathAppended("pyvenv.cfg").exists(); } -static bool isUsableHelper(QHash *cache, const QString &keyString, - const QString &commandArg, const FilePath &python) +static bool isUsableHelper( + SynchronizedValue> *cache, + const QString &commandArg, + const FilePath &python) { - auto it = cache->find(python); - if (it == cache->end()) { - const Key key = keyFromString(keyString); - Process process; - process.setCommand({python, {"-m", commandArg, "-h"}}); - process.runBlocking(); - const bool usable = process.result() == ProcessResult::FinishedWithSuccess; - it = cache->insert(python, usable); - } - return *it; + std::optional result; + cache->read([&result, python](const QHash &cache) { + if (auto it = cache.find(python); it != cache.end()) + result = it.value(); + }); + if (result) + return *result; + + Process process; + process.setCommand({python, {"-m", commandArg, "-h"}}); + process.runBlocking(); + const bool usable = process.result() == ProcessResult::FinishedWithSuccess; + cache->writeLocked()->insert(python, usable); + return usable; } bool venvIsUsable(const FilePath &python) { - static QHash cache; - return isUsableHelper(&cache, "pyVenvIsUsable", "venv", python); + static SynchronizedValue> cache; + return isUsableHelper(&cache, "venv", python); } bool pipIsUsable(const FilePath &python) { - static QHash cache; - return isUsableHelper(&cache, "pyPipIsUsable", "pip", python); + static SynchronizedValue> cache; + return isUsableHelper(&cache, "pip", python); } QString pythonVersion(const FilePath &python) From 00cef252c5defc312feb7449a7ebb3ec6f99b459 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 13 Dec 2024 14:32:28 +0100 Subject: [PATCH 526/989] Editor: add text style for diagnostic info Fixes: QTCREATORBUG-32163 Change-Id: Ifc066c7845afa3374f97c278e4481d81bfcc67c2 Reviewed-by: Sami Shalayel Reviewed-by: Alessandro Portale --- share/qtcreator/styles/creator-dark.xml | 2 ++ share/qtcreator/styles/dark-2024.xml | 2 ++ share/qtcreator/styles/dark.xml | 2 ++ share/qtcreator/styles/default_classic.xml | 2 ++ share/qtcreator/styles/grayscale.xml | 2 ++ share/qtcreator/styles/mabakor.xml | 2 ++ share/qtcreator/styles/solarized-dark.xml | 2 ++ share/qtcreator/styles/solarized-light.xml | 2 ++ src/plugins/languageclient/diagnosticmanager.cpp | 2 ++ src/plugins/texteditor/texteditorconstants.cpp | 2 ++ src/plugins/texteditor/texteditorconstants.h | 2 ++ src/plugins/texteditor/texteditorsettings.cpp | 12 ++++++++++++ 12 files changed, 34 insertions(+) diff --git a/share/qtcreator/styles/creator-dark.xml b/share/qtcreator/styles/creator-dark.xml index 088feb7a2ed..275290c4319 100644 --- a/share/qtcreator/styles/creator-dark.xml +++ b/share/qtcreator/styles/creator-dark.xml @@ -68,6 +68,8 @@